NeoMutt  2025-12-11-177-g48e272
Teaching an old dog new tricks
DOXYGEN
Loading...
Searching...
No Matches
send.c File Reference

Prepare and send an email. More...

#include "config.h"
#include <errno.h>
#include <locale.h>
#include <stdbool.h>
#include <stdio.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/types.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 "attach/lib.h"
#include "browser/lib.h"
#include "compose/lib.h"
#include "editor/lib.h"
#include "expando/lib.h"
#include "history/lib.h"
#include "hooks/lib.h"
#include "imap/lib.h"
#include "index/lib.h"
#include "ncrypt/lib.h"
#include "pager/lib.h"
#include "pattern/lib.h"
#include "postpone/lib.h"
#include "question/lib.h"
#include "body.h"
#include "expando_greeting.h"
#include "expando_msgid.h"
#include "globals.h"
#include "header.h"
#include "multipart.h"
#include "mutt_logging.h"
#include "muttlib.h"
#include "mx.h"
#include "nntp/mdata.h"
#include "sendlib.h"
#include "sendmail.h"
#include "smtp.h"
#include "notmuch/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.
 
static void remove_user (struct AddressList *al, bool leave_only)
 Remove any address which matches the current user.
 
static void add_mailing_lists (struct AddressList *out, const struct AddressList *t, const struct AddressList *c)
 Search Address lists for mailing lists.
 
int mutt_edit_address (struct AddressList *al, const char *field, bool expand_aliases)
 Edit an email address.
 
static int edit_envelope (struct Envelope *en, SendFlags flags, struct ConfigSubset *sub)
 Edit Envelope fields.
 
static char * nntp_get_header (const char *s)
 Get the trimmed header.
 
static void process_user_recips (struct Envelope *env)
 Process the user headers.
 
static void process_user_header (struct Envelope *env)
 Process the user headers.
 
void mutt_forward_intro (struct Email *e, FILE *fp, struct ConfigSubset *sub)
 Add the "start of forwarded message" text.
 
void mutt_forward_trailer (struct Email *e, FILE *fp, struct ConfigSubset *sub)
 Add a "end of forwarded message" text.
 
static int include_forward (struct Mailbox *m, struct Email *e, FILE *fp_out, struct ConfigSubset *sub)
 Write out a forwarded message.
 
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.
 
static void format_attribution (const struct Expando *exp, struct Email *e, FILE *fp_out, struct ConfigSubset *sub)
 Format an attribution prefix/suffix.
 
void mutt_make_attribution_intro (struct Email *e, FILE *fp_out, struct ConfigSubset *sub)
 Add "on DATE, PERSON wrote" header.
 
void mutt_make_attribution_trailer (struct Email *e, FILE *fp_out, struct ConfigSubset *sub)
 Add suffix to replied email text.
 
static void mutt_make_greeting (struct Email *e, FILE *fp_out, struct ConfigSubset *sub)
 Add greetings string.
 
static int include_reply (struct Mailbox *m, struct Email *e, FILE *fp_out, struct ConfigSubset *sub)
 Generate the reply text for an email.
 
static const struct AddressList * choose_default_to (const struct Address *from, const struct Envelope *env, struct ConfigSubset *sub)
 Pick the best 'to:' value.
 
static int default_to (struct AddressList *to, struct Envelope *env, SendFlags flags, int hmfupto, struct ConfigSubset *sub)
 Generate default email addresses.
 
int mutt_fetch_recips (struct Envelope *out, struct Envelope *in, SendFlags flags, struct ConfigSubset *sub)
 Generate recpients for a reply email.
 
static void add_references (struct ListHead *head, struct Envelope *env)
 Add the email's references to a list.
 
static void add_message_id (struct ListHead *head, struct Envelope *env)
 Add the email's message ID to a list.
 
void mutt_fix_reply_recipients (struct Envelope *env, struct ConfigSubset *sub)
 Remove duplicate recipients.
 
void mutt_make_forward_subject (struct Envelope *env, struct Email *e, struct ConfigSubset *sub)
 Create a subject for a forwarded email.
 
void mutt_make_misc_reply_headers (struct Envelope *env, struct Envelope *env_cur, struct ConfigSubset *sub)
 Set subject for a reply.
 
void mutt_add_to_reference_headers (struct Envelope *env, struct Envelope *env_cur, struct ConfigSubset *sub)
 Generate references for a reply email.
 
static void make_reference_headers (struct EmailArray *ea, struct Envelope *env, struct ConfigSubset *sub)
 Generate reference headers for an email.
 
static int envelope_defaults (struct Envelope *env, struct EmailArray *ea, SendFlags flags, struct ConfigSubset *sub)
 Fill in some defaults for a new email.
 
static int generate_body (FILE *fp_tmp, struct Email *e, SendFlags flags, struct Mailbox *m, struct EmailArray *ea, struct ConfigSubset *sub)
 Create a new email body.
 
void mutt_set_followup_to (struct Envelope *env, struct ConfigSubset *sub)
 Set followup-to field.
 
static void set_reverse_name (struct AddressList *al, struct Envelope *env, struct ConfigSubset *sub)
 Try to set the 'from' field from the recipients.
 
struct Addressmutt_default_from (struct ConfigSubset *sub)
 Get a default 'from' Address.
 
static int invoke_mta (struct Mailbox *m, struct Email *e, struct ConfigSubset *sub)
 Send an email.
 
void mutt_encode_descriptions (struct Body *b, bool recurse, struct ConfigSubset *sub)
 RFC2047 encode the content-descriptions.
 
static void decode_descriptions (struct Body *b)
 RFC2047 decode them in case of an error.
 
static void fix_end_of_file (const char *data)
 Ensure a file ends with a linefeed.
 
int mutt_resend_message (FILE *fp, struct Mailbox *m, struct Email *e_cur, struct ConfigSubset *sub)
 Resend an email.
 
static bool is_reply (struct Email *reply, struct Email *orig)
 Is one email a reply to another?
 
static bool search_attach_keyword (char *filename, struct ConfigSubset *sub)
 Search an email for 'attachment' keywords.
 
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.
 
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.
 
static bool is_text_plain (const struct Body *b)
 Is a Body a text/plain MIME part?
 
static bool abort_for_missing_attachments (const struct Body *b, struct ConfigSubset *sub)
 Should we abort sending because of missing attachments?
 
int mutt_send_message (SendFlags flags, struct Email *e_templ, const char *tempfile, struct Mailbox *m, struct EmailArray *ea, struct ConfigSubset *sub)
 Send an email.
 
static bool send_simple_email (struct Mailbox *m, struct EmailArray *ea, const char *mailto, const char *subj, const char *body)
 Compose an email given a few basic ingredients.
 
bool mutt_send_list_subscribe (struct Mailbox *m, struct Email *e)
 Send a mailing-list subscription email.
 
bool mutt_send_list_unsubscribe (struct Mailbox *m, struct Email *e)
 Send a mailing-list unsubscription email.
 

Detailed Description

Prepare and send an email.

Authors
  • Richard Russon
  • Pietro Cerutti
  • Jakub Jindra
  • Thomas Sanchez
  • Ashish Panigrahi
  • Charalampos Kardaris
  • Thomas Bracht Laumann Jespersen
  • Viktor Cheburkin
  • David Purton
  • Dennis Schön
  • Whitney Cumber
  • наб
  • Alejandro Colomar
  • Tóth János

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 99 of file send.c.

100{
101 const char *const c_signature = cs_subset_path(sub, "signature");
102 if (!c_signature)
103 return;
104
105 // If the user hasn't set $signature, don't warn them if it doesn't exist
106 struct Buffer *def_sig = buf_pool_get();
107 cs_str_initial_get(sub->cs, "signature", def_sig);
108 mutt_path_canon(def_sig, NeoMutt->home_dir, false);
109 bool notify_missing = !mutt_str_equal(c_signature, buf_string(def_sig));
110 buf_pool_release(&def_sig);
111
112 pid_t pid = 0;
113 FILE *fp_tmp = mutt_open_read(c_signature, &pid);
114 if (!fp_tmp)
115 {
116 if (notify_missing)
117 mutt_perror("%s", c_signature);
118 return;
119 }
120
121 const bool c_sig_dashes = cs_subset_bool(sub, "sig_dashes");
122 if (c_sig_dashes)
123 fputs("\n-- \n", fp);
124 mutt_file_copy_stream(fp_tmp, fp);
125 mutt_file_fclose(&fp_tmp);
126 if (pid != -1)
127 filter_wait(pid);
128}
static const char * buf_string(const struct Buffer *buf)
Convert a buffer to a const char * "string".
Definition buffer.h:96
const char * cs_subset_path(const struct ConfigSubset *sub, const char *name)
Get a path config item by name.
Definition helpers.c:168
bool cs_subset_bool(const struct ConfigSubset *sub, const char *name)
Get a boolean config item by name.
Definition helpers.c:47
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:594
int mutt_file_copy_stream(FILE *fp_in, FILE *fp_out)
Copy the contents of one file into another.
Definition file.c:226
#define mutt_file_fclose(FP)
Definition file.h:139
#define mutt_perror(...)
Definition logging2.h:95
int filter_wait(pid_t pid)
Wait for the exit of a process and return its status.
Definition filter.c:220
bool mutt_path_canon(struct Buffer *path, const char *homedir, bool is_dir)
Create the canonical version of a path.
Definition path.c:248
bool mutt_str_equal(const char *a, const char *b)
Compare two strings.
Definition string.c:662
FILE * mutt_open_read(const char *path, pid_t *thepid)
Run a command to read from.
Definition muttlib.c:699
struct Buffer * buf_pool_get(void)
Get a Buffer from the pool.
Definition pool.c:82
void buf_pool_release(struct Buffer **ptr)
Return a Buffer to the pool.
Definition pool.c:96
String manipulation buffer.
Definition buffer.h:36
struct ConfigSet * cs
Parent ConfigSet.
Definition subset.h:50
Container for Accounts, Notifications.
Definition neomutt.h:128
char * home_dir
User's home directory.
Definition neomutt.h:141
+ 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 136 of file send.c.

137{
138 struct Address *a = NULL, *tmp = NULL;
139 TAILQ_FOREACH_SAFE(a, al, entries, tmp)
140 {
141 if (mutt_addr_is_user(a) && (!leave_only || TAILQ_NEXT(a, entries)))
142 {
143 TAILQ_REMOVE(al, a, entries);
144 mutt_addr_free(&a);
145 }
146 }
147}
void mutt_addr_free(struct Address **ptr)
Free a single Address.
Definition address.c:462
bool mutt_addr_is_user(const struct Address *addr)
Does the address belong to the user.
Definition alias.c:594
#define TAILQ_FOREACH_SAFE(var, head, field, tvar)
Definition queue.h:792
#define TAILQ_REMOVE(head, elm, field)
Definition queue.h:901
#define TAILQ_NEXT(elm, field)
Definition queue.h:889
An email address.
Definition address.h:35
+ 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 155 of file send.c.

157{
158 const struct AddressList *const als[] = { t, c };
159
160 for (size_t i = 0; i < countof(als); i++)
161 {
162 const struct AddressList *al = als[i];
163 struct Address *a = NULL;
164 TAILQ_FOREACH(a, al, entries)
165 {
166 if (!a->group && mutt_is_mail_list(a))
167 {
169 }
170 }
171 }
172}
void mutt_addrlist_append(struct AddressList *al, struct Address *a)
Append an Address to an AddressList.
Definition address.c:1480
struct Address * mutt_addr_copy(const struct Address *addr)
Copy the real address.
Definition address.c:745
bool mutt_is_mail_list(const struct Address *addr)
Is this the email address of a mailing list?
Definition maillist.c:44
#define countof(x)
Definition memory.h:45
#define TAILQ_FOREACH(var, head, field)
Definition queue.h:782
bool group
Group mailbox?
Definition address.h:38
+ 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 182 of file send.c.

183{
184 int rc = 0;
185 struct Buffer *buf = buf_pool_get();
186 buf_alloc(buf, 8192);
187 char *err = NULL;
188 int idna_ok = 0;
189
190 do
191 {
193 buf_reset(buf);
194 mutt_addrlist_write(al, buf, false);
195 if (!buf_is_empty(buf))
196 buf_addstr(buf, ", ");
197
198 if (mw_get_field(field, buf, MUTT_COMP_NO_FLAGS, HC_ALIAS, &CompleteAliasOps, NULL) != 0)
199 {
200 rc = -1;
201 goto done;
202 }
205 if (expand_aliases)
207 idna_ok = mutt_addrlist_to_intl(al, &err);
208 if (idna_ok != 0)
209 {
210 mutt_error(_("Bad IDN: '%s'"), err);
211 FREE(&err);
212 }
213 } while (idna_ok != 0);
214
215done:
216 buf_pool_release(&buf);
217 return rc;
218}
void mutt_addrlist_clear(struct AddressList *al)
Unlink and free all Address in an AddressList.
Definition address.c:1460
int mutt_addrlist_to_local(struct AddressList *al)
Convert an Address list from Punycode.
Definition address.c:1378
size_t mutt_addrlist_write(const struct AddressList *al, struct Buffer *buf, bool display)
Write an Address to a buffer.
Definition address.c:1206
int mutt_addrlist_parse2(struct AddressList *al, const char *s)
Parse a list of email addresses.
Definition address.c:644
int mutt_addrlist_to_intl(struct AddressList *al, char **err)
Convert an Address list to Punycode.
Definition address.c:1293
const struct CompleteOps CompleteAliasOps
Auto-Completion of Aliases.
Definition complete.c:108
void mutt_expand_aliases(struct AddressList *al)
Expand aliases in a List of Addresses.
Definition alias.c:293
void buf_reset(struct Buffer *buf)
Reset an existing Buffer.
Definition buffer.c:76
bool buf_is_empty(const struct Buffer *buf)
Is the Buffer empty?
Definition buffer.c:291
size_t buf_addstr(struct Buffer *buf, const char *s)
Add a string to a Buffer.
Definition buffer.c:226
void buf_alloc(struct Buffer *buf, size_t new_size)
Make sure a buffer can store at least new_size bytes.
Definition buffer.c:337
#define MUTT_COMP_NO_FLAGS
No flags are set.
Definition wdata.h:43
int mw_get_field(const char *prompt, struct Buffer *buf, CompletionFlags complete, enum HistoryClass hclass, const struct CompleteOps *comp_api, void *cdata)
Ask the user for a string -.
Definition window.c:271
#define mutt_error(...)
Definition logging2.h:94
@ HC_ALIAS
Aliases.
Definition lib.h:56
#define FREE(x)
Definition memory.h:63
#define _(a)
Definition message.h:28
+ 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 228 of file send.c.

229{
230 int rc = -1;
231 struct Buffer *buf = buf_pool_get();
232 buf_alloc(buf, 8192);
233
234 if (OptNewsSend)
235 {
236 if (en->newsgroups)
237 buf_strcpy(buf, en->newsgroups);
238 else
239 buf_reset(buf);
240
241 if (mw_get_field("Newsgroups: ", buf, MUTT_COMP_NO_FLAGS, HC_OTHER, NULL, NULL) != 0)
242 {
243 goto done;
244 }
246
247 if (en->followup_to)
248 buf_strcpy(buf, en->followup_to);
249 else
250 buf_reset(buf);
251
252 const bool c_ask_followup_to = cs_subset_bool(sub, "ask_followup_to");
253 if (c_ask_followup_to && (mw_get_field("Followup-To: ", buf, MUTT_COMP_NO_FLAGS,
254 HC_OTHER, NULL, NULL) != 0))
255 {
256 goto done;
257 }
259
260 if (en->x_comment_to)
261 buf_strcpy(buf, en->x_comment_to);
262 else
263 buf_reset(buf);
264
265 const bool c_x_comment_to = cs_subset_bool(sub, "x_comment_to");
266 const bool c_ask_x_comment_to = cs_subset_bool(sub, "ask_x_comment_to");
267 if (c_x_comment_to && c_ask_x_comment_to &&
268 (mw_get_field("X-Comment-To: ", buf, MUTT_COMP_NO_FLAGS, HC_OTHER, NULL, NULL) != 0))
269 {
270 goto done;
271 }
273 }
274 else
275 {
276 const bool c_fast_reply = cs_subset_bool(sub, "fast_reply");
277 if (TAILQ_EMPTY(&en->to) || !c_fast_reply || (flags & SEND_REVIEW_TO))
278 {
279 if ((mutt_edit_address(&en->to, _("To: "), true) == -1))
280 goto done;
281 }
282
283 const bool c_ask_cc = cs_subset_bool(sub, "ask_cc");
284 if (TAILQ_EMPTY(&en->cc) || !c_fast_reply)
285 {
286 if (c_ask_cc && (mutt_edit_address(&en->cc, _("Cc: "), true) == -1))
287 goto done;
288 }
289
290 const bool c_ask_bcc = cs_subset_bool(sub, "ask_bcc");
291 if (TAILQ_EMPTY(&en->bcc) || !c_fast_reply)
292 {
293 if (c_ask_bcc && (mutt_edit_address(&en->bcc, _("Bcc: "), true) == -1))
294 goto done;
295 }
296
297 if (TAILQ_EMPTY(&en->to) && TAILQ_EMPTY(&en->cc) && TAILQ_EMPTY(&en->bcc))
298 {
299 mutt_warning(_("No recipients specified"));
300 goto done;
301 }
302
303 const bool c_reply_with_xorig = cs_subset_bool(sub, "reply_with_xorig");
304 if (c_reply_with_xorig && (flags & (SEND_REPLY | SEND_LIST_REPLY | SEND_GROUP_REPLY)) &&
305 (mutt_edit_address(&en->from, "From: ", true) == -1))
306 {
307 goto done;
308 }
309 }
310
311 if (en->subject)
312 {
313 const bool c_fast_reply = cs_subset_bool(sub, "fast_reply");
314 if (c_fast_reply)
315 {
316 rc = 0;
317 goto done;
318 }
319 buf_strcpy(buf, en->subject);
320 }
321 else
322 {
323 const char *p = NULL;
324
325 buf_reset(buf);
326 struct ListNode *uh = NULL;
327 STAILQ_FOREACH(uh, &UserHeader, entries)
328 {
329 size_t plen = mutt_istr_startswith(uh->data, "subject:");
330 if (plen)
331 {
332 p = mutt_str_skip_email_wsp(uh->data + plen);
333 buf_strcpy(buf, p);
334 }
335 }
336 }
337
338 if ((mw_get_field(_("Subject: "), buf, MUTT_COMP_NO_FLAGS, HC_OTHER, NULL, NULL) != 0) ||
339 (buf_is_empty(buf) &&
340 (query_quadoption(_("No subject, abort?"), sub, "abort_nosubject") != MUTT_NO)))
341 {
342 mutt_message(_("No subject, aborting"));
343 goto done;
344 }
346 rc = 0;
347
348done:
349 buf_pool_release(&buf);
350 return rc;
351}
size_t buf_strcpy(struct Buffer *buf, const char *s)
Copy a string into a Buffer.
Definition buffer.c:395
void mutt_env_set_subject(struct Envelope *env, const char *subj)
Set both subject and real_subj to subj.
Definition envelope.c:68
struct ListHead UserHeader
List of custom headers to add to outgoing emails.
Definition globals.c:49
bool OptNewsSend
(pseudo) used to change behavior when posting
Definition globals.c:65
#define mutt_warning(...)
Definition logging2.h:92
#define mutt_message(...)
Definition logging2.h:93
@ HC_OTHER
Miscellaneous strings.
Definition lib.h:60
char * mutt_str_skip_email_wsp(const char *s)
Skip over whitespace as defined by RFC5322.
Definition string.c:610
size_t mutt_istr_startswith(const char *str, const char *prefix)
Check whether a string starts with a prefix, ignoring case.
Definition string.c:246
char * mutt_str_replace(char **p, const char *s)
Replace one string with another.
Definition string.c:284
@ MUTT_NO
User answered 'No', or assume 'No'.
Definition quad.h:38
enum QuadOption query_quadoption(const char *prompt, struct ConfigSubset *sub, const char *name)
Ask the user a quad-question.
Definition question.c:378
#define STAILQ_FOREACH(var, head, field)
Definition queue.h:390
#define TAILQ_EMPTY(head)
Definition queue.h:778
int mutt_edit_address(struct AddressList *al, const char *field, bool expand_aliases)
Edit an email address.
Definition send.c:182
#define SEND_GROUP_REPLY
Reply to all.
Definition send.h:43
#define SEND_LIST_REPLY
Reply to mailing list.
Definition send.h:44
#define SEND_REPLY
Reply to sender.
Definition send.h:42
#define SEND_REVIEW_TO
Allow the user to edit the To field.
Definition send.h:56
char *const subject
Email's subject.
Definition envelope.h:70
struct AddressList to
Email's 'To' list.
Definition envelope.h:60
char * followup_to
List of 'followup-to' fields.
Definition envelope.h:80
char * x_comment_to
List of 'X-comment-to' fields.
Definition envelope.h:81
char * newsgroups
List of newsgroups.
Definition envelope.h:78
struct AddressList cc
Email's 'Cc' list.
Definition envelope.h:61
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:37
char * data
String.
Definition list.h:38
+ 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:257
#define SKIPWS(ch)
Definition string2.h:52
+ 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 370 of file send.c.

371{
372 struct ListNode *uh = NULL;
373 STAILQ_FOREACH(uh, &UserHeader, entries)
374 {
375 size_t plen;
376 if ((plen = mutt_istr_startswith(uh->data, "to:")))
377 mutt_addrlist_parse(&env->to, uh->data + plen);
378 else if ((plen = mutt_istr_startswith(uh->data, "cc:")))
379 mutt_addrlist_parse(&env->cc, uh->data + plen);
380 else if ((plen = mutt_istr_startswith(uh->data, "bcc:")))
381 mutt_addrlist_parse(&env->bcc, uh->data + plen);
382 else if ((plen = mutt_istr_startswith(uh->data, "newsgroups:")))
383 env->newsgroups = nntp_get_header(uh->data + plen);
384 else if ((plen = mutt_istr_startswith(uh->data, "followup-to:")))
385 env->followup_to = nntp_get_header(uh->data + plen);
386 else if ((plen = mutt_istr_startswith(uh->data, "x-comment-to:")))
387 env->x_comment_to = nntp_get_header(uh->data + plen);
388 }
389}
int mutt_addrlist_parse(struct AddressList *al, const char *s)
Parse a list of email addresses.
Definition address.c:480
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 395 of file send.c.

396{
397 struct ListNode *uh = NULL;
398 STAILQ_FOREACH(uh, &UserHeader, entries)
399 {
400 size_t plen;
401 if ((plen = mutt_istr_startswith(uh->data, "from:")))
402 {
403 /* User has specified a default From: address. Remove default address */
405 mutt_addrlist_parse(&env->from, uh->data + plen);
406 }
407 else if ((plen = mutt_istr_startswith(uh->data, "reply-to:")))
408 {
410 mutt_addrlist_parse(&env->reply_to, uh->data + plen);
411 }
412 else if ((plen = mutt_istr_startswith(uh->data, "message-id:")))
413 {
414 char *tmp = mutt_extract_message_id(uh->data + plen, NULL);
415 if (mutt_addr_valid_msgid(tmp))
416 {
417 FREE(&env->message_id);
418 env->message_id = tmp;
419 }
420 else
421 {
422 FREE(&tmp);
423 }
424 }
425 else if (!mutt_istr_startswith(uh->data, "to:") &&
426 !mutt_istr_startswith(uh->data, "cc:") &&
427 !mutt_istr_startswith(uh->data, "bcc:") &&
428 !mutt_istr_startswith(uh->data, "newsgroups:") &&
429 !mutt_istr_startswith(uh->data, "followup-to:") &&
430 !mutt_istr_startswith(uh->data, "x-comment-to:") &&
431 !mutt_istr_startswith(uh->data, "supersedes:") &&
432 !mutt_istr_startswith(uh->data, "subject:") &&
433 !mutt_istr_startswith(uh->data, "return-path:"))
434 {
436 }
437 }
438}
bool mutt_addr_valid_msgid(const char *msgid)
Is this a valid Message ID?
Definition address.c:792
char * mutt_extract_message_id(const char *s, size_t *len)
Find a message-id.
Definition parse.c:401
struct ListNode * mutt_list_insert_tail(struct ListHead *h, char *s)
Append a string to the end of a List.
Definition list.c:65
struct ListHead userhdrs
user defined headers
Definition envelope.h:85
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 446 of file send.c.

447{
448 const struct Expando *c_forward_attribution_intro = cs_subset_expando(sub, "forward_attribution_intro");
449 if (!c_forward_attribution_intro || !fp)
450 return;
451
452 const char *const c_attribution_locale = cs_subset_string(sub, "attribution_locale");
453
454 struct Buffer *buf = buf_pool_get();
455 setlocale(LC_TIME, NONULL(c_attribution_locale));
456 mutt_make_string(buf, -1, c_forward_attribution_intro, NULL, -1, e,
458 setlocale(LC_TIME, "");
459 fputs(buf_string(buf), fp);
460 fputs("\n\n", fp);
461 buf_pool_release(&buf);
462}
const char * cs_subset_string(const struct ConfigSubset *sub, const char *name)
Get a string config item by name.
Definition helpers.c:291
const struct Expando * cs_subset_expando(const struct ConfigSubset *sub, const char *name)
Get an Expando config item by name.
int mutt_make_string(struct Buffer *buf, size_t max_cols, const struct Expando *exp, struct Mailbox *m, int inpgr, struct Email *e, MuttFormatFlags flags, const char *progress)
Create formatted strings using mailbox expandos.
Definition dlg_index.c:800
#define MUTT_FORMAT_NO_FLAGS
No flags are set.
Definition render.h:33
#define NONULL(x)
Definition string2.h:44
Parsed Expando trees.
Definition expando.h:41
+ 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 470 of file send.c.

471{
472 const struct Expando *c_forward_attribution_trailer = cs_subset_expando(sub, "forward_attribution_trailer");
473 if (!c_forward_attribution_trailer || !fp)
474 return;
475
476 const char *const c_attribution_locale = cs_subset_string(sub, "attribution_locale");
477
478 struct Buffer *buf = buf_pool_get();
479 setlocale(LC_TIME, NONULL(c_attribution_locale));
480 mutt_make_string(buf, -1, c_forward_attribution_trailer, NULL, -1, e,
482 setlocale(LC_TIME, "");
483 fputc('\n', fp);
484 fputs(buf_string(buf), fp);
485 fputc('\n', fp);
486 buf_pool_release(&buf);
487}
+ 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 498 of file send.c.

500{
501 CopyHeaderFlags chflags = CH_DECODE;
503
504 struct Message *msg = mx_msg_open(m, e);
505 if (!msg)
506 {
507 return -1;
508 }
511
512 const bool c_forward_decode = cs_subset_bool(sub, "forward_decode");
513 if ((WithCrypto != 0) && (e->security & SEC_ENCRYPT) && c_forward_decode)
514 {
515 /* make sure we have the user's passphrase before proceeding... */
517 {
518 mx_msg_close(m, &msg);
519 return -1;
520 }
521 }
522
523 mutt_forward_intro(e, fp_out, sub);
524
525 if (c_forward_decode)
526 {
527 cmflags |= MUTT_CM_DECODE | MUTT_CM_CHARCONV;
528
529 const bool c_weed = cs_subset_bool(sub, "weed");
530 if (c_weed)
531 {
532 chflags |= CH_WEED | CH_REORDER;
533 cmflags |= MUTT_CM_WEED;
534 }
535 }
536
537 const bool c_forward_quote = cs_subset_bool(sub, "forward_quote");
538 if (c_forward_quote)
539 cmflags |= MUTT_CM_PREFIX;
540
541 mutt_copy_message(fp_out, e, msg, cmflags, chflags, 0);
542 mx_msg_close(m, &msg);
543 mutt_forward_trailer(e, fp_out, sub);
544 return 0;
545}
void mutt_parse_mime_message(struct Email *e, FILE *fp)
Parse a MIME email.
Definition commands.c:630
@ CMD_MESSAGE_HOOK
:message-hook
Definition command.h:92
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_email.c:916
#define CH_DECODE
Do RFC2047 header decoding.
Definition copy_email.h:56
#define MUTT_CM_WEED
Weed message/rfc822 attachment headers.
Definition copy_email.h:43
#define MUTT_CM_PREFIX
Quote the header and body.
Definition copy_email.h:39
#define MUTT_CM_DECODE
Decode the message body into text/plain.
Definition copy_email.h:40
#define CH_WEED
Weed the headers?
Definition copy_email.h:55
#define CH_REORDER
Re-order output of headers (specified by 'header-order')
Definition copy_email.h:61
#define MUTT_CM_CHARCONV
Perform character set conversions.
Definition copy_email.h:44
uint32_t CopyHeaderFlags
Flags for mutt_copy_header(), e.g. CH_UPDATE.
Definition copy_email.h:52
#define MUTT_CM_NO_FLAGS
No flags are set.
Definition copy_email.h:37
uint16_t CopyMessageFlags
Flags for mutt_copy_message(), e.g. MUTT_CM_NOHEADER.
Definition copy_email.h:36
bool crypt_valid_passphrase(SecurityFlags flags)
Check that we have a usable passphrase, ask if not.
Definition crypt.c:131
int mx_msg_close(struct Mailbox *m, struct Message **ptr)
Close a message.
Definition mx.c:1182
struct Message * mx_msg_open(struct Mailbox *m, struct Email *e)
Return a stream pointer for a message.
Definition mx.c:1136
#define SEC_ENCRYPT
Email is encrypted.
Definition lib.h:86
#define WithCrypto
Definition lib.h:124
void mutt_message_hook(struct Mailbox *m, struct Email *e, enum CommandId id)
Perform a message hook.
Definition run.c:132
void mutt_forward_intro(struct Email *e, FILE *fp, struct ConfigSubset *sub)
Add the "start of forwarded message" text.
Definition send.c:446
void mutt_forward_trailer(struct Email *e, FILE *fp, struct ConfigSubset *sub)
Add a "end of forwarded message" text.
Definition send.c:470
SecurityFlags security
bit 0-10: flags, bit 11,12: application, bit 13: traditional pgp See: ncrypt/lib.h pgplib....
Definition email.h:43
A local copy of an email.
Definition message.h:34
FILE * fp
pointer to the message data
Definition message.h:35
+ 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 557 of file send.c.

560{
561 struct Body **last = *plast;
562 struct Body *body = NULL;
563 struct AttachCtx *actx = NULL;
564 int rc = 0, i;
565
566 struct Message *msg = mx_msg_open(m, e);
567 if (!msg)
568 {
569 return -1;
570 }
571
574
575 actx = MUTT_MEM_CALLOC(1, struct AttachCtx);
576 actx->email = e;
577 actx->fp_root = msg->fp;
578
579 mutt_generate_recvattach_list(actx, actx->email, actx->email->body,
580 actx->fp_root, -1, 0, 0);
581
582 for (i = 0; i < actx->idxlen; i++)
583 {
584 body = actx->idx[i]->body;
585 if ((body->type != TYPE_MULTIPART) && mutt_prefer_as_attachment(body) &&
586 !((body->type == TYPE_APPLICATION) &&
587 (mutt_istr_equal(body->subtype, "pgp-signature") ||
588 mutt_istr_equal(body->subtype, "x-pkcs7-signature") ||
589 mutt_istr_equal(body->subtype, "pkcs7-signature"))))
590 {
591 /* Ask the quadoption only once */
592 if (*forwardq == MUTT_ABORT)
593 {
594 /* L10N: This is the prompt for $forward_attachments.
595 When inline forwarding ($mime_forward answered "no"), this prompts
596 whether to add non-decodable attachments from the original email.
597 Text/plain parts and the like will already be included in the
598 message contents, but other attachment, such as PDF files, will also
599 be added as attachments to the new mail, if this is answered yes. */
600 *forwardq = query_quadoption(_("Forward attachments?"), sub, "forward_attachments");
601 if (*forwardq != MUTT_YES)
602 {
603 if (*forwardq == -1)
604 rc = -1;
605 goto cleanup;
606 }
607 }
608 if (mutt_body_copy(actx->idx[i]->fp, last, body) == -1)
609 {
610 rc = -1;
611 goto cleanup;
612 }
613 last = &((*last)->next);
614 }
615 }
616
617cleanup:
618 *plast = last;
619 mx_msg_close(m, &msg);
620 mutt_actx_free(&actx);
621 return rc;
622}
void mutt_actx_free(struct AttachCtx **ptr)
Free an Attachment Context.
Definition attach.c:198
int mutt_body_copy(FILE *fp, struct Body **b_dst, struct Body *b_src)
Create a send-mode duplicate from a receive-mode body.
Definition copy_body.c:50
bool mutt_prefer_as_attachment(struct Body *b)
Do we want this part as an attachment?
Definition handler.c:1855
#define MUTT_MEM_CALLOC(n, type)
Definition memory.h:48
@ 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:674
@ 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 *b, FILE *fp, int parent_type, int level, bool decrypted)
Create a list of attachments.
A set of attachments.
Definition attach.h:63
FILE * fp_root
Used by recvattach for updating.
Definition attach.h:65
struct Email * email
Used by recvattach for updating.
Definition attach.h:64
struct AttachPtr ** idx
Array of attachments.
Definition attach.h:67
short idxlen
Number of attachmentes.
Definition attach.h:68
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:61
unsigned int type
content-type primary type, ContentType
Definition body.h:40
struct Body * body
List of MIME parts.
Definition email.h:69
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ format_attribution()

static void format_attribution ( const struct Expando * exp,
struct Email * e,
FILE * fp_out,
struct ConfigSubset * sub )
static

Format an attribution prefix/suffix.

Parameters
expExpando to format
eEmail
fp_outFile to write to
subConfig Subset

Definition at line 631 of file send.c.

633{
634 if (!exp || !fp_out)
635 return;
636
637 const char *const c_attribution_locale = cs_subset_string(sub, "attribution_locale");
638
639 struct Buffer *buf = buf_pool_get();
640 setlocale(LC_TIME, NONULL(c_attribution_locale));
641 mutt_make_string(buf, -1, exp, NULL, -1, e, MUTT_FORMAT_NO_FLAGS, NULL);
642 setlocale(LC_TIME, "");
643 fputs(buf_string(buf), fp_out);
644 fputc('\n', fp_out);
645 buf_pool_release(&buf);
646}
+ 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 654 of file send.c.

655{
656 format_attribution(cs_subset_expando(sub, "attribution_intro"), e, fp_out, sub);
657}
static void format_attribution(const struct Expando *exp, struct Email *e, FILE *fp_out, struct ConfigSubset *sub)
Format an attribution prefix/suffix.
Definition send.c:631
+ 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 665 of file send.c.

666{
667 format_attribution(cs_subset_expando(sub, "attribution_trailer"), e, fp_out, sub);
668}
+ 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

Definition at line 678 of file send.c.

679{
680 const struct Expando *c_greeting = cs_subset_expando(sub, "greeting");
681 if (!c_greeting || !fp_out)
682 return;
683
684 struct Buffer *buf = buf_pool_get();
685
687 buf->dsize, NeoMutt->env, buf);
688
689 fputs(buf_string(buf), fp_out);
690 fputc('\n', fp_out);
691 buf_pool_release(&buf);
692}
int expando_filter(const struct Expando *exp, const struct ExpandoRenderCallback *erc, void *data, MuttFormatFlags flags, int max_cols, char **env_list, struct Buffer *buf)
Render an Expando and run the result through a filter.
Definition filter.c:138
const struct ExpandoRenderCallback GreetingRenderCallbacks[]
Callbacks for Greeting Expandos.
size_t dsize
Length of data.
Definition buffer.h:39
char ** env
Private copy of the environment variables.
Definition neomutt.h:143
+ 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 703 of file send.c.

705{
707 CopyHeaderFlags chflags = CH_DECODE;
708
709 if ((WithCrypto != 0) && (e->security & SEC_ENCRYPT))
710 {
711 /* make sure we have the user's passphrase before proceeding... */
713 return -1;
714 }
715
716 struct Message *msg = mx_msg_open(m, e);
717 if (!msg)
718 {
719 return -1;
720 }
723
724 mutt_make_attribution_intro(e, fp_out, sub);
725
726 const bool c_header = cs_subset_bool(sub, "header");
727 if (!c_header)
728 cmflags |= MUTT_CM_NOHEADER;
729
730 const bool c_weed = cs_subset_bool(sub, "weed");
731 if (c_weed)
732 {
733 chflags |= CH_WEED | CH_REORDER;
734 cmflags |= MUTT_CM_WEED;
735 }
736
737 mutt_copy_message(fp_out, e, msg, cmflags, chflags, 0);
738 mx_msg_close(m, &msg);
739
740 mutt_make_attribution_trailer(e, fp_out, sub);
741
742 return 0;
743}
#define MUTT_CM_REPLYING
Replying the message.
Definition copy_email.h:46
#define MUTT_CM_NOHEADER
Don't copy the message header.
Definition copy_email.h:38
void mutt_make_attribution_intro(struct Email *e, FILE *fp_out, struct ConfigSubset *sub)
Add "on DATE, PERSON wrote" header.
Definition send.c:654
void mutt_make_attribution_trailer(struct Email *e, FILE *fp_out, struct ConfigSubset *sub)
Add suffix to replied email text.
Definition send.c:665
+ 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 752 of file send.c.

755{
756 const bool c_reply_self = cs_subset_bool(sub, "reply_self");
757 if (!c_reply_self && mutt_addr_is_user(from))
758 {
759 /* mail is from the user, assume replying to recipients */
760 return &env->to;
761 }
762 else
763 {
764 return &env->from;
765 }
766}
+ 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 778 of file send.c.

780{
781 const struct Address *from = TAILQ_FIRST(&env->from);
782 const struct Address *reply_to = TAILQ_FIRST(&env->reply_to);
783
784 if (flags && !TAILQ_EMPTY(&env->mail_followup_to) && (hmfupto == MUTT_YES))
785 {
786 mutt_addrlist_copy(to, &env->mail_followup_to, true);
787 return 0;
788 }
789
790 /* Exit now if we're setting up the default Cc list for list-reply
791 * (only set if Mail-Followup-To is present and honoured). */
792 if (flags & SEND_LIST_REPLY)
793 return 0;
794
795 const struct AddressList *default_to = choose_default_to(from, env, sub);
796
797 if (reply_to)
798 {
799 const bool from_is_reply_to = mutt_addr_cmp(from, reply_to);
800 const bool multiple_reply_to = reply_to &&
801 TAILQ_NEXT(TAILQ_FIRST(&env->reply_to), entries);
802
803 const bool c_ignore_list_reply_to = cs_subset_bool(sub, "ignore_list_reply_to");
804 const enum QuadOption c_reply_to = cs_subset_quad(sub, "reply_to");
805 if ((from_is_reply_to && !multiple_reply_to && !reply_to->personal) ||
806 (c_ignore_list_reply_to && mutt_is_mail_list(reply_to) &&
807 (mutt_addrlist_search(&env->to, reply_to) || mutt_addrlist_search(&env->cc, reply_to))))
808 {
809 /* If the Reply-To: address is a mailing list, assume that it was
810 * put there by the mailing list, and use the From: address
811 *
812 * We also take the from header if our correspondent has a reply-to
813 * header which is identical to the electronic mail address given
814 * in his From header, and the reply-to has no display-name. */
815 mutt_addrlist_copy(to, &env->from, false);
816 }
817 else if (!(from_is_reply_to && !multiple_reply_to) && (c_reply_to != MUTT_YES))
818 {
819 char prompt[256] = { 0 };
820 /* There are quite a few mailing lists which set the Reply-To:
821 * header field to the list address, which makes it quite impossible
822 * to send a message to only the sender of the message. This
823 * provides a way to do that. */
824 /* L10N: Asks whether the user respects the reply-to header.
825 If she says no, neomutt will reply to the from header's address instead. */
826 snprintf(prompt, sizeof(prompt), _("Reply to %s%s?"),
827 buf_string(reply_to->mailbox), multiple_reply_to ? ",..." : "");
828 switch (query_quadoption(prompt, sub, "reply_to"))
829 {
830 case MUTT_YES:
831 mutt_addrlist_copy(to, &env->reply_to, false);
832 break;
833
834 case MUTT_NO:
835 mutt_addrlist_copy(to, default_to, false);
836 break;
837
838 default:
839 return -1; /* abort */
840 }
841 }
842 else
843 {
844 mutt_addrlist_copy(to, &env->reply_to, false);
845 }
846 }
847 else
848 {
849 mutt_addrlist_copy(to, default_to, false);
850 }
851
852 return 0;
853}
void mutt_addrlist_copy(struct AddressList *dst, const struct AddressList *src, bool prune)
Copy a list of addresses into another list.
Definition address.c:765
bool mutt_addr_cmp(const struct Address *a, const struct Address *b)
Compare two e-mail addresses.
Definition address.c:892
bool mutt_addrlist_search(const struct AddressList *haystack, const struct Address *needle)
Search for an e-mail address in a list.
Definition address.c:909
enum QuadOption cs_subset_quad(const struct ConfigSubset *sub, const char *name)
Get a quad-value config item by name.
Definition helpers.c:192
QuadOption
Possible values for a quad-option.
Definition quad.h:36
#define TAILQ_FIRST(head)
Definition queue.h:780
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:752
static int default_to(struct AddressList *to, struct Envelope *env, SendFlags flags, int hmfupto, struct ConfigSubset *sub)
Generate default email addresses.
Definition send.c:778
struct Buffer * personal
Real name of address.
Definition address.h:36
struct Buffer * mailbox
Mailbox and host 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 864 of file send.c.

866{
867 enum QuadOption hmfupto = MUTT_ABORT;
868 const struct Address *followup_to = TAILQ_FIRST(&in->mail_followup_to);
869
870 if ((flags & (SEND_LIST_REPLY | SEND_GROUP_REPLY | SEND_GROUP_CHAT_REPLY)) && followup_to)
871 {
872 char prompt[256] = { 0 };
873 snprintf(prompt, sizeof(prompt), _("Follow-up to %s%s?"),
874 buf_string(followup_to->mailbox),
875 TAILQ_NEXT(TAILQ_FIRST(&in->mail_followup_to), entries) ? ",..." : "");
876
877 hmfupto = query_quadoption(prompt, sub, "honor_followup_to");
878 if (hmfupto == MUTT_ABORT)
879 return -1;
880 }
881
882 if (flags & SEND_LIST_REPLY)
883 {
884 add_mailing_lists(&out->to, &in->to, &in->cc);
885
886 if (followup_to && (hmfupto == MUTT_YES) &&
887 (default_to(&out->cc, in, flags & SEND_LIST_REPLY, (hmfupto == MUTT_YES), sub) == MUTT_ABORT))
888 {
889 return -1; /* abort */
890 }
891 }
892 else if (flags & SEND_TO_SENDER)
893 {
894 mutt_addrlist_copy(&out->to, &in->from, false);
895 }
896 else
897 {
898 if (default_to(&out->to, in, flags & (SEND_GROUP_REPLY | SEND_GROUP_CHAT_REPLY),
899 (hmfupto == MUTT_YES), sub) == -1)
900 {
901 return -1; /* abort */
902 }
903
904 if ((flags & (SEND_GROUP_REPLY | SEND_GROUP_CHAT_REPLY)) &&
905 (!followup_to || (hmfupto != MUTT_YES)))
906 {
907 /* if(!mutt_addr_is_user(in->to)) */
908 if (flags & SEND_GROUP_REPLY)
909 mutt_addrlist_copy(&out->cc, &in->to, true);
910 else
911 mutt_addrlist_copy(&out->to, &in->to, true);
912 mutt_addrlist_copy(&out->cc, &in->cc, true);
913 }
914 }
915 return 0;
916}
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:155
#define SEND_GROUP_CHAT_REPLY
Reply to all recipients preserving To/Cc.
Definition send.h:54
#define SEND_TO_SENDER
Compose new email to sender.
Definition send.h:53
+ 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 923 of file send.c.

924{
925 struct ListHead *src = STAILQ_EMPTY(&env->references) ? &env->in_reply_to : &env->references;
926 mutt_list_copy_tail(head, src);
927}
void mutt_list_copy_tail(struct ListHead *dst, const struct ListHead *src)
Copy a list into another list.
Definition list.c:275
#define STAILQ_EMPTY(head)
Definition queue.h:382
struct ListHead references
message references (in reverse order)
Definition envelope.h:83
struct ListHead in_reply_to
in-reply-to header content
Definition envelope.h:84
+ 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 934 of file send.c.

935{
936 if (env->message_id)
937 {
939 }
940}
struct ListNode * mutt_list_insert_head(struct ListHead *h, char *s)
Insert a string at the beginning of a List.
Definition list.c:46
+ 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 947 of file send.c.

948{
949 const bool c_me_too = cs_subset_bool(sub, "me_too");
950 if (!c_me_too)
951 {
952 const bool c_reply_self = cs_subset_bool(sub, "reply_self");
953
954 /* the order is important here. do the CC: first so that if the
955 * the user is the only recipient, it ends up on the TO: field */
956 remove_user(&env->cc, TAILQ_EMPTY(&env->to));
957 remove_user(&env->to, TAILQ_EMPTY(&env->cc) || c_reply_self);
958 }
959
960 /* the CC field can get cluttered, especially with lists */
963 mutt_addrlist_remove_xrefs(&env->to, &env->cc);
964
965 if (!TAILQ_EMPTY(&env->cc) && TAILQ_EMPTY(&env->to))
966 {
967 TAILQ_SWAP(&env->to, &env->cc, Address, entries);
968 }
969}
void mutt_addrlist_remove_xrefs(const struct AddressList *a, struct AddressList *b)
Remove cross-references.
Definition address.c:1433
void mutt_addrlist_dedupe(struct AddressList *al)
Remove duplicate addresses.
Definition address.c:1397
#define TAILQ_SWAP(head1, head2, type, field)
Definition queue.h:937
static void remove_user(struct AddressList *al, bool leave_only)
Remove any address which matches the current user.
Definition send.c:136
+ 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 977 of file send.c.

978{
979 if (!env)
980 return;
981
982 const struct Expando *c_forward_format = cs_subset_expando(sub, "forward_format");
983
984 struct Buffer *buf = buf_pool_get();
985 /* set the default subject for the message. */
986 mutt_make_string(buf, -1, c_forward_format, NULL, -1, e, MUTT_FORMAT_NO_FLAGS, NULL);
988 buf_pool_release(&buf);
989}
+ 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 * env_cur,
struct ConfigSubset * sub )

Set subject for a reply.

Parameters
envEnvelope for result
env_curEnvelope of source email
subConfig Subset

Definition at line 997 of file send.c.

999{
1000 if (!env || !env_cur)
1001 return;
1002
1003 /* This takes precedence over a subject that might have
1004 * been taken from a List-Post header. Is that correct? */
1005 if (env_cur->real_subj)
1006 {
1007 char *subj = NULL;
1008 mutt_str_asprintf(&subj, "Re: %s", env_cur->real_subj);
1009 mutt_env_set_subject(env, subj);
1010 FREE(&subj);
1011 }
1012 else if (!env->subject)
1013 {
1014 const char *const c_empty_subject = cs_subset_string(sub, "empty_subject");
1015 mutt_env_set_subject(env, c_empty_subject);
1016 }
1017}
int mutt_str_asprintf(char **strp, const char *fmt,...)
Definition string.c:805
char *const 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 * env_cur,
struct ConfigSubset * sub )

Generate references for a reply email.

Parameters
envEnvelope for result
env_curEnvelope of source email
subConfig Subset

Definition at line 1025 of file send.c.

1027{
1028 add_references(&env->references, env_cur);
1029 add_message_id(&env->references, env_cur);
1030 add_message_id(&env->in_reply_to, env_cur);
1031
1032 const bool c_x_comment_to = cs_subset_bool(sub, "x_comment_to");
1033 if (OptNewsSend && c_x_comment_to && !TAILQ_EMPTY(&env_cur->from))
1035}
const char * mutt_get_name(const struct Address *a)
Pick the best name to display from an address.
Definition sort.c:138
static void add_message_id(struct ListHead *head, struct Envelope *env)
Add the email's message ID to a list.
Definition send.c:934
static void add_references(struct ListHead *head, struct Envelope *env)
Add the email's references to a list.
Definition send.c:923
+ 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 EmailArray * ea,
struct Envelope * env,
struct ConfigSubset * sub )
static

Generate reference headers for an email.

Parameters
eaArray of source Emails
envEnvelope for result
subConfig Subset

Definition at line 1043 of file send.c.

1045{
1046 if (!ea || !env || ARRAY_EMPTY(ea))
1047 return;
1048
1049 struct Email **ep = NULL;
1050 ARRAY_FOREACH(ep, ea)
1051 {
1052 struct Email *e = *ep;
1054 }
1055
1056 /* if there's more than entry in In-Reply-To (i.e. message has multiple
1057 * parents), don't generate a References: header as it's discouraged by
1058 * RFC2822, sect. 3.6.4 */
1059 if ((ARRAY_SIZE(ea) > 1) && !STAILQ_EMPTY(&env->in_reply_to) &&
1061 {
1063 }
1064}
#define ARRAY_FOREACH(elem, head)
Iterate over all elements of the array.
Definition array.h:223
#define ARRAY_EMPTY(head)
Check if an array is empty.
Definition array.h:74
#define ARRAY_SIZE(head)
The number of elements stored.
Definition array.h:87
void mutt_list_free(struct ListHead *h)
Free a List AND its strings.
Definition list.c:123
#define STAILQ_FIRST(head)
Definition queue.h:388
#define STAILQ_NEXT(elm, field)
Definition queue.h:439
void mutt_add_to_reference_headers(struct Envelope *env, struct Envelope *env_cur, struct ConfigSubset *sub)
Generate references for a reply email.
Definition send.c:1025
The envelope/body of an email.
Definition email.h:39
struct Envelope * env
Envelope information.
Definition email.h:68
+ 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 EmailArray * ea,
SendFlags flags,
struct ConfigSubset * sub )
static

Fill in some defaults for a new email.

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

Definition at line 1075 of file send.c.

1077{
1078 if (!ea || ARRAY_EMPTY(ea))
1079 return -1;
1080
1081 struct Email *e_cur = *ARRAY_GET(ea, 0);
1082 bool single = (ARRAY_SIZE(ea) == 1);
1083
1084 struct Envelope *env_cur = e_cur->env;
1085 if (!env_cur)
1086 return -1;
1087
1088 if (flags & (SEND_REPLY | SEND_TO_SENDER))
1089 {
1090 if ((flags & SEND_NEWS))
1091 {
1092 /* in case followup set Newsgroups: with Followup-To: if it present */
1093 if (!env->newsgroups && !mutt_istr_equal(env_cur->followup_to, "poster"))
1094 {
1095 env->newsgroups = mutt_str_dup(env_cur->followup_to);
1096 }
1097 }
1098 else if (!single)
1099 {
1100 struct Email **ep = NULL;
1101 ARRAY_FOREACH(ep, ea)
1102 {
1103 struct Email *e = *ep;
1104 if (mutt_fetch_recips(env, e->env, flags, sub) == -1)
1105 return -1;
1106 }
1107 }
1108 else if (mutt_fetch_recips(env, env_cur, flags, sub) == -1)
1109 {
1110 return -1;
1111 }
1112
1113 if ((flags & SEND_LIST_REPLY) && TAILQ_EMPTY(&env->to))
1114 {
1115 mutt_error(_("No mailing lists found"));
1116 return -1;
1117 }
1118
1119 if (flags & SEND_REPLY)
1120 {
1121 mutt_make_misc_reply_headers(env, env_cur, sub);
1122 make_reference_headers(ea, env, sub);
1123 }
1124 }
1125 else if (flags & SEND_FORWARD)
1126 {
1127 mutt_make_forward_subject(env, e_cur, sub);
1128
1129 const bool c_forward_references = cs_subset_bool(sub, "forward_references");
1130 if (c_forward_references)
1131 make_reference_headers(ea, env, sub);
1132 }
1133
1134 return 0;
1135}
#define ARRAY_GET(head, idx)
Return the element at index.
Definition array.h:109
void mutt_make_misc_reply_headers(struct Envelope *env, struct Envelope *env_cur, struct ConfigSubset *sub)
Set subject for a reply.
Definition send.c:997
void mutt_make_forward_subject(struct Envelope *env, struct Email *e, struct ConfigSubset *sub)
Create a subject for a forwarded email.
Definition send.c:977
static void make_reference_headers(struct EmailArray *ea, struct Envelope *env, struct ConfigSubset *sub)
Generate reference headers for an email.
Definition send.c:1043
int mutt_fetch_recips(struct Envelope *out, struct Envelope *in, SendFlags flags, struct ConfigSubset *sub)
Generate recpients for a reply email.
Definition send.c:864
#define SEND_NEWS
Reply to a news article.
Definition send.h:55
#define SEND_FORWARD
Forward email.
Definition send.h:45
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 EmailArray * ea,
struct ConfigSubset * sub )
static

Create a new email body.

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

Definition at line 1148 of file send.c.

1150{
1151 /* An EmailList is required for replying and forwarding */
1152 if (!ea && (flags & (SEND_REPLY | SEND_FORWARD)))
1153 return -1;
1154
1155 if (flags & SEND_REPLY)
1156 {
1157 enum QuadOption ans = query_quadoption(_("Include message in reply?"), sub, "include");
1158 if (ans == MUTT_ABORT)
1159 return -1;
1160
1161 if (ans == MUTT_YES)
1162 {
1163 mutt_message(_("Including quoted message..."));
1164 struct Email **ep = NULL;
1165 size_t count = ARRAY_SIZE(ea) - 1;
1166 ARRAY_FOREACH(ep, ea)
1167 {
1168 if (include_reply(m, *ep, fp_tmp, sub) == -1)
1169 {
1170 mutt_error(_("Could not include all requested messages"));
1171 return -1;
1172 }
1173 if (ARRAY_FOREACH_IDX_ep < count)
1174 {
1175 fputc('\n', fp_tmp);
1176 }
1177 }
1178 }
1179 }
1180 else if (flags & SEND_FORWARD)
1181 {
1182 enum QuadOption ans = query_quadoption(_("Forward as attachment?"), sub, "mime_forward");
1183 if (ans == MUTT_YES)
1184 {
1185 struct Body *last = e->body;
1186
1187 mutt_message(_("Preparing forwarded message..."));
1188
1189 while (last && last->next)
1190 last = last->next;
1191
1192 struct Email **ep = NULL;
1193 ARRAY_FOREACH(ep, ea)
1194 {
1195 struct Body *tmp = mutt_make_message_attach(m, *ep, false, sub);
1196 if (last)
1197 {
1198 last->next = tmp;
1199 last = tmp;
1200 }
1201 else
1202 {
1203 last = tmp;
1204 e->body = tmp;
1205 }
1206 }
1207 }
1208 else if (ans != MUTT_ABORT)
1209 {
1210 enum QuadOption forwardq = MUTT_ABORT;
1211 struct Body **last = NULL;
1212
1213 const bool c_forward_decode = cs_subset_bool(sub, "forward_decode");
1214 const enum QuadOption c_forward_attachments = cs_subset_quad(sub, "forward_attachments");
1215 if (c_forward_decode && (c_forward_attachments != MUTT_NO))
1216 {
1217 last = &e->body;
1218 while (*last)
1219 last = &((*last)->next);
1220 }
1221
1222 struct Email **ep = NULL;
1223 ARRAY_FOREACH(ep, ea)
1224 {
1225 struct Email *e_cur = *ep;
1226 include_forward(m, e_cur, fp_tmp, sub);
1227 if (c_forward_decode && (c_forward_attachments != MUTT_NO))
1228 {
1229 if (inline_forward_attachments(m, e_cur, &last, &forwardq, sub) != 0)
1230 return -1;
1231 }
1232 }
1233 }
1234 else
1235 {
1236 return -1;
1237 }
1238 }
1239 else if (((WithCrypto & APPLICATION_PGP) != 0) && (flags & SEND_KEY))
1240 {
1241 struct Body *b = NULL;
1242
1243 if (((WithCrypto & APPLICATION_PGP) != 0) && !(b = crypt_pgp_make_key_attachment()))
1244 {
1245 return -1;
1246 }
1247
1248 b->next = e->body;
1249 e->body = b;
1250 }
1251
1253
1254 return 0;
1255}
struct Body * crypt_pgp_make_key_attachment(void)
Wrapper for CryptModuleSpecs::pgp_make_key_attachment()
Definition cryptglue.c:304
void mutt_clear_error(void)
Clear the message line (bottom line of screen)
#define APPLICATION_PGP
Use PGP to encrypt/sign.
Definition lib.h:98
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:703
static int include_forward(struct Mailbox *m, struct Email *e, FILE *fp_out, struct ConfigSubset *sub)
Write out a forwarded message.
Definition send.c:498
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:557
#define SEND_KEY
Mail a PGP public key.
Definition send.h:48
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:453
struct Body * next
next attachment in the list
Definition body.h:72
+ 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 1262 of file send.c.

1263{
1264 /* Only generate the Mail-Followup-To if the user has requested it, and
1265 * it hasn't already been set */
1266
1267 const bool c_followup_to = cs_subset_bool(sub, "followup_to");
1268 if (!c_followup_to)
1269 return;
1270 if (OptNewsSend)
1271 {
1272 if (!env->followup_to && env->newsgroups && (strrchr(env->newsgroups, ',')))
1273 env->followup_to = mutt_str_dup(env->newsgroups);
1274 return;
1275 }
1276
1277 if (TAILQ_EMPTY(&env->mail_followup_to))
1278 {
1279 if (mutt_is_list_recipient(false, env))
1280 {
1281 /* this message goes to known mailing lists, so create a proper
1282 * mail-followup-to header */
1283
1284 mutt_addrlist_copy(&env->mail_followup_to, &env->to, false);
1285 mutt_addrlist_copy(&env->mail_followup_to, &env->cc, true);
1286 }
1287
1288 /* remove ourselves from the mail-followup-to header */
1289 remove_user(&env->mail_followup_to, false);
1290
1291 /* If we are not subscribed to any of the lists in question, re-add
1292 * ourselves to the mail-followup-to header. The mail-followup-to header
1293 * generated is a no-op with group-reply, but makes sure list-reply has the
1294 * desired effect. */
1295
1296 if (!TAILQ_EMPTY(&env->mail_followup_to) &&
1298 {
1299 struct AddressList *al = NULL;
1300 if (!TAILQ_EMPTY(&env->reply_to))
1301 al = &env->reply_to;
1302 else if (!TAILQ_EMPTY(&env->from))
1303 al = &env->from;
1304
1305 if (al)
1306 {
1307 struct Address *a = NULL;
1308 TAILQ_FOREACH_REVERSE(a, al, AddressList, entries)
1309 {
1311 }
1312 }
1313 else
1314 {
1316 }
1317 }
1318
1320 }
1321}
void mutt_addrlist_prepend(struct AddressList *al, struct Address *a)
Prepend an Address to an AddressList.
Definition address.c:1491
bool mutt_is_subscribed_list_recipient(bool all_addr, struct Envelope *env)
Matches subscribed mailing lists.
Definition exec.c:494
bool mutt_is_list_recipient(bool all_addr, struct Envelope *env)
Matches known mailing lists.
Definition exec.c:507
#define TAILQ_FOREACH_REVERSE(var, head, headname, field)
Definition queue.h:802
struct Address * mutt_default_from(struct ConfigSubset *sub)
Get a default 'from' Address.
Definition send.c:1386
+ 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 1333 of file send.c.

1335{
1336 struct Address *a = NULL;
1337 if (TAILQ_EMPTY(al))
1338 {
1339 TAILQ_FOREACH(a, &env->to, entries)
1340 {
1341 if (mutt_addr_is_user(a))
1342 {
1344 break;
1345 }
1346 }
1347 }
1348
1349 if (TAILQ_EMPTY(al))
1350 {
1351 TAILQ_FOREACH(a, &env->cc, entries)
1352 {
1353 if (mutt_addr_is_user(a))
1354 {
1356 break;
1357 }
1358 }
1359 }
1360
1361 if (TAILQ_EMPTY(al))
1362 {
1363 struct Address *from = TAILQ_FIRST(&env->from);
1364 if (from && mutt_addr_is_user(from))
1365 {
1367 }
1368 }
1369
1370 if (!TAILQ_EMPTY(al))
1371 {
1372 /* when $reverse_real_name is not set, clear the personal name so that it
1373 * may be set via a reply- or send-hook. */
1374
1375 const bool c_reverse_real_name = cs_subset_bool(sub, "reverse_real_name");
1376 if (!c_reverse_real_name)
1377 FREE(&TAILQ_FIRST(al)->personal);
1378 }
1379}
+ 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.

Parameters
subConfig Subset
Return values
ptrNewly allocated Address

Definition at line 1386 of file send.c.

1387{
1388 /* Note: We let $from override $real_name here.
1389 * Is this the right thing to do?
1390 */
1391
1392 const struct Address *c_from = cs_subset_address(sub, "from");
1393 if (c_from)
1394 {
1395 return mutt_addr_copy(c_from);
1396 }
1397
1398 char domain[1024] = { 0 };
1399 const char *mailbox = NeoMutt->username;
1400 const bool c_use_domain = cs_subset_bool(sub, "use_domain");
1401 if (c_use_domain)
1402 {
1403 snprintf(domain, sizeof(domain), "%s@%s", NONULL(NeoMutt->username),
1404 NONULL(mutt_fqdn(true, sub)));
1405 mailbox = domain;
1406 }
1407
1408 return mutt_addr_create(NULL, mailbox);
1409}
struct Address * mutt_addr_create(const char *personal, const char *mailbox)
Create and populate a new Address.
Definition address.c:414
const struct Address * cs_subset_address(const struct ConfigSubset *sub, const char *name)
Get an Address config item by name.
const char * mutt_fqdn(bool may_hide_host, const struct ConfigSubset *sub)
Get the Fully-Qualified Domain Name.
Definition sendlib.c:706
char * username
User's login name.
Definition neomutt.h:142
+ 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 1419 of file send.c.

1420{
1421 struct Buffer *tempfile = NULL;
1422 int rc = -1;
1423
1424 /* Write out the message in MIME form. */
1425 tempfile = buf_pool_get();
1426 buf_mktemp(tempfile);
1427 FILE *fp_tmp = mutt_file_fopen(buf_string(tempfile), "w");
1428 if (!fp_tmp)
1429 goto cleanup;
1430
1431 const bool c_write_bcc = cs_subset_bool(sub, "write_bcc");
1432 const char *const c_smtp_url = cs_subset_string(sub, "smtp_url");
1433 if (c_smtp_url)
1434 cs_subset_str_native_set(sub, "write_bcc", false, NULL);
1435
1437 false, mutt_should_hide_protected_subject(e), sub);
1438
1439 cs_subset_str_native_set(sub, "write_bcc", c_write_bcc, NULL);
1440
1441 fputc('\n', fp_tmp); /* tie off the header. */
1442
1443 if ((mutt_write_mime_body(e->body, fp_tmp, sub) == -1))
1444 goto cleanup;
1445
1446 if (mutt_file_fclose(&fp_tmp) != 0)
1447 {
1448 mutt_perror("%s", buf_string(tempfile));
1449 unlink(buf_string(tempfile));
1450 goto cleanup;
1451 }
1452
1453 if (OptNewsSend)
1454 goto sendmail;
1455
1456 if (c_smtp_url)
1457 {
1458 rc = mutt_smtp_send(&e->env->from, &e->env->to, &e->env->cc, &e->env->bcc,
1459 buf_string(tempfile), (e->body->encoding == ENC_8BIT), sub);
1460 goto cleanup;
1461 }
1462
1463sendmail:
1464 rc = mutt_invoke_sendmail(m, &e->env->from, &e->env->to, &e->env->cc, &e->env->bcc,
1465 buf_string(tempfile), (e->body->encoding == ENC_8BIT), sub);
1466cleanup:
1467 if (fp_tmp)
1468 {
1469 mutt_file_fclose(&fp_tmp);
1470 unlink(buf_string(tempfile));
1471 }
1472 buf_pool_release(&tempfile);
1473 return rc;
1474}
bool mutt_should_hide_protected_subject(struct Email *e)
Should NeoMutt hide the protected subject?
Definition crypt.c:1100
#define mutt_file_fopen(PATH, MODE)
Definition file.h:138
@ ENC_8BIT
8-bit text
Definition mime.h:50
int mutt_write_mime_body(struct Body *b, FILE *fp, struct ConfigSubset *sub)
Write a MIME part.
Definition body.c:300
int mutt_rfc822_write_header(FILE *fp, struct Envelope *env, struct Body *b, enum MuttWriteHeaderMode mode, bool privacy, bool hide_protected_subject, struct ConfigSubset *sub)
Write out one RFC822 header line.
Definition header.c:578
@ MUTT_WRITE_HEADER_NORMAL
A normal Email, write full header + MIME headers.
Definition header.h:38
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:298
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:1099
unsigned int encoding
content-transfer-encoding, ContentEncoding
Definition body.h:41
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:303
#define buf_mktemp(buf)
Definition tmp.h:33
+ 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 1482 of file send.c.

1483{
1484 const struct Slist *const c_send_charset = cs_subset_slist(sub, "send_charset");
1485 for (struct Body *t = b; t; t = t->next)
1486 {
1487 if (t->description)
1488 {
1489 rfc2047_encode(&t->description, NULL, sizeof("Content-Description:"), c_send_charset);
1490 }
1491 if (recurse && t->parts)
1492 mutt_encode_descriptions(t->parts, recurse, sub);
1493 }
1494}
const struct Slist * cs_subset_slist(const struct ConfigSubset *sub, const char *name)
Get a string-list config item by name.
Definition helpers.c:242
void rfc2047_encode(char **pd, const char *specials, int col, const struct Slist *charsets)
RFC-2047-encode a string.
Definition rfc2047.c:628
void mutt_encode_descriptions(struct Body *b, bool recurse, struct ConfigSubset *sub)
RFC2047 encode the content-descriptions.
Definition send.c:1482
String list.
Definition slist.h:37
+ 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 1500 of file send.c.

1501{
1502 for (struct Body *t = b; t; t = t->next)
1503 {
1504 if (t->description)
1505 {
1506 rfc2047_decode(&t->description);
1507 }
1508 if (t->parts)
1509 decode_descriptions(t->parts);
1510 }
1511}
void rfc2047_decode(char **pd)
Decode any RFC2047-encoded header fields.
Definition rfc2047.c:661
static void decode_descriptions(struct Body *b)
RFC2047 decode them in case of an error.
Definition send.c:1500
+ 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 1517 of file send.c.

1518{
1519 FILE *fp = mutt_file_fopen(data, "a+");
1520 if (!fp)
1521 return;
1522
1523 if ((mutt_file_get_size_fp(fp) > 0) && mutt_file_seek(fp, -1, SEEK_END))
1524 {
1525 int c = fgetc(fp);
1526 if (c != '\n')
1527 fputc('\n', fp);
1528 }
1529 mutt_file_fclose(&fp);
1530}
long mutt_file_get_size_fp(FILE *fp)
Get the size of a file.
Definition file.c:1431
bool mutt_file_seek(FILE *fp, LOFF_T offset, int whence)
Wrapper for fseeko with error handling.
Definition file.c:656
+ 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 1542 of file send.c.

1544{
1545 struct Email *e_new = email_new();
1546
1547 if (mutt_prepare_template(fp, m, e_new, e_cur, true) < 0)
1548 {
1549 email_free(&e_new);
1550 return -1;
1551 }
1552
1553 if (WithCrypto)
1554 {
1555 /* mutt_prepare_template doesn't always flip on an application bit.
1556 * so fix that here */
1557 if (!(e_new->security & (APPLICATION_SMIME | APPLICATION_PGP)))
1558 {
1559 const bool c_smime_is_default = cs_subset_bool(sub, "smime_is_default");
1560 if (((WithCrypto & APPLICATION_SMIME) != 0) && c_smime_is_default)
1561 e_new->security |= APPLICATION_SMIME;
1562 else if (WithCrypto & APPLICATION_PGP)
1563 e_new->security |= APPLICATION_PGP;
1564 else
1565 e_new->security |= APPLICATION_SMIME;
1566 }
1567
1568 const bool c_crypt_opportunistic_encrypt = cs_subset_bool(sub, "crypt_opportunistic_encrypt");
1569 if (c_crypt_opportunistic_encrypt)
1570 {
1571 e_new->security |= SEC_OPPENCRYPT;
1573 }
1574 }
1575
1576 struct EmailArray ea = ARRAY_HEAD_INITIALIZER;
1577 ARRAY_ADD(&ea, e_cur);
1578 int rc = mutt_send_message(SEND_RESEND, e_new, NULL, m, &ea, sub);
1579 ARRAY_FREE(&ea);
1580
1581 return rc;
1582}
#define ARRAY_ADD(head, elem)
Add an element at the end of the array.
Definition array.h:157
#define ARRAY_FREE(head)
Release all memory.
Definition array.h:209
#define ARRAY_HEAD_INITIALIZER
Static initializer for arrays.
Definition array.h:58
void crypt_opportunistic_encrypt(struct Email *e)
Can all recipients be determined.
Definition crypt.c:1045
struct Email * email_new(void)
Create a new Email.
Definition email.c:77
void email_free(struct Email **ptr)
Free an Email.
Definition email.c:46
#define SEC_OPPENCRYPT
Opportunistic encrypt mode.
Definition lib.h:94
#define APPLICATION_SMIME
Use SMIME to encrypt/sign.
Definition lib.h:99
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:484
int mutt_send_message(SendFlags flags, struct Email *e_templ, const char *tempfile, struct Mailbox *m, struct EmailArray *ea, struct ConfigSubset *sub)
Send an email.
Definition send.c:2027
#define SEND_RESEND
Reply using the current email as a template.
Definition send.h:49
+ 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 1591 of file send.c.

1592{
1593 if (!reply || !reply->env || !orig || !orig->env)
1594 return false;
1595 return mutt_list_find(&orig->env->references, reply->env->message_id) ||
1596 mutt_list_find(&orig->env->in_reply_to, reply->env->message_id);
1597}
struct ListNode * mutt_list_find(const struct ListHead *h, const char *data)
Find a string in a List.
Definition list.c:103
+ 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 1610 of file send.c.

1611{
1612 const struct Regex *c_abort_noattach_regex = cs_subset_regex(sub, "abort_noattach_regex");
1613 const struct Regex *c_quote_regex = cs_subset_regex(sub, "quote_regex");
1614
1615 /* Search for the regex in `$abort_noattach_regex` within a file */
1616 if (!c_abort_noattach_regex || !c_abort_noattach_regex->regex ||
1617 !c_quote_regex || !c_quote_regex->regex)
1618 {
1619 return false;
1620 }
1621
1622 FILE *fp_att = mutt_file_fopen(filename, "r");
1623 if (!fp_att)
1624 return false;
1625
1626 char *inputline = MUTT_MEM_MALLOC(1024, char);
1627 bool found = false;
1628 while (!feof(fp_att) && fgets(inputline, 1024, fp_att))
1629 {
1630 if (!mutt_is_quote_line(inputline, NULL) &&
1631 mutt_regex_match(c_abort_noattach_regex, inputline))
1632 {
1633 found = true;
1634 break;
1635 }
1636 }
1637 FREE(&inputline);
1638 mutt_file_fclose(&fp_att);
1639 return found;
1640}
const struct Regex * cs_subset_regex(const struct ConfigSubset *sub, const char *name)
Get a regex config item by name.
Definition helpers.c:217
bool mutt_is_quote_line(char *line, regmatch_t *pmatch)
Is a line of message text a quote?
Definition display.c:323
#define MUTT_MEM_MALLOC(n, type)
Definition memory.h:49
bool mutt_regex_match(const struct Regex *regex, const char *str)
Shorthand to mutt_regex_capture()
Definition regex.c:614
Cached regular expression.
Definition regex3.h:86
regex_t * regex
compiled expression
Definition regex3.h:88
+ 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 1655 of file send.c.

1658{
1659 int rc = 0;
1660 struct Body *save_content = NULL;
1661
1662 buf_expand_path(fcc);
1663
1664 /* Don't save a copy when we are in batch-mode, and the FCC
1665 * folder is on an IMAP server: This would involve possibly lots
1666 * of user interaction, which is not available in batch mode.
1667 *
1668 * Note: A patch to fix the problems with the use of IMAP servers
1669 * from non-curses mode is available from Brendan Cully. However,
1670 * I'd like to think a bit more about this before including it. */
1671
1672 if ((flags & SEND_BATCH) && !buf_is_empty(fcc) &&
1673 (imap_path_probe(buf_string(fcc), NULL) == MUTT_IMAP))
1674 {
1675 mutt_error(_("Warning: Fcc to an IMAP mailbox is not supported in batch mode"));
1676 /* L10N: Printed after the "Fcc to an IMAP mailbox is not supported" message.
1677 To make it clearer that the message doesn't mean NeoMutt is aborting
1678 sending the mail too.
1679 %s is the full mailbox URL, including imap(s)://
1680 */
1681 mutt_error(_("Skipping Fcc to %s"), buf_string(fcc));
1682 buf_reset(fcc);
1683 return rc;
1684 }
1685
1686 if (buf_is_empty(fcc) || mutt_str_equal("/dev/null", buf_string(fcc)))
1687 return rc;
1688
1689 struct Body *tmpbody = e->body;
1690 struct Body *save_sig = NULL;
1691 struct Body *save_parts = NULL;
1692
1693 const bool c_fcc_before_send = cs_subset_bool(sub, "fcc_before_send");
1694 /* Before sending, we don't allow message manipulation because it
1695 * will break message signatures. This is especially complicated by
1696 * Protected Headers. */
1697 if (!c_fcc_before_send)
1698 {
1699 const bool c_fcc_clear = cs_subset_bool(sub, "fcc_clear");
1700 if ((WithCrypto != 0) &&
1701 (e->security & (SEC_ENCRYPT | SEC_SIGN | SEC_AUTOCRYPT)) && c_fcc_clear)
1702 {
1703 e->body = clear_content;
1706 mutt_param_delete(&e->body->parameter, "protected-headers");
1707 }
1708
1709 const enum QuadOption c_fcc_attach = cs_subset_quad(sub, "fcc_attach");
1710
1711 /* check to see if the user wants copies of all attachments */
1712 bool save_atts = true;
1713 if (e->body->type == TYPE_MULTIPART)
1714 {
1715 /* In batch mode, save attachments if the quadoption is yes or ask-yes */
1716 if (flags & SEND_BATCH)
1717 {
1718 if ((c_fcc_attach == MUTT_NO) || (c_fcc_attach == MUTT_ASKNO))
1719 save_atts = false;
1720 }
1721 else if (query_quadoption(_("Save attachments in Fcc?"), sub, "fcc_attach") != MUTT_YES)
1722 {
1723 save_atts = false;
1724 }
1725 }
1726 if (!save_atts)
1727 {
1728 if ((WithCrypto != 0) && (e->security & (SEC_ENCRYPT | SEC_SIGN | SEC_AUTOCRYPT)) &&
1729 (mutt_str_equal(e->body->subtype, "encrypted") ||
1730 mutt_str_equal(e->body->subtype, "signed")))
1731 {
1732 if ((clear_content->type == TYPE_MULTIPART) &&
1733 (query_quadoption(_("Save attachments in Fcc?"), sub, "fcc_attach") != MUTT_YES))
1734 {
1735 if (!(e->security & SEC_ENCRYPT) && (e->security & SEC_SIGN))
1736 {
1737 /* save initial signature and attachments */
1738 save_sig = e->body->parts->next;
1739 save_parts = clear_content->parts->next;
1740 }
1741
1742 /* this means writing only the main part */
1743 e->body = clear_content->parts;
1744
1745 if (mutt_protect(e, pgpkeylist, false) == -1)
1746 {
1747 /* we can't do much about it at this point, so
1748 * fallback to saving the whole thing to fcc */
1749 e->body = tmpbody;
1750 save_sig = NULL;
1751 goto full_fcc;
1752 }
1753
1754 save_content = e->body;
1755 }
1756 }
1757 else
1758 {
1759 if (query_quadoption(_("Save attachments in Fcc?"), sub, "fcc_attach") != MUTT_YES)
1760 e->body = e->body->parts;
1761 }
1762 }
1763 }
1764
1765full_fcc:
1766 if (e->body)
1767 {
1768 /* update received time so that when storing to a mbox-style folder
1769 * the From_ line contains the current time instead of when the
1770 * message was first postponed. */
1771 e->received = mutt_date_now();
1772 rc = mutt_write_multiple_fcc(buf_string(fcc), e, NULL, false, NULL, finalpath, sub);
1773 while (rc && !(flags & SEND_BATCH))
1774 {
1776 int choice = mw_multi_choice(
1777 /* L10N: Called when saving to $record or Fcc failed after sending.
1778 (r)etry tries the same mailbox again.
1779 alternate (m)ailbox prompts for a different mailbox to try.
1780 (s)kip aborts saving. */
1781 _("Fcc failed. (r)etry, alternate (m)ailbox, or (s)kip?"),
1782 /* L10N: These correspond to the "Fcc failed" multi-choice prompt
1783 (r)etry, alternate (m)ailbox, or (s)kip.
1784 Any similarity to famous leaders of the FSF is coincidental. */
1785 _("rms"));
1786 switch (choice)
1787 {
1788 case 2: /* alternate (m)ailbox */
1789 /* L10N: This is the prompt to enter an "alternate (m)ailbox" when the
1790 initial Fcc fails. */
1791 rc = mw_enter_fname(_("Fcc mailbox"), fcc, true, m, false, NULL, NULL,
1793 if ((rc == -1) || buf_is_empty(fcc))
1794 {
1795 rc = 0;
1796 break;
1797 }
1799
1800 case 1: /* (r)etry */
1801 rc = mutt_write_multiple_fcc(buf_string(fcc), e, NULL, false, NULL, finalpath, sub);
1802 break;
1803
1804 case -1: /* abort */
1805 case 3: /* (s)kip */
1806 rc = 0;
1807 break;
1808 }
1809 }
1810 }
1811
1812 if (!c_fcc_before_send)
1813 {
1814 e->body = tmpbody;
1815
1816 if ((WithCrypto != 0) && save_sig)
1817 {
1818 /* cleanup the second signature structures */
1819 if (save_content->parts)
1820 {
1821 mutt_body_free(&save_content->parts->next);
1822 save_content->parts = NULL;
1823 }
1824 mutt_body_free(&save_content);
1825
1826 /* restore old signature and attachments */
1827 e->body->parts->next = save_sig;
1828 e->body->parts->parts->next = save_parts;
1829 }
1830 else if ((WithCrypto != 0) && save_content)
1831 {
1832 /* destroy the new encrypted body. */
1833 mutt_body_free(&save_content);
1834 }
1835 }
1836
1837 return 0;
1838}
#define MUTT_SEL_NO_FLAGS
No flags are set.
Definition lib.h:59
@ MUTT_IMAP
'IMAP' Mailbox type
Definition mailbox.h:50
int mutt_protect(struct Email *e, char *keylist, bool postpone)
Encrypt and/or sign a message.
Definition crypt.c:156
void mutt_body_free(struct Body **ptr)
Free a Body.
Definition body.c:58
void mutt_env_free(struct Envelope **ptr)
Free an Envelope.
Definition envelope.c:125
int mw_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:236
int mw_multi_choice(const char *prompt, const char *letters)
Offer the user a multiple choice question -.
Definition question.c:62
enum MailboxType imap_path_probe(const char *path, const struct stat *st)
Is this an IMAP Mailbox?
Definition imap.c:2470
time_t mutt_date_now(void)
Return the number of seconds since the Unix epoch.
Definition date.c:457
#define FALLTHROUGH
Definition lib.h:117
void buf_expand_path(struct Buffer *buf)
Create the canonical path.
Definition muttlib.c:314
#define SEC_AUTOCRYPT
(Autocrypt) Message will be, or was Autocrypt encrypt+signed
Definition lib.h:95
#define SEC_SIGN
Email is signed.
Definition lib.h:87
void mutt_param_delete(struct ParameterList *pl, const char *attribute)
Delete a matching Parameter.
Definition parameter.c:143
@ MUTT_ASKNO
Ask the user, defaulting to 'No'.
Definition quad.h:40
#define SEND_BATCH
Send email in batch mode (without user interaction)
Definition send.h:47
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:964
struct Body * parts
parts of a multipart or message/rfc822
Definition body.h:73
struct Envelope * mime_headers
Memory hole protected headers.
Definition body.h:76
struct ParameterList parameter
Parameters of the content-type.
Definition body.h:63
time_t received
Time when the message was placed in the mailbox.
Definition email.h:61
+ 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 1850 of file send.c.

1852{
1853 char *pgpkeylist = NULL;
1854 const char *encrypt_as = NULL;
1855 struct Body *clear_content = NULL;
1856
1857 const char *const c_postponed = cs_subset_string(sub, "postponed");
1858 if (!c_postponed)
1859 {
1860 mutt_error(_("Can't postpone. $postponed is unset"));
1861 return -1;
1862 }
1863
1864 if (e_post->body->next)
1865 e_post->body = mutt_make_multipart(e_post->body);
1866
1867 mutt_encode_descriptions(e_post->body, true, sub);
1868
1869 const bool c_postpone_encrypt = cs_subset_bool(sub, "postpone_encrypt");
1870 if ((WithCrypto != 0) && c_postpone_encrypt &&
1871 (e_post->security & (SEC_ENCRYPT | SEC_AUTOCRYPT)))
1872 {
1873 if (((WithCrypto & APPLICATION_PGP) != 0) && (e_post->security & APPLICATION_PGP))
1874 {
1875 const char *const c_pgp_default_key = cs_subset_string(sub, "pgp_default_key");
1876 encrypt_as = c_pgp_default_key;
1877 }
1878 else if (((WithCrypto & APPLICATION_SMIME) != 0) && (e_post->security & APPLICATION_SMIME))
1879 {
1880 const char *const c_smime_default_key = cs_subset_string(sub, "smime_default_key");
1881 encrypt_as = c_smime_default_key;
1882 }
1883 if (!encrypt_as)
1884 {
1885 const char *const c_postpone_encrypt_as = cs_subset_string(sub, "postpone_encrypt_as");
1886 encrypt_as = c_postpone_encrypt_as;
1887 }
1888
1889#ifdef USE_AUTOCRYPT
1890 if (e_post->security & SEC_AUTOCRYPT)
1891 {
1893 {
1894 if (mutt_istr_equal(e_post->body->subtype, "mixed"))
1895 e_post->body = mutt_remove_multipart(e_post->body);
1896 decode_descriptions(e_post->body);
1897 mutt_error(_("Error encrypting message. Check your crypt settings."));
1898 return -1;
1899 }
1900 encrypt_as = AutocryptDefaultKey;
1901 }
1902#endif
1903
1904 if (encrypt_as)
1905 {
1906 pgpkeylist = mutt_str_dup(encrypt_as);
1907 clear_content = e_post->body;
1908 if (mutt_protect(e_post, pgpkeylist, true) == -1)
1909 {
1910 FREE(&pgpkeylist);
1911 if (mutt_istr_equal(e_post->body->subtype, "mixed"))
1912 e_post->body = mutt_remove_multipart(e_post->body);
1913 decode_descriptions(e_post->body);
1914 mutt_error(_("Error encrypting message. Check your crypt settings."));
1915 return -1;
1916 }
1917
1918 FREE(&pgpkeylist);
1919
1920 mutt_encode_descriptions(e_post->body, false, sub);
1921 }
1922 }
1923
1924 /* make sure the message is written to the right part of a maildir
1925 * postponed folder. */
1926 e_post->read = false;
1927 e_post->old = false;
1928
1929 mutt_prepare_envelope(e_post->env, false, sub);
1930 mutt_env_to_intl(e_post->env, NULL, NULL); /* Handle bad IDNAs the next time. */
1931
1932 if (mutt_write_fcc(NONULL(c_postponed), e_post,
1933 (e_cur && (flags & SEND_REPLY)) ? e_cur->env->message_id : NULL,
1934 true, fcc, NULL, sub) < 0)
1935 {
1936 if (clear_content)
1937 {
1938 mutt_body_free(&e_post->body);
1939 e_post->body = clear_content;
1940 }
1941 mutt_env_free(&e_post->body->mime_headers); /* protected headers */
1942 mutt_param_delete(&e_post->body->parameter, "protected-headers");
1943 if (mutt_istr_equal(e_post->body->subtype, "mixed"))
1944 e_post->body = mutt_remove_multipart(e_post->body);
1945 decode_descriptions(e_post->body);
1947 return -1;
1948 }
1949
1951
1952 if (clear_content)
1953 mutt_body_free(&clear_content);
1954
1955 return 0;
1956}
char * AutocryptDefaultKey
Autocrypt default key id (used for postponing messages)
Definition config.c:38
int mutt_autocrypt_set_sign_as_default_key(struct Email *e)
Set the Autocrypt default key for signing.
Definition autocrypt.c:697
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:354
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:174
void mutt_unprepare_envelope(struct Envelope *env)
Undo the encodings of mutt_prepare_envelope()
Definition sendlib.c:778
void mutt_prepare_envelope(struct Envelope *env, bool final, struct ConfigSubset *sub)
Prepare an email header.
Definition sendlib.c:739
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:1017
bool read
Email is read.
Definition email.h:50
bool old
Email is seen, but unread.
Definition email.h:49
+ 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 1964 of file send.c.

1965{
1966 return (b->type == TYPE_TEXT) && mutt_istr_equal(b->subtype, "plain");
1967}
@ 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
trueAbort because of missing attachments

Definition at line 1975 of file send.c.

1976{
1977 const enum QuadOption c_abort_noattach = cs_subset_quad(sub, "abort_noattach");
1978
1979 if (c_abort_noattach == MUTT_NO)
1980 return false;
1981
1982 if (b->next)
1983 return false;
1984
1985 bool has_keyword = false;
1986
1987 /* search text/plain parts, whether they are main or alternative parts */
1988 if (is_text_plain(b))
1989 {
1990 has_keyword |= search_attach_keyword(b->filename, sub);
1991 }
1992 else
1993 {
1994 for (b = b->parts; b; b = b->next)
1995 {
1996 if (is_text_plain(b))
1997 {
1998 has_keyword |= search_attach_keyword(b->filename, sub);
1999 }
2000 }
2001 }
2002
2003 if (!has_keyword)
2004 return false;
2005
2006 if (c_abort_noattach == MUTT_YES)
2007 {
2008 mutt_error(_("Message contains text matching \"$abort_noattach_regex\". Not sending."));
2009 return true;
2010 }
2011
2012 return query_quadoption(_("No attachments, cancel sending?"), sub, "abort_noattach") != MUTT_NO;
2013}
static bool search_attach_keyword(char *filename, struct ConfigSubset *sub)
Search an email for 'attachment' keywords.
Definition send.c:1610
static bool is_text_plain(const struct Body *b)
Is a Body a text/plain MIME part?
Definition send.c:1964
char * filename
When sending a message, this is the file to which this structure refers.
Definition body.h:59
+ 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 EmailArray * ea,
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
eaArray 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 2027 of file send.c.

2029{
2030 struct Buffer *fcc = buf_pool_get(); /* where to copy this message */
2031 FILE *fp_tmp = NULL;
2032 struct Body *pbody = NULL;
2033 int i;
2034 bool free_clear_content = false;
2035
2036 struct Body *clear_content = NULL;
2037 char *pgpkeylist = NULL;
2038 /* save current value of "pgp_sign_as" and "smime_default_key" */
2039 char *pgp_sign_as = NULL;
2040 char *smime_sign_as = NULL;
2041 const char *tag = NULL;
2042 char *err = NULL;
2043 const char *ctype = NULL;
2044 char *finalpath = NULL;
2045 struct Email *e_cur = NULL;
2046
2047 if (ea && (ARRAY_SIZE(ea) == 1))
2048 e_cur = *ARRAY_GET(ea, 0);
2049
2050 int rc = -1;
2051
2052 if (flags & SEND_NEWS)
2053 OptNewsSend = true;
2054 else
2055 OptNewsSend = false;
2056
2057 const enum QuadOption c_recall = cs_subset_quad(sub, "recall");
2058
2059 if (!flags && !e_templ && (c_recall != MUTT_NO) && mutt_num_postponed(m, true))
2060 {
2061 /* If the user is composing a new message, check to see if there
2062 * are any postponed messages first. */
2063 enum QuadOption ans = query_quadoption(_("Recall postponed message?"), sub, "recall");
2064 if (ans == MUTT_ABORT)
2065 return rc;
2066
2067 if (ans == MUTT_YES)
2068 flags |= SEND_POSTPONED;
2069 }
2070
2071 if (flags & SEND_POSTPONED)
2072 {
2074 {
2075 const char *const c_pgp_sign_as = cs_subset_string(sub, "pgp_sign_as");
2076 pgp_sign_as = mutt_str_dup(c_pgp_sign_as);
2077 }
2079 {
2080 const char *const c_smime_sign_as = cs_subset_string(sub, "smime_sign_as");
2081 smime_sign_as = mutt_str_dup(c_smime_sign_as);
2082 }
2083 }
2084
2085 /* Delay expansion of aliases until absolutely necessary--shouldn't
2086 * be necessary unless we are prompting the user or about to execute a
2087 * send-hook. */
2088
2089 if (!e_templ)
2090 {
2091 e_templ = email_new();
2092
2093 if (flags == SEND_POSTPONED)
2094 {
2095 rc = mutt_get_postponed(m, e_templ, &e_cur, fcc);
2096 if (rc < 0)
2097 {
2098 flags = SEND_POSTPONED;
2099 goto cleanup;
2100 }
2101 flags = rc;
2102 /* If postponed message is a news article, it have
2103 * a "Newsgroups:" header line, then set appropriate flag. */
2104 if (e_templ->env->newsgroups)
2105 {
2106 flags |= SEND_NEWS;
2107 OptNewsSend = true;
2108 }
2109 else
2110 {
2111 flags &= ~SEND_NEWS;
2112 OptNewsSend = false;
2113 }
2114 }
2115
2116 if (flags & (SEND_POSTPONED | SEND_RESEND))
2117 {
2118 struct Body *b = e_templ->body;
2119 while (b->parts)
2120 b = b->parts;
2121 fp_tmp = mutt_file_fopen(b->filename, "a+");
2122 if (!fp_tmp)
2123 {
2124 mutt_perror("%s", b->filename);
2125 goto cleanup;
2126 }
2127 }
2128
2129 if (!e_templ->env)
2130 e_templ->env = mutt_env_new();
2131 }
2132
2133 /* Parse and use an eventual list-post header */
2134 if ((flags & SEND_LIST_REPLY) && e_cur && e_cur->env && e_cur->env->list_post)
2135 {
2136 /* Use any list-post header as a template */
2137 mutt_parse_mailto(e_templ->env, NULL, e_cur->env->list_post);
2138 /* We don't let them set the sender's address. */
2139 mutt_addrlist_clear(&e_templ->env->from);
2140 }
2141
2142 if (!(flags & (SEND_KEY | SEND_POSTPONED | SEND_RESEND)))
2143 {
2144 /* When SEND_DRAFT_FILE is set, the caller has already
2145 * created the "parent" body structure. */
2146 if (!(flags & SEND_DRAFT_FILE))
2147 {
2148 pbody = mutt_body_new();
2149 pbody->next = e_templ->body; /* don't kill command-line attachments */
2150 e_templ->body = pbody;
2151
2152 const char *const c_content_type = cs_subset_string(sub, "content_type");
2153 ctype = c_content_type;
2154 if (!ctype)
2155 ctype = "text/plain";
2156 mutt_parse_content_type(ctype, e_templ->body);
2157 e_templ->body->unlink = true;
2158 e_templ->body->use_disp = false;
2159 e_templ->body->disposition = DISP_INLINE;
2160
2161 if (tempfile)
2162 {
2163 fp_tmp = mutt_file_fopen(tempfile, "a+");
2164 e_templ->body->filename = mutt_str_dup(tempfile);
2165 if (flags & SEND_NO_FREE_HEADER)
2166 e_templ->body->unlink = false;
2167 }
2168 else
2169 {
2170 struct Buffer *buf = buf_pool_get();
2171 buf_mktemp(buf);
2172 fp_tmp = mutt_file_fopen(buf_string(buf), "w+");
2173 e_templ->body->filename = buf_strdup(buf);
2174 buf_pool_release(&buf);
2175 }
2176 }
2177 else
2178 {
2179 struct Body *b = e_templ->body;
2180 while (b->parts)
2181 b = b->parts;
2182 fp_tmp = mutt_file_fopen(b->filename, "a+");
2183 }
2184
2185 if (!fp_tmp)
2186 {
2187 mutt_debug(LL_DEBUG1, "can't create tempfile %s (errno=%d)\n",
2188 e_templ->body->filename, errno);
2189 mutt_perror("%s", e_templ->body->filename);
2190 goto cleanup;
2191 }
2192 }
2193
2194 const bool c_reverse_name = cs_subset_bool(sub, "reverse_name");
2195 /* this is handled here so that the user can match ~f in send-hook */
2196 if (e_cur && c_reverse_name && !(flags & (SEND_POSTPONED | SEND_RESEND)))
2197 {
2198 /* We shouldn't have to worry about alias expansion here since we are
2199 * either replying to a real or postponed message, therefore no aliases
2200 * should exist since the user has not had the opportunity to add
2201 * addresses to the list. We just have to ensure the postponed messages
2202 * have their aliases expanded. */
2203
2204 if (!TAILQ_EMPTY(&e_templ->env->from))
2205 {
2206 mutt_debug(LL_DEBUG5, "e_templ->env->from before set_reverse_name: %s\n",
2207 buf_string(TAILQ_FIRST(&e_templ->env->from)->mailbox));
2208 mutt_addrlist_clear(&e_templ->env->from);
2209 }
2210 set_reverse_name(&e_templ->env->from, e_cur->env, sub);
2211 }
2212
2213 const bool c_reply_with_xorig = cs_subset_bool(sub, "reply_with_xorig");
2214 if (e_cur && c_reply_with_xorig && !(flags & (SEND_POSTPONED | SEND_RESEND | SEND_FORWARD)))
2215 {
2216 /* We shouldn't have to worry about freeing 'e_templ->env->from' before
2217 * setting it here since this code will only execute when doing some
2218 * sort of reply. The pointer will only be set when using the -H command
2219 * line option.
2220 *
2221 * If there is already a from address recorded in 'e_templ->env->from',
2222 * then it theoretically comes from `$reverse_name` handling, and we don't use
2223 * the 'X-Original-To header'. */
2224 if (!TAILQ_EMPTY(&e_cur->env->x_original_to) && TAILQ_EMPTY(&e_templ->env->from))
2225 {
2226 mutt_addrlist_copy(&e_templ->env->from, &e_cur->env->x_original_to, false);
2227 mutt_debug(LL_DEBUG5, "e_templ->env->from extracted from X-Original-To: header: %s\n",
2228 buf_string(TAILQ_FIRST(&e_templ->env->from)->mailbox));
2229 }
2230 }
2231
2232 if (!e_templ->env->message_id)
2233 e_templ->env->message_id = msgid_generate();
2234
2235 const bool c_resume_draft_files = cs_subset_bool(sub, "resume_draft_files");
2236 if (!(flags & (SEND_POSTPONED | SEND_RESEND)) &&
2237 !((flags & SEND_DRAFT_FILE) && c_resume_draft_files))
2238 {
2239 if ((flags & (SEND_REPLY | SEND_FORWARD | SEND_TO_SENDER)) &&
2240 (envelope_defaults(e_templ->env, ea, flags, sub) == -1))
2241 {
2242 goto cleanup;
2243 }
2244
2245 const bool c_hdrs = cs_subset_bool(sub, "hdrs");
2246 if (c_hdrs)
2247 process_user_recips(e_templ->env);
2248
2249 /* Expand aliases and remove duplicates/crossrefs */
2250 mutt_expand_aliases_env(e_templ->env);
2251
2252 if (flags & SEND_REPLY)
2253 mutt_fix_reply_recipients(e_templ->env, sub);
2254
2255 if ((flags & SEND_NEWS) && (m && m->type == MUTT_NNTP) && !e_templ->env->newsgroups)
2256 {
2257 e_templ->env->newsgroups = mutt_str_dup(((struct NntpMboxData *) m->mdata)->group);
2258 }
2259
2260 const bool c_auto_edit = cs_subset_bool(sub, "auto_edit");
2261 const bool c_edit_headers = cs_subset_bool(sub, "edit_headers");
2262 const bool c_fast_reply = cs_subset_bool(sub, "fast_reply");
2263 if (!(flags & SEND_BATCH) && !(c_auto_edit && c_edit_headers) &&
2264 !((flags & SEND_REPLY) && c_fast_reply))
2265 {
2266 if (edit_envelope(e_templ->env, flags, sub) == -1)
2267 goto cleanup;
2268 }
2269
2270 /* the from address must be set here regardless of whether or not
2271 * $use_from is set so that the '~P' (from you) operator in send-hook
2272 * patterns will work. if $use_from is unset, the from address is killed
2273 * after send-hooks are evaluated */
2274
2275 const bool killfrom = TAILQ_EMPTY(&e_templ->env->from);
2276 if (killfrom)
2277 {
2279 }
2280
2281 if ((flags & SEND_REPLY) && e_cur)
2282 {
2283 /* change setting based upon message we are replying to */
2285
2286 /* set the replied flag for the message we are generating so that the
2287 * user can use ~Q in a send-hook to know when reply-hook's are also
2288 * being used. */
2289 e_templ->replied = true;
2290 }
2291
2292 /* change settings based upon recipients */
2293
2294 mutt_message_hook(NULL, e_templ, CMD_SEND_HOOK);
2295
2296 /* Unset the replied flag from the message we are composing since it is
2297 * no longer required. This is done here because the FCC'd copy of
2298 * this message was erroneously get the 'R'eplied flag when stored in
2299 * a maildir-style mailbox. */
2300 e_templ->replied = false;
2301
2302 /* $use_from and/or $from might have changed in a send-hook */
2303 if (killfrom)
2304 {
2305 mutt_addrlist_clear(&e_templ->env->from);
2306
2307 const bool c_use_from = cs_subset_bool(sub, "use_from");
2308 if (c_use_from && !(flags & (SEND_POSTPONED | SEND_RESEND)))
2310 }
2311
2312 if (c_hdrs)
2313 process_user_header(e_templ->env);
2314
2315 if ((flags & SEND_BATCH) && !(flags & SEND_CONSUMED_STDIN))
2316 {
2317 if (mutt_file_copy_stream(stdin, fp_tmp) < 0)
2318 {
2319 mutt_error(_("Error sending message"));
2320 goto cleanup;
2321 }
2322 }
2323
2324 if (!(flags & SEND_BATCH))
2325 mutt_make_greeting(e_templ, fp_tmp, sub);
2326
2327 const bool c_sig_on_top = cs_subset_bool(sub, "sig_on_top");
2328 const char *const c_editor = cs_subset_string(sub, "editor");
2329 if (c_sig_on_top && !(flags & (SEND_KEY | SEND_BATCH)) && c_editor)
2330 {
2331 append_signature(fp_tmp, sub);
2332 }
2333
2334 /* include replies/forwarded messages, unless we are given a template */
2335 if (!tempfile && (m || !(flags & (SEND_REPLY | SEND_FORWARD))) &&
2336 (generate_body(fp_tmp, e_templ, flags, m, ea, sub) == -1))
2337 {
2338 goto cleanup;
2339 }
2340
2341 if (!c_sig_on_top && !(flags & (SEND_KEY | SEND_BATCH)) && c_editor)
2342 {
2343 append_signature(fp_tmp, sub);
2344 }
2345 }
2346
2347 /* Only set format=flowed for new messages. postponed/resent/draftfiles
2348 * should respect the original email.
2349 *
2350 * This is set here so that send-hook can be used to turn the option on. */
2351 if (!(flags & (SEND_KEY | SEND_POSTPONED | SEND_RESEND | SEND_DRAFT_FILE)))
2352 {
2353 const bool c_text_flowed = cs_subset_bool(sub, "text_flowed");
2354 if (c_text_flowed && is_text_plain(e_templ->body))
2355 {
2356 mutt_param_set(&e_templ->body->parameter, "format", "flowed");
2357 }
2358 }
2359
2360 /* This hook is even called for postponed messages, and can, e.g., be used
2361 * for setting the editor, the sendmail path, or the envelope sender. */
2362 mutt_message_hook(NULL, e_templ, CMD_SEND2_HOOK);
2363
2364 /* wait until now to set the real name portion of our return address so
2365 * that $real_name can be set in a send-hook */
2366 {
2367 struct Address *from = TAILQ_FIRST(&e_templ->env->from);
2368 if (from && !from->personal && !(flags & (SEND_RESEND | SEND_POSTPONED)))
2369 {
2370 const char *const c_real_name = cs_subset_string(sub, "real_name");
2371 if (c_real_name)
2372 from->personal = buf_new(c_real_name);
2373 }
2374 }
2375
2376 if (!(((WithCrypto & APPLICATION_PGP) != 0) && (flags & SEND_KEY)))
2377 mutt_file_fclose(&fp_tmp);
2378
2379 if (!(flags & SEND_BATCH))
2380 {
2381 struct stat st = { 0 };
2382 time_t mtime;
2383 struct Body *b = e_templ->body;
2384 while (b->parts)
2385 b = b->parts;
2386 mtime = mutt_file_decrease_mtime(b->filename, NULL);
2387 if (mtime == (time_t) -1)
2388 {
2389 mutt_perror("%s", b->filename);
2390 goto cleanup;
2391 }
2392
2393 mutt_update_encoding(b, sub);
2394
2395 const bool c_edit_headers = cs_subset_bool(sub, "edit_headers");
2396 const bool c_auto_edit = cs_subset_bool(sub, "auto_edit");
2397
2398 /* Select whether or not the user's editor should be called now. We
2399 * don't want to do this when:
2400 * 1) we are sending a key/cert
2401 * 2) we are forwarding a message and the user doesn't want to edit it.
2402 * This is controlled by the quadoption $forward_edit. However, if
2403 * both $edit_headers and $auto_edit are set, we want to ignore the
2404 * setting of $forward_edit because the user probably needs to add the
2405 * recipients. */
2406 if (!(flags & SEND_KEY) &&
2407 (((flags & SEND_FORWARD) == 0) || (c_edit_headers && c_auto_edit) ||
2408 (query_quadoption(_("Edit forwarded message?"), sub, "forward_edit") == MUTT_YES)))
2409 {
2410 /* If the this isn't a text message, look for a mailcap edit command */
2411 const char *const c_editor = cs_subset_string(sub, "editor");
2412 b = e_templ->body;
2413 while (b->parts)
2414 b = b->parts;
2415 if (mutt_needs_mailcap(b))
2416 {
2417 if (!mutt_edit_attachment(b))
2418 goto cleanup;
2419 }
2420 else if (c_edit_headers)
2421 {
2422 mutt_env_to_local(e_templ->env);
2423 mutt_edit_headers(c_editor, b->filename, e_templ, fcc);
2424 mutt_env_to_intl(e_templ->env, NULL, NULL);
2425 }
2426 else
2427 {
2428 mutt_edit_file(c_editor, b->filename);
2429 if (stat(b->filename, &st) == 0)
2430 {
2431 if (mtime != st.st_mtime)
2433 }
2434 else
2435 {
2436 mutt_perror("%s", b->filename);
2437 }
2438 }
2439
2440 mutt_message_hook(NULL, e_templ, CMD_SEND2_HOOK);
2441 }
2442
2444 {
2445 if (stat(e_templ->body->filename, &st) == 0)
2446 {
2447 /* if the file was not modified, bail out now */
2448 if ((mtime == st.st_mtime) && !e_templ->body->next &&
2449 (query_quadoption(_("Abort unmodified message?"), sub, "abort_unmodified") == MUTT_YES))
2450 {
2451 mutt_message(_("Aborted unmodified message"));
2452 goto cleanup;
2453 }
2454 }
2455 else
2456 {
2457 mutt_perror("%s", e_templ->body->filename);
2458 }
2459 }
2460 }
2461
2462 /* Set the message security unless:
2463 * 1) crypto support is not enabled (WithCrypto==0)
2464 * 2) pgp: header field was present during message editing with $edit_headers (e_templ->security != 0)
2465 * 3) we are resending a message
2466 * 4) we are recalling a postponed message (don't override the user's saved settings)
2467 * 5) we are in batch mode
2468 * But 3, 4, and 5, can be overridden with '-C' in the command line (flags & SEND_CLI_CRYPTO)
2469 *
2470 * This is done after allowing the user to edit the message so that security
2471 * settings can be configured with send2-hook and $edit_headers. */
2472 if ((WithCrypto != 0) && (e_templ->security == 0) &&
2473 ((flags & SEND_CLI_CRYPTO) || !(flags & (SEND_BATCH | SEND_POSTPONED | SEND_RESEND))))
2474 {
2475 bool c_autocrypt = false;
2476 bool c_autocrypt_reply = false;
2477
2478#ifdef USE_AUTOCRYPT
2479 c_autocrypt = cs_subset_bool(sub, "autocrypt");
2480 c_autocrypt_reply = cs_subset_bool(sub, "autocrypt_reply");
2481#endif
2482
2483 if (c_autocrypt && c_autocrypt_reply && e_cur && (e_cur->security & SEC_AUTOCRYPT))
2484 {
2486 }
2487 else
2488 {
2489 const bool c_crypt_auto_sign = cs_subset_bool(sub, "crypt_auto_sign");
2490 const bool c_crypt_auto_encrypt = cs_subset_bool(sub, "crypt_auto_encrypt");
2491 const bool c_crypt_reply_encrypt = cs_subset_bool(sub, "crypt_reply_encrypt");
2492 const bool c_crypt_reply_sign = cs_subset_bool(sub, "crypt_reply_sign");
2493 const bool c_crypt_reply_sign_encrypted = cs_subset_bool(sub, "crypt_reply_sign_encrypted");
2494
2495 if (c_crypt_auto_sign)
2496 e_templ->security |= SEC_SIGN;
2497 if (c_crypt_auto_encrypt)
2498 e_templ->security |= SEC_ENCRYPT;
2499 if (c_crypt_reply_encrypt && e_cur && (e_cur->security & SEC_ENCRYPT))
2500 e_templ->security |= SEC_ENCRYPT;
2501 if (c_crypt_reply_sign && e_cur && (e_cur->security & SEC_SIGN))
2502 e_templ->security |= SEC_SIGN;
2503 if (c_crypt_reply_sign_encrypted && e_cur && (e_cur->security & SEC_ENCRYPT))
2504 e_templ->security |= SEC_SIGN;
2505
2506 const bool c_crypt_opportunistic_encrypt = cs_subset_bool(sub, "crypt_opportunistic_encrypt");
2507
2508 if (((WithCrypto & APPLICATION_PGP) != 0) &&
2509 ((e_templ->security & (SEC_ENCRYPT | SEC_SIGN)) || c_crypt_opportunistic_encrypt))
2510 {
2511 const bool c_pgp_auto_inline = cs_subset_bool(sub, "pgp_auto_inline");
2512 const bool c_pgp_reply_inline = cs_subset_bool(sub, "pgp_reply_inline");
2513
2514 if (c_pgp_auto_inline)
2515 e_templ->security |= SEC_INLINE;
2516 if (c_pgp_reply_inline && e_cur && (e_cur->security & SEC_INLINE))
2517 e_templ->security |= SEC_INLINE;
2518 }
2519 }
2520
2521 const bool c_crypt_opportunistic_encrypt = cs_subset_bool(sub, "crypt_opportunistic_encrypt");
2522
2523 if (e_templ->security || c_crypt_opportunistic_encrypt)
2524 {
2525 const bool c_crypt_auto_pgp = cs_subset_bool(sub, "crypt_auto_pgp");
2526 const bool c_crypt_auto_smime = cs_subset_bool(sub, "crypt_auto_smime");
2527
2528 /* When replying / forwarding, use the original message's
2529 * crypto system. According to the documentation,
2530 * smime_is_default should be disregarded here.
2531 *
2532 * Problem: At least with forwarding, this doesn't really
2533 * make much sense. Should we have an option to completely
2534 * disable individual mechanisms at run-time? */
2535 if (e_cur)
2536 {
2537 if (((WithCrypto & APPLICATION_PGP) != 0) && c_crypt_auto_pgp &&
2538 (e_cur->security & APPLICATION_PGP))
2539 {
2540 e_templ->security |= APPLICATION_PGP;
2541 }
2542 else if (((WithCrypto & APPLICATION_SMIME) != 0) &&
2543 c_crypt_auto_smime && (e_cur->security & APPLICATION_SMIME))
2544 {
2545 e_templ->security |= APPLICATION_SMIME;
2546 }
2547 }
2548
2549 const bool c_smime_is_default = cs_subset_bool(sub, "smime_is_default");
2550
2551 /* No crypto mechanism selected? Use availability + smime_is_default
2552 * for the decision. */
2553 if (!(e_templ->security & (APPLICATION_SMIME | APPLICATION_PGP)))
2554 {
2555 if (((WithCrypto & APPLICATION_SMIME) != 0) && c_crypt_auto_smime && c_smime_is_default)
2556 {
2557 e_templ->security |= APPLICATION_SMIME;
2558 }
2559 else if (((WithCrypto & APPLICATION_PGP) != 0) && c_crypt_auto_pgp)
2560 {
2561 e_templ->security |= APPLICATION_PGP;
2562 }
2563 else if (((WithCrypto & APPLICATION_SMIME) != 0) && c_crypt_auto_smime)
2564 {
2565 e_templ->security |= APPLICATION_SMIME;
2566 }
2567 }
2568 }
2569
2570 /* opportunistic encrypt relies on SMIME or PGP already being selected */
2571 if (c_crypt_opportunistic_encrypt)
2572 {
2573 /* If something has already enabled encryption, e.g. `$crypt_auto_encrypt`
2574 * or `$crypt_reply_encrypt`, then don't enable opportunistic encrypt for
2575 * the message. */
2576 if (!(e_templ->security & (SEC_ENCRYPT | SEC_AUTOCRYPT)))
2577 {
2578 e_templ->security |= SEC_OPPENCRYPT;
2580 }
2581 }
2582
2583 /* No permissible mechanisms found. Don't sign or encrypt. */
2584 if (!(e_templ->security & (APPLICATION_SMIME | APPLICATION_PGP)))
2585 e_templ->security = SEC_NO_FLAGS;
2586 }
2587
2588 /* Deal with the corner case where the crypto module backend is not available.
2589 * This can happen if configured without PGP/SMIME and with GPGME, but
2590 * $crypt_use_gpgme is unset. */
2591 if (e_templ->security && !crypt_has_module_backend(e_templ->security))
2592 {
2593 mutt_error(_("No crypto backend configured. Disabling message security setting."));
2594 e_templ->security = SEC_NO_FLAGS;
2595 }
2596
2597 /* specify a default fcc. if we are in batchmode, only save a copy of
2598 * the message if the value of $copy is yes or ask-yes */
2599
2600 const enum QuadOption c_copy = cs_subset_quad(sub, "copy");
2601
2602 if (buf_is_empty(fcc) && !(flags & SEND_POSTPONED_FCC) &&
2603 (!(flags & SEND_BATCH) || (c_copy & 0x1)))
2604 {
2605 /* set the default FCC */
2606 const bool killfrom = TAILQ_EMPTY(&e_templ->env->from);
2607 if (killfrom)
2608 {
2610 }
2611 mutt_select_fcc(fcc, e_templ);
2612 if (killfrom)
2613 {
2614 mutt_addrlist_clear(&e_templ->env->from);
2615 }
2616 }
2617
2618 mutt_rfc3676_space_stuff(e_templ);
2619
2620 mutt_update_encoding(e_templ->body, sub);
2621
2622 if (!(flags & SEND_BATCH))
2623 {
2624 main_loop:
2625
2626 buf_pretty_mailbox(fcc);
2627 i = dlg_compose(e_templ, fcc,
2628 ((flags & SEND_NO_FREE_HEADER) ? MUTT_COMPOSE_NOFREEHEADER : 0), sub);
2629 if (i == -1)
2630 {
2631 /* abort */
2632 if (flags & SEND_NEWS)
2633 mutt_message(_("Article not posted"));
2634 else
2635 mutt_message(_("Mail not sent"));
2636 goto cleanup;
2637 }
2638 else if (i == 1)
2639 {
2640 if (postpone_message(e_templ, e_cur, buf_string(fcc), flags, sub) != 0)
2641 goto main_loop;
2642 mutt_message(_("Message postponed"));
2643 rc = 1;
2644 goto cleanup;
2645 }
2646 }
2647
2648 if (!(flags & SEND_NEWS))
2649 {
2650 if ((mutt_addrlist_count_recips(&e_templ->env->to) == 0) &&
2651 (mutt_addrlist_count_recips(&e_templ->env->cc) == 0) &&
2652 (mutt_addrlist_count_recips(&e_templ->env->bcc) == 0))
2653 {
2654 if (flags & SEND_BATCH)
2655 {
2656 puts(_("No recipients specified"));
2657 goto cleanup;
2658 }
2659
2660 mutt_warning(_("No recipients specified"));
2661 goto main_loop;
2662 }
2663 }
2664
2665 if (mutt_env_to_intl(e_templ->env, &tag, &err))
2666 {
2667 mutt_error(_("Bad IDN in '%s': '%s'"), tag, err);
2668 FREE(&err);
2669 if (flags & SEND_BATCH)
2670 goto cleanup;
2671 goto main_loop;
2672 }
2673
2674 const enum QuadOption c_abort_nosubject = cs_subset_quad(sub, "abort_nosubject");
2675
2676 if (!e_templ->env->subject && !(flags & SEND_BATCH) &&
2677 (query_quadoption(_("No subject, abort sending?"), sub, "abort_nosubject") != MUTT_NO))
2678 {
2679 /* if the abort is automatic, print an error message */
2680 if (c_abort_nosubject == MUTT_YES)
2681 mutt_error(_("No subject specified"));
2682 goto main_loop;
2683 }
2684
2685 if ((flags & SEND_NEWS) && !e_templ->env->subject)
2686 {
2687 mutt_error(_("No subject specified"));
2688 goto main_loop;
2689 }
2690
2691 if ((flags & SEND_NEWS) && !e_templ->env->newsgroups)
2692 {
2693 mutt_error(_("No newsgroup specified"));
2694 goto main_loop;
2695 }
2696
2697 if (!(flags & SEND_BATCH) && abort_for_missing_attachments(e_templ->body, sub))
2698 {
2699 goto main_loop;
2700 }
2701
2702 const bool c_confirm_empty_to = cs_subset_bool(sub, "confirm_empty_to");
2703 if (c_confirm_empty_to && TAILQ_EMPTY(&e_templ->env->to) &&
2704 (query_yesorno(_("No recipients specified in To. Send anyway?"), MUTT_NO) == MUTT_NO))
2705 {
2706 goto main_loop;
2707 }
2708
2709 if (e_templ->body->next)
2710 e_templ->body = mutt_make_multipart(e_templ->body);
2711
2712 /* Ok, we need to do it this way instead of handling all fcc stuff in
2713 * one place in order to avoid going to main_loop with encoded "env"
2714 * in case of error. Ugh. */
2715
2716 mutt_encode_descriptions(e_templ->body, true, sub);
2717
2718 /* Make sure that clear_content and free_clear_content are
2719 * properly initialized -- we may visit this particular place in
2720 * the code multiple times, including after a failed call to
2721 * mutt_protect(). */
2722
2723 clear_content = NULL;
2724 free_clear_content = false;
2725
2726 if (WithCrypto)
2727 {
2728 if (e_templ->security & (SEC_ENCRYPT | SEC_SIGN | SEC_AUTOCRYPT))
2729 {
2730 /* save the decrypted attachments */
2731 clear_content = e_templ->body;
2732
2733 if ((crypt_get_keys(e_templ, &pgpkeylist, false) == -1) ||
2734 (mutt_protect(e_templ, pgpkeylist, false) == -1))
2735 {
2736 if (mutt_istr_equal(e_templ->body->subtype, "mixed"))
2737 e_templ->body = mutt_remove_multipart(e_templ->body);
2738
2739 FREE(&pgpkeylist);
2740
2741 decode_descriptions(e_templ->body);
2742
2743 if (flags & SEND_BATCH)
2744 {
2745 mutt_message(_("Missing encryption key; mail not sent"));
2746 rc = -1;
2747 goto cleanup;
2748 }
2749
2750 goto main_loop;
2751 }
2752 mutt_encode_descriptions(e_templ->body, false, sub);
2753 }
2754
2755 /* at this point, e_templ->body is one of the following three things:
2756 * - multipart/signed. In this case, clear_content is a child
2757 * - multipart/encrypted. In this case, clear_content exists independently
2758 * - application/pgp. In this case, clear_content exists independently
2759 * - something else. In this case, it's the same as clear_content */
2760
2761 /* This is ugly -- lack of "reporting back" from mutt_protect(). */
2762
2763 if (clear_content && (e_templ->body != clear_content) &&
2764 (e_templ->body->parts != clear_content))
2765 free_clear_content = true;
2766 }
2767
2768 if (OptGui)
2769 mutt_message(_("Sending message..."));
2770
2771 mutt_prepare_envelope(e_templ->env, true, sub);
2772
2773 const bool c_fcc_before_send = cs_subset_bool(sub, "fcc_before_send");
2774 if (c_fcc_before_send)
2775 save_fcc(m, e_templ, fcc, clear_content, pgpkeylist, flags, &finalpath, sub);
2776
2777 i = invoke_mta(m, e_templ, sub);
2778 if (i < 0)
2779 {
2780 if (!(flags & SEND_BATCH))
2781 {
2782 if (!WithCrypto)
2783 ; // do nothing
2784 else if ((e_templ->security & (SEC_ENCRYPT | SEC_AUTOCRYPT)) ||
2785 ((e_templ->security & SEC_SIGN) && (e_templ->body->type == TYPE_APPLICATION)))
2786 {
2787 if (e_templ->body != clear_content)
2788 {
2789 mutt_body_free(&e_templ->body); /* destroy PGP data */
2790 e_templ->body = clear_content; /* restore clear text. */
2791 }
2792 }
2793 else if ((e_templ->security & SEC_SIGN) && (e_templ->body->type == TYPE_MULTIPART))
2794 {
2795 mutt_body_free(&e_templ->body->parts->next); /* destroy sig */
2796 if (mutt_istr_equal(e_templ->body->subtype, "mixed") ||
2797 mutt_istr_equal(e_templ->body->subtype, "signed"))
2798 {
2799 e_templ->body = mutt_remove_multipart(e_templ->body);
2800 }
2801 }
2802
2803 FREE(&pgpkeylist);
2804 mutt_env_free(&e_templ->body->mime_headers); /* protected headers */
2805 mutt_param_delete(&e_templ->body->parameter, "protected-headers");
2806 if (mutt_istr_equal(e_templ->body->subtype, "mixed"))
2807 e_templ->body = mutt_remove_multipart(e_templ->body);
2808 decode_descriptions(e_templ->body);
2809 mutt_unprepare_envelope(e_templ->env);
2810 FREE(&finalpath);
2811 goto main_loop;
2812 }
2813 else
2814 {
2815 puts(_("Could not send the message"));
2816 goto cleanup;
2817 }
2818 }
2819
2820 if (!c_fcc_before_send)
2821 save_fcc(m, e_templ, fcc, clear_content, pgpkeylist, flags, &finalpath, sub);
2822
2823 if (OptGui)
2824 {
2825 mutt_message((i != 0) ? _("Sending in background") :
2826 (flags & SEND_NEWS) ? _("Article posted") :
2827 _("Mail sent"));
2828#ifdef USE_NOTMUCH
2829 const bool c_nm_record = cs_subset_bool(sub, "nm_record");
2830 if (c_nm_record)
2831 nm_record_message(m, finalpath, e_cur);
2832#endif
2833 mutt_sleep(0);
2834 }
2835
2836 if (WithCrypto)
2837 FREE(&pgpkeylist);
2838
2839 if ((WithCrypto != 0) && free_clear_content)
2840 mutt_body_free(&clear_content);
2841
2842 /* set 'replied' flag only if the user didn't change/remove
2843 * In-Reply-To: and References: headers during edit */
2844 if (flags & SEND_REPLY)
2845 {
2846 if (!(flags & SEND_POSTPONED) && m)
2847 {
2848 struct Email **ep = NULL;
2849 ARRAY_FOREACH(ep, ea)
2850 {
2851 struct Email *e = *ep;
2852 mutt_set_flag(m, e, MUTT_REPLIED, is_reply(e, e_templ), true);
2853 }
2854 }
2855 }
2856
2857 rc = 0;
2858
2859cleanup:
2860 buf_pool_release(&fcc);
2861
2862 if (flags & SEND_POSTPONED)
2863 {
2865 {
2866 cs_subset_str_string_set(sub, "pgp_sign_as", pgp_sign_as, NULL);
2867 FREE(&pgp_sign_as);
2868 }
2870 {
2871 cs_subset_str_string_set(sub, "smime_sign_as", smime_sign_as, NULL);
2872 FREE(&smime_sign_as);
2873 }
2874 }
2875
2876 mutt_file_fclose(&fp_tmp);
2877 if (!(flags & SEND_NO_FREE_HEADER))
2878 email_free(&e_templ);
2879
2880 FREE(&finalpath);
2881 return rc;
2882}
int mutt_addrlist_count_recips(const struct AddressList *al)
Count the number of Addresses with valid recipients.
Definition address.c:872
void mutt_expand_aliases_env(struct Envelope *env)
Expand aliases in all the fields of an Envelope.
Definition alias.c:307
struct Buffer * buf_new(const char *str)
Allocate a new Buffer.
Definition buffer.c:304
char * buf_strdup(const struct Buffer *buf)
Copy a Buffer's string.
Definition buffer.c:571
@ CMD_SEND_HOOK
:send-hook
Definition command.h:105
@ CMD_SEND2_HOOK
:send2-hook
Definition command.h:104
@ CMD_REPLY_HOOK
:reply-hook
Definition command.h:100
#define MUTT_COMPOSE_NOFREEHEADER
Definition lib.h:54
@ MUTT_NNTP
'NNTP' (Usenet) Mailbox type
Definition mailbox.h:49
int crypt_get_keys(struct Email *e, char **keylist, bool oppenc_mode)
Check we have all the keys we need.
Definition crypt.c:961
bool crypt_has_module_backend(SecurityFlags type)
Is there a crypto backend for a given type?
Definition cryptglue.c:170
void mutt_edit_file(const char *editor, const char *file)
Let the user edit a file.
Definition curs_lib.c:116
struct Body * mutt_body_new(void)
Create a new Body.
Definition body.c:44
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 header.c:182
void mutt_parse_content_type(const char *s, struct Body *b)
Parse a content type.
Definition parse.c:463
bool mutt_parse_mailto(struct Envelope *env, char **body, const char *src)
Parse a mailto:// url.
Definition parse.c:1754
struct Envelope * mutt_env_new(void)
Create a new Envelope.
Definition envelope.c:45
void mutt_env_to_local(struct Envelope *env)
Convert an Envelope's Address fields to local format.
Definition envelope.c:316
char * msgid_generate(void)
Generate a Message-Id.
time_t mutt_file_decrease_mtime(const char *fp, struct stat *st)
Decrease a file's modification time by 1 second.
Definition file.c:906
void mutt_set_flag(struct Mailbox *m, struct Email *e, enum MessageType flag, bool bf, bool upd_mbox)
Set a flag on an email.
Definition flags.c:54
bool OptGui
(pseudo) when the gui (and curses) are started
Definition globals.c:59
int dlg_compose(struct Email *e, struct Buffer *fcc, uint8_t flags, struct ConfigSubset *sub)
Allow the user to edit the message envelope -.
#define mutt_debug(LEVEL,...)
Definition logging2.h:91
@ LL_DEBUG5
Log at debug level 5.
Definition logging2.h:49
@ LL_DEBUG1
Log at debug level 1.
Definition logging2.h:45
@ DISP_INLINE
Content is inline.
Definition mime.h:62
@ MUTT_REPLIED
Messages that have been replied to.
Definition mutt.h:91
bool mutt_edit_attachment(struct Body *b)
Edit an attachment.
void mutt_sleep(short s)
Sleep for a while.
Definition muttlib.c:841
void buf_pretty_mailbox(struct Buffer *buf)
Shorten a mailbox path using '~' or '='.
Definition muttlib.c:518
bool mutt_needs_mailcap(struct Body *b)
Does this type need a mailcap entry do display.
Definition muttlib.c:378
#define SEC_INLINE
Email has an inline signature.
Definition lib.h:93
#define SEC_NO_FLAGS
No flags are set.
Definition lib.h:85
#define SEC_AUTOCRYPT_OVERRIDE
(Autocrypt) Indicates manual set/unset of encryption
Definition lib.h:96
int nm_record_message(struct Mailbox *m, char *path, struct Email *e)
Add a message to the Notmuch database.
Definition notmuch.c:1910
void mutt_param_set(struct ParameterList *pl, const char *attribute, const char *value)
Set a Parameter.
Definition parameter.c:111
int mutt_num_postponed(struct Mailbox *m, bool force)
Return the number of postponed messages.
Definition postpone.c:67
int mutt_get_postponed(struct Mailbox *m_cur, struct Email *hdr, struct Email **cur, struct Buffer *fcc)
Recall a postponed message.
Definition postpone.c:658
enum QuadOption query_yesorno(const char *prompt, enum QuadOption def)
Ask the user a Yes/No question.
Definition question.c:326
void mutt_rfc3676_space_stuff(struct Email *e)
Perform RFC3676 space stuffing on an Email.
Definition rfc3676.c:489
void mutt_select_fcc(struct Buffer *path, struct Email *e)
Select the FCC path for an email.
Definition run.c:249
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:1850
static bool is_reply(struct Email *reply, struct Email *orig)
Is one email a reply to another?
Definition send.c:1591
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:1655
static int envelope_defaults(struct Envelope *env, struct EmailArray *ea, SendFlags flags, struct ConfigSubset *sub)
Fill in some defaults for a new email.
Definition send.c:1075
void mutt_fix_reply_recipients(struct Envelope *env, struct ConfigSubset *sub)
Remove duplicate recipients.
Definition send.c:947
static int generate_body(FILE *fp_tmp, struct Email *e, SendFlags flags, struct Mailbox *m, struct EmailArray *ea, struct ConfigSubset *sub)
Create a new email body.
Definition send.c:1148
static void mutt_make_greeting(struct Email *e, FILE *fp_out, struct ConfigSubset *sub)
Add greetings string.
Definition send.c:678
static int invoke_mta(struct Mailbox *m, struct Email *e, struct ConfigSubset *sub)
Send an email.
Definition send.c:1419
static void process_user_recips(struct Envelope *env)
Process the user headers.
Definition send.c:370
static void process_user_header(struct Envelope *env)
Process the user headers.
Definition send.c:395
static int edit_envelope(struct Envelope *en, SendFlags flags, struct ConfigSubset *sub)
Edit Envelope fields.
Definition send.c:228
static bool abort_for_missing_attachments(const struct Body *b, struct ConfigSubset *sub)
Should we abort sending because of missing attachments?
Definition send.c:1975
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:1333
static void fix_end_of_file(const char *data)
Ensure a file ends with a linefeed.
Definition send.c:1517
static void append_signature(FILE *fp, struct ConfigSubset *sub)
Append a signature to an email.
Definition send.c:99
#define SEND_POSTPONED_FCC
Used by mutt_get_postponed() to signal that the Mutt-Fcc header field was present.
Definition send.h:50
#define SEND_NO_FREE_HEADER
Used by the -E flag.
Definition send.h:51
#define SEND_DRAFT_FILE
Used by the -H flag.
Definition send.h:52
#define SEND_POSTPONED
Recall a postponed email.
Definition send.h:46
#define SEND_CONSUMED_STDIN
stdin has been read; don't read it twice
Definition send.h:57
#define SEND_CLI_CRYPTO
Enable message security in modes that by default don't enable it.
Definition send.h:58
void mutt_update_encoding(struct Body *b, struct ConfigSubset *sub)
Update the encoding type.
Definition sendlib.c:421
bool unlink
If true, filename should be unlink()ed before free()ing this structure.
Definition body.h:68
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:51
struct AddressList x_original_to
Email's 'X-Original-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:34
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:392
+ Here is the caller graph for this function:

◆ send_simple_email()

static bool send_simple_email ( struct Mailbox * m,
struct EmailArray * ea,
const char * mailto,
const char * subj,
const char * body )
static

Compose an email given a few basic ingredients.

Parameters
mMailbox
eaArray 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 2894 of file send.c.

2896{
2897 struct Email *e = email_new();
2898
2899 /* envelope */
2900 e->env = mutt_env_new();
2901 mutt_parse_mailto(e->env, NULL, mailto);
2902 if (!e->env->subject)
2903 {
2904 mutt_env_set_subject(e->env, subj);
2905 }
2906 if (TAILQ_EMPTY(&e->env->to) && !mutt_addrlist_parse(&e->env->to, NULL))
2907 {
2908 mutt_warning(_("No recipient specified"));
2909 }
2910
2911 /* body */
2912 e->body = mutt_body_new();
2913 char ctype[] = "text/plain";
2914 mutt_parse_content_type(ctype, e->body);
2915
2916 struct Buffer *tempfile = buf_pool_get();
2917 buf_mktemp(tempfile);
2918 if (body)
2919 {
2920 FILE *fp = mutt_file_fopen(buf_string(tempfile), "w+");
2921 if (!fp)
2922 {
2923 email_free(&e);
2924 buf_pool_release(&tempfile);
2925 return false;
2926 }
2927 fprintf(fp, "%s\n", body);
2928 mutt_file_fclose(&fp);
2929 }
2930 e->body->filename = buf_strdup(tempfile);
2931 e->body->unlink = true;
2932 buf_pool_release(&tempfile);
2933
2934 const int rc = mutt_send_message(SEND_DRAFT_FILE, e, NULL, m, ea, NeoMutt->sub);
2935 return rc >= 0;
2936}
struct ConfigSubset * sub
Inherited config items.
Definition neomutt.h:134
+ 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 2945 of file send.c.

2946{
2947 if (!e || !e->env)
2948 {
2949 return false;
2950 }
2951
2952 const char *mailto = e->env->list_subscribe;
2953 if (!mailto)
2954 {
2955 mutt_warning(_("No List-Subscribe header found"));
2956 return false;
2957 }
2958
2959 struct EmailArray ea = ARRAY_HEAD_INITIALIZER;
2960 ARRAY_ADD(&ea, e);
2961 bool rc = send_simple_email(m, &ea, mailto, "Subscribe", "subscribe");
2962 ARRAY_FREE(&ea);
2963
2964 return rc;
2965}
static bool send_simple_email(struct Mailbox *m, struct EmailArray *ea, const char *mailto, const char *subj, const char *body)
Compose an email given a few basic ingredients.
Definition send.c:2894
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 2974 of file send.c.

2975{
2976 if (!e || !e->env)
2977 {
2978 return false;
2979 }
2980
2981 const char *mailto = e->env->list_unsubscribe;
2982 if (!mailto)
2983 {
2984 mutt_warning(_("No List-Unsubscribe header found"));
2985 return false;
2986 }
2987
2988 struct EmailArray ea = ARRAY_HEAD_INITIALIZER;
2989 ARRAY_ADD(&ea, e);
2990 bool rc = send_simple_email(m, &ea, mailto, "Unsubscribe", "unsubscribe");
2991 ARRAY_FREE(&ea);
2992
2993 return rc;
2994}
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: