NeoMutt  2025-01-09-117-gace867
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.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 106 of file send.c.

107{
108 const char *const c_signature = cs_subset_path(sub, "signature");
109 if (!c_signature)
110 return;
111
112 // If the user hasn't set $signature, don't warn them if it doesn't exist
113 struct Buffer *def_sig = buf_pool_get();
114 cs_str_initial_get(sub->cs, "signature", def_sig);
115 mutt_path_canon(def_sig, NeoMutt->home_dir, false);
116 bool notify_missing = !mutt_str_equal(c_signature, buf_string(def_sig));
117 buf_pool_release(&def_sig);
118
119 pid_t pid = 0;
120 FILE *fp_tmp = mutt_open_read(c_signature, &pid);
121 if (!fp_tmp)
122 {
123 if (notify_missing)
124 mutt_perror("%s", c_signature);
125 return;
126 }
127
128 const bool c_sig_dashes = cs_subset_bool(sub, "sig_dashes");
129 if (c_sig_dashes)
130 fputs("\n-- \n", fp);
131 mutt_file_copy_stream(fp_tmp, fp);
132 mutt_file_fclose(&fp_tmp);
133 if (pid != -1)
134 filter_wait(pid);
135}
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:661
FILE * mutt_open_read(const char *path, pid_t *thepid)
Run a command to read from.
Definition: muttlib.c:700
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:53
+ 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 143 of file send.c.

144{
145 struct Address *a = NULL, *tmp = NULL;
146 TAILQ_FOREACH_SAFE(a, al, entries, tmp)
147 {
148 if (mutt_addr_is_user(a) && (!leave_only || TAILQ_NEXT(a, entries)))
149 {
150 TAILQ_REMOVE(al, a, entries);
151 mutt_addr_free(&a);
152 }
153 }
154}
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:596
#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:36
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ add_mailing_lists()

static void add_mailing_lists ( struct AddressList *  out,
const struct AddressList *  t,
const struct AddressList *  c 
)
static

Search Address lists for mailing lists.

Parameters
outAddress list where to append matching mailing lists
t'To' Address list
c'Cc' Address list

Definition at line 162 of file send.c.

164{
165 const struct AddressList *const als[] = { t, c };
166
167 for (size_t i = 0; i < mutt_array_size(als); i++)
168 {
169 const struct AddressList *al = als[i];
170 struct Address *a = NULL;
171 TAILQ_FOREACH(a, al, entries)
172 {
173 if (!a->group && mutt_is_mail_list(a))
174 {
176 }
177 }
178 }
179}
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? - Implements addr_predicate_t -.
Definition: maillist.c:44
#define mutt_array_size(x)
Definition: memory.h:38
#define TAILQ_FOREACH(var, head, field)
Definition: queue.h:782
bool group
Group mailbox?
Definition: address.h:39
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_edit_address()

int mutt_edit_address ( struct AddressList *  al,
const char *  field,
bool  expand_aliases 
)

Edit an email address.

Parameters
[in,out]alAddressList to edit
[in]fieldPrompt for user
[in]expand_aliasesIf true, expand Address aliases
Return values
0Success
-1Failure

Definition at line 189 of file send.c.

190{
191 int rc = 0;
192 struct Buffer *buf = buf_pool_get();
193 buf_alloc(buf, 8192);
194 char *err = NULL;
195 int idna_ok = 0;
196
197 do
198 {
200 buf_reset(buf);
201 mutt_addrlist_write(al, buf, false);
202 if (!buf_is_empty(buf))
203 buf_addstr(buf, ", ");
204
205 if (mw_get_field(field, buf, MUTT_COMP_NO_FLAGS, HC_ALIAS, &CompleteAliasOps, NULL) != 0)
206 {
207 rc = -1;
208 goto done;
209 }
212 if (expand_aliases)
214 idna_ok = mutt_addrlist_to_intl(al, &err);
215 if (idna_ok != 0)
216 {
217 mutt_error(_("Bad IDN: '%s'"), err);
218 FREE(&err);
219 }
220 } while (idna_ok != 0);
221
222done:
223 buf_pool_release(&buf);
224 return rc;
225}
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:295
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:273
#define mutt_error(...)
Definition: logging2.h:93
@ HC_ALIAS
Aliases.
Definition: lib.h:54
#define FREE(x)
Definition: memory.h:55
#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 235 of file send.c.

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

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

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

403{
404 struct ListNode *uh = NULL;
405 STAILQ_FOREACH(uh, &UserHeader, entries)
406 {
407 size_t plen;
408 if ((plen = mutt_istr_startswith(uh->data, "from:")))
409 {
410 /* User has specified a default From: address. Remove default address */
412 mutt_addrlist_parse(&env->from, uh->data + plen);
413 }
414 else if ((plen = mutt_istr_startswith(uh->data, "reply-to:")))
415 {
417 mutt_addrlist_parse(&env->reply_to, uh->data + plen);
418 }
419 else if ((plen = mutt_istr_startswith(uh->data, "message-id:")))
420 {
421 char *tmp = mutt_extract_message_id(uh->data + plen, NULL);
422 if (mutt_addr_valid_msgid(tmp))
423 {
424 FREE(&env->message_id);
425 env->message_id = tmp;
426 }
427 else
428 {
429 FREE(&tmp);
430 }
431 }
432 else if (!mutt_istr_startswith(uh->data, "to:") &&
433 !mutt_istr_startswith(uh->data, "cc:") &&
434 !mutt_istr_startswith(uh->data, "bcc:") &&
435 !mutt_istr_startswith(uh->data, "newsgroups:") &&
436 !mutt_istr_startswith(uh->data, "followup-to:") &&
437 !mutt_istr_startswith(uh->data, "x-comment-to:") &&
438 !mutt_istr_startswith(uh->data, "supersedes:") &&
439 !mutt_istr_startswith(uh->data, "subject:") &&
440 !mutt_istr_startswith(uh->data, "return-path:"))
441 {
443 }
444 }
445}
bool mutt_addr_valid_msgid(const char *msgid)
Is this a valid Message ID?
Definition: address.c:792
char * mutt_extract_message_id(const char *s, size_t *len)
Find a message-id.
Definition: parse.c:401
struct ListNode * mutt_list_insert_tail(struct ListHead *h, char *s)
Append a string to the end of a List.
Definition: list.c:65
struct ListHead userhdrs
user defined headers
Definition: envelope.h:85
struct AddressList reply_to
Email's 'reply-to'.
Definition: envelope.h:64
char * message_id
Message ID.
Definition: envelope.h:73
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_forward_intro()

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

Add the "start of forwarded message" text.

Parameters
eEmail
subConfig Subset
fpFile to write to

Definition at line 453 of file send.c.

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

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

507{
508 CopyHeaderFlags chflags = CH_DECODE;
510
511 struct Message *msg = mx_msg_open(m, e);
512 if (!msg)
513 {
514 return -1;
515 }
518
519 const bool c_forward_decode = cs_subset_bool(sub, "forward_decode");
520 if ((WithCrypto != 0) && (e->security & SEC_ENCRYPT) && c_forward_decode)
521 {
522 /* make sure we have the user's passphrase before proceeding... */
524 {
525 mx_msg_close(m, &msg);
526 return -1;
527 }
528 }
529
530 mutt_forward_intro(e, fp_out, sub);
531
532 if (c_forward_decode)
533 {
534 cmflags |= MUTT_CM_DECODE | MUTT_CM_CHARCONV;
535
536 const bool c_weed = cs_subset_bool(sub, "weed");
537 if (c_weed)
538 {
539 chflags |= CH_WEED | CH_REORDER;
540 cmflags |= MUTT_CM_WEED;
541 }
542 }
543
544 const bool c_forward_quote = cs_subset_bool(sub, "forward_quote");
545 if (c_forward_quote)
546 cmflags |= MUTT_CM_PREFIX;
547
548 mutt_copy_message(fp_out, e, msg, cmflags, chflags, 0);
549 mx_msg_close(m, &msg);
550 mutt_forward_trailer(e, fp_out, sub);
551 return 0;
552}
void mutt_parse_mime_message(struct Email *e, FILE *fp)
Parse a MIME email.
Definition: attachments.c:596
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:911
#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:132
void mutt_message_hook(struct Mailbox *m, struct Email *e, HookFlags type)
Perform a message hook.
Definition: hook.c:701
#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:453
void mutt_forward_trailer(struct Email *e, FILE *fp, struct ConfigSubset *sub)
Add a "end of forwarded message" text.
Definition: send.c:477
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 564 of file send.c.

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

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

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

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

686{
687 const struct Expando *c_greeting = cs_subset_expando(sub, "greeting");
688 if (!c_greeting || !fp_out)
689 return;
690
691 struct Buffer *buf = buf_pool_get();
692
694 buf->dsize, NeoMutt->env, buf);
695
696 fputs(buf_string(buf), fp_out);
697 fputc('\n', fp_out);
698 buf_pool_release(&buf);
699}
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:139
#define TOKEN_NO_FLAGS
No flags are set.
Definition: extract.h:46
const struct ExpandoRenderCallback GreetingRenderCallbacks[]
Callbacks for Greeting Expandos.
Definition: expando.c:110
size_t dsize
Length of data.
Definition: buffer.h:39
char ** env
Private copy of the environment variables.
Definition: neomutt.h:55
+ 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 710 of file send.c.

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

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

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

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

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

942{
943 if (env->message_id)
944 {
946 }
947}
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 954 of file send.c.

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

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

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

1034{
1035 add_references(&env->references, env_cur);
1036 add_message_id(&env->references, env_cur);
1037 add_message_id(&env->in_reply_to, env_cur);
1038
1039 const bool c_x_comment_to = cs_subset_bool(sub, "x_comment_to");
1040 if (OptNewsSend && c_x_comment_to && !TAILQ_EMPTY(&env_cur->from))
1042}
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:941
static void add_references(struct ListHead *head, struct Envelope *env)
Add the email's references to a list.
Definition: send.c:930
+ 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 1050 of file send.c.

1052{
1053 if (!ea || !env || ARRAY_EMPTY(ea))
1054 return;
1055
1056 struct Email **ep = NULL;
1057 ARRAY_FOREACH(ep, ea)
1058 {
1059 struct Email *e = *ep;
1061 }
1062
1063 /* if there's more than entry in In-Reply-To (i.e. message has multiple
1064 * parents), don't generate a References: header as it's discouraged by
1065 * RFC2822, sect. 3.6.4 */
1066 if ((ARRAY_SIZE(ea) > 1) && !STAILQ_EMPTY(&env->in_reply_to) &&
1068 {
1070 }
1071}
#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:1032
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 1082 of file send.c.

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

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

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

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

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

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

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

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

1525{
1526 FILE *fp = mutt_file_fopen(data, "a+");
1527 if (!fp)
1528 return;
1529
1530 if ((mutt_file_get_size_fp(fp) > 0) && mutt_file_seek(fp, -1, SEEK_END))
1531 {
1532 int c = fgetc(fp);
1533 if (c != '\n')
1534 fputc('\n', fp);
1535 }
1536 mutt_file_fclose(&fp);
1537}
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 1549 of file send.c.

1551{
1552 struct Email *e_new = email_new();
1553
1554 if (mutt_prepare_template(fp, m, e_new, e_cur, true) < 0)
1555 {
1556 email_free(&e_new);
1557 return -1;
1558 }
1559
1560 if (WithCrypto)
1561 {
1562 /* mutt_prepare_template doesn't always flip on an application bit.
1563 * so fix that here */
1564 if (!(e_new->security & (APPLICATION_SMIME | APPLICATION_PGP)))
1565 {
1566 const bool c_smime_is_default = cs_subset_bool(sub, "smime_is_default");
1567 if (((WithCrypto & APPLICATION_SMIME) != 0) && c_smime_is_default)
1568 e_new->security |= APPLICATION_SMIME;
1569 else if (WithCrypto & APPLICATION_PGP)
1570 e_new->security |= APPLICATION_PGP;
1571 else
1572 e_new->security |= APPLICATION_SMIME;
1573 }
1574
1575 const bool c_crypt_opportunistic_encrypt = cs_subset_bool(sub, "crypt_opportunistic_encrypt");
1576 if (c_crypt_opportunistic_encrypt)
1577 {
1578 e_new->security |= SEC_OPPENCRYPT;
1580 }
1581 }
1582
1583 struct EmailArray ea = ARRAY_HEAD_INITIALIZER;
1584 ARRAY_ADD(&ea, e_cur);
1585 int rc = mutt_send_message(SEND_RESEND, e_new, NULL, m, &ea, sub);
1586 ARRAY_FREE(&ea);
1587
1588 return rc;
1589}
#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:2034
#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 1598 of file send.c.

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

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

◆ save_fcc()

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

Save an Email to a 'sent mail' folder.

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

Definition at line 1662 of file send.c.

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

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

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

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

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

◆ send_simple_email()

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

Compose an email given a few basic ingredients.

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

Definition at line 2894 of file send.c.

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

2946{
2947 if (!e || !e->env)
2948 {
2949 return false;
2950 }
2951
2952 const char *mailto = e->env->list_subscribe;
2953 if (!mailto)
2954 {
2955 mutt_warning(_("No List-Subscribe header found"));
2956 return false;
2957 }
2958
2959 struct EmailArray ea = ARRAY_HEAD_INITIALIZER;
2960 ARRAY_ADD(&ea, e);
2961 bool rc = send_simple_email(m, &ea, mailto, "Subscribe", "subscribe");
2962 ARRAY_FREE(&ea);
2963
2964 return rc;
2965}
static bool send_simple_email(struct Mailbox *m, struct EmailArray *ea, const char *mailto, const char *subj, const char *body)
Compose an email given a few basic ingredients.
Definition: send.c:2894
char * list_subscribe
This stores a mailto URL, or nothing.
Definition: envelope.h:68
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_send_list_unsubscribe()

bool mutt_send_list_unsubscribe ( struct Mailbox m,
struct Email e 
)

Send a mailing-list unsubscription email.

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

Definition at line 2974 of file send.c.

2975{
2976 if (!e || !e->env)
2977 {
2978 return false;
2979 }
2980
2981 const char *mailto = e->env->list_unsubscribe;
2982 if (!mailto)
2983 {
2984 mutt_warning(_("No List-Unsubscribe header found"));
2985 return false;
2986 }
2987
2988 struct EmailArray ea = ARRAY_HEAD_INITIALIZER;
2989 ARRAY_ADD(&ea, e);
2990 bool rc = send_simple_email(m, &ea, mailto, "Unsubscribe", "unsubscribe");
2991 ARRAY_FREE(&ea);
2992
2993 return rc;
2994}
char * list_unsubscribe
This stores a mailto URL, or nothing.
Definition: envelope.h:69
+ Here is the call graph for this function:
+ Here is the caller graph for this function: