NeoMutt
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 <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 "history/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 "format_flags.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 "protos.h"
#include "rfc3676.h"
#include "sendlib.h"
#include "sendmail.h"
#include "smtp.h"
#include "sort.h"
#include "mx.h"
#include "nntp/mdata.h"
#include "mixmaster/lib.h"
#include "notmuch/lib.h"
#include "imap/lib.h"
#include "autocrypt/lib.h"

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 char *s, struct Email *e, FILE *fp_out, struct ConfigSubset *sub)
 Format an attribution prefix/suffix.
 
void mutt_make_attribution_intro (struct Email *e, FILE *fp_out, struct ConfigSubset *sub)
 Add "on DATE, PERSON wrote" header.
 
void mutt_make_attribution_trailer (struct Email *e, FILE *fp_out, struct ConfigSubset *sub)
 Add suffix to replied email text.
 
static const char * greeting_format_str (char *buf, size_t buflen, size_t col, int cols, char op, const char *src, const char *prec, const char *if_str, const char *else_str, intptr_t data, MuttFormatFlags flags)
 Format a greetings string - Implements format_t -.
 
static void mutt_make_greeting (struct Email *e, FILE *fp_out, struct ConfigSubset *sub)
 Add greetings string.
 
static int include_reply (struct Mailbox *m, struct Email *e, FILE *fp_out, struct ConfigSubset *sub)
 Generate the reply text for an email.
 
static const struct AddressList * choose_default_to (const struct Address *from, const struct Envelope *env, struct ConfigSubset *sub)
 Pick the best 'to:' value.
 
static int default_to (struct AddressList *to, struct Envelope *env, SendFlags flags, int hmfupto, struct ConfigSubset *sub)
 Generate default email addresses.
 
int mutt_fetch_recips (struct Envelope *out, struct Envelope *in, SendFlags flags, struct ConfigSubset *sub)
 Generate recpients for a reply email.
 
static void add_references (struct ListHead *head, struct Envelope *env)
 Add the email's references to a list.
 
static void add_message_id (struct ListHead *head, struct Envelope *env)
 Add the email's message ID to a list.
 
void mutt_fix_reply_recipients (struct Envelope *env, struct ConfigSubset *sub)
 Remove duplicate recipients.
 
void mutt_make_forward_subject (struct Envelope *env, struct Email *e, struct ConfigSubset *sub)
 Create a subject for a forwarded email.
 
void mutt_make_misc_reply_headers (struct Envelope *env, struct Envelope *env_cur, struct ConfigSubset *sub)
 Set subject for a reply.
 
void mutt_add_to_reference_headers (struct Envelope *env, struct Envelope *env_cur, struct ConfigSubset *sub)
 Generate references for a reply email.
 
static void make_reference_headers (struct EmailArray *ea, struct Envelope *env, struct ConfigSubset *sub)
 Generate reference headers for an email.
 
static int envelope_defaults (struct Envelope *env, struct EmailArray *ea, SendFlags flags, struct ConfigSubset *sub)
 Fill in some defaults for a new email.
 
static int generate_body (FILE *fp_tmp, struct Email *e, SendFlags flags, struct Mailbox *m, struct EmailArray *ea, struct ConfigSubset *sub)
 Create a new email body.
 
void mutt_set_followup_to (struct Envelope *env, struct ConfigSubset *sub)
 Set followup-to field.
 
static void set_reverse_name (struct AddressList *al, struct Envelope *env, struct ConfigSubset *sub)
 Try to set the 'from' field from the recipients.
 
struct Addressmutt_default_from (struct ConfigSubset *sub)
 Get a default 'from' Address.
 
static int invoke_mta (struct Mailbox *m, struct Email *e, struct ConfigSubset *sub)
 Send an email.
 
void mutt_encode_descriptions (struct Body *b, bool recurse, struct ConfigSubset *sub)
 RFC2047 encode the content-descriptions.
 
static void decode_descriptions (struct Body *b)
 RFC2047 decode them in case of an error.
 
static void fix_end_of_file (const char *data)
 Ensure a file ends with a linefeed.
 
int mutt_resend_message (FILE *fp, struct Mailbox *m, struct Email *e_cur, struct ConfigSubset *sub)
 Resend an email.
 
static bool is_reply (struct Email *reply, struct Email *orig)
 Is one email a reply to another?
 
static bool search_attach_keyword (char *filename, struct ConfigSubset *sub)
 Search an email for 'attachment' keywords.
 
static int save_fcc (struct Mailbox *m, struct Email *e, struct Buffer *fcc, struct Body *clear_content, char *pgpkeylist, SendFlags flags, char **finalpath, struct ConfigSubset *sub)
 Save an Email to a 'sent mail' folder.
 
static int postpone_message (struct Email *e_post, struct Email *e_cur, const char *fcc, SendFlags flags, struct ConfigSubset *sub)
 Save an Email for another day.
 
static bool is_text_plain (const struct Body *b)
 Is a Body a text/plain MIME part?
 
static bool abort_for_missing_attachments (const struct Body *b, struct ConfigSubset *sub)
 Should we abort sending because of missing attachments?
 
int mutt_send_message (SendFlags flags, struct Email *e_templ, const char *tempfile, struct Mailbox *m, struct EmailArray *ea, struct ConfigSubset *sub)
 Send an email.
 
static bool send_simple_email (struct Mailbox *m, struct EmailArray *ea, const char *mailto, const char *subj, const char *body)
 Compose an email given a few basic ingredients.
 
bool mutt_send_list_subscribe (struct Mailbox *m, struct Email *e)
 Send a mailing-list subscription email.
 
bool mutt_send_list_unsubscribe (struct Mailbox *m, struct Email *e)
 Send a mailing-list unsubscription email.
 

Detailed Description

Prepare and send an email.

Authors
  • Michael R. Elkins
  • Pietro Cerutti

This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.

You should have received a copy of the GNU General Public License along with this program. If not, see http://www.gnu.org/licenses/.

Definition in file send.c.

Function Documentation

◆ append_signature()

static void append_signature ( FILE *  fp,
struct ConfigSubset sub 
)
static

Append a signature to an email.

Parameters
fpFile to write to
subConfig Subset

Definition at line 100 of file send.c.

101{
102 const char *const c_signature = cs_subset_path(sub, "signature");
103 if (!c_signature)
104 return;
105
106 // If the user hasn't set $signature, don't warn them if it doesn't exist
107 struct Buffer *def_sig = buf_pool_get();
108 cs_str_initial_get(sub->cs, "signature", def_sig);
109 mutt_path_canon(def_sig, HomeDir, false);
110 bool notify_missing = !mutt_str_equal(c_signature, buf_string(def_sig));
111 buf_pool_release(&def_sig);
112
113 pid_t pid = 0;
114 FILE *fp_tmp = mutt_open_read(c_signature, &pid);
115 if (!fp_tmp)
116 {
117 if (notify_missing)
118 mutt_perror("%s", c_signature);
119 return;
120 }
121
122 const bool c_sig_dashes = cs_subset_bool(sub, "sig_dashes");
123 if (c_sig_dashes)
124 fputs("\n-- \n", fp);
125 mutt_file_copy_stream(fp_tmp, fp);
126 mutt_file_fclose(&fp_tmp);
127 if (pid != -1)
128 filter_wait(pid);
129}
static const char * buf_string(const struct Buffer *buf)
Convert a buffer to a const char * "string".
Definition: buffer.h:93
const char * cs_subset_path(const struct ConfigSubset *sub, const char *name)
Get a path config item by name.
Definition: helpers.c:169
bool cs_subset_bool(const struct ConfigSubset *sub, const char *name)
Get a boolean config item by name.
Definition: helpers.c:48
char * HomeDir
User's home directory.
Definition: globals.c:39
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:564
int mutt_file_copy_stream(FILE *fp_in, FILE *fp_out)
Copy the contents of one file into another.
Definition: file.c:262
int mutt_file_fclose(FILE **fp)
Close a FILE handle (and NULL the pointer)
Definition: file.c:152
int filter_wait(pid_t pid)
Wait for the exit of a process and return its status.
Definition: filter.c:218
#define mutt_perror(...)
Definition: logging2.h:93
bool mutt_path_canon(struct Buffer *path, const char *homedir, bool is_dir)
Create the canonical version of a path.
Definition: path.c:280
bool mutt_str_equal(const char *a, const char *b)
Compare two strings.
Definition: string.c:798
FILE * mutt_open_read(const char *path, pid_t *thepid)
Run a command to read from.
Definition: muttlib.c:1282
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:34
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 137 of file send.c.

138{
139 struct Address *a = NULL, *tmp = NULL;
140 TAILQ_FOREACH_SAFE(a, al, entries, tmp)
141 {
142 if (mutt_addr_is_user(a) && (!leave_only || TAILQ_NEXT(a, entries)))
143 {
144 TAILQ_REMOVE(al, a, entries);
145 mutt_addr_free(&a);
146 }
147 }
148}
void mutt_addr_free(struct Address **ptr)
Free a single Address.
Definition: address.c:460
bool mutt_addr_is_user(const struct Address *addr)
Does the address belong to the user.
Definition: alias.c:570
#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 156 of file send.c.

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

184{
185 int rc = 0;
186 struct Buffer *buf = buf_pool_get();
187 buf_alloc(buf, 8192);
188 char *err = NULL;
189 int idna_ok = 0;
190
191 do
192 {
194 buf_reset(buf);
195 mutt_addrlist_write(al, buf, false);
196 if (mw_get_field(field, buf, MUTT_COMP_NO_FLAGS, HC_ALIAS, &CompleteAliasOps, NULL) != 0)
197 {
198 rc = -1;
199 goto done;
200 }
203 if (expand_aliases)
205 idna_ok = mutt_addrlist_to_intl(al, &err);
206 if (idna_ok != 0)
207 {
208 mutt_error(_("Bad IDN: '%s'"), err);
209 FREE(&err);
210 }
211 } while (idna_ok != 0);
212
213done:
214 buf_pool_release(&buf);
215 return rc;
216}
void mutt_addrlist_clear(struct AddressList *al)
Unlink and free all Address in an AddressList.
Definition: address.c:1461
int mutt_addrlist_to_local(struct AddressList *al)
Convert an Address list from Punycode.
Definition: address.c:1379
size_t mutt_addrlist_write(const struct AddressList *al, struct Buffer *buf, bool display)
Write an Address to a buffer.
Definition: address.c:1207
int mutt_addrlist_parse2(struct AddressList *al, const char *s)
Parse a list of email addresses.
Definition: address.c:641
int mutt_addrlist_to_intl(struct AddressList *al, char **err)
Convert an Address list to Punycode.
Definition: address.c:1294
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:298
void buf_reset(struct Buffer *buf)
Reset an existing Buffer.
Definition: buffer.c:88
void buf_alloc(struct Buffer *buf, size_t new_size)
Make sure a buffer can store at least new_size bytes.
Definition: buffer.c:349
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:275
#define mutt_error(...)
Definition: logging2.h:92
@ HC_ALIAS
Aliases.
Definition: lib.h:50
#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:55
+ 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 226 of file send.c.

227{
228 int rc = -1;
229 struct Buffer *buf = buf_pool_get();
230 buf_alloc(buf, 8192);
231
232#ifdef USE_NNTP
233 if (OptNewsSend)
234 {
235 if (en->newsgroups)
236 buf_strcpy(buf, en->newsgroups);
237 else
238 buf_reset(buf);
239
240 if (mw_get_field("Newsgroups: ", buf, MUTT_COMP_NO_FLAGS, HC_OTHER, NULL, NULL) != 0)
241 {
242 goto done;
243 }
245
246 if (en->followup_to)
247 buf_strcpy(buf, en->followup_to);
248 else
249 buf_reset(buf);
250
251 const bool c_ask_followup_to = cs_subset_bool(sub, "ask_followup_to");
252 if (c_ask_followup_to && (mw_get_field("Followup-To: ", buf, MUTT_COMP_NO_FLAGS,
253 HC_OTHER, NULL, NULL) != 0))
254 {
255 goto done;
256 }
258
259 if (en->x_comment_to)
260 buf_strcpy(buf, en->x_comment_to);
261 else
262 buf_reset(buf);
263
264 const bool c_x_comment_to = cs_subset_bool(sub, "x_comment_to");
265 const bool c_ask_x_comment_to = cs_subset_bool(sub, "ask_x_comment_to");
266 if (c_x_comment_to && c_ask_x_comment_to &&
267 (mw_get_field("X-Comment-To: ", buf, MUTT_COMP_NO_FLAGS, HC_OTHER, NULL, NULL) != 0))
268 {
269 goto done;
270 }
272 }
273 else
274#endif
275 {
276 const bool c_fast_reply = cs_subset_bool(sub, "fast_reply");
277 if (TAILQ_EMPTY(&en->to) || !c_fast_reply || (flags & SEND_REVIEW_TO))
278 {
279 if ((mutt_edit_address(&en->to, _("To: "), true) == -1))
280 goto done;
281 }
282
283 const bool c_ask_cc = cs_subset_bool(sub, "ask_cc");
284 if (TAILQ_EMPTY(&en->cc) || !c_fast_reply)
285 {
286 if (c_ask_cc && (mutt_edit_address(&en->cc, _("Cc: "), true) == -1))
287 goto done;
288 }
289
290 const bool c_ask_bcc = cs_subset_bool(sub, "ask_bcc");
291 if (TAILQ_EMPTY(&en->bcc) || !c_fast_reply)
292 {
293 if (c_ask_bcc && (mutt_edit_address(&en->bcc, _("Bcc: "), true) == -1))
294 goto done;
295 }
296
297 if (TAILQ_EMPTY(&en->to) && TAILQ_EMPTY(&en->cc) && TAILQ_EMPTY(&en->bcc))
298 {
299 mutt_warning(_("No recipients specified"));
300 goto done;
301 }
302
303 const bool c_reply_with_xorig = cs_subset_bool(sub, "reply_with_xorig");
304 if (c_reply_with_xorig && (flags & (SEND_REPLY | SEND_LIST_REPLY | SEND_GROUP_REPLY)) &&
305 (mutt_edit_address(&en->from, "From: ", true) == -1))
306 {
307 goto done;
308 }
309 }
310
311 if (en->subject)
312 {
313 const bool c_fast_reply = cs_subset_bool(sub, "fast_reply");
314 if (c_fast_reply)
315 {
316 rc = 0;
317 goto done;
318 }
319 buf_strcpy(buf, en->subject);
320 }
321 else
322 {
323 const char *p = NULL;
324
325 buf_reset(buf);
326 struct ListNode *uh = NULL;
327 STAILQ_FOREACH(uh, &UserHeader, entries)
328 {
329 size_t plen = mutt_istr_startswith(uh->data, "subject:");
330 if (plen)
331 {
332 p = mutt_str_skip_email_wsp(uh->data + plen);
333 buf_strcpy(buf, p);
334 }
335 }
336 }
337
338 if ((mw_get_field(_("Subject: "), buf, MUTT_COMP_NO_FLAGS, HC_OTHER, NULL, NULL) != 0) ||
339 (buf_is_empty(buf) &&
340 (query_quadoption(_("No subject, abort?"), sub, "abort_nosubject") != MUTT_NO)))
341 {
342 mutt_message(_("No subject, aborting"));
343 goto done;
344 }
346 rc = 0;
347
348done:
349 buf_pool_release(&buf);
350 return rc;
351}
bool buf_is_empty(const struct Buffer *buf)
Is the Buffer empty?
Definition: buffer.c:303
size_t buf_strcpy(struct Buffer *buf, const char *s)
Copy a string into a Buffer.
Definition: buffer.c:407
struct ListHead UserHeader
List of custom headers to add to outgoing emails.
Definition: globals.c:55
bool OptNewsSend
(pseudo) used to change behavior when posting
Definition: globals.c:77
#define mutt_warning(...)
Definition: logging2.h:90
#define mutt_message(...)
Definition: logging2.h:91
@ HC_OTHER
Miscellaneous strings.
Definition: lib.h:54
char * mutt_str_skip_email_wsp(const char *s)
Skip over whitespace as defined by RFC5322.
Definition: string.c:680
size_t mutt_istr_startswith(const char *str, const char *prefix)
Check whether a string starts with a prefix, ignoring case.
Definition: string.c:240
char * mutt_str_replace(char **p, const char *s)
Replace one string with another.
Definition: string.c:327
@ 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:369
#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:183
#define SEND_GROUP_REPLY
Reply to all.
Definition: send.h:41
#define SEND_LIST_REPLY
Reply to mailing list.
Definition: send.h:42
#define SEND_REPLY
Reply to sender.
Definition: send.h:40
#define SEND_REVIEW_TO
Allow the user to edit the To field.
Definition: send.h:54
struct AddressList to
Email's 'To' list.
Definition: envelope.h:60
char * followup_to
List of 'followup-to' fields.
Definition: envelope.h:81
char * x_comment_to
List of 'X-comment-to' fields.
Definition: envelope.h:82
char * newsgroups
List of newsgroups.
Definition: envelope.h:79
struct AddressList cc
Email's 'Cc' list.
Definition: envelope.h:61
char * subject
Email's subject.
Definition: envelope.h:70
struct AddressList bcc
Email's 'Bcc' list.
Definition: envelope.h:62
struct AddressList from
Email's 'From' list.
Definition: envelope.h:59
A List node for strings.
Definition: list.h:35
char * data
String.
Definition: list.h:36
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ nntp_get_header()

static char * nntp_get_header ( const char *  s)
static

Get the trimmed header.

Parameters
sHeader line with leading whitespace
Return values
ptrCopy of string
Note
The caller should free the returned string.

Definition at line 361 of file send.c.

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

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

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

◆ mutt_forward_intro()

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

Add the "start of forwarded message" text.

Parameters
eEmail
subConfig Subset
fpFile to write to

Definition at line 452 of file send.c.

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

◆ mutt_forward_trailer()

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

Add a "end of forwarded message" text.

Parameters
eEmail
subConfig Subset
fpFile to write to

Definition at line 475 of file send.c.

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

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

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

◆ format_attribution()

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

Format an attribution prefix/suffix.

Parameters
sString to format
eEmail
fp_outFile to write to
subConfig Subset

Definition at line 635 of file send.c.

637{
638 if (!s || !fp_out)
639 return;
640
641 const char *const c_attribution_locale = cs_subset_string(sub, "attribution_locale");
642
643 char buf[1024] = { 0 };
644 setlocale(LC_TIME, NONULL(c_attribution_locale));
645 mutt_make_string(buf, sizeof(buf), 0, s, NULL, -1, e, MUTT_FORMAT_NO_FLAGS, NULL);
646 setlocale(LC_TIME, "");
647 fputs(buf, fp_out);
648 fputc('\n', fp_out);
649}
+ 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 657 of file send.c.

658{
659 format_attribution(cs_subset_string(sub, "attribution_intro"), e, fp_out, sub);
660}
static void format_attribution(const char *s, struct Email *e, FILE *fp_out, struct ConfigSubset *sub)
Format an attribution prefix/suffix.
Definition: send.c:635
+ 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 668 of file send.c.

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

◆ mutt_make_greeting()

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

Add greetings string.

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

Definition at line 746 of file send.c.

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

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

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

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

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

◆ add_references()

static void add_references ( struct ListHead *  head,
struct Envelope env 
)
static

Add the email's references to a list.

Parameters
headList of references
envEnvelope of message

Definition at line 990 of file send.c.

991{
992 struct ListNode *np = NULL;
993
994 struct ListHead *src = STAILQ_EMPTY(&env->references) ? &env->in_reply_to : &env->references;
995 STAILQ_FOREACH(np, src, entries)
996 {
998 }
999}
#define STAILQ_EMPTY(head)
Definition: queue.h:348
struct ListHead references
message references (in reverse order)
Definition: envelope.h:85
struct ListHead in_reply_to
in-reply-to header content
Definition: envelope.h:86
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ add_message_id()

static void add_message_id ( struct ListHead *  head,
struct Envelope env 
)
static

Add the email's message ID to a list.

Parameters
headList of message IDs
envEnvelope of message

Definition at line 1006 of file send.c.

1007{
1008 if (env->message_id)
1009 {
1011 }
1012}
struct ListNode * mutt_list_insert_head(struct ListHead *h, char *s)
Insert a string at the beginning of a List.
Definition: list.c:45
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_fix_reply_recipients()

void mutt_fix_reply_recipients ( struct Envelope env,
struct ConfigSubset sub 
)

Remove duplicate recipients.

Parameters
envEnvelope to fix
subConfig Subset

Definition at line 1019 of file send.c.

1020{
1021 const bool c_me_too = cs_subset_bool(sub, "me_too");
1022 if (!c_me_too)
1023 {
1024 const bool c_reply_self = cs_subset_bool(sub, "reply_self");
1025
1026 /* the order is important here. do the CC: first so that if the
1027 * the user is the only recipient, it ends up on the TO: field */
1028 remove_user(&env->cc, TAILQ_EMPTY(&env->to));
1029 remove_user(&env->to, TAILQ_EMPTY(&env->cc) || c_reply_self);
1030 }
1031
1032 /* the CC field can get cluttered, especially with lists */
1033 mutt_addrlist_dedupe(&env->to);
1034 mutt_addrlist_dedupe(&env->cc);
1035 mutt_addrlist_remove_xrefs(&env->to, &env->cc);
1036
1037 if (!TAILQ_EMPTY(&env->cc) && TAILQ_EMPTY(&env->to))
1038 {
1039 TAILQ_SWAP(&env->to, &env->cc, Address, entries);
1040 }
1041}
void mutt_addrlist_remove_xrefs(const struct AddressList *a, struct AddressList *b)
Remove cross-references.
Definition: address.c:1434
void mutt_addrlist_dedupe(struct AddressList *al)
Remove duplicate addresses.
Definition: address.c:1398
#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:137
+ 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 1049 of file send.c.

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

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

◆ mutt_add_to_reference_headers()

void mutt_add_to_reference_headers ( struct Envelope env,
struct Envelope 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 1095 of file send.c.

1097{
1098 add_references(&env->references, env_cur);
1099 add_message_id(&env->references, env_cur);
1100 add_message_id(&env->in_reply_to, env_cur);
1101
1102#ifdef USE_NNTP
1103 const bool c_x_comment_to = cs_subset_bool(sub, "x_comment_to");
1104 if (OptNewsSend && c_x_comment_to && !TAILQ_EMPTY(&env_cur->from))
1106#endif
1107}
static void add_message_id(struct ListHead *head, struct Envelope *env)
Add the email's message ID to a list.
Definition: send.c:1006
static void add_references(struct ListHead *head, struct Envelope *env)
Add the email's references to a list.
Definition: send.c:990
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 1115 of file send.c.

1117{
1118 if (!ea || !env || ARRAY_EMPTY(ea))
1119 return;
1120
1121 struct Email **ep = NULL;
1122 ARRAY_FOREACH(ep, ea)
1123 {
1124 struct Email *e = *ep;
1126 }
1127
1128 /* if there's more than entry in In-Reply-To (i.e. message has multiple
1129 * parents), don't generate a References: header as it's discouraged by
1130 * RFC2822, sect. 3.6.4 */
1131 if ((ARRAY_SIZE(ea) > 1) && !STAILQ_EMPTY(&env->in_reply_to) &&
1133 {
1135 }
1136}
#define ARRAY_FOREACH(elem, head)
Iterate over all elements of the array.
Definition: array.h:211
#define ARRAY_EMPTY(head)
Check if an array is empty.
Definition: array.h:73
#define ARRAY_SIZE(head)
The number of elements stored.
Definition: array.h:86
void mutt_list_free(struct ListHead *h)
Free a List AND its strings.
Definition: list.c:122
#define STAILQ_FIRST(head)
Definition: queue.h:350
#define STAILQ_NEXT(elm, field)
Definition: queue.h:400
void mutt_add_to_reference_headers(struct Envelope *env, struct Envelope *env_cur, struct ConfigSubset *sub)
Generate references for a reply email.
Definition: send.c:1095
The envelope/body of an email.
Definition: email.h:37
struct Envelope * env
Envelope information.
Definition: email.h:66
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ envelope_defaults()

static int envelope_defaults ( struct Envelope env,
struct 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 1147 of file send.c.

1149{
1150 if (!ea || ARRAY_EMPTY(ea))
1151 return -1;
1152
1153 struct Email *e_cur = *ARRAY_GET(ea, 0);
1154 bool single = (ARRAY_SIZE(ea) == 1);
1155
1156 struct Envelope *env_cur = e_cur->env;
1157 if (!env_cur)
1158 return -1;
1159
1160 if (flags & (SEND_REPLY | SEND_TO_SENDER))
1161 {
1162#ifdef USE_NNTP
1163 if ((flags & SEND_NEWS))
1164 {
1165 /* in case followup set Newsgroups: with Followup-To: if it present */
1166 if (!env->newsgroups && !mutt_istr_equal(env_cur->followup_to, "poster"))
1167 {
1168 env->newsgroups = mutt_str_dup(env_cur->followup_to);
1169 }
1170 }
1171 else
1172#endif
1173 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:108
void mutt_make_misc_reply_headers(struct Envelope *env, struct Envelope *env_cur, struct ConfigSubset *sub)
Set subject for a reply.
Definition: send.c:1069
void mutt_make_forward_subject(struct Envelope *env, struct Email *e, struct ConfigSubset *sub)
Create a subject for a forwarded email.
Definition: send.c:1049
static void make_reference_headers(struct EmailArray *ea, struct Envelope *env, struct ConfigSubset *sub)
Generate reference headers for an email.
Definition: send.c:1115
int mutt_fetch_recips(struct Envelope *out, struct Envelope *in, SendFlags flags, struct ConfigSubset *sub)
Generate recpients for a reply email.
Definition: send.c:931
#define SEND_NEWS
Reply to a news article.
Definition: send.h:53
#define SEND_FORWARD
Forward email.
Definition: send.h:43
The header of an Email.
Definition: envelope.h:57
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ generate_body()

static int generate_body ( FILE *  fp_tmp,
struct Email e,
SendFlags  flags,
struct Mailbox m,
struct 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:305
void mutt_clear_error(void)
Clear the message line (bottom line of screen)
Definition: mutt_logging.c:73
#define APPLICATION_PGP
Use PGP to encrypt/sign.
Definition: lib.h:91
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:770
static int include_forward(struct Mailbox *m, struct Email *e, FILE *fp_out, struct ConfigSubset *sub)
Write out a forwarded message.
Definition: send.c:502
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:561
#define SEND_KEY
Mail a PGP public key.
Definition: send.h:46
struct Body * mutt_make_message_attach(struct Mailbox *m, struct Email *e, bool attach_msg, struct ConfigSubset *sub)
Create a message attachment.
Definition: sendlib.c:452
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#ifdef USE_NNTP
1346 if (OptNewsSend)
1347 {
1348 if (!env->followup_to && env->newsgroups && (strrchr(env->newsgroups, ',')))
1349 env->followup_to = mutt_str_dup(env->newsgroups);
1350 return;
1351 }
1352#endif
1353
1354 if (TAILQ_EMPTY(&env->mail_followup_to))
1355 {
1356 if (mutt_is_list_recipient(false, env))
1357 {
1358 /* this message goes to known mailing lists, so create a proper
1359 * mail-followup-to header */
1360
1361 mutt_addrlist_copy(&env->mail_followup_to, &env->to, false);
1362 mutt_addrlist_copy(&env->mail_followup_to, &env->cc, true);
1363 }
1364
1365 /* remove ourselves from the mail-followup-to header */
1366 remove_user(&env->mail_followup_to, false);
1367
1368 /* If we are not subscribed to any of the lists in question, re-add
1369 * ourselves to the mail-followup-to header. The mail-followup-to header
1370 * generated is a no-op with group-reply, but makes sure list-reply has the
1371 * desired effect. */
1372
1373 if (!TAILQ_EMPTY(&env->mail_followup_to) &&
1375 {
1376 struct AddressList *al = NULL;
1377 if (!TAILQ_EMPTY(&env->reply_to))
1378 al = &env->reply_to;
1379 else if (!TAILQ_EMPTY(&env->from))
1380 al = &env->from;
1381
1382 if (al)
1383 {
1384 struct Address *a = NULL;
1385 TAILQ_FOREACH_REVERSE(a, al, AddressList, entries)
1386 {
1388 }
1389 }
1390 else
1391 {
1393 }
1394 }
1395
1397 }
1398}
void mutt_addrlist_prepend(struct AddressList *al, struct Address *a)
Prepend an Address to an AddressList.
Definition: address.c:1492
bool mutt_is_subscribed_list_recipient(bool all_addr, struct Envelope *env)
Matches subscribed mailing lists.
Definition: exec.c:476
bool mutt_is_list_recipient(bool all_addr, struct Envelope *env)
Matches known mailing lists.
Definition: exec.c:489
#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:1463
+ 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 1410 of file send.c.

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

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

1497{
1498 struct Buffer *tempfile = NULL;
1499 int rc = -1;
1500
1501 /* Write out the message in MIME form. */
1502 tempfile = buf_pool_get();
1503 buf_mktemp(tempfile);
1504 FILE *fp_tmp = mutt_file_fopen(buf_string(tempfile), "w");
1505 if (!fp_tmp)
1506 goto cleanup;
1507
1508#ifdef USE_SMTP
1509 const bool c_write_bcc = cs_subset_bool(sub, "write_bcc");
1510 const char *const c_smtp_url = cs_subset_string(sub, "smtp_url");
1511 if (c_smtp_url)
1512 cs_subset_str_native_set(sub, "write_bcc", false, NULL);
1513#endif
1514#ifdef MIXMASTER
1516 !STAILQ_EMPTY(&e->chain),
1518#endif
1519#ifndef MIXMASTER
1521 false, mutt_should_hide_protected_subject(e), sub);
1522#endif
1523#ifdef USE_SMTP
1524 cs_subset_str_native_set(sub, "write_bcc", c_write_bcc, NULL);
1525#endif
1526
1527 fputc('\n', fp_tmp); /* tie off the header. */
1528
1529 if ((mutt_write_mime_body(e->body, fp_tmp, sub) == -1))
1530 goto cleanup;
1531
1532 if (mutt_file_fclose(&fp_tmp) != 0)
1533 {
1534 mutt_perror("%s", buf_string(tempfile));
1535 unlink(buf_string(tempfile));
1536 goto cleanup;
1537 }
1538
1539#ifdef MIXMASTER
1540 if (!STAILQ_EMPTY(&e->chain))
1541 {
1542 rc = mix_send_message(&e->chain, buf_string(tempfile));
1543 goto cleanup;
1544 }
1545#endif
1546
1547#ifdef USE_NNTP
1548 if (OptNewsSend)
1549 goto sendmail;
1550#endif
1551
1552#ifdef USE_SMTP
1553 if (c_smtp_url)
1554 {
1555 rc = mutt_smtp_send(&e->env->from, &e->env->to, &e->env->cc, &e->env->bcc,
1556 buf_string(tempfile), (e->body->encoding == ENC_8BIT), sub);
1557 goto cleanup;
1558 }
1559#endif
1560
1561sendmail:
1562 rc = mutt_invoke_sendmail(m, &e->env->from, &e->env->to, &e->env->cc, &e->env->bcc,
1563 buf_string(tempfile), (e->body->encoding == ENC_8BIT), sub);
1564cleanup:
1565 if (fp_tmp)
1566 {
1567 mutt_file_fclose(&fp_tmp);
1568 unlink(buf_string(tempfile));
1569 }
1570 buf_pool_release(&tempfile);
1571 return rc;
1572}
bool mutt_should_hide_protected_subject(struct Email *e)
Should NeoMutt hide the protected subject?
Definition: crypt.c:1089
FILE * mutt_file_fopen(const char *path, const char *mode)
Call fopen() safely.
Definition: file.c:636
int mutt_rfc822_write_header(FILE *fp, struct Envelope *env, struct Body *attach, enum MuttWriteHeaderMode mode, bool privacy, bool hide_protected_subject, struct ConfigSubset *sub)
Write out one RFC822 header line.
Definition: header.c:575
@ 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 *a, FILE *fp, struct ConfigSubset *sub)
Write a MIME part.
Definition: body.c:301
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:297
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:1107
unsigned int encoding
content-transfer-encoding, ContentEncoding
Definition: body.h:41
struct ListHead chain
Mixmaster chain.
Definition: email.h:89
int cs_subset_str_native_set(const struct ConfigSubset *sub, const char *name, intptr_t value, struct Buffer *err)
Natively set the value of a string config item.
Definition: subset.c:304
#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 1580 of file send.c.

1581{
1582 const struct Slist *const c_send_charset = cs_subset_slist(sub, "send_charset");
1583 for (struct Body *t = b; t; t = t->next)
1584 {
1585 if (t->description)
1586 {
1587 rfc2047_encode(&t->description, NULL, sizeof("Content-Description:"), c_send_charset);
1588 }
1589 if (recurse && t->parts)
1590 mutt_encode_descriptions(t->parts, recurse, sub);
1591 }
1592}
const struct Slist * cs_subset_slist(const struct ConfigSubset *sub, const char *name)
Get a string-list config item by name.
Definition: helpers.c:243
void rfc2047_encode(char **pd, const char *specials, int col, const struct Slist *charsets)
RFC-2047-encode a string.
Definition: rfc2047.c:626
void mutt_encode_descriptions(struct Body *b, bool recurse, struct ConfigSubset *sub)
RFC2047 encode the content-descriptions.
Definition: send.c:1580
String list.
Definition: slist.h:47
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ decode_descriptions()

static void decode_descriptions ( struct Body b)
static

RFC2047 decode them in case of an error.

Parameters
bMIME parts to decode

Definition at line 1598 of file send.c.

1599{
1600 for (struct Body *t = b; t; t = t->next)
1601 {
1602 if (t->description)
1603 {
1604 rfc2047_decode(&t->description);
1605 }
1606 if (t->parts)
1607 decode_descriptions(t->parts);
1608 }
1609}
void rfc2047_decode(char **pd)
Decode any RFC2047-encoded header fields.
Definition: rfc2047.c:659
static void decode_descriptions(struct Body *b)
RFC2047 decode them in case of an error.
Definition: send.c:1598
+ 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 1615 of file send.c.

1616{
1617 FILE *fp = mutt_file_fopen(data, "a+");
1618 if (!fp)
1619 return;
1620
1621 if ((mutt_file_get_size_fp(fp) > 0) && mutt_file_seek(fp, -1, SEEK_END))
1622 {
1623 int c = fgetc(fp);
1624 if (c != '\n')
1625 fputc('\n', fp);
1626 }
1627 mutt_file_fclose(&fp);
1628}
long mutt_file_get_size_fp(FILE *fp)
Get the size of a file.
Definition: file.c:1578
bool mutt_file_seek(FILE *fp, LOFF_T offset, int whence)
Wrapper for fseeko with error handling.
Definition: file.c:733
+ 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 1640 of file send.c.

1642{
1643 struct Email *e_new = email_new();
1644
1645 if (mutt_prepare_template(fp, m, e_new, e_cur, true) < 0)
1646 {
1647 email_free(&e_new);
1648 return -1;
1649 }
1650
1651 if (WithCrypto)
1652 {
1653 /* mutt_prepare_template doesn't always flip on an application bit.
1654 * so fix that here */
1655 if (!(e_new->security & (APPLICATION_SMIME | APPLICATION_PGP)))
1656 {
1657 const bool c_smime_is_default = cs_subset_bool(sub, "smime_is_default");
1658 if (((WithCrypto & APPLICATION_SMIME) != 0) && c_smime_is_default)
1659 e_new->security |= APPLICATION_SMIME;
1660 else if (WithCrypto & APPLICATION_PGP)
1661 e_new->security |= APPLICATION_PGP;
1662 else
1663 e_new->security |= APPLICATION_SMIME;
1664 }
1665
1666 const bool c_crypt_opportunistic_encrypt = cs_subset_bool(sub, "crypt_opportunistic_encrypt");
1667 if (c_crypt_opportunistic_encrypt)
1668 {
1669 e_new->security |= SEC_OPPENCRYPT;
1671 }
1672 }
1673
1674 struct EmailArray ea = ARRAY_HEAD_INITIALIZER;
1675 ARRAY_ADD(&ea, e_cur);
1676 int rc = mutt_send_message(SEND_RESEND, e_new, NULL, m, &ea, sub);
1677 ARRAY_FREE(&ea);
1678
1679 return rc;
1680}
#define ARRAY_ADD(head, elem)
Add an element at the end of the array.
Definition: array.h:155
#define ARRAY_FREE(head)
Release all memory.
Definition: array.h:203
#define ARRAY_HEAD_INITIALIZER
Static initializer for arrays.
Definition: array.h:57
void crypt_opportunistic_encrypt(struct Email *e)
Can all recipients be determined.
Definition: crypt.c:1034
struct Email * email_new(void)
Create a new Email.
Definition: email.c:78
void email_free(struct Email **ptr)
Free an Email.
Definition: email.c:44
#define SEC_OPPENCRYPT
Opportunistic encrypt mode.
Definition: lib.h:87
#define APPLICATION_SMIME
Use SMIME to encrypt/sign.
Definition: lib.h:92
int mutt_prepare_template(FILE *fp, struct Mailbox *m, struct Email *e_new, struct Email *e, bool resend)
Prepare a message template.
Definition: postpone.c:491
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:2127
#define SEND_RESEND
Reply using the current email as a template.
Definition: send.h:47
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ is_reply()

static bool is_reply ( struct Email reply,
struct Email orig 
)
static

Is one email a reply to another?

Parameters
replyEmail to test
origOriginal email
Return values
trueIt is a reply
falseIt is not a reply

Definition at line 1689 of file send.c.

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

◆ search_attach_keyword()

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

Search an email for 'attachment' keywords.

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

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

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

Definition at line 1708 of file send.c.

1709{
1710 const struct Regex *c_abort_noattach_regex = cs_subset_regex(sub, "abort_noattach_regex");
1711 const struct Regex *c_quote_regex = cs_subset_regex(sub, "quote_regex");
1712
1713 /* Search for the regex in `$abort_noattach_regex` within a file */
1714 if (!c_abort_noattach_regex || !c_abort_noattach_regex->regex ||
1715 !c_quote_regex || !c_quote_regex->regex)
1716 {
1717 return false;
1718 }
1719
1720 FILE *fp_att = mutt_file_fopen(filename, "r");
1721 if (!fp_att)
1722 return false;
1723
1724 char *inputline = mutt_mem_malloc(1024);
1725 bool found = false;
1726 while (!feof(fp_att) && fgets(inputline, 1024, fp_att))
1727 {
1728 if (!mutt_is_quote_line(inputline, NULL) &&
1729 mutt_regex_match(c_abort_noattach_regex, inputline))
1730 {
1731 found = true;
1732 break;
1733 }
1734 }
1735 FREE(&inputline);
1736 mutt_file_fclose(&fp_att);
1737 return found;
1738}
const struct Regex * cs_subset_regex(const struct ConfigSubset *sub, const char *name)
Get a regex config item by name.
Definition: helpers.c:218
bool mutt_is_quote_line(char *line, regmatch_t *pmatch)
Is a line of message text a quote?
Definition: display.c:320
void * mutt_mem_malloc(size_t size)
Allocate memory on the heap.
Definition: memory.c:90
bool mutt_regex_match(const struct Regex *regex, const char *str)
Shorthand to mutt_regex_capture()
Definition: regex.c:636
Cached regular expression.
Definition: regex3.h:89
regex_t * regex
compiled expression
Definition: regex3.h:91
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ save_fcc()

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

Save an Email to a 'sent mail' folder.

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

Definition at line 1753 of file send.c.

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

◆ postpone_message()

static int postpone_message ( struct Email e_post,
struct Email e_cur,
const char *  fcc,
SendFlags  flags,
struct ConfigSubset sub 
)
static

Save an Email for another day.

Parameters
e_postEmail to postpone
e_curCurrent Email in the index
fccFolder for 'sent mail'
flagsSend mode, see SendFlags
subConfig Subset
Return values
0Success
-1Error

Definition at line 1950 of file send.c.

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

◆ is_text_plain()

static bool is_text_plain ( const struct Body b)
static

Is a Body a text/plain MIME part?

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

Definition at line 2064 of file send.c.

2065{
2066 return (b->type == TYPE_TEXT) && mutt_istr_equal(b->subtype, "plain");
2067}
@ 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 2075 of file send.c.

2076{
2077 const enum QuadOption c_abort_noattach = cs_subset_quad(sub, "abort_noattach");
2078
2079 if (c_abort_noattach == MUTT_NO)
2080 return false;
2081
2082 if (b->next)
2083 return false;
2084
2085 bool has_keyword = false;
2086
2087 /* search text/plain parts, whether they are main or alternative parts */
2088 if (is_text_plain(b))
2089 {
2090 has_keyword |= search_attach_keyword(b->filename, sub);
2091 }
2092 else
2093 {
2094 for (b = b->parts; b; b = b->next)
2095 {
2096 if (is_text_plain(b))
2097 {
2098 has_keyword |= search_attach_keyword(b->filename, sub);
2099 }
2100 }
2101 }
2102
2103 if (!has_keyword)
2104 return false;
2105
2106 if (c_abort_noattach == MUTT_YES)
2107 {
2108 mutt_error(_("Message contains text matching \"$abort_noattach_regex\". Not sending."));
2109 return true;
2110 }
2111
2112 return query_quadoption(_("No attachments, cancel sending?"), sub, "abort_noattach") != MUTT_NO;
2113}
static bool search_attach_keyword(char *filename, struct ConfigSubset *sub)
Search an email for 'attachment' keywords.
Definition: send.c:1708
static bool is_text_plain(const struct Body *b)
Is a Body a text/plain MIME part?
Definition: send.c:2064
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 2127 of file send.c.

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

2991{
2992 struct Email *e = email_new();
2993
2994 /* envelope */
2995 e->env = mutt_env_new();
2996 mutt_parse_mailto(e->env, NULL, mailto);
2997 if (!e->env->subject)
2998 {
2999 e->env->subject = mutt_str_dup(subj);
3000 }
3001 if (TAILQ_EMPTY(&e->env->to) && !mutt_addrlist_parse(&e->env->to, NULL))
3002 {
3003 mutt_warning(_("No recipient specified"));
3004 }
3005
3006 /* body */
3007 e->body = mutt_body_new();
3008 char ctype[] = "text/plain";
3009 mutt_parse_content_type(ctype, e->body);
3010
3011 struct Buffer *tempfile = buf_pool_get();
3012 buf_mktemp(tempfile);
3013 if (body)
3014 {
3015 FILE *fp = mutt_file_fopen(buf_string(tempfile), "w+");
3016 if (!fp)
3017 {
3018 email_free(&e);
3019 buf_pool_release(&tempfile);
3020 return false;
3021 }
3022 fprintf(fp, "%s\n", body);
3023 mutt_file_fclose(&fp);
3024 }
3025 e->body->filename = buf_strdup(tempfile);
3026 e->body->unlink = true;
3027 buf_pool_release(&tempfile);
3028
3029 const int rc = mutt_send_message(SEND_DRAFT_FILE, e, NULL, m, ea, NeoMutt->sub);
3030 return rc >= 0;
3031}
Container for Accounts, Notifications.
Definition: neomutt.h:41
struct ConfigSubset * sub
Inherited config items.
Definition: neomutt.h:45
+ 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 3040 of file send.c.

3041{
3042 if (!e || !e->env)
3043 {
3044 return false;
3045 }
3046
3047 const char *mailto = e->env->list_subscribe;
3048 if (!mailto)
3049 {
3050 mutt_warning(_("No List-Subscribe header found"));
3051 return false;
3052 }
3053
3054 struct EmailArray ea = ARRAY_HEAD_INITIALIZER;
3055 ARRAY_ADD(&ea, e);
3056 bool rc = send_simple_email(m, &ea, mailto, "Subscribe", "subscribe");
3057 ARRAY_FREE(&ea);
3058
3059 return rc;
3060}
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:2989
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 3069 of file send.c.

3070{
3071 if (!e || !e->env)
3072 {
3073 return false;
3074 }
3075
3076 const char *mailto = e->env->list_unsubscribe;
3077 if (!mailto)
3078 {
3079 mutt_warning(_("No List-Unsubscribe header found"));
3080 return false;
3081 }
3082
3083 struct EmailArray ea = ARRAY_HEAD_INITIALIZER;
3084 ARRAY_ADD(&ea, e);
3085 bool rc = send_simple_email(m, &ea, mailto, "Unsubscribe", "unsubscribe");
3086 ARRAY_FREE(&ea);
3087
3088 return rc;
3089}
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: