Send an email.
2039{
2041 FILE *fp_tmp = NULL;
2042 struct Body *pbody = NULL;
2043 int i;
2044 bool free_clear_content = false;
2045
2046 struct Body *clear_content = NULL;
2047 char *pgpkeylist = NULL;
2048
2049 char *pgp_sign_as = NULL;
2050 char *smime_sign_as = NULL;
2051 const char *tag = NULL;
2052 char *err = NULL;
2053 const char *ctype = NULL;
2054 char *finalpath = NULL;
2055 struct Email *e_cur = NULL;
2056
2059
2060 int rc = -1;
2061
2064 else
2066
2068
2070 {
2071
2072
2075 return rc;
2076
2079 }
2080
2082 {
2084 {
2087 }
2089 {
2090 const char *
const c_smime_sign_as =
cs_subset_string(sub,
"smime_sign_as");
2092 }
2093 }
2094
2095
2096
2097
2098
2099 if (!e_templ)
2100 {
2102
2104 {
2106 if (rc < 0)
2107 {
2109 goto cleanup;
2110 }
2111 flags = rc;
2112
2113
2115 {
2118 }
2119 else
2120 {
2123 }
2124 }
2125
2127 {
2132 if (!fp_tmp)
2133 {
2135 goto cleanup;
2136 }
2137 }
2138
2141 }
2142
2143
2145 {
2146
2148
2150 }
2151
2153 {
2154
2155
2157 {
2160 e_templ->
body = pbody;
2161
2163 ctype = c_content_type;
2164 if (!ctype)
2165 ctype = "text/plain";
2170
2171 if (tempfile)
2172 {
2177 }
2178 else
2179 {
2185 }
2186 }
2187 else
2188 {
2193 }
2194
2195 if (!fp_tmp)
2196 {
2200 goto cleanup;
2201 }
2202 }
2203
2205
2207 {
2208
2209
2210
2211
2212
2213
2215 {
2219 }
2221 }
2222
2223 const bool c_reply_with_xorig =
cs_subset_bool(sub,
"reply_with_xorig");
2225 {
2226
2227
2228
2229
2230
2231
2232
2233
2235 {
2239 }
2240 }
2241
2244
2245 const bool c_resume_draft_files =
cs_subset_bool(sub,
"resume_draft_files");
2248 {
2251 {
2252 goto cleanup;
2253 }
2254
2256 if (c_hdrs)
2258
2259
2261
2264
2266 {
2268 }
2269
2273 if (!(flags &
SEND_BATCH) && !(c_auto_edit && c_edit_headers) &&
2275 {
2277 goto cleanup;
2278 }
2279
2280
2281
2282
2283
2284
2286 if (killfrom)
2287 {
2289 }
2290
2292 {
2293
2295
2296
2297
2298
2300 }
2301
2302
2303
2305
2306
2307
2308
2309
2311
2312
2313 if (killfrom)
2314 {
2316
2320 }
2321
2322 if (c_hdrs)
2324
2326 {
2328 {
2330 goto cleanup;
2331 }
2332 }
2333
2336
2340 {
2342 }
2343
2344
2347 {
2348 goto cleanup;
2349 }
2350
2352 {
2354 }
2355 }
2356
2357
2358
2359
2360
2362 {
2365 {
2367 }
2368 }
2369
2370
2371
2373
2374
2375
2376 {
2379 {
2381 if (c_real_name)
2383 }
2384 }
2385
2388
2390 {
2391 struct stat st = { 0 };
2392 time_t mtime;
2397 if (mtime == (time_t) -1)
2398 {
2400 goto cleanup;
2401 }
2402
2404
2407
2408
2409
2410
2411
2412
2413
2414
2415
2417 (((flags &
SEND_FORWARD) == 0) || (c_edit_headers && c_auto_edit) ||
2419 {
2420
2426 {
2428 goto cleanup;
2429 }
2430 else if (c_edit_headers)
2431 {
2435 }
2436 else
2437 {
2440 {
2441 if (mtime != st.st_mtime)
2443 }
2444 else
2445 {
2447 }
2448 }
2449
2451 }
2452
2454 {
2456 {
2457
2458 if ((mtime == st.st_mtime) && !e_templ->
body->
next &&
2460 {
2462 goto cleanup;
2463 }
2464 }
2465 else
2466 {
2468 }
2469 }
2470 }
2471
2472
2473
2474
2475
2476
2477
2478
2479
2480
2481
2484 {
2485 bool c_autocrypt = false;
2486 bool c_autocrypt_reply = false;
2487
2488#ifdef USE_AUTOCRYPT
2491#endif
2492
2494 {
2496 }
2497 else
2498 {
2499 const bool c_crypt_auto_sign =
cs_subset_bool(sub,
"crypt_auto_sign");
2500 const bool c_crypt_auto_encrypt =
cs_subset_bool(sub,
"crypt_auto_encrypt");
2501 const bool c_crypt_reply_encrypt =
cs_subset_bool(sub,
"crypt_reply_encrypt");
2502 const bool c_crypt_reply_sign =
cs_subset_bool(sub,
"crypt_reply_sign");
2503 const bool c_crypt_reply_sign_encrypted =
cs_subset_bool(sub,
"crypt_reply_sign_encrypted");
2504
2505 if (c_crypt_auto_sign)
2507 if (c_crypt_auto_encrypt)
2515
2516 const bool c_crypt_opportunistic_encrypt =
cs_subset_bool(sub,
"crypt_opportunistic_encrypt");
2517
2520 {
2521 const bool c_pgp_auto_inline =
cs_subset_bool(sub,
"pgp_auto_inline");
2522 const bool c_pgp_reply_inline =
cs_subset_bool(sub,
"pgp_reply_inline");
2523
2524 if (c_pgp_auto_inline)
2528 }
2529 }
2530
2531 const bool c_crypt_opportunistic_encrypt =
cs_subset_bool(sub,
"crypt_opportunistic_encrypt");
2532
2533 if (e_templ->
security || c_crypt_opportunistic_encrypt)
2534 {
2535 const bool c_crypt_auto_pgp =
cs_subset_bool(sub,
"crypt_auto_pgp");
2536 const bool c_crypt_auto_smime =
cs_subset_bool(sub,
"crypt_auto_smime");
2537
2538
2539
2540
2541
2542
2543
2544
2545 if (e_cur)
2546 {
2549 {
2551 }
2554 {
2556 }
2557 }
2558
2559 const bool c_smime_is_default =
cs_subset_bool(sub,
"smime_is_default");
2560
2561
2562
2564 {
2566 {
2568 }
2570 {
2572 }
2574 {
2576 }
2577 }
2578 }
2579
2580
2581 if (c_crypt_opportunistic_encrypt)
2582 {
2583
2584
2585
2587 {
2590 }
2591 }
2592
2593
2596 }
2597
2598
2599
2600
2602 {
2603 mutt_error(
_(
"No crypto backend configured. Disabling message security setting."));
2605 }
2606
2607
2608
2609
2611
2614 {
2615
2617 if (killfrom)
2618 {
2620 }
2622 if (killfrom)
2623 {
2625 }
2626 }
2627
2629
2631
2633 {
2634 main_loop:
2635
2639 if (i == -1)
2640 {
2641
2644 else
2646 goto cleanup;
2647 }
2648 else if (i == 1)
2649 {
2651 goto main_loop;
2653 rc = 1;
2654 goto cleanup;
2655 }
2656 }
2657
2659 {
2663 {
2665 {
2666 puts(
_(
"No recipients specified"));
2667 goto cleanup;
2668 }
2669
2671 goto main_loop;
2672 }
2673 }
2674
2676 {
2680 goto cleanup;
2681 goto main_loop;
2682 }
2683
2685
2688 {
2689
2692 goto main_loop;
2693 }
2694
2696 {
2698 goto main_loop;
2699 }
2700
2702 {
2704 goto main_loop;
2705 }
2706
2708 {
2709 goto main_loop;
2710 }
2711
2712 const bool c_confirm_empty_to =
cs_subset_bool(sub,
"confirm_empty_to");
2715 {
2716 goto main_loop;
2717 }
2718
2721
2722
2723
2724
2725
2727
2728
2729
2730
2731
2732
2733 clear_content = NULL;
2734 free_clear_content = false;
2735
2737 {
2739 {
2740
2741 clear_content = e_templ->
body;
2742
2745 {
2748
2750
2752
2754 {
2756 rc = -1;
2757 goto cleanup;
2758 }
2759
2760 goto main_loop;
2761 }
2763 }
2764
2765
2766
2767
2768
2769
2770
2771
2772
2773 if (clear_content && (e_templ->
body != clear_content) &&
2774 (e_templ->
body->
parts != clear_content))
2775 free_clear_content = true;
2776 }
2777
2780
2782
2783 const bool c_fcc_before_send =
cs_subset_bool(sub,
"fcc_before_send");
2784 if (c_fcc_before_send)
2785 save_fcc(m, e_templ, fcc, clear_content, pgpkeylist, flags, &finalpath, sub);
2786
2788 if (i < 0)
2789 {
2791 {
2793 ;
2796 {
2797 if (e_templ->
body != clear_content)
2798 {
2800 e_templ->
body = clear_content;
2801 }
2802 }
2804 {
2808 {
2810 }
2811 }
2812
2821 goto main_loop;
2822 }
2823 else
2824 {
2825 puts(
_(
"Could not send the message"));
2826 goto cleanup;
2827 }
2828 }
2829
2830 if (!c_fcc_before_send)
2831 save_fcc(m, e_templ, fcc, clear_content, pgpkeylist, flags, &finalpath, sub);
2832
2834 {
2838#ifdef USE_NOTMUCH
2840 if (c_nm_record)
2842#endif
2844 }
2845
2848
2851
2852
2853
2855 {
2857 {
2858 struct Email **ep = NULL;
2860 {
2861 struct Email *e = *ep;
2863 }
2864 }
2865 }
2866
2867 rc = 0;
2868
2869cleanup:
2871
2873 {
2875 {
2878 }
2880 {
2882 FREE(&smime_sign_as);
2883 }
2884 }
2885
2889
2891 return rc;
2892}
void mutt_addrlist_append(struct AddressList *al, struct Address *a)
Append an Address to an AddressList.
int mutt_addrlist_count_recips(const struct AddressList *al)
Count the number of Addresses with valid recipients.
void mutt_expand_aliases_env(struct Envelope *env)
Expand aliases in all the fields of an Envelope.
#define ARRAY_FOREACH(elem, head)
Iterate over all elements of the array.
#define ARRAY_SIZE(head)
The number of elements stored.
#define ARRAY_GET(head, idx)
Return the element at index.
struct Buffer * buf_new(const char *str)
Allocate a new Buffer.
char * buf_strdup(const struct Buffer *buf)
Copy a Buffer's string.
@ CMD_SEND_HOOK
:send-hook
@ CMD_SEND2_HOOK
:send2-hook
@ CMD_REPLY_HOOK
:reply-hook
#define MUTT_COMPOSE_NOFREEHEADER
Don't free the header when closing compose dialog.
enum QuadOption cs_subset_quad(const struct ConfigSubset *sub, const char *name)
Get a quad-value config item by name.
@ MUTT_NNTP
'NNTP' (Usenet) Mailbox type
int mutt_protect(struct Email *e, char *keylist, bool postpone)
Encrypt and/or sign a message.
int crypt_get_keys(struct Email *e, char **keylist, bool oppenc_mode)
Check we have all the keys we need.
bool crypt_has_module_backend(SecurityFlags type)
Is there a crypto backend for a given type?
void mutt_edit_file(const char *editor, const char *file)
Let the user edit a file.
void mutt_body_free(struct Body **ptr)
Free a Body.
struct Body * mutt_body_new(void)
Create a new Body.
void mutt_parse_content_type(const char *s, struct Body *b)
Parse a content type.
bool mutt_parse_mailto(struct Envelope *env, char **body, const char *src)
Parse a mailto:// url.
int mutt_env_to_intl(struct Envelope *env, const char **tag, char **err)
Convert an Envelope's Address fields to Punycode format.
void mutt_env_free(struct Envelope **ptr)
Free an Envelope.
struct Envelope * mutt_env_new(void)
Create a new Envelope.
void mutt_env_to_local(struct Envelope *env)
Convert an Envelope's Address fields to local format.
char * msgid_generate(void)
Generate a Message-Id.
int mutt_file_copy_stream(FILE *fp_in, FILE *fp_out)
Copy the contents of one file into another.
time_t mutt_file_decrease_mtime(const char *fp, struct stat *st)
Decrease a file's modification time by 1 second.
#define mutt_file_fclose(FP)
#define mutt_file_fopen(PATH, MODE)
void mutt_set_flag(struct Mailbox *m, struct Email *e, enum MessageType flag, bool bf, bool upd_mbox)
Set a flag on an email.
bool OptGui
(pseudo) when the gui (and curses) are started
int dlg_compose(struct Email *e, struct Buffer *fcc, uint8_t flags, struct ConfigSubset *sub)
Allow the user to edit the message envelope -.
#define mutt_warning(...)
#define mutt_message(...)
#define mutt_debug(LEVEL,...)
void mutt_select_fcc(struct Buffer *path, struct Email *e)
Select the FCC path for an email.
void exec_message_hook(struct Mailbox *m, struct Email *e, enum CommandId id)
Perform a message hook.
@ LL_DEBUG5
Log at debug level 5.
@ LL_DEBUG1
Log at debug level 1.
@ TYPE_MULTIPART
Type: 'multipart/*'.
@ TYPE_APPLICATION
Type: 'application/*'.
@ DISP_INLINE
Content is inline.
struct Body * mutt_remove_multipart(struct Body *b)
Extract the multipart body if it exists.
struct Body * mutt_make_multipart(struct Body *b)
Create a multipart email.
bool mutt_istr_equal(const char *a, const char *b)
Compare two strings, ignoring case.
@ MUTT_REPLIED
Messages that have been replied to.
bool mutt_edit_attachment(struct Body *b)
Edit an attachment.
void mutt_sleep(short s)
Sleep for a while.
void pretty_mailbox(struct Buffer *buf)
Shorten a mailbox path using '~' or '='.
bool mutt_needs_mailcap(struct Body *b)
Does this type need a mailcap entry do display.
#define SEC_INLINE
Email has an inline signature.
#define SEC_AUTOCRYPT
(Autocrypt) Message will be, or was Autocrypt encrypt+signed
#define SEC_NO_FLAGS
No flags are set.
#define SEC_ENCRYPT
Email is encrypted.
#define SEC_AUTOCRYPT_OVERRIDE
(Autocrypt) Indicates manual set/unset of encryption
#define SEC_SIGN
Email is signed.
int nm_record_message(struct Mailbox *m, char *path, struct Email *e)
Add a message to the Notmuch database.
void mutt_param_delete(struct ParameterList *pl, const char *attribute)
Delete a matching Parameter.
void mutt_param_set(struct ParameterList *pl, const char *attribute, const char *value)
Set a Parameter.
int mutt_num_postponed(struct Mailbox *m, bool force)
Return the number of postponed messages.
int mutt_get_postponed(struct Mailbox *m_cur, struct Email *hdr, struct Email **cur, struct Buffer *fcc)
Recall a postponed message.
@ MUTT_NO
User answered 'No', or assume 'No'.
enum QuadOption query_yesorno(const char *prompt, enum QuadOption def)
Ask the user a Yes/No question.
void mutt_rfc3676_space_stuff(struct Email *e)
Perform RFC3676 space stuffing on an Email.
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_reply(struct Email *reply, struct Email *orig)
Is one email a reply to another?
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 envelope_defaults(struct Envelope *env, struct EmailArray *ea, SendFlags flags, struct ConfigSubset *sub)
Fill in some defaults for a new email.
void mutt_fix_reply_recipients(struct Envelope *env, struct ConfigSubset *sub)
Remove duplicate recipients.
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.
static void mutt_make_greeting(struct Email *e, FILE *fp_out, struct ConfigSubset *sub)
Add greetings string.
static int invoke_mta(struct Mailbox *m, struct Email *e, struct ConfigSubset *sub)
Send an email.
struct Address * mutt_default_from(struct ConfigSubset *sub)
Get a default 'from' Address.
static void process_user_recips(struct Envelope *env)
Process the user headers.
static void process_user_header(struct Envelope *env)
Process the user headers.
static int edit_envelope(struct Envelope *en, SendFlags flags, struct ConfigSubset *sub)
Edit Envelope fields.
static bool abort_for_missing_attachments(const struct Body *b, struct ConfigSubset *sub)
Should we abort sending because of missing attachments?
static void set_reverse_name(struct AddressList *al, struct Envelope *env, struct ConfigSubset *sub)
Try to set the 'from' field from the recipients.
static void fix_end_of_file(const char *data)
Ensure a file ends with a linefeed.
static bool is_text_plain(const struct Body *b)
Is a Body a text/plain MIME part?
static void decode_descriptions(struct Body *b)
RFC2047 decode them in case of an error.
static void append_signature(FILE *fp, struct ConfigSubset *sub)
Append a signature to an email.
#define SEND_POSTPONED_FCC
Used by mutt_get_postponed() to signal that the Mutt-Fcc header field was present.
#define SEND_BATCH
Send email in batch mode (without user interaction)
#define SEND_NO_FREE_HEADER
Used by the -E flag.
#define SEND_DRAFT_FILE
Used by the -H flag.
#define SEND_KEY
Mail a PGP public key.
#define SEND_POSTPONED
Recall a postponed email.
#define SEND_CONSUMED_STDIN
stdin has been read; don't read it twice
#define SEND_CLI_CRYPTO
Enable message security in modes that by default don't enable it.
#define SEND_REPLY
Reply to sender.
#define SEND_NEWS
Reply to a news article.
#define SEND_FORWARD
Forward email.
void mutt_update_encoding(struct Body *b, struct ConfigSubset *sub)
Update the encoding type.
void mutt_unprepare_envelope(struct Envelope *env)
Undo the encodings of mutt_prepare_envelope()
void mutt_prepare_envelope(struct Envelope *env, bool final, struct ConfigSubset *sub)
Prepare an email header.
struct Buffer * personal
Real name of address.
struct Body * parts
parts of a multipart or message/rfc822
bool unlink
If true, filename should be unlink()ed before free()ing this structure.
struct Envelope * mime_headers
Memory hole protected headers.
struct ParameterList parameter
Parameters of the content-type.
bool use_disp
Content-Disposition uses filename= ?
unsigned int disposition
content-disposition, ContentDisposition
char * subtype
content-type subtype
unsigned int type
content-type primary type, ContentType
char * filename
When sending a message, this is the file to which this structure refers.
struct Envelope * env
Envelope information.
struct Body * body
List of MIME parts.
bool replied
Email has been replied to.
char * message_id
Message ID.
struct AddressList x_original_to
Email's 'X-Original-to'.
char * newsgroups
List of newsgroups.
struct AddressList bcc
Email's 'Bcc' list.
char * list_post
This stores a mailto URL, or nothing.
enum MailboxType type
Mailbox type.
void * mdata
Driver specific data.
NNTP-specific Mailbox data -.
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.