NeoMutt  2025-12-11-58-g09398d
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 "imap/lib.h"
#include "index/lib.h"
#include "ncrypt/lib.h"
#include "pager/lib.h"
#include "parse/lib.h"
#include "pattern/lib.h"
#include "postpone/lib.h"
#include "question/lib.h"
#include "body.h"
#include "copy.h"
#include "expando_greeting.h"
#include "expando_msgid.h"
#include "globals.h"
#include "handler.h"
#include "header.h"
#include "hook.h"
#include "maillist.h"
#include "multipart.h"
#include "mutt_body.h"
#include "mutt_header.h"
#include "mutt_logging.h"
#include "muttlib.h"
#include "mx.h"
#include "nntp/mdata.h"
#include "protos.h"
#include "rfc3676.h"
#include "sendlib.h"
#include "sendmail.h"
#include "smtp.h"
#include "notmuch/lib.h"
#include "autocrypt/lib.h"

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

108{
109 const char *const c_signature = cs_subset_path(sub, "signature");
110 if (!c_signature)
111 return;
112
113 // If the user hasn't set $signature, don't warn them if it doesn't exist
114 struct Buffer *def_sig = buf_pool_get();
115 cs_str_initial_get(sub->cs, "signature", def_sig);
116 mutt_path_canon(def_sig, NeoMutt->home_dir, false);
117 bool notify_missing = !mutt_str_equal(c_signature, buf_string(def_sig));
118 buf_pool_release(&def_sig);
119
120 pid_t pid = 0;
121 FILE *fp_tmp = mutt_open_read(c_signature, &pid);
122 if (!fp_tmp)
123 {
124 if (notify_missing)
125 mutt_perror("%s", c_signature);
126 return;
127 }
128
129 const bool c_sig_dashes = cs_subset_bool(sub, "sig_dashes");
130 if (c_sig_dashes)
131 fputs("\n-- \n", fp);
132 mutt_file_copy_stream(fp_tmp, fp);
133 mutt_file_fclose(&fp_tmp);
134 if (pid != -1)
135 filter_wait(pid);
136}
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:593
int mutt_file_copy_stream(FILE *fp_in, FILE *fp_out)
Copy the contents of one file into another.
Definition file.c:225
#define mutt_file_fclose(FP)
Definition file.h:139
#define mutt_perror(...)
Definition logging2.h:94
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:660
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:43
char * home_dir
User's home directory.
Definition neomutt.h:54
+ 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 144 of file send.c.

145{
146 struct Address *a = NULL, *tmp = NULL;
147 TAILQ_FOREACH_SAFE(a, al, entries, tmp)
148 {
149 if (mutt_addr_is_user(a) && (!leave_only || TAILQ_NEXT(a, entries)))
150 {
151 TAILQ_REMOVE(al, a, entries);
152 mutt_addr_free(&a);
153 }
154 }
155}
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:595
#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 163 of file send.c.

165{
166 const struct AddressList *const als[] = { t, c };
167
168 for (size_t i = 0; i < countof(als); i++)
169 {
170 const struct AddressList *al = als[i];
171 struct Address *a = NULL;
172 TAILQ_FOREACH(a, al, entries)
173 {
174 if (!a->group && mutt_is_mail_list(a))
175 {
177 }
178 }
179 }
180}
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:44
#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 190 of file send.c.

191{
192 int rc = 0;
193 struct Buffer *buf = buf_pool_get();
194 buf_alloc(buf, 8192);
195 char *err = NULL;
196 int idna_ok = 0;
197
198 do
199 {
201 buf_reset(buf);
202 mutt_addrlist_write(al, buf, false);
203 if (!buf_is_empty(buf))
204 buf_addstr(buf, ", ");
205
206 if (mw_get_field(field, buf, MUTT_COMP_NO_FLAGS, HC_ALIAS, &CompleteAliasOps, NULL) != 0)
207 {
208 rc = -1;
209 goto done;
210 }
213 if (expand_aliases)
215 idna_ok = mutt_addrlist_to_intl(al, &err);
216 if (idna_ok != 0)
217 {
218 mutt_error(_("Bad IDN: '%s'"), err);
219 FREE(&err);
220 }
221 } while (idna_ok != 0);
222
223done:
224 buf_pool_release(&buf);
225 return rc;
226}
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:294
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
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:272
#define mutt_error(...)
Definition logging2.h:93
@ HC_ALIAS
Aliases.
Definition lib.h:55
#define FREE(x)
Definition memory.h:62
#define _(a)
Definition message.h:28
#define MUTT_COMP_NO_FLAGS
No flags are set.
Definition mutt.h:56
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ edit_envelope()

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

Edit Envelope fields.

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

Definition at line 236 of file send.c.

237{
238 int rc = -1;
239 struct Buffer *buf = buf_pool_get();
240 buf_alloc(buf, 8192);
241
242 if (OptNewsSend)
243 {
244 if (en->newsgroups)
245 buf_strcpy(buf, en->newsgroups);
246 else
247 buf_reset(buf);
248
249 if (mw_get_field("Newsgroups: ", buf, MUTT_COMP_NO_FLAGS, HC_OTHER, NULL, NULL) != 0)
250 {
251 goto done;
252 }
254
255 if (en->followup_to)
256 buf_strcpy(buf, en->followup_to);
257 else
258 buf_reset(buf);
259
260 const bool c_ask_followup_to = cs_subset_bool(sub, "ask_followup_to");
261 if (c_ask_followup_to && (mw_get_field("Followup-To: ", buf, MUTT_COMP_NO_FLAGS,
262 HC_OTHER, NULL, NULL) != 0))
263 {
264 goto done;
265 }
267
268 if (en->x_comment_to)
269 buf_strcpy(buf, en->x_comment_to);
270 else
271 buf_reset(buf);
272
273 const bool c_x_comment_to = cs_subset_bool(sub, "x_comment_to");
274 const bool c_ask_x_comment_to = cs_subset_bool(sub, "ask_x_comment_to");
275 if (c_x_comment_to && c_ask_x_comment_to &&
276 (mw_get_field("X-Comment-To: ", buf, MUTT_COMP_NO_FLAGS, HC_OTHER, NULL, NULL) != 0))
277 {
278 goto done;
279 }
281 }
282 else
283 {
284 const bool c_fast_reply = cs_subset_bool(sub, "fast_reply");
285 if (TAILQ_EMPTY(&en->to) || !c_fast_reply || (flags & SEND_REVIEW_TO))
286 {
287 if ((mutt_edit_address(&en->to, _("To: "), true) == -1))
288 goto done;
289 }
290
291 const bool c_ask_cc = cs_subset_bool(sub, "ask_cc");
292 if (TAILQ_EMPTY(&en->cc) || !c_fast_reply)
293 {
294 if (c_ask_cc && (mutt_edit_address(&en->cc, _("Cc: "), true) == -1))
295 goto done;
296 }
297
298 const bool c_ask_bcc = cs_subset_bool(sub, "ask_bcc");
299 if (TAILQ_EMPTY(&en->bcc) || !c_fast_reply)
300 {
301 if (c_ask_bcc && (mutt_edit_address(&en->bcc, _("Bcc: "), true) == -1))
302 goto done;
303 }
304
305 if (TAILQ_EMPTY(&en->to) && TAILQ_EMPTY(&en->cc) && TAILQ_EMPTY(&en->bcc))
306 {
307 mutt_warning(_("No recipients specified"));
308 goto done;
309 }
310
311 const bool c_reply_with_xorig = cs_subset_bool(sub, "reply_with_xorig");
312 if (c_reply_with_xorig && (flags & (SEND_REPLY | SEND_LIST_REPLY | SEND_GROUP_REPLY)) &&
313 (mutt_edit_address(&en->from, "From: ", true) == -1))
314 {
315 goto done;
316 }
317 }
318
319 if (en->subject)
320 {
321 const bool c_fast_reply = cs_subset_bool(sub, "fast_reply");
322 if (c_fast_reply)
323 {
324 rc = 0;
325 goto done;
326 }
327 buf_strcpy(buf, en->subject);
328 }
329 else
330 {
331 const char *p = NULL;
332
333 buf_reset(buf);
334 struct ListNode *uh = NULL;
335 STAILQ_FOREACH(uh, &UserHeader, entries)
336 {
337 size_t plen = mutt_istr_startswith(uh->data, "subject:");
338 if (plen)
339 {
340 p = mutt_str_skip_email_wsp(uh->data + plen);
341 buf_strcpy(buf, p);
342 }
343 }
344 }
345
346 if ((mw_get_field(_("Subject: "), buf, MUTT_COMP_NO_FLAGS, HC_OTHER, NULL, NULL) != 0) ||
347 (buf_is_empty(buf) &&
348 (query_quadoption(_("No subject, abort?"), sub, "abort_nosubject") != MUTT_NO)))
349 {
350 mutt_message(_("No subject, aborting"));
351 goto done;
352 }
354 rc = 0;
355
356done:
357 buf_pool_release(&buf);
358 return rc;
359}
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:91
#define mutt_message(...)
Definition logging2.h:92
@ HC_OTHER
Miscellaneous strings.
Definition lib.h:59
char * mutt_str_skip_email_wsp(const char *s)
Skip over whitespace as defined by RFC5322.
Definition string.c:608
size_t mutt_istr_startswith(const char *str, const char *prefix)
Check whether a string starts with a prefix, ignoring case.
Definition string.c:244
char * mutt_str_replace(char **p, const char *s)
Replace one string with another.
Definition string.c:282
@ 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:377
#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:190
#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 368 of file send.c.

369{
370 SKIPWS(s);
371 return mutt_str_dup(s);
372}
char * mutt_str_dup(const char *str)
Copy a string, safely.
Definition string.c:255
#define SKIPWS(ch)
Definition string2.h:51
+ 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 378 of file send.c.

379{
380 struct ListNode *uh = NULL;
381 STAILQ_FOREACH(uh, &UserHeader, entries)
382 {
383 size_t plen;
384 if ((plen = mutt_istr_startswith(uh->data, "to:")))
385 mutt_addrlist_parse(&env->to, uh->data + plen);
386 else if ((plen = mutt_istr_startswith(uh->data, "cc:")))
387 mutt_addrlist_parse(&env->cc, uh->data + plen);
388 else if ((plen = mutt_istr_startswith(uh->data, "bcc:")))
389 mutt_addrlist_parse(&env->bcc, uh->data + plen);
390 else if ((plen = mutt_istr_startswith(uh->data, "newsgroups:")))
391 env->newsgroups = nntp_get_header(uh->data + plen);
392 else if ((plen = mutt_istr_startswith(uh->data, "followup-to:")))
393 env->followup_to = nntp_get_header(uh->data + plen);
394 else if ((plen = mutt_istr_startswith(uh->data, "x-comment-to:")))
395 env->x_comment_to = nntp_get_header(uh->data + plen);
396 }
397}
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:368
+ 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 403 of file send.c.

404{
405 struct ListNode *uh = NULL;
406 STAILQ_FOREACH(uh, &UserHeader, entries)
407 {
408 size_t plen;
409 if ((plen = mutt_istr_startswith(uh->data, "from:")))
410 {
411 /* User has specified a default From: address. Remove default address */
413 mutt_addrlist_parse(&env->from, uh->data + plen);
414 }
415 else if ((plen = mutt_istr_startswith(uh->data, "reply-to:")))
416 {
418 mutt_addrlist_parse(&env->reply_to, uh->data + plen);
419 }
420 else if ((plen = mutt_istr_startswith(uh->data, "message-id:")))
421 {
422 char *tmp = mutt_extract_message_id(uh->data + plen, NULL);
423 if (mutt_addr_valid_msgid(tmp))
424 {
425 FREE(&env->message_id);
426 env->message_id = tmp;
427 }
428 else
429 {
430 FREE(&tmp);
431 }
432 }
433 else if (!mutt_istr_startswith(uh->data, "to:") &&
434 !mutt_istr_startswith(uh->data, "cc:") &&
435 !mutt_istr_startswith(uh->data, "bcc:") &&
436 !mutt_istr_startswith(uh->data, "newsgroups:") &&
437 !mutt_istr_startswith(uh->data, "followup-to:") &&
438 !mutt_istr_startswith(uh->data, "x-comment-to:") &&
439 !mutt_istr_startswith(uh->data, "supersedes:") &&
440 !mutt_istr_startswith(uh->data, "subject:") &&
441 !mutt_istr_startswith(uh->data, "return-path:"))
442 {
444 }
445 }
446}
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:400
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 454 of file send.c.

455{
456 const struct Expando *c_forward_attribution_intro = cs_subset_expando(sub, "forward_attribution_intro");
457 if (!c_forward_attribution_intro || !fp)
458 return;
459
460 const char *const c_attribution_locale = cs_subset_string(sub, "attribution_locale");
461
462 struct Buffer *buf = buf_pool_get();
463 setlocale(LC_TIME, NONULL(c_attribution_locale));
464 mutt_make_string(buf, -1, c_forward_attribution_intro, NULL, -1, e,
466 setlocale(LC_TIME, "");
467 fputs(buf_string(buf), fp);
468 fputs("\n\n", fp);
469 buf_pool_release(&buf);
470}
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:802
#define MUTT_FORMAT_NO_FLAGS
No flags are set.
Definition render.h:33
#define NONULL(x)
Definition string2.h:43
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 478 of file send.c.

479{
480 const struct Expando *c_forward_attribution_trailer = cs_subset_expando(sub, "forward_attribution_trailer");
481 if (!c_forward_attribution_trailer || !fp)
482 return;
483
484 const char *const c_attribution_locale = cs_subset_string(sub, "attribution_locale");
485
486 struct Buffer *buf = buf_pool_get();
487 setlocale(LC_TIME, NONULL(c_attribution_locale));
488 mutt_make_string(buf, -1, c_forward_attribution_trailer, NULL, -1, e,
490 setlocale(LC_TIME, "");
491 fputc('\n', fp);
492 fputs(buf_string(buf), fp);
493 fputc('\n', fp);
494 buf_pool_release(&buf);
495}
+ 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 506 of file send.c.

508{
509 CopyHeaderFlags chflags = CH_DECODE;
511
512 struct Message *msg = mx_msg_open(m, e);
513 if (!msg)
514 {
515 return -1;
516 }
519
520 const bool c_forward_decode = cs_subset_bool(sub, "forward_decode");
521 if ((WithCrypto != 0) && (e->security & SEC_ENCRYPT) && c_forward_decode)
522 {
523 /* make sure we have the user's passphrase before proceeding... */
525 {
526 mx_msg_close(m, &msg);
527 return -1;
528 }
529 }
530
531 mutt_forward_intro(e, fp_out, sub);
532
533 if (c_forward_decode)
534 {
535 cmflags |= MUTT_CM_DECODE | MUTT_CM_CHARCONV;
536
537 const bool c_weed = cs_subset_bool(sub, "weed");
538 if (c_weed)
539 {
540 chflags |= CH_WEED | CH_REORDER;
541 cmflags |= MUTT_CM_WEED;
542 }
543 }
544
545 const bool c_forward_quote = cs_subset_bool(sub, "forward_quote");
546 if (c_forward_quote)
547 cmflags |= MUTT_CM_PREFIX;
548
549 mutt_copy_message(fp_out, e, msg, cmflags, chflags, 0);
550 mx_msg_close(m, &msg);
551 mutt_forward_trailer(e, fp_out, sub);
552 return 0;
553}
void mutt_parse_mime_message(struct Email *e, FILE *fp)
Parse a MIME email.
Definition commands.c:629
int mutt_copy_message(FILE *fp_out, struct Email *e, struct Message *msg, CopyMessageFlags cmflags, CopyHeaderFlags chflags, int wraplen)
Copy a message from a Mailbox.
Definition copy.c:908
#define CH_DECODE
Do RFC2047 header decoding.
Definition copy.h:56
#define MUTT_CM_WEED
Weed message/rfc822 attachment headers.
Definition copy.h:43
#define MUTT_CM_PREFIX
Quote the header and body.
Definition copy.h:39
#define MUTT_CM_DECODE
Decode the message body into text/plain.
Definition copy.h:40
#define CH_WEED
Weed the headers?
Definition copy.h:55
#define CH_REORDER
Re-order output of headers (specified by 'hdr_order')
Definition copy.h:61
#define MUTT_CM_CHARCONV
Perform character set conversions.
Definition copy.h:44
uint32_t CopyHeaderFlags
Flags for mutt_copy_header(), e.g. CH_UPDATE.
Definition copy.h:52
#define MUTT_CM_NO_FLAGS
No flags are set.
Definition copy.h:37
uint16_t CopyMessageFlags
Flags for mutt_copy_message(), e.g. MUTT_CM_NOHEADER.
Definition copy.h:36
bool crypt_valid_passphrase(SecurityFlags flags)
Check that we have a usable passphrase, ask if not.
Definition crypt.c:131
void mutt_message_hook(struct Mailbox *m, struct Email *e, HookFlags type)
Perform a message hook.
Definition hook.c:1360
#define MUTT_MESSAGE_HOOK
message-hook: run before displaying a message
Definition hook.h:44
int mx_msg_close(struct Mailbox *m, struct Message **ptr)
Close a message.
Definition mx.c:1185
struct Message * mx_msg_open(struct Mailbox *m, struct Email *e)
Return a stream pointer for a message.
Definition mx.c:1139
#define SEC_ENCRYPT
Email is encrypted.
Definition lib.h:84
#define WithCrypto
Definition lib.h:122
void mutt_forward_intro(struct Email *e, FILE *fp, struct ConfigSubset *sub)
Add the "start of forwarded message" text.
Definition send.c:454
void mutt_forward_trailer(struct Email *e, FILE *fp, struct ConfigSubset *sub)
Add a "end of forwarded message" text.
Definition send.c:478
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 565 of file send.c.

568{
569 struct Body **last = *plast;
570 struct Body *body = NULL;
571 struct AttachCtx *actx = NULL;
572 int rc = 0, i;
573
574 struct Message *msg = mx_msg_open(m, e);
575 if (!msg)
576 {
577 return -1;
578 }
579
582
583 actx = MUTT_MEM_CALLOC(1, struct AttachCtx);
584 actx->email = e;
585 actx->fp_root = msg->fp;
586
587 mutt_generate_recvattach_list(actx, actx->email, actx->email->body,
588 actx->fp_root, -1, 0, 0);
589
590 for (i = 0; i < actx->idxlen; i++)
591 {
592 body = actx->idx[i]->body;
593 if ((body->type != TYPE_MULTIPART) && mutt_prefer_as_attachment(body) &&
594 !((body->type == TYPE_APPLICATION) &&
595 (mutt_istr_equal(body->subtype, "pgp-signature") ||
596 mutt_istr_equal(body->subtype, "x-pkcs7-signature") ||
597 mutt_istr_equal(body->subtype, "pkcs7-signature"))))
598 {
599 /* Ask the quadoption only once */
600 if (*forwardq == MUTT_ABORT)
601 {
602 /* L10N: This is the prompt for $forward_attachments.
603 When inline forwarding ($mime_forward answered "no"), this prompts
604 whether to add non-decodable attachments from the original email.
605 Text/plain parts and the like will already be included in the
606 message contents, but other attachment, such as PDF files, will also
607 be added as attachments to the new mail, if this is answered yes. */
608 *forwardq = query_quadoption(_("Forward attachments?"), sub, "forward_attachments");
609 if (*forwardq != MUTT_YES)
610 {
611 if (*forwardq == -1)
612 rc = -1;
613 goto cleanup;
614 }
615 }
616 if (mutt_body_copy(actx->idx[i]->fp, last, body) == -1)
617 {
618 rc = -1;
619 goto cleanup;
620 }
621 last = &((*last)->next);
622 }
623 }
624
625cleanup:
626 *plast = last;
627 mx_msg_close(m, &msg);
628 mutt_actx_free(&actx);
629 return rc;
630}
void mutt_actx_free(struct AttachCtx **ptr)
Free an Attachment Context.
Definition attach.c:198
bool mutt_prefer_as_attachment(struct Body *b)
Do we want this part as an attachment?
Definition handler.c:1850
#define MUTT_MEM_CALLOC(n, type)
Definition memory.h:47
@ 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:672
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 mutt_body.c:49
@ 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 639 of file send.c.

641{
642 if (!exp || !fp_out)
643 return;
644
645 const char *const c_attribution_locale = cs_subset_string(sub, "attribution_locale");
646
647 struct Buffer *buf = buf_pool_get();
648 setlocale(LC_TIME, NONULL(c_attribution_locale));
649 mutt_make_string(buf, -1, exp, NULL, -1, e, MUTT_FORMAT_NO_FLAGS, NULL);
650 setlocale(LC_TIME, "");
651 fputs(buf_string(buf), fp_out);
652 fputc('\n', fp_out);
653 buf_pool_release(&buf);
654}
+ 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 662 of file send.c.

663{
664 format_attribution(cs_subset_expando(sub, "attribution_intro"), e, fp_out, sub);
665}
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:639
+ 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 673 of file send.c.

674{
675 format_attribution(cs_subset_expando(sub, "attribution_trailer"), e, fp_out, sub);
676}
+ 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 686 of file send.c.

687{
688 const struct Expando *c_greeting = cs_subset_expando(sub, "greeting");
689 if (!c_greeting || !fp_out)
690 return;
691
692 struct Buffer *buf = buf_pool_get();
693
695 buf->dsize, NeoMutt->env, buf);
696
697 fputs(buf_string(buf), fp_out);
698 fputc('\n', fp_out);
699 buf_pool_release(&buf);
700}
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:56
+ 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 711 of file send.c.

713{
715 CopyHeaderFlags chflags = CH_DECODE;
716
717 if ((WithCrypto != 0) && (e->security & SEC_ENCRYPT))
718 {
719 /* make sure we have the user's passphrase before proceeding... */
721 return -1;
722 }
723
724 struct Message *msg = mx_msg_open(m, e);
725 if (!msg)
726 {
727 return -1;
728 }
731
732 mutt_make_attribution_intro(e, fp_out, sub);
733
734 const bool c_header = cs_subset_bool(sub, "header");
735 if (!c_header)
736 cmflags |= MUTT_CM_NOHEADER;
737
738 const bool c_weed = cs_subset_bool(sub, "weed");
739 if (c_weed)
740 {
741 chflags |= CH_WEED | CH_REORDER;
742 cmflags |= MUTT_CM_WEED;
743 }
744
745 mutt_copy_message(fp_out, e, msg, cmflags, chflags, 0);
746 mx_msg_close(m, &msg);
747
748 mutt_make_attribution_trailer(e, fp_out, sub);
749
750 return 0;
751}
#define MUTT_CM_REPLYING
Replying the message.
Definition copy.h:46
#define MUTT_CM_NOHEADER
Don't copy the message header.
Definition copy.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:662
void mutt_make_attribution_trailer(struct Email *e, FILE *fp_out, struct ConfigSubset *sub)
Add suffix to replied email text.
Definition send.c:673
+ 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 760 of file send.c.

763{
764 const bool c_reply_self = cs_subset_bool(sub, "reply_self");
765 if (!c_reply_self && mutt_addr_is_user(from))
766 {
767 /* mail is from the user, assume replying to recipients */
768 return &env->to;
769 }
770 else
771 {
772 return &env->from;
773 }
774}
+ 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 786 of file send.c.

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

874{
875 enum QuadOption hmfupto = MUTT_ABORT;
876 const struct Address *followup_to = TAILQ_FIRST(&in->mail_followup_to);
877
878 if ((flags & (SEND_LIST_REPLY | SEND_GROUP_REPLY | SEND_GROUP_CHAT_REPLY)) && followup_to)
879 {
880 char prompt[256] = { 0 };
881 snprintf(prompt, sizeof(prompt), _("Follow-up to %s%s?"),
882 buf_string(followup_to->mailbox),
883 TAILQ_NEXT(TAILQ_FIRST(&in->mail_followup_to), entries) ? ",..." : "");
884
885 hmfupto = query_quadoption(prompt, sub, "honor_followup_to");
886 if (hmfupto == MUTT_ABORT)
887 return -1;
888 }
889
890 if (flags & SEND_LIST_REPLY)
891 {
892 add_mailing_lists(&out->to, &in->to, &in->cc);
893
894 if (followup_to && (hmfupto == MUTT_YES) &&
895 (default_to(&out->cc, in, flags & SEND_LIST_REPLY, (hmfupto == MUTT_YES), sub) == MUTT_ABORT))
896 {
897 return -1; /* abort */
898 }
899 }
900 else if (flags & SEND_TO_SENDER)
901 {
902 mutt_addrlist_copy(&out->to, &in->from, false);
903 }
904 else
905 {
906 if (default_to(&out->to, in, flags & (SEND_GROUP_REPLY | SEND_GROUP_CHAT_REPLY),
907 (hmfupto == MUTT_YES), sub) == -1)
908 {
909 return -1; /* abort */
910 }
911
912 if ((flags & (SEND_GROUP_REPLY | SEND_GROUP_CHAT_REPLY)) &&
913 (!followup_to || (hmfupto != MUTT_YES)))
914 {
915 /* if(!mutt_addr_is_user(in->to)) */
916 if (flags & SEND_GROUP_REPLY)
917 mutt_addrlist_copy(&out->cc, &in->to, true);
918 else
919 mutt_addrlist_copy(&out->to, &in->to, true);
920 mutt_addrlist_copy(&out->cc, &in->cc, true);
921 }
922 }
923 return 0;
924}
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:163
#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 931 of file send.c.

932{
933 struct ListHead *src = STAILQ_EMPTY(&env->references) ? &env->in_reply_to : &env->references;
934 mutt_list_copy_tail(head, src);
935}
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 942 of file send.c.

943{
944 if (env->message_id)
945 {
947 }
948}
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 955 of file send.c.

956{
957 const bool c_me_too = cs_subset_bool(sub, "me_too");
958 if (!c_me_too)
959 {
960 const bool c_reply_self = cs_subset_bool(sub, "reply_self");
961
962 /* the order is important here. do the CC: first so that if the
963 * the user is the only recipient, it ends up on the TO: field */
964 remove_user(&env->cc, TAILQ_EMPTY(&env->to));
965 remove_user(&env->to, TAILQ_EMPTY(&env->cc) || c_reply_self);
966 }
967
968 /* the CC field can get cluttered, especially with lists */
971 mutt_addrlist_remove_xrefs(&env->to, &env->cc);
972
973 if (!TAILQ_EMPTY(&env->cc) && TAILQ_EMPTY(&env->to))
974 {
975 TAILQ_SWAP(&env->to, &env->cc, Address, entries);
976 }
977}
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:144
+ 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 985 of file send.c.

986{
987 if (!env)
988 return;
989
990 const struct Expando *c_forward_format = cs_subset_expando(sub, "forward_format");
991
992 struct Buffer *buf = buf_pool_get();
993 /* set the default subject for the message. */
994 mutt_make_string(buf, -1, c_forward_format, NULL, -1, e, MUTT_FORMAT_NO_FLAGS, NULL);
996 buf_pool_release(&buf);
997}
+ 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 1005 of file send.c.

1007{
1008 if (!env || !env_cur)
1009 return;
1010
1011 /* This takes precedence over a subject that might have
1012 * been taken from a List-Post header. Is that correct? */
1013 if (env_cur->real_subj)
1014 {
1015 char *subj = NULL;
1016 mutt_str_asprintf(&subj, "Re: %s", env_cur->real_subj);
1017 mutt_env_set_subject(env, subj);
1018 FREE(&subj);
1019 }
1020 else if (!env->subject)
1021 {
1022 const char *const c_empty_subject = cs_subset_string(sub, "empty_subject");
1023 mutt_env_set_subject(env, c_empty_subject);
1024 }
1025}
int mutt_str_asprintf(char **strp, const char *fmt,...)
Definition string.c:803
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 1033 of file send.c.

1035{
1036 add_references(&env->references, env_cur);
1037 add_message_id(&env->references, env_cur);
1038 add_message_id(&env->in_reply_to, env_cur);
1039
1040 const bool c_x_comment_to = cs_subset_bool(sub, "x_comment_to");
1041 if (OptNewsSend && c_x_comment_to && !TAILQ_EMPTY(&env_cur->from))
1043}
const char * mutt_get_name(const struct Address *a)
Pick the best name to display from an address.
Definition sort.c:139
static void add_message_id(struct ListHead *head, struct Envelope *env)
Add the email's message ID to a list.
Definition send.c:942
static void add_references(struct ListHead *head, struct Envelope *env)
Add the email's references to a list.
Definition send.c:931
+ 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 1051 of file send.c.

1053{
1054 if (!ea || !env || ARRAY_EMPTY(ea))
1055 return;
1056
1057 struct Email **ep = NULL;
1058 ARRAY_FOREACH(ep, ea)
1059 {
1060 struct Email *e = *ep;
1062 }
1063
1064 /* if there's more than entry in In-Reply-To (i.e. message has multiple
1065 * parents), don't generate a References: header as it's discouraged by
1066 * RFC2822, sect. 3.6.4 */
1067 if ((ARRAY_SIZE(ea) > 1) && !STAILQ_EMPTY(&env->in_reply_to) &&
1069 {
1071 }
1072}
#define ARRAY_FOREACH(elem, head)
Iterate over all elements of the array.
Definition array.h:214
#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:1033
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 1083 of file send.c.

1085{
1086 if (!ea || ARRAY_EMPTY(ea))
1087 return -1;
1088
1089 struct Email *e_cur = *ARRAY_GET(ea, 0);
1090 bool single = (ARRAY_SIZE(ea) == 1);
1091
1092 struct Envelope *env_cur = e_cur->env;
1093 if (!env_cur)
1094 return -1;
1095
1096 if (flags & (SEND_REPLY | SEND_TO_SENDER))
1097 {
1098 if ((flags & SEND_NEWS))
1099 {
1100 /* in case followup set Newsgroups: with Followup-To: if it present */
1101 if (!env->newsgroups && !mutt_istr_equal(env_cur->followup_to, "poster"))
1102 {
1103 env->newsgroups = mutt_str_dup(env_cur->followup_to);
1104 }
1105 }
1106 else if (!single)
1107 {
1108 struct Email **ep = NULL;
1109 ARRAY_FOREACH(ep, ea)
1110 {
1111 struct Email *e = *ep;
1112 if (mutt_fetch_recips(env, e->env, flags, sub) == -1)
1113 return -1;
1114 }
1115 }
1116 else if (mutt_fetch_recips(env, env_cur, flags, sub) == -1)
1117 {
1118 return -1;
1119 }
1120
1121 if ((flags & SEND_LIST_REPLY) && TAILQ_EMPTY(&env->to))
1122 {
1123 mutt_error(_("No mailing lists found"));
1124 return -1;
1125 }
1126
1127 if (flags & SEND_REPLY)
1128 {
1129 mutt_make_misc_reply_headers(env, env_cur, sub);
1130 make_reference_headers(ea, env, sub);
1131 }
1132 }
1133 else if (flags & SEND_FORWARD)
1134 {
1135 mutt_make_forward_subject(env, e_cur, sub);
1136
1137 const bool c_forward_references = cs_subset_bool(sub, "forward_references");
1138 if (c_forward_references)
1139 make_reference_headers(ea, env, sub);
1140 }
1141
1142 return 0;
1143}
#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:1005
void mutt_make_forward_subject(struct Envelope *env, struct Email *e, struct ConfigSubset *sub)
Create a subject for a forwarded email.
Definition send.c:985
static void make_reference_headers(struct EmailArray *ea, struct Envelope *env, struct ConfigSubset *sub)
Generate reference headers for an email.
Definition send.c:1051
int mutt_fetch_recips(struct Envelope *out, struct Envelope *in, SendFlags flags, struct ConfigSubset *sub)
Generate recpients for a reply email.
Definition send.c:872
#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 1156 of file send.c.

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

1271{
1272 /* Only generate the Mail-Followup-To if the user has requested it, and
1273 * it hasn't already been set */
1274
1275 const bool c_followup_to = cs_subset_bool(sub, "followup_to");
1276 if (!c_followup_to)
1277 return;
1278 if (OptNewsSend)
1279 {
1280 if (!env->followup_to && env->newsgroups && (strrchr(env->newsgroups, ',')))
1281 env->followup_to = mutt_str_dup(env->newsgroups);
1282 return;
1283 }
1284
1285 if (TAILQ_EMPTY(&env->mail_followup_to))
1286 {
1287 if (mutt_is_list_recipient(false, env))
1288 {
1289 /* this message goes to known mailing lists, so create a proper
1290 * mail-followup-to header */
1291
1292 mutt_addrlist_copy(&env->mail_followup_to, &env->to, false);
1293 mutt_addrlist_copy(&env->mail_followup_to, &env->cc, true);
1294 }
1295
1296 /* remove ourselves from the mail-followup-to header */
1297 remove_user(&env->mail_followup_to, false);
1298
1299 /* If we are not subscribed to any of the lists in question, re-add
1300 * ourselves to the mail-followup-to header. The mail-followup-to header
1301 * generated is a no-op with group-reply, but makes sure list-reply has the
1302 * desired effect. */
1303
1304 if (!TAILQ_EMPTY(&env->mail_followup_to) &&
1306 {
1307 struct AddressList *al = NULL;
1308 if (!TAILQ_EMPTY(&env->reply_to))
1309 al = &env->reply_to;
1310 else if (!TAILQ_EMPTY(&env->from))
1311 al = &env->from;
1312
1313 if (al)
1314 {
1315 struct Address *a = NULL;
1316 TAILQ_FOREACH_REVERSE(a, al, AddressList, entries)
1317 {
1319 }
1320 }
1321 else
1322 {
1324 }
1325 }
1326
1328 }
1329}
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:496
bool mutt_is_list_recipient(bool all_addr, struct Envelope *env)
Matches known mailing lists.
Definition exec.c:509
#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:1394
+ 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 1341 of file send.c.

1343{
1344 struct Address *a = NULL;
1345 if (TAILQ_EMPTY(al))
1346 {
1347 TAILQ_FOREACH(a, &env->to, entries)
1348 {
1349 if (mutt_addr_is_user(a))
1350 {
1352 break;
1353 }
1354 }
1355 }
1356
1357 if (TAILQ_EMPTY(al))
1358 {
1359 TAILQ_FOREACH(a, &env->cc, entries)
1360 {
1361 if (mutt_addr_is_user(a))
1362 {
1364 break;
1365 }
1366 }
1367 }
1368
1369 if (TAILQ_EMPTY(al))
1370 {
1371 struct Address *from = TAILQ_FIRST(&env->from);
1372 if (from && mutt_addr_is_user(from))
1373 {
1375 }
1376 }
1377
1378 if (!TAILQ_EMPTY(al))
1379 {
1380 /* when $reverse_real_name is not set, clear the personal name so that it
1381 * may be set via a reply- or send-hook. */
1382
1383 const bool c_reverse_real_name = cs_subset_bool(sub, "reverse_real_name");
1384 if (!c_reverse_real_name)
1385 FREE(&TAILQ_FIRST(al)->personal);
1386 }
1387}
+ 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 1394 of file send.c.

1395{
1396 /* Note: We let $from override $real_name here.
1397 * Is this the right thing to do?
1398 */
1399
1400 const struct Address *c_from = cs_subset_address(sub, "from");
1401 if (c_from)
1402 {
1403 return mutt_addr_copy(c_from);
1404 }
1405
1406 char domain[1024] = { 0 };
1407 const char *mailbox = NeoMutt->username;
1408 const bool c_use_domain = cs_subset_bool(sub, "use_domain");
1409 if (c_use_domain)
1410 {
1411 snprintf(domain, sizeof(domain), "%s@%s", NONULL(NeoMutt->username),
1412 NONULL(mutt_fqdn(true, sub)));
1413 mailbox = domain;
1414 }
1415
1416 return mutt_addr_create(NULL, mailbox);
1417}
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:707
char * username
User's login name.
Definition neomutt.h:55
+ 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 1427 of file send.c.

1428{
1429 struct Buffer *tempfile = NULL;
1430 int rc = -1;
1431
1432 /* Write out the message in MIME form. */
1433 tempfile = buf_pool_get();
1434 buf_mktemp(tempfile);
1435 FILE *fp_tmp = mutt_file_fopen(buf_string(tempfile), "w");
1436 if (!fp_tmp)
1437 goto cleanup;
1438
1439 const bool c_write_bcc = cs_subset_bool(sub, "write_bcc");
1440 const char *const c_smtp_url = cs_subset_string(sub, "smtp_url");
1441 if (c_smtp_url)
1442 cs_subset_str_native_set(sub, "write_bcc", false, NULL);
1443
1445 false, mutt_should_hide_protected_subject(e), sub);
1446
1447 cs_subset_str_native_set(sub, "write_bcc", c_write_bcc, NULL);
1448
1449 fputc('\n', fp_tmp); /* tie off the header. */
1450
1451 if ((mutt_write_mime_body(e->body, fp_tmp, sub) == -1))
1452 goto cleanup;
1453
1454 if (mutt_file_fclose(&fp_tmp) != 0)
1455 {
1456 mutt_perror("%s", buf_string(tempfile));
1457 unlink(buf_string(tempfile));
1458 goto cleanup;
1459 }
1460
1461 if (OptNewsSend)
1462 goto sendmail;
1463
1464 if (c_smtp_url)
1465 {
1466 rc = mutt_smtp_send(&e->env->from, &e->env->to, &e->env->cc, &e->env->bcc,
1467 buf_string(tempfile), (e->body->encoding == ENC_8BIT), sub);
1468 goto cleanup;
1469 }
1470
1471sendmail:
1472 rc = mutt_invoke_sendmail(m, &e->env->from, &e->env->to, &e->env->cc, &e->env->bcc,
1473 buf_string(tempfile), (e->body->encoding == ENC_8BIT), sub);
1474cleanup:
1475 if (fp_tmp)
1476 {
1477 mutt_file_fclose(&fp_tmp);
1478 unlink(buf_string(tempfile));
1479 }
1480 buf_pool_release(&tempfile);
1481 return rc;
1482}
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
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:577
@ MUTT_WRITE_HEADER_NORMAL
A normal Email, write full header + MIME headers.
Definition header.h:40
@ ENC_8BIT
8-bit text
Definition mime.h:50
int mutt_write_mime_body(struct Body *b, FILE *fp, struct ConfigSubset *sub)
Write a MIME part.
Definition body.c:300
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 1490 of file send.c.

1491{
1492 const struct Slist *const c_send_charset = cs_subset_slist(sub, "send_charset");
1493 for (struct Body *t = b; t; t = t->next)
1494 {
1495 if (t->description)
1496 {
1497 rfc2047_encode(&t->description, NULL, sizeof("Content-Description:"), c_send_charset);
1498 }
1499 if (recurse && t->parts)
1500 mutt_encode_descriptions(t->parts, recurse, sub);
1501 }
1502}
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:1490
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 1508 of file send.c.

1509{
1510 for (struct Body *t = b; t; t = t->next)
1511 {
1512 if (t->description)
1513 {
1514 rfc2047_decode(&t->description);
1515 }
1516 if (t->parts)
1517 decode_descriptions(t->parts);
1518 }
1519}
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:1508
+ 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 1525 of file send.c.

1526{
1527 FILE *fp = mutt_file_fopen(data, "a+");
1528 if (!fp)
1529 return;
1530
1531 if ((mutt_file_get_size_fp(fp) > 0) && mutt_file_seek(fp, -1, SEEK_END))
1532 {
1533 int c = fgetc(fp);
1534 if (c != '\n')
1535 fputc('\n', fp);
1536 }
1537 mutt_file_fclose(&fp);
1538}
long mutt_file_get_size_fp(FILE *fp)
Get the size of a file.
Definition file.c:1430
bool mutt_file_seek(FILE *fp, LOFF_T offset, int whence)
Wrapper for fseeko with error handling.
Definition file.c:655
+ 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 1550 of file send.c.

1552{
1553 struct Email *e_new = email_new();
1554
1555 if (mutt_prepare_template(fp, m, e_new, e_cur, true) < 0)
1556 {
1557 email_free(&e_new);
1558 return -1;
1559 }
1560
1561 if (WithCrypto)
1562 {
1563 /* mutt_prepare_template doesn't always flip on an application bit.
1564 * so fix that here */
1565 if (!(e_new->security & (APPLICATION_SMIME | APPLICATION_PGP)))
1566 {
1567 const bool c_smime_is_default = cs_subset_bool(sub, "smime_is_default");
1568 if (((WithCrypto & APPLICATION_SMIME) != 0) && c_smime_is_default)
1569 e_new->security |= APPLICATION_SMIME;
1570 else if (WithCrypto & APPLICATION_PGP)
1571 e_new->security |= APPLICATION_PGP;
1572 else
1573 e_new->security |= APPLICATION_SMIME;
1574 }
1575
1576 const bool c_crypt_opportunistic_encrypt = cs_subset_bool(sub, "crypt_opportunistic_encrypt");
1577 if (c_crypt_opportunistic_encrypt)
1578 {
1579 e_new->security |= SEC_OPPENCRYPT;
1581 }
1582 }
1583
1584 struct EmailArray ea = ARRAY_HEAD_INITIALIZER;
1585 ARRAY_ADD(&ea, e_cur);
1586 int rc = mutt_send_message(SEND_RESEND, e_new, NULL, m, &ea, sub);
1587 ARRAY_FREE(&ea);
1588
1589 return rc;
1590}
#define ARRAY_ADD(head, elem)
Add an element at the end of the array.
Definition array.h:156
#define ARRAY_FREE(head)
Release all memory.
Definition array.h:204
#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:92
#define APPLICATION_SMIME
Use SMIME to encrypt/sign.
Definition lib.h:97
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:487
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:2035
#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 1599 of file send.c.

1600{
1601 if (!reply || !reply->env || !orig || !orig->env)
1602 return false;
1603 return mutt_list_find(&orig->env->references, reply->env->message_id) ||
1604 mutt_list_find(&orig->env->in_reply_to, reply->env->message_id);
1605}
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 1618 of file send.c.

1619{
1620 const struct Regex *c_abort_noattach_regex = cs_subset_regex(sub, "abort_noattach_regex");
1621 const struct Regex *c_quote_regex = cs_subset_regex(sub, "quote_regex");
1622
1623 /* Search for the regex in `$abort_noattach_regex` within a file */
1624 if (!c_abort_noattach_regex || !c_abort_noattach_regex->regex ||
1625 !c_quote_regex || !c_quote_regex->regex)
1626 {
1627 return false;
1628 }
1629
1630 FILE *fp_att = mutt_file_fopen(filename, "r");
1631 if (!fp_att)
1632 return false;
1633
1634 char *inputline = MUTT_MEM_MALLOC(1024, char);
1635 bool found = false;
1636 while (!feof(fp_att) && fgets(inputline, 1024, fp_att))
1637 {
1638 if (!mutt_is_quote_line(inputline, NULL) &&
1639 mutt_regex_match(c_abort_noattach_regex, inputline))
1640 {
1641 found = true;
1642 break;
1643 }
1644 }
1645 FREE(&inputline);
1646 mutt_file_fclose(&fp_att);
1647 return found;
1648}
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:322
#define MUTT_MEM_MALLOC(n, type)
Definition memory.h:48
bool mutt_regex_match(const struct Regex *regex, const char *str)
Shorthand to mutt_regex_capture()
Definition regex.c:613
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 1663 of file send.c.

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

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

1973{
1974 return (b->type == TYPE_TEXT) && mutt_istr_equal(b->subtype, "plain");
1975}
@ 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 1983 of file send.c.

1984{
1985 const enum QuadOption c_abort_noattach = cs_subset_quad(sub, "abort_noattach");
1986
1987 if (c_abort_noattach == MUTT_NO)
1988 return false;
1989
1990 if (b->next)
1991 return false;
1992
1993 bool has_keyword = false;
1994
1995 /* search text/plain parts, whether they are main or alternative parts */
1996 if (is_text_plain(b))
1997 {
1998 has_keyword |= search_attach_keyword(b->filename, sub);
1999 }
2000 else
2001 {
2002 for (b = b->parts; b; b = b->next)
2003 {
2004 if (is_text_plain(b))
2005 {
2006 has_keyword |= search_attach_keyword(b->filename, sub);
2007 }
2008 }
2009 }
2010
2011 if (!has_keyword)
2012 return false;
2013
2014 if (c_abort_noattach == MUTT_YES)
2015 {
2016 mutt_error(_("Message contains text matching \"$abort_noattach_regex\". Not sending."));
2017 return true;
2018 }
2019
2020 return query_quadoption(_("No attachments, cancel sending?"), sub, "abort_noattach") != MUTT_NO;
2021}
static bool search_attach_keyword(char *filename, struct ConfigSubset *sub)
Search an email for 'attachment' keywords.
Definition send.c:1618
static bool is_text_plain(const struct Body *b)
Is a Body a text/plain MIME part?
Definition send.c:1972
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 2035 of file send.c.

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

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

2954{
2955 if (!e || !e->env)
2956 {
2957 return false;
2958 }
2959
2960 const char *mailto = e->env->list_subscribe;
2961 if (!mailto)
2962 {
2963 mutt_warning(_("No List-Subscribe header found"));
2964 return false;
2965 }
2966
2967 struct EmailArray ea = ARRAY_HEAD_INITIALIZER;
2968 ARRAY_ADD(&ea, e);
2969 bool rc = send_simple_email(m, &ea, mailto, "Subscribe", "subscribe");
2970 ARRAY_FREE(&ea);
2971
2972 return rc;
2973}
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:2902
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 2982 of file send.c.

2983{
2984 if (!e || !e->env)
2985 {
2986 return false;
2987 }
2988
2989 const char *mailto = e->env->list_unsubscribe;
2990 if (!mailto)
2991 {
2992 mutt_warning(_("No List-Unsubscribe header found"));
2993 return false;
2994 }
2995
2996 struct EmailArray ea = ARRAY_HEAD_INITIALIZER;
2997 ARRAY_ADD(&ea, e);
2998 bool rc = send_simple_email(m, &ea, mailto, "Unsubscribe", "unsubscribe");
2999 ARRAY_FREE(&ea);
3000
3001 return rc;
3002}
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: