NeoMutt  2024-04-25-89-g194907
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 "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 "globals.h"
#include "handler.h"
#include "hdrline.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 "sort.h"
#include "mixmaster/lib.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.
 
void greeting_n (const struct ExpandoNode *node, void *data, MuttFormatFlags flags, int max_cols, struct Buffer *buf)
 Greeting: Real name - Implements ExpandoRenderData::get_string() -.
 
void greeting_u (const struct ExpandoNode *node, void *data, MuttFormatFlags flags, int max_cols, struct Buffer *buf)
 Greeting: Login name - Implements ExpandoRenderData::get_string() -.
 
void greeting_v (const struct ExpandoNode *node, void *data, MuttFormatFlags flags, int max_cols, struct Buffer *buf)
 Greeting: First name - Implements ExpandoRenderData::get_string() -.
 
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.
 

Variables

const struct ExpandoRenderData GreetingRenderData []
 Callbacks for Greeting Expandos.
 

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

112{
113 const char *const c_signature = cs_subset_path(sub, "signature");
114 if (!c_signature)
115 return;
116
117 // If the user hasn't set $signature, don't warn them if it doesn't exist
118 struct Buffer *def_sig = buf_pool_get();
119 cs_str_initial_get(sub->cs, "signature", def_sig);
120 mutt_path_canon(def_sig, HomeDir, false);
121 bool notify_missing = !mutt_str_equal(c_signature, buf_string(def_sig));
122 buf_pool_release(&def_sig);
123
124 pid_t pid = 0;
125 FILE *fp_tmp = mutt_open_read(c_signature, &pid);
126 if (!fp_tmp)
127 {
128 if (notify_missing)
129 mutt_perror("%s", c_signature);
130 return;
131 }
132
133 const bool c_sig_dashes = cs_subset_bool(sub, "sig_dashes");
134 if (c_sig_dashes)
135 fputs("\n-- \n", fp);
136 mutt_file_copy_stream(fp_tmp, fp);
137 mutt_file_fclose(&fp_tmp);
138 if (pid != -1)
139 filter_wait(pid);
140}
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
char * HomeDir
User's home directory.
Definition: globals.c:38
int cs_str_initial_get(const struct ConfigSet *cs, const char *name, struct Buffer *result)
Get the initial, or parent, value of a config item.
Definition: set.c:565
int mutt_file_copy_stream(FILE *fp_in, FILE *fp_out)
Copy the contents of one file into another.
Definition: file.c:287
#define mutt_file_fclose(FP)
Definition: file.h:149
#define mutt_perror(...)
Definition: logging2.h:93
int filter_wait(pid_t pid)
Wait for the exit of a process and return its status.
Definition: filter.c:220
bool mutt_path_canon(struct Buffer *path, const char *homedir, bool is_dir)
Create the canonical version of a path.
Definition: path.c:248
bool mutt_str_equal(const char *a, const char *b)
Compare two strings.
Definition: string.c:660
FILE * mutt_open_read(const char *path, pid_t *thepid)
Run a command to read from.
Definition: muttlib.c:701
struct Buffer * buf_pool_get(void)
Get a Buffer from the pool.
Definition: pool.c:81
void buf_pool_release(struct Buffer **ptr)
Return a Buffer to the pool.
Definition: pool.c:94
String manipulation buffer.
Definition: buffer.h:36
struct ConfigSet * cs
Parent ConfigSet.
Definition: subset.h:51
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ remove_user()

static void remove_user ( struct AddressList *  al,
bool  leave_only 
)
static

Remove any address which matches the current user.

Parameters
alList of addresses
leave_onlyIf set, don't remove the user's address if it it the only one in the list

Definition at line 148 of file send.c.

149{
150 struct Address *a = NULL, *tmp = NULL;
151 TAILQ_FOREACH_SAFE(a, al, entries, tmp)
152 {
153 if (mutt_addr_is_user(a) && (!leave_only || TAILQ_NEXT(a, entries)))
154 {
155 TAILQ_REMOVE(al, a, entries);
156 mutt_addr_free(&a);
157 }
158 }
159}
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:600
#define TAILQ_FOREACH_SAFE(var, head, field, tvar)
Definition: queue.h:735
#define TAILQ_REMOVE(head, elm, field)
Definition: queue.h:841
#define TAILQ_NEXT(elm, field)
Definition: queue.h:832
An email address.
Definition: address.h:36
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ add_mailing_lists()

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

Search Address lists for mailing lists.

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

Definition at line 167 of file send.c.

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

◆ mutt_edit_address()

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

Edit an email address.

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

Definition at line 194 of file send.c.

195{
196 int rc = 0;
197 struct Buffer *buf = buf_pool_get();
198 buf_alloc(buf, 8192);
199 char *err = NULL;
200 int idna_ok = 0;
201
202 do
203 {
205 buf_reset(buf);
206 mutt_addrlist_write(al, buf, false);
207 if (mw_get_field(field, buf, MUTT_COMP_NO_FLAGS, HC_ALIAS, &CompleteAliasOps, NULL) != 0)
208 {
209 rc = -1;
210 goto done;
211 }
214 if (expand_aliases)
216 idna_ok = mutt_addrlist_to_intl(al, &err);
217 if (idna_ok != 0)
218 {
219 mutt_error(_("Bad IDN: '%s'"), err);
220 FREE(&err);
221 }
222 } while (idna_ok != 0);
223
224done:
225 buf_pool_release(&buf);
226 return rc;
227}
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
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:274
#define mutt_error(...)
Definition: logging2.h:92
@ HC_ALIAS
Aliases.
Definition: lib.h:52
#define FREE(x)
Definition: memory.h:45
#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 237 of file send.c.

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

370{
371 SKIPWS(s);
372 return mutt_str_dup(s);
373}
char * mutt_str_dup(const char *str)
Copy a string, safely.
Definition: string.c:253
#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 379 of file send.c.

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

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

456{
457 const struct Expando *c_forward_attribution_intro = cs_subset_expando(sub, "forward_attribution_intro");
458 if (!c_forward_attribution_intro || !fp)
459 return;
460
461 const char *const c_attribution_locale = cs_subset_string(sub, "attribution_locale");
462
463 struct Buffer *buf = buf_pool_get();
464 setlocale(LC_TIME, NONULL(c_attribution_locale));
465 mutt_make_string(buf, -1, c_forward_attribution_intro, NULL, -1, e,
467 setlocale(LC_TIME, "");
468 fputs(buf_string(buf), fp);
469 fputs("\n\n", fp);
470 buf_pool_release(&buf);
471}
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:357
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: hdrline.c:1796
#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 479 of file send.c.

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

509{
510 CopyHeaderFlags chflags = CH_DECODE;
512
513 struct Message *msg = mx_msg_open(m, e);
514 if (!msg)
515 {
516 return -1;
517 }
520
521 const bool c_forward_decode = cs_subset_bool(sub, "forward_decode");
522 if ((WithCrypto != 0) && (e->security & SEC_ENCRYPT) && c_forward_decode)
523 {
524 /* make sure we have the user's passphrase before proceeding... */
526 {
527 mx_msg_close(m, &msg);
528 return -1;
529 }
530 }
531
532 mutt_forward_intro(e, fp_out, sub);
533
534 if (c_forward_decode)
535 {
536 cmflags |= MUTT_CM_DECODE | MUTT_CM_CHARCONV;
537
538 const bool c_weed = cs_subset_bool(sub, "weed");
539 if (c_weed)
540 {
541 chflags |= CH_WEED | CH_REORDER;
542 cmflags |= MUTT_CM_WEED;
543 }
544 }
545
546 const bool c_forward_quote = cs_subset_bool(sub, "forward_quote");
547 if (c_forward_quote)
548 cmflags |= MUTT_CM_PREFIX;
549
550 mutt_copy_message(fp_out, e, msg, cmflags, chflags, 0);
551 mx_msg_close(m, &msg);
552 mutt_forward_trailer(e, fp_out, sub);
553 return 0;
554}
void mutt_parse_mime_message(struct Email *e, FILE *fp)
Parse a MIME email.
Definition: attachments.c:597
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:907
#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:692
#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:1180
struct Message * mx_msg_open(struct Mailbox *m, struct Email *e)
Return a stream pointer for a message.
Definition: mx.c:1134
#define SEC_ENCRYPT
Email is encrypted.
Definition: lib.h:78
#define WithCrypto
Definition: lib.h:116
void mutt_forward_intro(struct Email *e, FILE *fp, struct ConfigSubset *sub)
Add the "start of forwarded message" text.
Definition: send.c:455
void mutt_forward_trailer(struct Email *e, FILE *fp, struct ConfigSubset *sub)
Add a "end of forwarded message" text.
Definition: send.c:479
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 566 of file send.c.

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

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

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

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

755{
756 const struct Expando *c_greeting = cs_subset_expando(sub, "greeting");
757 if (!c_greeting || !fp_out)
758 return;
759
760 struct Buffer *buf = buf_pool_get();
761
762 expando_filter(c_greeting, GreetingRenderData, e, TOKEN_NO_FLAGS, buf->dsize, buf);
763
764 fputs(buf_string(buf), fp_out);
765 fputc('\n', fp_out);
766 buf_pool_release(&buf);
767}
int expando_filter(const struct Expando *exp, const struct ExpandoRenderData *rdata, void *data, MuttFormatFlags flags, int max_cols, struct Buffer *buf)
Render an Expando and run the result through a filter.
Definition: filter.c:141
#define TOKEN_NO_FLAGS
No flags are set.
Definition: extract.h:46
const struct ExpandoRenderData GreetingRenderData[]
Callbacks for Greeting Expandos.
Definition: send.c:104
size_t dsize
Length of data.
Definition: buffer.h:39
+ 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 778 of file send.c.

780{
782 CopyHeaderFlags chflags = CH_DECODE;
783
784 if ((WithCrypto != 0) && (e->security & SEC_ENCRYPT))
785 {
786 /* make sure we have the user's passphrase before proceeding... */
788 return -1;
789 }
790
791 struct Message *msg = mx_msg_open(m, e);
792 if (!msg)
793 {
794 return -1;
795 }
798
799 mutt_make_attribution_intro(e, fp_out, sub);
800
801 const bool c_header = cs_subset_bool(sub, "header");
802 if (!c_header)
803 cmflags |= MUTT_CM_NOHEADER;
804
805 const bool c_weed = cs_subset_bool(sub, "weed");
806 if (c_weed)
807 {
808 chflags |= CH_WEED | CH_REORDER;
809 cmflags |= MUTT_CM_WEED;
810 }
811
812 mutt_copy_message(fp_out, e, msg, cmflags, chflags, 0);
813 mx_msg_close(m, &msg);
814
815 mutt_make_attribution_trailer(e, fp_out, sub);
816
817 return 0;
818}
#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:663
void mutt_make_attribution_trailer(struct Email *e, FILE *fp_out, struct ConfigSubset *sub)
Add suffix to replied email text.
Definition: send.c:674
+ 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 827 of file send.c.

830{
831 const bool c_reply_self = cs_subset_bool(sub, "reply_self");
832 if (!c_reply_self && mutt_addr_is_user(from))
833 {
834 /* mail is from the user, assume replying to recipients */
835 return &env->to;
836 }
837 else
838 {
839 return &env->from;
840 }
841}
+ 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 853 of file send.c.

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

941{
942 enum QuadOption hmfupto = MUTT_ABORT;
943 const struct Address *followup_to = TAILQ_FIRST(&in->mail_followup_to);
944
945 if ((flags & (SEND_LIST_REPLY | SEND_GROUP_REPLY | SEND_GROUP_CHAT_REPLY)) && followup_to)
946 {
947 char prompt[256] = { 0 };
948 snprintf(prompt, sizeof(prompt), _("Follow-up to %s%s?"),
949 buf_string(followup_to->mailbox),
950 TAILQ_NEXT(TAILQ_FIRST(&in->mail_followup_to), entries) ? ",..." : "");
951
952 hmfupto = query_quadoption(prompt, sub, "honor_followup_to");
953 if (hmfupto == MUTT_ABORT)
954 return -1;
955 }
956
957 if (flags & SEND_LIST_REPLY)
958 {
959 add_mailing_lists(&out->to, &in->to, &in->cc);
960
961 if (followup_to && (hmfupto == MUTT_YES) &&
962 (default_to(&out->cc, in, flags & SEND_LIST_REPLY, (hmfupto == MUTT_YES), sub) == MUTT_ABORT))
963 {
964 return -1; /* abort */
965 }
966 }
967 else if (flags & SEND_TO_SENDER)
968 {
969 mutt_addrlist_copy(&out->to, &in->from, false);
970 }
971 else
972 {
973 if (default_to(&out->to, in, flags & (SEND_GROUP_REPLY | SEND_GROUP_CHAT_REPLY),
974 (hmfupto == MUTT_YES), sub) == -1)
975 {
976 return -1; /* abort */
977 }
978
979 if ((flags & (SEND_GROUP_REPLY | SEND_GROUP_CHAT_REPLY)) &&
980 (!followup_to || (hmfupto != MUTT_YES)))
981 {
982 /* if(!mutt_addr_is_user(in->to)) */
983 if (flags & SEND_GROUP_REPLY)
984 mutt_addrlist_copy(&out->cc, &in->to, true);
985 else
986 mutt_addrlist_copy(&out->to, &in->to, true);
987 mutt_addrlist_copy(&out->cc, &in->cc, true);
988 }
989 }
990 return 0;
991}
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:167
#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 998 of file send.c.

999{
1000 struct ListHead *src = STAILQ_EMPTY(&env->references) ? &env->in_reply_to : &env->references;
1001 mutt_list_copy_tail(head, src);
1002}
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:348
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 1009 of file send.c.

1010{
1011 if (env->message_id)
1012 {
1014 }
1015}
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 1022 of file send.c.

1023{
1024 const bool c_me_too = cs_subset_bool(sub, "me_too");
1025 if (!c_me_too)
1026 {
1027 const bool c_reply_self = cs_subset_bool(sub, "reply_self");
1028
1029 /* the order is important here. do the CC: first so that if the
1030 * the user is the only recipient, it ends up on the TO: field */
1031 remove_user(&env->cc, TAILQ_EMPTY(&env->to));
1032 remove_user(&env->to, TAILQ_EMPTY(&env->cc) || c_reply_self);
1033 }
1034
1035 /* the CC field can get cluttered, especially with lists */
1036 mutt_addrlist_dedupe(&env->to);
1037 mutt_addrlist_dedupe(&env->cc);
1038 mutt_addrlist_remove_xrefs(&env->to, &env->cc);
1039
1040 if (!TAILQ_EMPTY(&env->cc) && TAILQ_EMPTY(&env->to))
1041 {
1042 TAILQ_SWAP(&env->to, &env->cc, Address, entries);
1043 }
1044}
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:859
static void remove_user(struct AddressList *al, bool leave_only)
Remove any address which matches the current user.
Definition: send.c:148
+ 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 1052 of file send.c.

1053{
1054 if (!env)
1055 return;
1056
1057 const struct Expando *c_forward_format = cs_subset_expando(sub, "forward_format");
1058
1059 struct Buffer *buf = buf_pool_get();
1060 /* set the default subject for the message. */
1061 mutt_make_string(buf, -1, c_forward_format, NULL, -1, e, MUTT_FORMAT_NO_FLAGS, NULL);
1063 buf_pool_release(&buf);
1064}
+ 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 1072 of file send.c.

1074{
1075 if (!env || !env_cur)
1076 return;
1077
1078 /* This takes precedence over a subject that might have
1079 * been taken from a List-Post header. Is that correct? */
1080 if (env_cur->real_subj)
1081 {
1082 char *subj = NULL;
1083 mutt_str_asprintf(&subj, "Re: %s", env_cur->real_subj);
1084 mutt_env_set_subject(env, subj);
1085 FREE(&subj);
1086 }
1087 else if (!env->subject)
1088 {
1089 const char *const c_empty_subject = cs_subset_string(sub, "empty_subject");
1090 mutt_env_set_subject(env, c_empty_subject);
1091 }
1092}
int mutt_str_asprintf(char **strp, const char *fmt,...)
Definition: string.c:803
char *const real_subj
Offset of the real subject.
Definition: envelope.h:71
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_add_to_reference_headers()

void mutt_add_to_reference_headers ( struct Envelope env,
struct Envelope env_cur,
struct ConfigSubset sub 
)

Generate references for a reply email.

Parameters
envEnvelope for result
env_curEnvelope of source email
subConfig Subset

Definition at line 1100 of file send.c.

1102{
1103 add_references(&env->references, env_cur);
1104 add_message_id(&env->references, env_cur);
1105 add_message_id(&env->in_reply_to, env_cur);
1106
1107 const bool c_x_comment_to = cs_subset_bool(sub, "x_comment_to");
1108 if (OptNewsSend && c_x_comment_to && !TAILQ_EMPTY(&env_cur->from))
1110}
static void add_message_id(struct ListHead *head, struct Envelope *env)
Add the email's message ID to a list.
Definition: send.c:1009
static void add_references(struct ListHead *head, struct Envelope *env)
Add the email's references to a list.
Definition: send.c:998
const char * mutt_get_name(const struct Address *a)
Pick the best name to display from an address.
Definition: sort.c:134
+ 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 1118 of file send.c.

1120{
1121 if (!ea || !env || ARRAY_EMPTY(ea))
1122 return;
1123
1124 struct Email **ep = NULL;
1125 ARRAY_FOREACH(ep, ea)
1126 {
1127 struct Email *e = *ep;
1129 }
1130
1131 /* if there's more than entry in In-Reply-To (i.e. message has multiple
1132 * parents), don't generate a References: header as it's discouraged by
1133 * RFC2822, sect. 3.6.4 */
1134 if ((ARRAY_SIZE(ea) > 1) && !STAILQ_EMPTY(&env->in_reply_to) &&
1136 {
1138 }
1139}
#define ARRAY_FOREACH(elem, head)
Iterate over all elements of the array.
Definition: array.h:212
#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:350
#define STAILQ_NEXT(elm, field)
Definition: queue.h:400
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:1100
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 1150 of file send.c.

1152{
1153 if (!ea || ARRAY_EMPTY(ea))
1154 return -1;
1155
1156 struct Email *e_cur = *ARRAY_GET(ea, 0);
1157 bool single = (ARRAY_SIZE(ea) == 1);
1158
1159 struct Envelope *env_cur = e_cur->env;
1160 if (!env_cur)
1161 return -1;
1162
1163 if (flags & (SEND_REPLY | SEND_TO_SENDER))
1164 {
1165 if ((flags & SEND_NEWS))
1166 {
1167 /* in case followup set Newsgroups: with Followup-To: if it present */
1168 if (!env->newsgroups && !mutt_istr_equal(env_cur->followup_to, "poster"))
1169 {
1170 env->newsgroups = mutt_str_dup(env_cur->followup_to);
1171 }
1172 }
1173 else if (!single)
1174 {
1175 struct Email **ep = NULL;
1176 ARRAY_FOREACH(ep, ea)
1177 {
1178 struct Email *e = *ep;
1179 if (mutt_fetch_recips(env, e->env, flags, sub) == -1)
1180 return -1;
1181 }
1182 }
1183 else if (mutt_fetch_recips(env, env_cur, flags, sub) == -1)
1184 {
1185 return -1;
1186 }
1187
1188 if ((flags & SEND_LIST_REPLY) && TAILQ_EMPTY(&env->to))
1189 {
1190 mutt_error(_("No mailing lists found"));
1191 return -1;
1192 }
1193
1194 if (flags & SEND_REPLY)
1195 {
1196 mutt_make_misc_reply_headers(env, env_cur, sub);
1197 make_reference_headers(ea, env, sub);
1198 }
1199 }
1200 else if (flags & SEND_FORWARD)
1201 {
1202 mutt_make_forward_subject(env, e_cur, sub);
1203
1204 const bool c_forward_references = cs_subset_bool(sub, "forward_references");
1205 if (c_forward_references)
1206 make_reference_headers(ea, env, sub);
1207 }
1208
1209 return 0;
1210}
#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:1072
void mutt_make_forward_subject(struct Envelope *env, struct Email *e, struct ConfigSubset *sub)
Create a subject for a forwarded email.
Definition: send.c:1052
static void make_reference_headers(struct EmailArray *ea, struct Envelope *env, struct ConfigSubset *sub)
Generate reference headers for an email.
Definition: send.c:1118
int mutt_fetch_recips(struct Envelope *out, struct Envelope *in, SendFlags flags, struct ConfigSubset *sub)
Generate recpients for a reply email.
Definition: send.c:939
#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 1223 of file send.c.

1225{
1226 /* An EmailList is required for replying and forwarding */
1227 if (!ea && (flags & (SEND_REPLY | SEND_FORWARD)))
1228 return -1;
1229
1230 if (flags & SEND_REPLY)
1231 {
1232 enum QuadOption ans = query_quadoption(_("Include message in reply?"), sub, "include");
1233 if (ans == MUTT_ABORT)
1234 return -1;
1235
1236 if (ans == MUTT_YES)
1237 {
1238 mutt_message(_("Including quoted message..."));
1239 struct Email **ep = NULL;
1240 size_t count = ARRAY_SIZE(ea) - 1;
1241 ARRAY_FOREACH(ep, ea)
1242 {
1243 if (include_reply(m, *ep, fp_tmp, sub) == -1)
1244 {
1245 mutt_error(_("Could not include all requested messages"));
1246 return -1;
1247 }
1248 if (ARRAY_FOREACH_IDX < count)
1249 {
1250 fputc('\n', fp_tmp);
1251 }
1252 }
1253 }
1254 }
1255 else if (flags & SEND_FORWARD)
1256 {
1257 enum QuadOption ans = query_quadoption(_("Forward as attachment?"), sub, "mime_forward");
1258 if (ans == MUTT_YES)
1259 {
1260 struct Body *last = e->body;
1261
1262 mutt_message(_("Preparing forwarded message..."));
1263
1264 while (last && last->next)
1265 last = last->next;
1266
1267 struct Email **ep = NULL;
1268 ARRAY_FOREACH(ep, ea)
1269 {
1270 struct Body *tmp = mutt_make_message_attach(m, *ep, false, sub);
1271 if (last)
1272 {
1273 last->next = tmp;
1274 last = tmp;
1275 }
1276 else
1277 {
1278 last = tmp;
1279 e->body = tmp;
1280 }
1281 }
1282 }
1283 else if (ans != MUTT_ABORT)
1284 {
1285 enum QuadOption forwardq = MUTT_ABORT;
1286 struct Body **last = NULL;
1287
1288 const bool c_forward_decode = cs_subset_bool(sub, "forward_decode");
1289 const enum QuadOption c_forward_attachments = cs_subset_quad(sub, "forward_attachments");
1290 if (c_forward_decode && (c_forward_attachments != MUTT_NO))
1291 {
1292 last = &e->body;
1293 while (*last)
1294 last = &((*last)->next);
1295 }
1296
1297 struct Email **ep = NULL;
1298 ARRAY_FOREACH(ep, ea)
1299 {
1300 struct Email *e_cur = *ep;
1301 include_forward(m, e_cur, fp_tmp, sub);
1302 if (c_forward_decode && (c_forward_attachments != MUTT_NO))
1303 {
1304 if (inline_forward_attachments(m, e_cur, &last, &forwardq, sub) != 0)
1305 return -1;
1306 }
1307 }
1308 }
1309 else
1310 {
1311 return -1;
1312 }
1313 }
1314 else if (((WithCrypto & APPLICATION_PGP) != 0) && (flags & SEND_KEY))
1315 {
1316 struct Body *b = NULL;
1317
1318 if (((WithCrypto & APPLICATION_PGP) != 0) && !(b = crypt_pgp_make_key_attachment()))
1319 {
1320 return -1;
1321 }
1322
1323 b->next = e->body;
1324 e->body = b;
1325 }
1326
1328
1329 return 0;
1330}
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:90
static int include_reply(struct Mailbox *m, struct Email *e, FILE *fp_out, struct ConfigSubset *sub)
Generate the reply text for an email.
Definition: send.c:778
static int include_forward(struct Mailbox *m, struct Email *e, FILE *fp_out, struct ConfigSubset *sub)
Write out a forwarded message.
Definition: send.c:507
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:566
#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:71
+ 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 1337 of file send.c.

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

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

1462{
1463 /* Note: We let $from override $real_name here.
1464 * Is this the right thing to do?
1465 */
1466
1467 const struct Address *c_from = cs_subset_address(sub, "from");
1468 if (c_from)
1469 {
1470 return mutt_addr_copy(c_from);
1471 }
1472
1473 char domain[1024] = { 0 };
1474 const char *mailbox = Username;
1475 const bool c_use_domain = cs_subset_bool(sub, "use_domain");
1476 if (c_use_domain)
1477 {
1478 snprintf(domain, sizeof(domain), "%s@%s", NONULL(Username),
1479 NONULL(mutt_fqdn(true, sub)));
1480 mailbox = domain;
1481 }
1482
1483 return mutt_addr_create(NULL, mailbox);
1484}
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:272
char * Username
User's login name.
Definition: globals.c:41
const char * mutt_fqdn(bool may_hide_host, const struct ConfigSubset *sub)
Get the Fully-Qualified Domain Name.
Definition: sendlib.c:707
+ 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 1494 of file send.c.

1495{
1496 struct Buffer *tempfile = NULL;
1497 int rc = -1;
1498
1499 /* Write out the message in MIME form. */
1500 tempfile = buf_pool_get();
1501 buf_mktemp(tempfile);
1502 FILE *fp_tmp = mutt_file_fopen(buf_string(tempfile), "w");
1503 if (!fp_tmp)
1504 goto cleanup;
1505
1506 const bool c_write_bcc = cs_subset_bool(sub, "write_bcc");
1507 const char *const c_smtp_url = cs_subset_string(sub, "smtp_url");
1508 if (c_smtp_url)
1509 cs_subset_str_native_set(sub, "write_bcc", false, NULL);
1510
1511#ifdef MIXMASTER
1513 !STAILQ_EMPTY(&e->chain),
1515#else
1517 false, mutt_should_hide_protected_subject(e), sub);
1518#endif
1519
1520 cs_subset_str_native_set(sub, "write_bcc", c_write_bcc, NULL);
1521
1522 fputc('\n', fp_tmp); /* tie off the header. */
1523
1524 if ((mutt_write_mime_body(e->body, fp_tmp, sub) == -1))
1525 goto cleanup;
1526
1527 if (mutt_file_fclose(&fp_tmp) != 0)
1528 {
1529 mutt_perror("%s", buf_string(tempfile));
1530 unlink(buf_string(tempfile));
1531 goto cleanup;
1532 }
1533
1534#ifdef MIXMASTER
1535 if (!STAILQ_EMPTY(&e->chain))
1536 {
1537 rc = mix_send_message(&e->chain, buf_string(tempfile));
1538 goto cleanup;
1539 }
1540#endif
1541
1542 if (OptNewsSend)
1543 goto sendmail;
1544
1545 if (c_smtp_url)
1546 {
1547 rc = mutt_smtp_send(&e->env->from, &e->env->to, &e->env->cc, &e->env->bcc,
1548 buf_string(tempfile), (e->body->encoding == ENC_8BIT), sub);
1549 goto cleanup;
1550 }
1551
1552sendmail:
1553 rc = mutt_invoke_sendmail(m, &e->env->from, &e->env->to, &e->env->cc, &e->env->bcc,
1554 buf_string(tempfile), (e->body->encoding == ENC_8BIT), sub);
1555cleanup:
1556 if (fp_tmp)
1557 {
1558 mutt_file_fclose(&fp_tmp);
1559 unlink(buf_string(tempfile));
1560 }
1561 buf_pool_release(&tempfile);
1562 return rc;
1563}
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:148
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 mix_send_message(struct ListHead *chain, const char *tempfile)
Send an email via Mixmaster.
Definition: mixmaster.c:101
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:1100
unsigned int encoding
content-transfer-encoding, ContentEncoding
Definition: body.h:41
struct ListHead chain
Mixmaster chain.
Definition: email.h:93
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:297
#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 1571 of file send.c.

1572{
1573 const struct Slist *const c_send_charset = cs_subset_slist(sub, "send_charset");
1574 for (struct Body *t = b; t; t = t->next)
1575 {
1576 if (t->description)
1577 {
1578 rfc2047_encode(&t->description, NULL, sizeof("Content-Description:"), c_send_charset);
1579 }
1580 if (recurse && t->parts)
1581 mutt_encode_descriptions(t->parts, recurse, sub);
1582 }
1583}
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:1571
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 1589 of file send.c.

1590{
1591 for (struct Body *t = b; t; t = t->next)
1592 {
1593 if (t->description)
1594 {
1595 rfc2047_decode(&t->description);
1596 }
1597 if (t->parts)
1598 decode_descriptions(t->parts);
1599 }
1600}
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:1589
+ 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 1606 of file send.c.

1607{
1608 FILE *fp = mutt_file_fopen(data, "a+");
1609 if (!fp)
1610 return;
1611
1612 if ((mutt_file_get_size_fp(fp) > 0) && mutt_file_seek(fp, -1, SEEK_END))
1613 {
1614 int c = fgetc(fp);
1615 if (c != '\n')
1616 fputc('\n', fp);
1617 }
1618 mutt_file_fclose(&fp);
1619}
long mutt_file_get_size_fp(FILE *fp)
Get the size of a file.
Definition: file.c:1537
bool mutt_file_seek(FILE *fp, LOFF_T offset, int whence)
Wrapper for fseeko with error handling.
Definition: file.c:778
+ 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 1631 of file send.c.

1633{
1634 struct Email *e_new = email_new();
1635
1636 if (mutt_prepare_template(fp, m, e_new, e_cur, true) < 0)
1637 {
1638 email_free(&e_new);
1639 return -1;
1640 }
1641
1642 if (WithCrypto)
1643 {
1644 /* mutt_prepare_template doesn't always flip on an application bit.
1645 * so fix that here */
1646 if (!(e_new->security & (APPLICATION_SMIME | APPLICATION_PGP)))
1647 {
1648 const bool c_smime_is_default = cs_subset_bool(sub, "smime_is_default");
1649 if (((WithCrypto & APPLICATION_SMIME) != 0) && c_smime_is_default)
1650 e_new->security |= APPLICATION_SMIME;
1651 else if (WithCrypto & APPLICATION_PGP)
1652 e_new->security |= APPLICATION_PGP;
1653 else
1654 e_new->security |= APPLICATION_SMIME;
1655 }
1656
1657 const bool c_crypt_opportunistic_encrypt = cs_subset_bool(sub, "crypt_opportunistic_encrypt");
1658 if (c_crypt_opportunistic_encrypt)
1659 {
1660 e_new->security |= SEC_OPPENCRYPT;
1662 }
1663 }
1664
1665 struct EmailArray ea = ARRAY_HEAD_INITIALIZER;
1666 ARRAY_ADD(&ea, e_cur);
1667 int rc = mutt_send_message(SEND_RESEND, e_new, NULL, m, &ea, sub);
1668 ARRAY_FREE(&ea);
1669
1670 return rc;
1671}
#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:80
void email_free(struct Email **ptr)
Free an Email.
Definition: email.c:46
#define SEC_OPPENCRYPT
Opportunistic encrypt mode.
Definition: lib.h:86
#define APPLICATION_SMIME
Use SMIME to encrypt/sign.
Definition: lib.h:91
int mutt_prepare_template(FILE *fp, struct Mailbox *m, struct Email *e_new, struct Email *e, bool resend)
Prepare a message template.
Definition: postpone.c:484
int mutt_send_message(SendFlags flags, struct Email *e_templ, const char *tempfile, struct Mailbox *m, struct EmailArray *ea, struct ConfigSubset *sub)
Send an email.
Definition: send.c:2116
#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 1680 of file send.c.

1681{
1682 if (!reply || !reply->env || !orig || !orig->env)
1683 return false;
1684 return mutt_list_find(&orig->env->references, reply->env->message_id) ||
1685 mutt_list_find(&orig->env->in_reply_to, reply->env->message_id);
1686}
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 1699 of file send.c.

1700{
1701 const struct Regex *c_abort_noattach_regex = cs_subset_regex(sub, "abort_noattach_regex");
1702 const struct Regex *c_quote_regex = cs_subset_regex(sub, "quote_regex");
1703
1704 /* Search for the regex in `$abort_noattach_regex` within a file */
1705 if (!c_abort_noattach_regex || !c_abort_noattach_regex->regex ||
1706 !c_quote_regex || !c_quote_regex->regex)
1707 {
1708 return false;
1709 }
1710
1711 FILE *fp_att = mutt_file_fopen(filename, "r");
1712 if (!fp_att)
1713 return false;
1714
1715 char *inputline = mutt_mem_malloc(1024);
1716 bool found = false;
1717 while (!feof(fp_att) && fgets(inputline, 1024, fp_att))
1718 {
1719 if (!mutt_is_quote_line(inputline, NULL) &&
1720 mutt_regex_match(c_abort_noattach_regex, inputline))
1721 {
1722 found = true;
1723 break;
1724 }
1725 }
1726 FREE(&inputline);
1727 mutt_file_fclose(&fp_att);
1728 return found;
1729}
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
void * mutt_mem_malloc(size_t size)
Allocate memory on the heap.
Definition: memory.c:91
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:85
regex_t * regex
compiled expression
Definition: regex3.h:87
+ 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 1744 of file send.c.

1747{
1748 int rc = 0;
1749 struct Body *save_content = NULL;
1750
1751 buf_expand_path(fcc);
1752
1753 /* Don't save a copy when we are in batch-mode, and the FCC
1754 * folder is on an IMAP server: This would involve possibly lots
1755 * of user interaction, which is not available in batch mode.
1756 *
1757 * Note: A patch to fix the problems with the use of IMAP servers
1758 * from non-curses mode is available from Brendan Cully. However,
1759 * I'd like to think a bit more about this before including it. */
1760
1761 if ((flags & SEND_BATCH) && !buf_is_empty(fcc) &&
1762 (imap_path_probe(buf_string(fcc), NULL) == MUTT_IMAP))
1763 {
1764 mutt_error(_("Warning: Fcc to an IMAP mailbox is not supported in batch mode"));
1765 /* L10N: Printed after the "Fcc to an IMAP mailbox is not supported" message.
1766 To make it clearer that the message doesn't mean NeoMutt is aborting
1767 sending the mail too.
1768 %s is the full mailbox URL, including imap(s)://
1769 */
1770 mutt_error(_("Skipping Fcc to %s"), buf_string(fcc));
1771 buf_reset(fcc);
1772 return rc;
1773 }
1774
1775 if (buf_is_empty(fcc) || mutt_str_equal("/dev/null", buf_string(fcc)))
1776 return rc;
1777
1778 struct Body *tmpbody = e->body;
1779 struct Body *save_sig = NULL;
1780 struct Body *save_parts = NULL;
1781
1782 const bool c_fcc_before_send = cs_subset_bool(sub, "fcc_before_send");
1783 /* Before sending, we don't allow message manipulation because it
1784 * will break message signatures. This is especially complicated by
1785 * Protected Headers. */
1786 if (!c_fcc_before_send)
1787 {
1788 const bool c_fcc_clear = cs_subset_bool(sub, "fcc_clear");
1789 if ((WithCrypto != 0) &&
1790 (e->security & (SEC_ENCRYPT | SEC_SIGN | SEC_AUTOCRYPT)) && c_fcc_clear)
1791 {
1792 e->body = clear_content;
1795 mutt_param_delete(&e->body->parameter, "protected-headers");
1796 }
1797
1798 const enum QuadOption c_fcc_attach = cs_subset_quad(sub, "fcc_attach");
1799
1800 /* check to see if the user wants copies of all attachments */
1801 bool save_atts = true;
1802 if (e->body->type == TYPE_MULTIPART)
1803 {
1804 /* In batch mode, save attachments if the quadoption is yes or ask-yes */
1805 if (flags & SEND_BATCH)
1806 {
1807 if ((c_fcc_attach == MUTT_NO) || (c_fcc_attach == MUTT_ASKNO))
1808 save_atts = false;
1809 }
1810 else if (query_quadoption(_("Save attachments in Fcc?"), sub, "fcc_attach") != MUTT_YES)
1811 {
1812 save_atts = false;
1813 }
1814 }
1815 if (!save_atts)
1816 {
1817 if ((WithCrypto != 0) && (e->security & (SEC_ENCRYPT | SEC_SIGN | SEC_AUTOCRYPT)) &&
1818 (mutt_str_equal(e->body->subtype, "encrypted") ||
1819 mutt_str_equal(e->body->subtype, "signed")))
1820 {
1821 if ((clear_content->type == TYPE_MULTIPART) &&
1822 (query_quadoption(_("Save attachments in Fcc?"), sub, "fcc_attach") != MUTT_YES))
1823 {
1824 if (!(e->security & SEC_ENCRYPT) && (e->security & SEC_SIGN))
1825 {
1826 /* save initial signature and attachments */
1827 save_sig = e->body->parts->next;
1828 save_parts = clear_content->parts->next;
1829 }
1830
1831 /* this means writing only the main part */
1832 e->body = clear_content->parts;
1833
1834 if (mutt_protect(e, pgpkeylist, false) == -1)
1835 {
1836 /* we can't do much about it at this point, so
1837 * fallback to saving the whole thing to fcc */
1838 e->body = tmpbody;
1839 save_sig = NULL;
1840 goto full_fcc;
1841 }
1842
1843 save_content = e->body;
1844 }
1845 }
1846 else
1847 {
1848 if (query_quadoption(_("Save attachments in Fcc?"), sub, "fcc_attach") != MUTT_YES)
1849 e->body = e->body->parts;
1850 }
1851 }
1852 }
1853
1854full_fcc:
1855 if (e->body)
1856 {
1857 /* update received time so that when storing to a mbox-style folder
1858 * the From_ line contains the current time instead of when the
1859 * message was first postponed. */
1860 e->received = mutt_date_now();
1861 rc = mutt_write_multiple_fcc(buf_string(fcc), e, NULL, false, NULL, finalpath, sub);
1862 while (rc && !(flags & SEND_BATCH))
1863 {
1865 int choice = mw_multi_choice(
1866 /* L10N: Called when saving to $record or Fcc failed after sending.
1867 (r)etry tries the same mailbox again.
1868 alternate (m)ailbox prompts for a different mailbox to try.
1869 (s)kip aborts saving. */
1870 _("Fcc failed. (r)etry, alternate (m)ailbox, or (s)kip?"),
1871 /* L10N: These correspond to the "Fcc failed" multi-choice prompt
1872 (r)etry, alternate (m)ailbox, or (s)kip.
1873 Any similarity to famous leaders of the FSF is coincidental. */
1874 _("rms"));
1875 switch (choice)
1876 {
1877 case 2: /* alternate (m)ailbox */
1878 /* L10N: This is the prompt to enter an "alternate (m)ailbox" when the
1879 initial Fcc fails. */
1880 rc = mw_enter_fname(_("Fcc mailbox"), fcc, true, m, false, NULL, NULL,
1882 if ((rc == -1) || buf_is_empty(fcc))
1883 {
1884 rc = 0;
1885 break;
1886 }
1888
1889 case 1: /* (r)etry */
1890 rc = mutt_write_multiple_fcc(buf_string(fcc), e, NULL, false, NULL, finalpath, sub);
1891 break;
1892
1893 case -1: /* abort */
1894 case 3: /* (s)kip */
1895 rc = 0;
1896 break;
1897 }
1898 }
1899 }
1900
1901 if (!c_fcc_before_send)
1902 {
1903 e->body = tmpbody;
1904
1905 if ((WithCrypto != 0) && save_sig)
1906 {
1907 /* cleanup the second signature structures */
1908 if (save_content->parts)
1909 {
1910 mutt_body_free(&save_content->parts->next);
1911 save_content->parts = NULL;
1912 }
1913 mutt_body_free(&save_content);
1914
1915 /* restore old signature and attachments */
1916 e->body->parts->next = save_sig;
1917 e->body->parts->parts->next = save_parts;
1918 }
1919 else if ((WithCrypto != 0) && save_content)
1920 {
1921 /* destroy the new encrypted body. */
1922 mutt_body_free(&save_content);
1923 }
1924 }
1925
1926 return 0;
1927}
#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:236
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:2345
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:87
#define SEC_SIGN
Email is signed.
Definition: lib.h:79
void mutt_param_delete(struct ParameterList *pl, const char *attribute)
Delete a matching Parameter.
Definition: parameter.c: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:72
struct Envelope * mime_headers
Memory hole protected headers.
Definition: body.h:75
struct ParameterList parameter
Parameters of the content-type.
Definition: body.h:62
time_t received
Time when the message was placed in the mailbox.
Definition: email.h: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 1939 of file send.c.

1941{
1942 char *pgpkeylist = NULL;
1943 const char *encrypt_as = NULL;
1944 struct Body *clear_content = NULL;
1945
1946 const char *const c_postponed = cs_subset_string(sub, "postponed");
1947 if (!c_postponed)
1948 {
1949 mutt_error(_("Can't postpone. $postponed is unset"));
1950 return -1;
1951 }
1952
1953 if (e_post->body->next)
1954 e_post->body = mutt_make_multipart(e_post->body);
1955
1956 mutt_encode_descriptions(e_post->body, true, sub);
1957
1958 const bool c_postpone_encrypt = cs_subset_bool(sub, "postpone_encrypt");
1959 if ((WithCrypto != 0) && c_postpone_encrypt &&
1960 (e_post->security & (SEC_ENCRYPT | SEC_AUTOCRYPT)))
1961 {
1962 if (((WithCrypto & APPLICATION_PGP) != 0) && (e_post->security & APPLICATION_PGP))
1963 {
1964 const char *const c_pgp_default_key = cs_subset_string(sub, "pgp_default_key");
1965 encrypt_as = c_pgp_default_key;
1966 }
1967 else if (((WithCrypto & APPLICATION_SMIME) != 0) && (e_post->security & APPLICATION_SMIME))
1968 {
1969 const char *const c_smime_default_key = cs_subset_string(sub, "smime_default_key");
1970 encrypt_as = c_smime_default_key;
1971 }
1972 if (!encrypt_as)
1973 {
1974 const char *const c_postpone_encrypt_as = cs_subset_string(sub, "postpone_encrypt_as");
1975 encrypt_as = c_postpone_encrypt_as;
1976 }
1977
1978#ifdef USE_AUTOCRYPT
1979 if (e_post->security & SEC_AUTOCRYPT)
1980 {
1982 {
1983 if (mutt_istr_equal(e_post->body->subtype, "mixed"))
1984 e_post->body = mutt_remove_multipart(e_post->body);
1985 decode_descriptions(e_post->body);
1986 mutt_error(_("Error encrypting message. Check your crypt settings."));
1987 return -1;
1988 }
1989 encrypt_as = AutocryptDefaultKey;
1990 }
1991#endif
1992
1993 if (encrypt_as)
1994 {
1995 pgpkeylist = mutt_str_dup(encrypt_as);
1996 clear_content = e_post->body;
1997 if (mutt_protect(e_post, pgpkeylist, true) == -1)
1998 {
1999 FREE(&pgpkeylist);
2000 if (mutt_istr_equal(e_post->body->subtype, "mixed"))
2001 e_post->body = mutt_remove_multipart(e_post->body);
2002 decode_descriptions(e_post->body);
2003 mutt_error(_("Error encrypting message. Check your crypt settings."));
2004 return -1;
2005 }
2006
2007 FREE(&pgpkeylist);
2008
2009 mutt_encode_descriptions(e_post->body, false, sub);
2010 }
2011 }
2012
2013 /* make sure the message is written to the right part of a maildir
2014 * postponed folder. */
2015 e_post->read = false;
2016 e_post->old = false;
2017
2018 mutt_prepare_envelope(e_post->env, false, sub);
2019 mutt_env_to_intl(e_post->env, NULL, NULL); /* Handle bad IDNAs the next time. */
2020
2021 if (mutt_write_fcc(NONULL(c_postponed), e_post,
2022 (e_cur && (flags & SEND_REPLY)) ? e_cur->env->message_id : NULL,
2023 true, fcc, NULL, sub) < 0)
2024 {
2025 if (clear_content)
2026 {
2027 mutt_body_free(&e_post->body);
2028 e_post->body = clear_content;
2029 }
2030 mutt_env_free(&e_post->body->mime_headers); /* protected headers */
2031 mutt_param_delete(&e_post->body->parameter, "protected-headers");
2032 if (mutt_istr_equal(e_post->body->subtype, "mixed"))
2033 e_post->body = mutt_remove_multipart(e_post->body);
2034 decode_descriptions(e_post->body);
2036 return -1;
2037 }
2038
2040
2041 if (clear_content)
2042 mutt_body_free(&clear_content);
2043
2044 return 0;
2045}
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:699
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:178
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 2053 of file send.c.

2054{
2055 return (b->type == TYPE_TEXT) && mutt_istr_equal(b->subtype, "plain");
2056}
@ 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 2064 of file send.c.

2065{
2066 const enum QuadOption c_abort_noattach = cs_subset_quad(sub, "abort_noattach");
2067
2068 if (c_abort_noattach == MUTT_NO)
2069 return false;
2070
2071 if (b->next)
2072 return false;
2073
2074 bool has_keyword = false;
2075
2076 /* search text/plain parts, whether they are main or alternative parts */
2077 if (is_text_plain(b))
2078 {
2079 has_keyword |= search_attach_keyword(b->filename, sub);
2080 }
2081 else
2082 {
2083 for (b = b->parts; b; b = b->next)
2084 {
2085 if (is_text_plain(b))
2086 {
2087 has_keyword |= search_attach_keyword(b->filename, sub);
2088 }
2089 }
2090 }
2091
2092 if (!has_keyword)
2093 return false;
2094
2095 if (c_abort_noattach == MUTT_YES)
2096 {
2097 mutt_error(_("Message contains text matching \"$abort_noattach_regex\". Not sending."));
2098 return true;
2099 }
2100
2101 return query_quadoption(_("No attachments, cancel sending?"), sub, "abort_noattach") != MUTT_NO;
2102}
static bool search_attach_keyword(char *filename, struct ConfigSubset *sub)
Search an email for 'attachment' keywords.
Definition: send.c:1699
static bool is_text_plain(const struct Body *b)
Is a Body a text/plain MIME part?
Definition: send.c:2053
char * filename
When sending a message, this is the file to which this structure refers.
Definition: body.h:58
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_send_message()

int mutt_send_message ( SendFlags  flags,
struct Email e_templ,
const char *  tempfile,
struct Mailbox m,
struct 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 2116 of file send.c.

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

2975{
2976 struct Email *e = email_new();
2977
2978 /* envelope */
2979 e->env = mutt_env_new();
2980 mutt_parse_mailto(e->env, NULL, mailto);
2981 if (!e->env->subject)
2982 {
2983 mutt_env_set_subject(e->env, subj);
2984 }
2985 if (TAILQ_EMPTY(&e->env->to) && !mutt_addrlist_parse(&e->env->to, NULL))
2986 {
2987 mutt_warning(_("No recipient specified"));
2988 }
2989
2990 /* body */
2991 e->body = mutt_body_new();
2992 char ctype[] = "text/plain";
2993 mutt_parse_content_type(ctype, e->body);
2994
2995 struct Buffer *tempfile = buf_pool_get();
2996 buf_mktemp(tempfile);
2997 if (body)
2998 {
2999 FILE *fp = mutt_file_fopen(buf_string(tempfile), "w+");
3000 if (!fp)
3001 {
3002 email_free(&e);
3003 buf_pool_release(&tempfile);
3004 return false;
3005 }
3006 fprintf(fp, "%s\n", body);
3007 mutt_file_fclose(&fp);
3008 }
3009 e->body->filename = buf_strdup(tempfile);
3010 e->body->unlink = true;
3011 buf_pool_release(&tempfile);
3012
3013 const int rc = mutt_send_message(SEND_DRAFT_FILE, e, NULL, m, ea, NeoMutt->sub);
3014 return rc >= 0;
3015}
Container for Accounts, Notifications.
Definition: neomutt.h:42
struct ConfigSubset * sub
Inherited config items.
Definition: neomutt.h:46
+ 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 3024 of file send.c.

3025{
3026 if (!e || !e->env)
3027 {
3028 return false;
3029 }
3030
3031 const char *mailto = e->env->list_subscribe;
3032 if (!mailto)
3033 {
3034 mutt_warning(_("No List-Subscribe header found"));
3035 return false;
3036 }
3037
3038 struct EmailArray ea = ARRAY_HEAD_INITIALIZER;
3039 ARRAY_ADD(&ea, e);
3040 bool rc = send_simple_email(m, &ea, mailto, "Subscribe", "subscribe");
3041 ARRAY_FREE(&ea);
3042
3043 return rc;
3044}
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:2973
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 3053 of file send.c.

3054{
3055 if (!e || !e->env)
3056 {
3057 return false;
3058 }
3059
3060 const char *mailto = e->env->list_unsubscribe;
3061 if (!mailto)
3062 {
3063 mutt_warning(_("No List-Unsubscribe header found"));
3064 return false;
3065 }
3066
3067 struct EmailArray ea = ARRAY_HEAD_INITIALIZER;
3068 ARRAY_ADD(&ea, e);
3069 bool rc = send_simple_email(m, &ea, mailto, "Unsubscribe", "unsubscribe");
3070 ARRAY_FREE(&ea);
3071
3072 return rc;
3073}
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:

Variable Documentation

◆ GreetingRenderData

const struct ExpandoRenderData GreetingRenderData
Initial value:
= {
{ -1, -1, NULL, NULL },
}
@ ED_ENVELOPE
Envelope ED_ENV_ ExpandoDataEnvelope.
Definition: domain.h:42
@ ED_ENV_REAL_NAME
Envelope.to (first)
Definition: envelope.h:111
@ ED_ENV_USER_NAME
Envelope.to (first)
Definition: envelope.h:122
@ ED_ENV_FIRST_NAME
Envelope.from, Envelope.to, Envelope.cc.
Definition: envelope.h:101
void greeting_n(const struct ExpandoNode *node, void *data, MuttFormatFlags flags, int max_cols, struct Buffer *buf)
Greeting: Real name - Implements ExpandoRenderData::get_string() -.
Definition: send.c:682
void greeting_u(const struct ExpandoNode *node, void *data, MuttFormatFlags flags, int max_cols, struct Buffer *buf)
Greeting: Login name - Implements ExpandoRenderData::get_string() -.
Definition: send.c:695
void greeting_v(const struct ExpandoNode *node, void *data, MuttFormatFlags flags, int max_cols, struct Buffer *buf)
Greeting: First name - Implements ExpandoRenderData::get_string() -.
Definition: send.c:719

Callbacks for Greeting Expandos.

See also
GreetingFormatDef, ExpandoDataEnvelope

Definition at line 104 of file send.c.