Send an email.
2122{
2124 FILE *fp_tmp = NULL;
2125 struct Body *pbody = NULL;
2126 int i;
2127 bool free_clear_content = false;
2128
2129 struct Body *clear_content = NULL;
2130 char *pgpkeylist = NULL;
2131
2132 char *pgp_sign_as = NULL;
2133 char *smime_sign_as = NULL;
2134 const char *tag = NULL;
2135 char *err = NULL;
2136 const char *ctype = NULL;
2137 char *finalpath = NULL;
2138 struct Email *e_cur = NULL;
2139
2142
2143 int rc = -1;
2144
2147 else
2149
2151
2153 {
2154
2155
2158 return rc;
2159
2162 }
2163
2164
2165
2167
2169 {
2171 {
2174 }
2176 {
2177 const char *
const c_smime_sign_as =
cs_subset_string(sub,
"smime_sign_as");
2179 }
2180 }
2181
2182
2183
2184
2185
2186 if (!e_templ)
2187 {
2189
2191 {
2193 if (rc < 0)
2194 {
2196 goto cleanup;
2197 }
2198 flags = rc;
2199
2200
2202 {
2205 }
2206 else
2207 {
2208 flags &= ~SEND_NEWS;
2210 }
2211 }
2212
2214 {
2219 if (!fp_tmp)
2220 {
2222 goto cleanup;
2223 }
2224 }
2225
2228 }
2229
2230
2232 {
2233
2235
2237 }
2238
2240 {
2241
2242
2244 {
2247 e_templ->
body = pbody;
2248
2250 ctype = c_content_type;
2251 if (!ctype)
2252 ctype = "text/plain";
2257
2258 if (tempfile)
2259 {
2264 }
2265 else
2266 {
2272 }
2273 }
2274 else
2275 {
2280 }
2281
2282 if (!fp_tmp)
2283 {
2287 goto cleanup;
2288 }
2289 }
2290
2292
2294 {
2295
2296
2297
2298
2299
2300
2302 {
2306 }
2308 }
2309
2310 const bool c_reply_with_xorig =
cs_subset_bool(sub,
"reply_with_xorig");
2312 {
2313
2314
2315
2316
2317
2318
2319
2320
2322 {
2326 }
2327 }
2328
2329 const bool c_resume_draft_files =
cs_subset_bool(sub,
"resume_draft_files");
2332 {
2335 {
2336 goto cleanup;
2337 }
2338
2340 if (c_hdrs)
2342
2343
2345
2348
2350 {
2352 }
2353
2357 if (!(flags &
SEND_BATCH) && !(c_auto_edit && c_edit_headers) &&
2359 {
2361 goto cleanup;
2362 }
2363
2364
2365
2366
2367
2368
2370 if (killfrom)
2371 {
2373 }
2374
2376 {
2377
2379
2380
2381
2382
2384 }
2385
2386
2387
2389
2390
2391
2392
2393
2395
2396
2397 if (killfrom)
2398 {
2400
2404 }
2405
2406 if (c_hdrs)
2408
2410 {
2412 {
2414 goto cleanup;
2415 }
2416 }
2417
2420
2424 {
2426 }
2427
2428
2431 {
2432 goto cleanup;
2433 }
2434
2436 {
2438 }
2439 }
2440
2441
2442
2443
2444
2446 {
2449 {
2451 }
2452 }
2453
2454
2455
2457
2458
2459
2460 {
2463 {
2465 if (c_real_name)
2467 }
2468 }
2469
2472
2474 {
2475 struct stat st = { 0 };
2476 time_t mtime;
2481 if (mtime == (time_t) -1)
2482 {
2484 goto cleanup;
2485 }
2486
2488
2491
2492
2493
2494
2495
2496
2497
2498
2499
2501 (((flags &
SEND_FORWARD) == 0) || (c_edit_headers && c_auto_edit) ||
2503 {
2504
2510 {
2512 goto cleanup;
2513 }
2514 else if (c_edit_headers)
2515 {
2519 }
2520 else
2521 {
2524 {
2525 if (mtime != st.st_mtime)
2527 }
2528 else
2529 {
2531 }
2532 }
2533
2535 }
2536
2538 {
2540 {
2541
2542 if ((mtime == st.st_mtime) && !e_templ->
body->
next &&
2544 {
2546 goto cleanup;
2547 }
2548 }
2549 else
2550 {
2552 }
2553 }
2554 }
2555
2556
2557
2558
2559
2560
2561
2562
2563
2564
2565
2568 {
2569 bool c_autocrypt = false;
2570 bool c_autocrypt_reply = false;
2571
2572#ifdef USE_AUTOCRYPT
2575#endif
2576
2578 {
2580 }
2581 else
2582 {
2583 const bool c_crypt_auto_sign =
cs_subset_bool(sub,
"crypt_auto_sign");
2584 const bool c_crypt_auto_encrypt =
cs_subset_bool(sub,
"crypt_auto_encrypt");
2585 const bool c_crypt_reply_encrypt =
cs_subset_bool(sub,
"crypt_reply_encrypt");
2586 const bool c_crypt_reply_sign =
cs_subset_bool(sub,
"crypt_reply_sign");
2587 const bool c_crypt_reply_sign_encrypted =
cs_subset_bool(sub,
"crypt_reply_sign_encrypted");
2588
2589 if (c_crypt_auto_sign)
2591 if (c_crypt_auto_encrypt)
2599
2600 const bool c_crypt_opportunistic_encrypt =
cs_subset_bool(sub,
"crypt_opportunistic_encrypt");
2601
2604 {
2605 const bool c_pgp_auto_inline =
cs_subset_bool(sub,
"pgp_auto_inline");
2606 const bool c_pgp_reply_inline =
cs_subset_bool(sub,
"pgp_reply_inline");
2607
2608 if (c_pgp_auto_inline)
2612 }
2613 }
2614
2615 const bool c_crypt_opportunistic_encrypt =
cs_subset_bool(sub,
"crypt_opportunistic_encrypt");
2616
2617 if (e_templ->
security || c_crypt_opportunistic_encrypt)
2618 {
2619 const bool c_crypt_auto_pgp =
cs_subset_bool(sub,
"crypt_auto_pgp");
2620 const bool c_crypt_auto_smime =
cs_subset_bool(sub,
"crypt_auto_smime");
2621
2622
2623
2624
2625
2626
2627
2628
2629 if (e_cur)
2630 {
2633 {
2635 }
2638 {
2640 }
2641 }
2642
2643 const bool c_smime_is_default =
cs_subset_bool(sub,
"smime_is_default");
2644
2645
2646
2648 {
2650 {
2652 }
2654 {
2656 }
2658 {
2660 }
2661 }
2662 }
2663
2664
2665 if (c_crypt_opportunistic_encrypt)
2666 {
2667
2668
2669
2671 {
2674 }
2675 }
2676
2677
2680 }
2681
2682
2683
2684
2686 {
2687 mutt_error(
_(
"No crypto backend configured. Disabling message security setting."));
2689 }
2690
2691
2692
2693
2695
2698 {
2699
2701 if (killfrom)
2702 {
2704 }
2706 if (killfrom)
2707 {
2709 }
2710 }
2711
2713
2715
2717 {
2718 main_loop:
2719
2723 if (i == -1)
2724 {
2725
2728 else
2730 goto cleanup;
2731 }
2732 else if (i == 1)
2733 {
2735 goto main_loop;
2737 rc = 1;
2738 goto cleanup;
2739 }
2740 }
2741
2743 {
2747 {
2749 {
2750 puts(
_(
"No recipients specified"));
2751 goto cleanup;
2752 }
2753
2755 goto main_loop;
2756 }
2757 }
2758
2760 {
2764 goto cleanup;
2765 goto main_loop;
2766 }
2767
2769
2772 {
2773
2776 goto main_loop;
2777 }
2778
2780 {
2782 goto main_loop;
2783 }
2784
2786 {
2788 goto main_loop;
2789 }
2790
2792 {
2793 goto main_loop;
2794 }
2795
2798
2799
2800
2801
2802
2804
2805
2806
2807
2808
2809
2810 clear_content = NULL;
2811 free_clear_content = false;
2812
2814 {
2816 {
2817
2818 clear_content = e_templ->
body;
2819
2822 {
2825
2827
2829
2831 {
2833 rc = -1;
2834 goto cleanup;
2835 }
2836
2837 goto main_loop;
2838 }
2840 }
2841
2842
2843
2844
2845
2846
2847
2848
2849
2850 if (clear_content && (e_templ->
body != clear_content) &&
2851 (e_templ->
body->
parts != clear_content))
2852 free_clear_content = true;
2853 }
2854
2857
2859
2860 const bool c_fcc_before_send =
cs_subset_bool(sub,
"fcc_before_send");
2861 if (c_fcc_before_send)
2862 save_fcc(m, e_templ, &fcc, clear_content, pgpkeylist, flags, &finalpath, sub);
2863
2865 if (i < 0)
2866 {
2868 {
2870 ;
2873 {
2874 if (e_templ->
body != clear_content)
2875 {
2877 e_templ->
body = clear_content;
2878 }
2879 }
2881 {
2885 {
2887 }
2888 }
2889
2898 goto main_loop;
2899 }
2900 else
2901 {
2902 puts(
_(
"Could not send the message"));
2903 goto cleanup;
2904 }
2905 }
2906
2907 if (!c_fcc_before_send)
2908 save_fcc(m, e_templ, &fcc, clear_content, pgpkeylist, flags, &finalpath, sub);
2909
2911 {
2915#ifdef USE_NOTMUCH
2917 if (c_nm_record)
2919#endif
2921 }
2922
2925
2928
2929
2930
2932 {
2934 {
2935 struct Email **ep = NULL;
2937 {
2938 struct Email *e = *ep;
2940 }
2941 }
2942 }
2943
2944 rc = 0;
2945
2946cleanup:
2948
2950 {
2952 {
2955 }
2957 {
2959 FREE(&smime_sign_as);
2960 }
2961 }
2962
2966
2968 return rc;
2969}
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.
void buf_dealloc(struct Buffer *buf)
Release the memory allocated by a buffer.
bool buf_is_empty(const struct Buffer *buf)
Is the Buffer empty?
struct Buffer buf_make(size_t size)
Make a new buffer on the stack.
struct Buffer * buf_new(const char *str)
Allocate a new Buffer.
char * buf_strdup(const struct Buffer *buf)
Copy a Buffer's string.
#define MUTT_COMPOSE_NOFREEHEADER
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.
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 OptNoCurses
(pseudo) when sending in batch mode
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 mutt_message_hook(struct Mailbox *m, struct Email *e, HookFlags type)
Perform a message hook.
#define MUTT_SEND_HOOK
send-hook: when composing a new email
#define MUTT_SEND2_HOOK
send2-hook: when changing fields in the compose menu
#define MUTT_REPLY_HOOK
reply-hook: when replying to an email
@ 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 buf_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'.
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.
struct AddressList x_original_to
Email's 'X-Orig-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.