NeoMutt  2025-12-11-980-ge38c27
Teaching an old dog new tricks
DOXYGEN
Loading...
Searching...
No Matches
sendlib.c File Reference

Miscellaneous functions for sending an email. More...

#include "config.h"
#include <inttypes.h>
#include <limits.h>
#include <stdbool.h>
#include <stdio.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#include "mutt/lib.h"
#include "address/lib.h"
#include "config/lib.h"
#include "email/lib.h"
#include "core/lib.h"
#include "mutt.h"
#include "sendlib.h"
#include "attach/lib.h"
#include "convert/lib.h"
#include "ncrypt/lib.h"
#include "body.h"
#include "expando_msgid.h"
#include "globals.h"
#include "header.h"
#include "mutt_mailbox.h"
#include "muttlib.h"
#include "mx.h"
#include "send.h"
#include "sendmail.h"
#include "smtp.h"
+ Include dependency graph for sendlib.c:

Go to the source code of this file.

Functions

enum ContentType mutt_lookup_mime_type (struct Body *b, const char *path)
 Find the MIME type for an attachment.
 
static void transform_to_7bit (struct Body *b, FILE *fp_in, struct ConfigSubset *sub)
 Convert MIME parts to 7-bit.
 
void mutt_message_to_7bit (struct Body *b, FILE *fp, struct ConfigSubset *sub)
 Convert an email's MIME parts to 7-bit.
 
static void set_encoding (struct Body *b, struct Content *info, struct ConfigSubset *sub)
 Determine which Content-Transfer-Encoding to use.
 
void mutt_stamp_attachment (struct Body *b)
 Timestamp an Attachment.
 
void mutt_update_encoding (struct Body *b, struct ConfigSubset *sub)
 Update the encoding type.
 
struct Bodymutt_make_message_attach (struct Mailbox *m, struct Email *e, bool attach_msg, struct ConfigSubset *sub)
 Create a message attachment.
 
static void run_mime_type_query (struct Body *b, struct ConfigSubset *sub)
 Run an external command to determine the MIME type.
 
struct Bodymutt_make_file_attach (const char *path, struct ConfigSubset *sub)
 Create a file attachment.
 
static void encode_headers (struct ListHead *h, struct ConfigSubset *sub)
 RFC2047-encode a list of headers.
 
const char * mutt_fqdn (bool may_hide_host, const struct ConfigSubset *sub)
 Get the Fully-Qualified Domain Name.
 
void mutt_prepare_envelope (struct Envelope *env, bool final, struct ConfigSubset *sub)
 Prepare an email header.
 
void mutt_unprepare_envelope (struct Envelope *env)
 Undo the encodings of mutt_prepare_envelope()
 
static int bounce_message (FILE *fp, struct Mailbox *m, struct Email *e, struct AddressList *to, const char *resent_from, struct AddressList *env_from, struct ConfigSubset *sub)
 Bounce an email message.
 
int mutt_bounce_message (FILE *fp, struct Mailbox *m, struct Email *e, struct AddressList *to, struct ConfigSubset *sub)
 Bounce an email message.
 
static void set_noconv_flags (struct Body *b, bool flag)
 Set/reset the "x-mutt-noconv" flag.
 
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.
 
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.
 

Detailed Description

Miscellaneous functions for sending an email.

Authors
  • R Primus
  • Richard Russon
  • Pietro Cerutti
  • Rayford Shireman
  • Thomas Klausner

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 sendlib.c.

Function Documentation

◆ mutt_lookup_mime_type()

enum ContentType mutt_lookup_mime_type ( struct Body * b,
const char * path )

Find the MIME type for an attachment.

Parameters
bEmail with attachment
pathPath to attachment
Return values
enumContentType, e.g. TYPE_IMAGE

Given a file at 'path', see if there is a registered MIME type. Returns the major MIME type, and copies the subtype to "d". First look in a system mime.types if we can find one, then look for ~/.mime.types. The longest match is used so that we can match 'ps.gz' when 'gz' also exists.

Definition at line 75 of file sendlib.c.

76{
77 FILE *fp = NULL;
78 char *p = NULL;
79 char *q = NULL;
80 char *ct = NULL;
81 char buf[PATH_MAX] = { 0 };
82 char subtype[256] = { 0 };
83 char xtype[256] = { 0 };
84 int sze;
85 int cur_sze = 0;
86 bool found_mimetypes = false;
87 enum ContentType type = TYPE_OTHER;
88
89 int szf = mutt_str_len(path);
90
91 for (int count = 0; count < 4; count++)
92 {
93 /* can't use strtok() because we use it in an inner loop below, so use
94 * a switch statement here instead. */
95 switch (count)
96 {
97 /* last file with last entry to match wins type/xtype */
98 case 0:
99 /* check default unix mimetypes location first */
100 mutt_str_copy(buf, "/etc/mime.types", sizeof(buf));
101 break;
102 case 1:
103 mutt_str_copy(buf, SYSCONFDIR "/mime.types", sizeof(buf));
104 break;
105 case 2:
106 mutt_str_copy(buf, PKGDATADIR "/mime.types", sizeof(buf));
107 break;
108 case 3:
109 snprintf(buf, sizeof(buf), "%s/.mime.types", NONULL(NeoMutt->home_dir));
110 break;
111 default:
112 mutt_debug(LL_DEBUG1, "Internal error, count = %d\n", count);
113 goto bye; /* shouldn't happen */
114 }
115
116 fp = mutt_file_fopen(buf, "r");
117 if (fp)
118 {
119 found_mimetypes = true;
120
121 while (fgets(buf, sizeof(buf) - 1, fp))
122 {
123 /* weed out any comments */
124 p = strchr(buf, '#');
125 if (p)
126 *p = '\0';
127
128 /* remove any leading space. */
129 ct = buf;
130 SKIPWS(ct);
131
132 /* position on the next field in this line */
133 p = strpbrk(ct, " \t");
134 if (!p)
135 continue;
136 *p++ = 0;
137 SKIPWS(p);
138
139 /* cycle through the file extensions */
140 while ((p = strtok(p, " \t\n")))
141 {
142 sze = mutt_str_len(p);
143 if ((sze > cur_sze) && (szf >= sze) && mutt_istr_equal(path + szf - sze, p) &&
144 ((szf == sze) || (path[szf - sze - 1] == '.')))
145 {
146 /* get the content-type */
147
148 p = strchr(ct, '/');
149 if (!p)
150 {
151 /* malformed line, just skip it. */
152 break;
153 }
154 *p++ = 0;
155
156 for (q = p; *q && !mutt_isspace(*q); q++)
157 ; // do nothing
158
159 mutt_strn_copy(subtype, p, q - p, sizeof(subtype));
160
161 type = mutt_check_mime_type(ct);
162 if (type == TYPE_OTHER)
163 mutt_str_copy(xtype, ct, sizeof(xtype));
164
165 cur_sze = sze;
166 }
167 p = NULL;
168 }
169 }
170 mutt_file_fclose(&fp);
171 }
172 }
173
174bye:
175
176 /* no mime.types file found */
177 if (!found_mimetypes)
178 {
179 mutt_error(_("Could not find any mime.types file"));
180 }
181
182 if ((type != TYPE_OTHER) || (*xtype != '\0'))
183 {
184 b->type = type;
185 mutt_str_replace(&b->subtype, subtype);
186 mutt_str_replace(&b->xtype, xtype);
187 }
188
189 return type;
190}
bool mutt_isspace(int arg)
Wrapper for isspace(3)
Definition ctype.c:96
enum ContentType mutt_check_mime_type(const char *s)
Check a MIME type string.
Definition parse.c:333
#define mutt_file_fclose(FP)
Definition file.h:144
#define mutt_file_fopen(PATH, MODE)
Definition file.h:143
#define mutt_error(...)
Definition logging2.h:94
#define mutt_debug(LEVEL,...)
Definition logging2.h:91
@ LL_DEBUG1
Log at debug level 1.
Definition logging2.h:45
ContentType
Content-Type.
Definition mime.h:30
@ TYPE_OTHER
Unknown Content-Type.
Definition mime.h:31
#define _(a)
Definition message.h:28
bool mutt_istr_equal(const char *a, const char *b)
Compare two strings, ignoring case.
Definition string.c:678
char * mutt_strn_copy(char *dest, const char *src, size_t len, size_t dsize)
Copy a sub-string into a buffer.
Definition string.c:364
size_t mutt_str_len(const char *a)
Calculate the length of a string, safely.
Definition string.c:503
size_t mutt_str_copy(char *dest, const char *src, size_t dsize)
Copy a string into a buffer (guaranteeing NUL-termination)
Definition string.c:587
char * mutt_str_replace(char **p, const char *s)
Replace one string with another.
Definition string.c:284
#define PATH_MAX
Definition mutt.h:49
#define NONULL(x)
Definition string2.h:44
#define SKIPWS(ch)
Definition string2.h:52
char * xtype
content-type if x-unknown
Definition body.h:62
char * subtype
content-type subtype
Definition body.h:61
unsigned int type
content-type primary type, ContentType
Definition body.h:40
Container for Accounts, Notifications.
Definition neomutt.h:41
char * home_dir
User's home directory.
Definition neomutt.h:55
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ transform_to_7bit()

static void transform_to_7bit ( struct Body * b,
FILE * fp_in,
struct ConfigSubset * sub )
static

Convert MIME parts to 7-bit.

Parameters
bBody of the email
fp_inFile to read
subConfig Subset

Definition at line 198 of file sendlib.c.

199{
200 struct Buffer *buf = NULL;
201 struct State state = { 0 };
202 struct stat st = { 0 };
203
204 for (; b; b = b->next)
205 {
206 if (b->type == TYPE_MULTIPART)
207 {
208 b->encoding = ENC_7BIT;
209 transform_to_7bit(b->parts, fp_in, sub);
210 }
211 else if (mutt_is_message_type(b->type, b->subtype))
212 {
213 mutt_message_to_7bit(b, fp_in, sub);
214 }
215 else
216 {
217 b->noconv = true;
218 b->force_charset = true;
219
220 /* Because of the potential recursion in message types, we
221 * restrict the lifetime of the buffer tightly */
222 buf = buf_pool_get();
223 buf_mktemp(buf);
224 state.fp_out = mutt_file_fopen(buf_string(buf), "w");
225 if (!state.fp_out)
226 {
227 mutt_perror("fopen");
228 buf_pool_release(&buf);
229 return;
230 }
231 state.fp_in = fp_in;
232 mutt_decode_attachment(b, &state);
233 mutt_file_fclose(&state.fp_out);
234 FREE(&b->d_filename);
235 b->d_filename = b->filename;
236 b->filename = buf_strdup(buf);
237 buf_pool_release(&buf);
238 b->unlink = true;
239 if (stat(b->filename, &st) == -1)
240 {
241 mutt_perror("stat");
242 return;
243 }
244 b->length = st.st_size;
245
246 mutt_update_encoding(b, sub);
247 if (b->encoding == ENC_8BIT)
249 else if (b->encoding == ENC_BINARY)
250 b->encoding = ENC_BASE64;
251 }
252 }
253}
char * buf_strdup(const struct Buffer *buf)
Copy a Buffer's string.
Definition buffer.c:577
static const char * buf_string(const struct Buffer *buf)
Convert a buffer to a const char * "string".
Definition buffer.h:96
bool mutt_is_message_type(int type, const char *subtype)
Determine if a mime type matches a message or not.
Definition parse.c:1620
#define mutt_perror(...)
Definition logging2.h:95
void mutt_decode_attachment(const struct Body *b, struct State *state)
Decode an email's attachment.
Definition handler.c:1943
#define FREE(x)
Free memory and set the pointer to NULL.
Definition memory.h:68
@ ENC_7BIT
7-bit text
Definition mime.h:49
@ ENC_BINARY
Binary.
Definition mime.h:53
@ ENC_BASE64
Base-64 encoded text.
Definition mime.h:52
@ ENC_8BIT
8-bit text
Definition mime.h:50
@ ENC_QUOTED_PRINTABLE
Quoted-printable text.
Definition mime.h:51
@ TYPE_MULTIPART
Type: 'multipart/*'.
Definition mime.h:37
struct Buffer * buf_pool_get(void)
Get a Buffer from the pool.
Definition pool.c:91
void buf_pool_release(struct Buffer **ptr)
Return a Buffer to the pool.
Definition pool.c:111
void mutt_update_encoding(struct Body *b, struct ConfigSubset *sub)
Update the encoding type.
Definition sendlib.c:424
static void transform_to_7bit(struct Body *b, FILE *fp_in, struct ConfigSubset *sub)
Convert MIME parts to 7-bit.
Definition sendlib.c:198
void mutt_message_to_7bit(struct Body *b, FILE *fp, struct ConfigSubset *sub)
Convert an email's MIME parts to 7-bit.
Definition sendlib.c:261
char * d_filename
filename to be used for the content-disposition header If NULL, filename is used instead.
Definition body.h:56
struct Body * parts
parts of a multipart or message/rfc822
Definition body.h:73
bool noconv
Don't do character set conversion.
Definition body.h:46
bool unlink
If true, filename should be unlink()ed before free()ing this structure.
Definition body.h:68
LOFF_T length
length (in bytes) of attachment
Definition body.h:53
struct Body * next
next attachment in the list
Definition body.h:72
bool force_charset
Send mode: don't adjust the character set when in send-mode.
Definition body.h:44
unsigned int encoding
content-transfer-encoding, ContentEncoding
Definition body.h:41
char * filename
When sending a message, this is the file to which this structure refers.
Definition body.h:59
String manipulation buffer.
Definition buffer.h:36
Keep track when processing files.
Definition state.h:54
FILE * fp_out
File to write to.
Definition state.h:56
FILE * fp_in
File to read from.
Definition state.h:55
#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_message_to_7bit()

void mutt_message_to_7bit ( struct Body * b,
FILE * fp,
struct ConfigSubset * sub )

Convert an email's MIME parts to 7-bit.

Parameters
bBody of the email
fpFile to read (OPTIONAL)
subConfig Subset

Definition at line 261 of file sendlib.c.

262{
263 struct Buffer *tempfile = buf_pool_get();
264 FILE *fp_in = NULL;
265 FILE *fp_out = NULL;
266 struct stat st = { 0 };
267
268 if (!b->filename && fp)
269 {
270 fp_in = fp;
271 }
272 else if (!b->filename || !(fp_in = mutt_file_fopen(b->filename, "r")))
273 {
274 mutt_error(_("Could not open %s"), b->filename ? b->filename : "(null)");
275 return;
276 }
277 else
278 {
279 b->offset = 0;
280 if (stat(b->filename, &st) == -1)
281 {
282 mutt_perror("stat");
283 mutt_file_fclose(&fp_in);
284 goto cleanup;
285 }
286 b->length = st.st_size;
287 }
288
289 /* Avoid buffer pool due to recursion */
290 buf_mktemp(tempfile);
291 fp_out = mutt_file_fopen(buf_string(tempfile), "w+");
292 if (!fp_out)
293 {
294 mutt_perror("fopen");
295 goto cleanup;
296 }
297
298 if (!mutt_file_seek(fp_in, b->offset, SEEK_SET))
299 {
300 goto cleanup;
301 }
302 b->parts = mutt_rfc822_parse_message(fp_in, b);
303
304 transform_to_7bit(b->parts, fp_in, sub);
305
306 mutt_copy_hdr(fp_in, fp_out, b->offset, b->offset + b->length,
307 CH_MIME | CH_NONEWLINE | CH_XMIT, NULL, 0);
308
309 fputs("MIME-Version: 1.0\n", fp_out);
310 mutt_write_mime_header(b->parts, fp_out, sub);
311 fputc('\n', fp_out);
312 mutt_write_mime_body(b->parts, fp_out, sub);
313
314 if (fp_in != fp)
315 mutt_file_fclose(&fp_in);
316 mutt_file_fclose(&fp_out);
317
318 b->encoding = ENC_7BIT;
319 FREE(&b->d_filename);
320 b->d_filename = b->filename;
321 if (b->filename && b->unlink)
322 unlink(b->filename);
323 b->filename = buf_strdup(tempfile);
324 b->unlink = true;
325 if (stat(b->filename, &st) == -1)
326 {
327 mutt_perror("stat");
328 goto cleanup;
329 }
330 b->length = st.st_size;
332 b->email->body = NULL;
333
334cleanup:
335 if (fp_in && (fp_in != fp))
336 mutt_file_fclose(&fp_in);
337
338 if (fp_out)
339 {
340 mutt_file_fclose(&fp_out);
341 mutt_file_unlink(buf_string(tempfile));
342 }
343
344 buf_pool_release(&tempfile);
345}
int mutt_copy_hdr(FILE *fp_in, FILE *fp_out, LOFF_T off_start, LOFF_T off_end, CopyHeaderFlags chflags, const char *prefix, int wraplen)
Copy header from one file to another.
Definition copy_email.c:112
@ CH_XMIT
Transmitting this message? (Ignore Lines: and Content-Length:)
Definition copy_email.h:69
@ CH_MIME
Ignore MIME fields.
Definition copy_email.h:75
@ CH_NONEWLINE
Don't output terminating newline after the header.
Definition copy_email.h:74
void mutt_body_free(struct Body **ptr)
Free a Body.
Definition body.c:58
struct Body * mutt_rfc822_parse_message(FILE *fp, struct Body *b)
Parse a Message/RFC822 body.
Definition parse.c:1964
bool mutt_file_seek(FILE *fp, LOFF_T offset, int whence)
Wrapper for fseeko with error handling.
Definition file.c:648
void mutt_file_unlink(const char *s)
Delete a file, carefully.
Definition file.c:156
int mutt_write_mime_body(struct Body *b, FILE *fp, struct ConfigSubset *sub)
Write a MIME part.
Definition body.c:304
int mutt_write_mime_header(struct Body *b, FILE *fp, struct ConfigSubset *sub)
Create a MIME header.
Definition header.c:763
LOFF_T offset
offset where the actual data begins
Definition body.h:52
struct Email * email
header information for message/rfc822
Definition body.h:74
struct Body * body
List of MIME parts.
Definition email.h:69
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ set_encoding()

static void set_encoding ( struct Body * b,
struct Content * info,
struct ConfigSubset * sub )
static

Determine which Content-Transfer-Encoding to use.

Parameters
[in]bBody of email
[out]infoInfo about the email
[in]subConfig Subset

Definition at line 353 of file sendlib.c.

354{
355 const bool c_allow_8bit = cs_subset_bool(sub, "allow_8bit");
356 if (b->type == TYPE_TEXT)
357 {
358 const bool c_encode_from = cs_subset_bool(sub, "encode_from");
359 char send_charset[128] = { 0 };
360 char *chsname = mutt_body_get_charset(b, send_charset, sizeof(send_charset));
361 if ((info->lobin && !mutt_istr_startswith(chsname, "iso-2022")) ||
362 (info->linemax > 990) || (info->from && c_encode_from))
363 {
365 }
366 else if (info->hibin)
367 {
368 b->encoding = c_allow_8bit ? ENC_8BIT : ENC_QUOTED_PRINTABLE;
369 }
370 else
371 {
372 b->encoding = ENC_7BIT;
373 }
374 }
375 else if ((b->type == TYPE_MESSAGE) || (b->type == TYPE_MULTIPART))
376 {
377 if (info->lobin || info->hibin)
378 {
379 if (c_allow_8bit && !info->lobin)
380 b->encoding = ENC_8BIT;
381 else
382 mutt_message_to_7bit(b, NULL, sub);
383 }
384 else
385 {
386 b->encoding = ENC_7BIT;
387 }
388 }
389 else if ((b->type == TYPE_APPLICATION) && mutt_istr_equal(b->subtype, "pgp-keys"))
390 {
391 b->encoding = ENC_7BIT;
392 }
393 else
394 {
395 /* Determine which encoding is smaller */
396 if (1.33f * (float) (info->lobin + info->hibin + info->ascii) <
397 3.0f * (float) (info->lobin + info->hibin) + (float) info->ascii)
398 {
399 b->encoding = ENC_BASE64;
400 }
401 else
402 {
404 }
405 }
406}
bool cs_subset_bool(const struct ConfigSubset *sub, const char *name)
Get a boolean config item by name.
Definition helpers.c:47
char * mutt_body_get_charset(struct Body *b, char *buf, size_t buflen)
Get a body's character set.
Definition body.c:134
@ TYPE_MESSAGE
Type: 'message/*'.
Definition mime.h:35
@ TYPE_APPLICATION
Type: 'application/*'.
Definition mime.h:33
@ TYPE_TEXT
Type: 'text/*'.
Definition mime.h:38
size_t mutt_istr_startswith(const char *str, const char *prefix)
Check whether a string starts with a prefix, ignoring case.
Definition string.c:246
long hibin
8-bit characters
Definition content.h:36
long ascii
Number of ascii chars.
Definition content.h:40
bool from
Has a line beginning with "From "?
Definition content.h:44
long linemax
Length of the longest line in the file.
Definition content.h:41
long lobin
Unprintable 7-bit chars (eg., control chars)
Definition content.h:37
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_stamp_attachment()

void mutt_stamp_attachment ( struct Body * b)

Timestamp an Attachment.

Parameters
bAttachment

Definition at line 412 of file sendlib.c.

413{
414 b->stamp = mutt_date_now();
415}
time_t mutt_date_now(void)
Return the number of seconds since the Unix epoch.
Definition date.c:459
time_t stamp
Time stamp of last encoding update.
Definition body.h:77
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_update_encoding()

void mutt_update_encoding ( struct Body * b,
struct ConfigSubset * sub )

Update the encoding type.

Parameters
bBody to update
subConfig Subset

Assumes called from send mode where Body->filename points to actual file

Definition at line 424 of file sendlib.c.

425{
426 struct Content *info = NULL;
427 char chsbuf[256] = { 0 };
428
429 /* override noconv when it's us-ascii */
430 if (mutt_ch_is_us_ascii(mutt_body_get_charset(b, chsbuf, sizeof(chsbuf))))
431 b->noconv = false;
432
433 if (!b->force_charset && !b->noconv)
434 mutt_param_delete(&b->parameter, "charset");
435
436 info = mutt_get_content_info(b->filename, b, sub);
437 if (!info)
438 return;
439
440 set_encoding(b, info, sub);
442
443 FREE(&b->content);
444 b->content = info;
445}
struct Content * mutt_get_content_info(const char *fname, struct Body *b, struct ConfigSubset *sub)
Analyze file to determine MIME encoding to use.
#define mutt_ch_is_us_ascii(str)
Definition charset.h:108
void mutt_param_delete(struct ParameterList *pl, const char *attribute)
Delete a matching Parameter.
Definition parameter.c:143
static void set_encoding(struct Body *b, struct Content *info, struct ConfigSubset *sub)
Determine which Content-Transfer-Encoding to use.
Definition sendlib.c:353
void mutt_stamp_attachment(struct Body *b)
Timestamp an Attachment.
Definition sendlib.c:412
struct ParameterList parameter
Parameters of the content-type.
Definition body.h:63
struct Content * content
Detailed info about the content of the attachment.
Definition body.h:70
Info about an attachment.
Definition content.h:35
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_make_message_attach()

struct Body * mutt_make_message_attach ( struct Mailbox * m,
struct Email * e,
bool attach_msg,
struct ConfigSubset * sub )

Create a message attachment.

Parameters
mMailbox
eEmail
attach_msgtrue if attaching a message
subConfig Subset
Return values
ptrNewly allocated Body
NULLError

Definition at line 456 of file sendlib.c.

458{
459 struct Body *body = NULL;
460 FILE *fp = NULL;
461 CopyMessageFlags cmflags;
463
464 /* Ensure we have a valid passphrase before decrypting encrypted messages */
465 const bool c_mime_forward_decode = cs_subset_bool(sub, "mime_forward_decode");
466 const bool c_forward_decrypt = cs_subset_bool(sub, "forward_decrypt");
467 if (WithCrypto)
468 {
469 if ((c_mime_forward_decode || c_forward_decrypt) && (e->security & SEC_ENCRYPT))
470 {
472 return NULL;
473 }
474 }
475
476 /* Create a temporary file to hold the serialised message/rfc822 body */
477 struct Buffer *tempfile = buf_pool_get();
478 buf_mktemp(tempfile);
479 fp = mutt_file_fopen_masked(buf_string(tempfile), "w+");
480 if (!fp)
481 {
482 buf_pool_release(&tempfile);
483 return NULL;
484 }
485
486 /* Build a new Body representing the message/rfc822 attachment */
487 body = mutt_body_new();
488 body->type = TYPE_MESSAGE;
489 body->subtype = mutt_str_dup("rfc822");
490 body->filename = mutt_str_dup(buf_string(tempfile));
491 body->unlink = true;
492 body->use_disp = false;
493 body->disposition = DISP_INLINE;
494 body->noconv = true;
495
496 buf_pool_release(&tempfile);
497
498 struct Message *msg = mx_msg_open(m, e);
499 if (!msg)
500 {
501 mutt_body_free(&body);
503 return NULL;
504 }
506
507 /* Determine copy flags based on decode/decrypt config options.
508 * When MIME-forwarding with decode, strip MIME headers and convert charset.
509 * When forwarding encrypted content with decrypt, handle PGP/SMIME separately. */
510 CopyHeaderFlags chflags = CH_XMIT;
511 cmflags = MUTT_CM_NONE;
512
513 /* If we are attaching a message, ignore `$mime_forward_decode` */
514 if (!attach_msg && c_mime_forward_decode)
515 {
516 chflags |= CH_MIME | CH_TXTPLAIN;
519 pgp &= ~PGP_ENCRYPT;
521 pgp &= ~SMIME_ENCRYPT;
522 }
523 else if ((WithCrypto != 0) && c_forward_decrypt && (e->security & SEC_ENCRYPT))
524 {
526 {
527 chflags |= CH_MIME | CH_NONEWLINE;
528 cmflags = MUTT_CM_DECODE_PGP;
529 pgp &= ~PGP_ENCRYPT;
530 }
531 else if (((WithCrypto & APPLICATION_PGP) != 0) &&
533 {
534 chflags |= CH_MIME | CH_TXTPLAIN;
536 pgp &= ~PGP_ENCRYPT;
537 }
538 else if (((WithCrypto & APPLICATION_SMIME) != 0) &&
540 {
541 chflags |= CH_MIME | CH_NONEWLINE;
542 cmflags = MUTT_CM_DECODE_SMIME;
543 pgp &= ~SMIME_ENCRYPT;
544 }
545 }
546
547 /* Copy the message content into the temp file, then reparse the headers */
548 mutt_copy_message(fp, e, msg, cmflags, chflags, 0);
549 mx_msg_close(m, &msg);
550
551 fflush(fp);
552 rewind(fp);
553
554 body->email = email_new();
555 body->email->offset = 0;
556 /* we don't need the user headers here */
557 body->email->env = mutt_rfc822_read_header(fp, body->email, false, false);
558 if (WithCrypto)
559 body->email->security = pgp;
560 mutt_update_encoding(body, sub);
561 body->parts = body->email->body;
562
564
565 return body;
566}
void mutt_parse_mime_message(struct Email *e, FILE *fp)
Parse a MIME email.
Definition commands.c:628
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_email.c:920
@ MUTT_CM_DECODE_SMIME
Used for decoding S/MIME messages.
Definition copy_email.h:52
@ MUTT_CM_DECODE_PGP
Used for decoding PGP messages.
Definition copy_email.h:51
@ MUTT_CM_DECODE
Decode the message body into text/plain.
Definition copy_email.h:44
@ MUTT_CM_CHARCONV
Perform character set conversions.
Definition copy_email.h:48
@ MUTT_CM_NONE
No flags are set.
Definition copy_email.h:41
uint32_t CopyHeaderFlags
Definition copy_email.h:89
@ CH_TXTPLAIN
Generate text/plain MIME headers.
Definition copy_email.h:77
uint16_t CopyMessageFlags
Definition copy_email.h:55
SecurityFlags mutt_is_application_smime(struct Body *b)
Does the message use S/MIME?
Definition crypt.c:610
bool crypt_valid_passphrase(SecurityFlags flags)
Check that we have a usable passphrase, ask if not.
Definition crypt.c:131
SecurityFlags mutt_is_multipart_encrypted(struct Body *b)
Does the message have encrypted parts?
Definition crypt.c:444
SecurityFlags mutt_is_application_pgp(const struct Body *b)
Does the message use PGP?
Definition crypt.c:549
struct Body * mutt_body_new(void)
Create a new Body.
Definition body.c:44
struct Email * email_new(void)
Create a new Email.
Definition email.c:77
struct Envelope * mutt_rfc822_read_header(FILE *fp, struct Email *e, bool user_hdrs, bool weed)
Parses an RFC822 header.
Definition parse.c:1325
@ DISP_INLINE
Content is inline.
Definition mime.h:62
char * mutt_str_dup(const char *str)
Copy a string, safely.
Definition string.c:257
int mx_msg_close(struct Mailbox *m, struct Message **ptr)
Close a message.
Definition mx.c:1185
struct Message * mx_msg_open(struct Mailbox *m, struct Email *e)
Return a stream pointer for a message.
Definition mx.c:1139
uint16_t SecurityFlags
Definition lib.h:104
@ SEC_NONE
No flags are set.
Definition lib.h:91
@ SEC_ENCRYPT
Email is encrypted.
Definition lib.h:92
#define APPLICATION_PGP
Use PGP to encrypt/sign.
Definition lib.h:106
#define PGP_ENCRYPT
Email is PGP encrypted.
Definition lib.h:112
#define APPLICATION_SMIME
Use SMIME to encrypt/sign.
Definition lib.h:107
#define SMIME_ENCRYPT
Email is S/MIME encrypted.
Definition lib.h:118
#define WithCrypto
Definition lib.h:132
#define mutt_file_fopen_masked(PATH, MODE)
Open a file with proper permissions, tracked for debugging.
Definition neomutt.h:92
The body of an email.
Definition body.h:36
bool use_disp
Content-Disposition uses filename= ?
Definition body.h:47
unsigned int disposition
content-disposition, ContentDisposition
Definition body.h:42
struct Envelope * env
Envelope information.
Definition email.h:68
SecurityFlags security
bit 0-10: flags, bit 11,12: application, bit 13: traditional pgp See: ncrypt/lib.h pgplib....
Definition email.h:43
LOFF_T offset
Where in the stream does this message begin?
Definition email.h:71
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:

◆ run_mime_type_query()

static void run_mime_type_query ( struct Body * b,
struct ConfigSubset * sub )
static

Run an external command to determine the MIME type.

Parameters
bAttachment
subConfig Subset

The command in $mime_type_query_command is run.

Definition at line 575 of file sendlib.c.

576{
577 FILE *fp = NULL;
578 FILE *fp_err = NULL;
579 char *buf = NULL;
580 size_t buflen = 0;
581 pid_t pid;
582 struct Buffer *cmd = buf_pool_get();
583
584 const char *const c_mime_type_query_command = cs_subset_string(sub, "mime_type_query_command");
585
586 buf_file_expand_fmt_quote(cmd, c_mime_type_query_command, b->filename);
587
588 pid = filter_create(buf_string(cmd), NULL, &fp, &fp_err, NeoMutt->env);
589 if (pid < 0)
590 {
591 mutt_error(_("Error running \"%s\""), buf_string(cmd));
592 buf_pool_release(&cmd);
593 return;
594 }
595 buf_pool_release(&cmd);
596
597 buf = mutt_file_read_line(buf, &buflen, fp, NULL, MUTT_RL_NONE);
598 if (buf)
599 {
600 if (strchr(buf, '/'))
602 FREE(&buf);
603 }
604
605 mutt_file_fclose(&fp);
606 mutt_file_fclose(&fp_err);
607 filter_wait(pid);
608}
const char * cs_subset_string(const struct ConfigSubset *sub, const char *name)
Get a string config item by name.
Definition helpers.c:291
void mutt_parse_content_type(const char *s, struct Body *b)
Parse a content type.
Definition parse.c:433
char * mutt_file_read_line(char *line, size_t *size, FILE *fp, int *line_num, ReadLineFlags flags)
Read a line from a file.
Definition file.c:678
void buf_file_expand_fmt_quote(struct Buffer *dest, const char *fmt, const char *src)
Replace s in a string with a filename.
Definition file.c:1352
@ MUTT_RL_NONE
No flags are set.
Definition file.h:43
int filter_wait(pid_t pid)
Wait for the exit of a process and return its status.
Definition filter.c:231
pid_t filter_create(const char *cmd, FILE **fp_in, FILE **fp_out, FILE **fp_err, char **envlist)
Set up filter program.
Definition filter.c:220
char ** env
Private copy of the environment variables.
Definition neomutt.h:57
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_make_file_attach()

struct Body * mutt_make_file_attach ( const char * path,
struct ConfigSubset * sub )

Create a file attachment.

Parameters
pathFile to attach
subConfig Subset
Return values
ptrNewly allocated Body
NULLError

Definition at line 617 of file sendlib.c.

618{
619 if (!path || (path[0] == '\0'))
620 return NULL;
621
622 struct Body *b = mutt_body_new();
623 b->filename = mutt_str_dup(path);
624
625 const char *const c_mime_type_query_command = cs_subset_string(sub, "mime_type_query_command");
626 const bool c_mime_type_query_first = cs_subset_bool(sub, "mime_type_query_first");
627
628 if (c_mime_type_query_command && c_mime_type_query_first)
629 run_mime_type_query(b, sub);
630
631 /* Attempt to determine the appropriate content-type based on the filename
632 * suffix. */
633 if (!b->subtype)
634 mutt_lookup_mime_type(b, path);
635
636 if (!b->subtype && c_mime_type_query_command && !c_mime_type_query_first)
637 {
638 run_mime_type_query(b, sub);
639 }
640
641 struct Content *info = mutt_get_content_info(path, b, sub);
642 if (!info)
643 {
644 mutt_body_free(&b);
645 return NULL;
646 }
647
648 if (!b->subtype)
649 {
650 if ((info->nulbin == 0) &&
651 ((info->lobin == 0) || ((info->lobin + info->hibin + info->ascii) / info->lobin >= 10)))
652 {
653 /* Statistically speaking, there should be more than 10% "lobin"
654 * chars if this is really a binary file... */
655 b->type = TYPE_TEXT;
656 b->subtype = mutt_str_dup("plain");
657 }
658 else
659 {
661 b->subtype = mutt_str_dup("octet-stream");
662 }
663 }
664
665 FREE(&info);
666 mutt_update_encoding(b, sub);
667 return b;
668}
enum ContentType mutt_lookup_mime_type(struct Body *b, const char *path)
Find the MIME type for an attachment.
Definition sendlib.c:75
static void run_mime_type_query(struct Body *b, struct ConfigSubset *sub)
Run an external command to determine the MIME type.
Definition sendlib.c:575
long nulbin
Null characters (0x0)
Definition content.h:38
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ encode_headers()

static void encode_headers ( struct ListHead * h,
struct ConfigSubset * sub )
static

RFC2047-encode a list of headers.

Parameters
hString List of headers
subConfig Subset

The strings are encoded in-place.

Definition at line 677 of file sendlib.c.

678{
679 char *tmp = NULL;
680 char *p = NULL;
681 int i;
682
683 const struct Slist *const c_send_charset = cs_subset_slist(sub, "send_charset");
684
685 struct ListNode *np = NULL;
686 STAILQ_FOREACH(np, h, entries)
687 {
688 p = strchr(NONULL(np->data), ':');
689 if (!p)
690 continue;
691
692 i = p - np->data;
693 p = mutt_str_skip_email_wsp(p + 1);
694 tmp = mutt_str_dup(p);
695
696 if (!tmp)
697 continue;
698
699 rfc2047_encode(&tmp, NULL, i + 2, c_send_charset);
700 MUTT_MEM_REALLOC(&np->data, i + 2 + mutt_str_len(tmp) + 1, char);
701
702 sprintf(np->data + i + 2, "%s", tmp);
703
704 FREE(&tmp);
705 }
706}
const struct Slist * cs_subset_slist(const struct ConfigSubset *sub, const char *name)
Get a string-list config item by name.
Definition helpers.c:242
#define MUTT_MEM_REALLOC(pptr, n, type)
Definition memory.h:55
char * mutt_str_skip_email_wsp(const char *s)
Skip over whitespace as defined by RFC5322.
Definition string.c:614
#define STAILQ_FOREACH(var, head, field)
Definition queue.h:390
void rfc2047_encode(char **pd, const char *specials, int col, const struct Slist *charsets)
RFC-2047-encode a string.
Definition rfc2047.c:646
A List node for strings.
Definition list.h:37
char * data
String.
Definition list.h:38
String list.
Definition slist.h:37
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_fqdn()

const char * mutt_fqdn ( bool may_hide_host,
const struct ConfigSubset * sub )

Get the Fully-Qualified Domain Name.

Parameters
may_hide_hostIf true, hide the hostname (leaving just the domain)
subConfig Subset
Return values
ptrstring pointer into Hostname
NULLError, e.g no Hostname
Warning
Do not free the returned pointer

Definition at line 717 of file sendlib.c.

718{
719 const char *const c_hostname = cs_subset_string(sub, "hostname");
720 if (!c_hostname || (c_hostname[0] == '@'))
721 return NULL;
722
723 const char *p = c_hostname;
724
725 const bool c_hidden_host = cs_subset_bool(sub, "hidden_host");
726 if (may_hide_host && c_hidden_host)
727 {
728 p = strchr(c_hostname, '.');
729 if (p)
730 p++;
731
732 // sanity check: don't hide the host if the fqdn is something like example.com
733 if (!p || !strchr(p, '.'))
734 p = c_hostname;
735 }
736
737 return p;
738}
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_prepare_envelope()

void mutt_prepare_envelope ( struct Envelope * env,
bool final,
struct ConfigSubset * sub )

Prepare an email header.

Parameters
envEnvelope to prepare
finaltrue if this email is going to be sent (not postponed)
subConfig Subset

Encode all the headers prior to sending the email.

For postponing (!final) do the necessary encodings only

Definition at line 750 of file sendlib.c.

751{
752 if (final)
753 {
754 if (!TAILQ_EMPTY(&env->bcc) && TAILQ_EMPTY(&env->to) && TAILQ_EMPTY(&env->cc))
755 {
756 /* some MTA's will put an Apparently-To: header field showing the Bcc:
757 * recipients if there is no To: or Cc: field, so attempt to suppress
758 * it by using an empty To: field. */
759 struct Address *to = mutt_addr_new();
760 to->group = true;
761 mutt_addrlist_append(&env->to, to);
763
764 char buf[1024] = { 0 };
765 buf[0] = '\0';
766 mutt_addr_cat(buf, sizeof(buf), "undisclosed-recipients", AddressSpecials);
767
768 buf_strcpy(to->mailbox, buf);
769 }
770
771 mutt_set_followup_to(env, sub);
772
773 if (!env->message_id)
774 env->message_id = msgid_generate();
775 }
776
777 /* Take care of 8-bit => 7-bit conversion. */
779 encode_headers(&env->userhdrs, sub);
780}
void mutt_addr_cat(char *buf, size_t buflen, const char *value, const char *specials)
Copy a string and wrap it in quotes if it contains special characters.
Definition address.c:715
void mutt_addrlist_append(struct AddressList *al, struct Address *a)
Append an Address to an AddressList.
Definition address.c:1496
struct Address * mutt_addr_new(void)
Create a new Address.
Definition address.c:401
const char AddressSpecials[]
Characters with special meaning for email addresses.
Definition address.c:45
size_t buf_strcpy(struct Buffer *buf, const char *s)
Copy a string into a Buffer.
Definition buffer.c:401
char * msgid_generate(void)
Generate a Message-ID.
#define TAILQ_EMPTY(head)
Definition queue.h:778
void rfc2047_encode_envelope(struct Envelope *env)
Encode the fields of an Envelope.
Definition rfc2047.c:875
void mutt_set_followup_to(struct Envelope *env, struct ConfigSubset *sub)
Set followup-to field.
Definition send.c:1281
static void encode_headers(struct ListHead *h, struct ConfigSubset *sub)
RFC2047-encode a list of headers.
Definition sendlib.c:677
An email address.
Definition address.h:35
bool group
Group mailbox?
Definition address.h:38
struct Buffer * mailbox
Mailbox and host address.
Definition address.h:37
struct ListHead userhdrs
user defined headers
Definition envelope.h:85
struct AddressList to
Email's 'To' list.
Definition envelope.h:60
char * message_id
Message ID.
Definition envelope.h:73
struct AddressList cc
Email's 'Cc' list.
Definition envelope.h:61
struct AddressList bcc
Email's 'Bcc' list.
Definition envelope.h:62
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_unprepare_envelope()

void mutt_unprepare_envelope ( struct Envelope * env)

Undo the encodings of mutt_prepare_envelope()

Parameters
envEnvelope to unprepare

Decode all the headers of an email, e.g. when the sending failed or was aborted.

Definition at line 789 of file sendlib.c.

790{
791 struct ListNode *item = NULL;
792 STAILQ_FOREACH(item, &env->userhdrs, entries)
793 {
794 rfc2047_decode(&item->data);
795 }
796
798
799 /* back conversions */
801}
void mutt_addrlist_clear(struct AddressList *al)
Unlink and free all Address in an AddressList.
Definition address.c:1475
void rfc2047_decode_envelope(struct Envelope *env)
Decode the fields of an Envelope.
Definition rfc2047.c:850
void rfc2047_decode(char **pd)
Decode any RFC2047-encoded header fields.
Definition rfc2047.c:679
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:

◆ bounce_message()

static int bounce_message ( FILE * fp,
struct Mailbox * m,
struct Email * e,
struct AddressList * to,
const char * resent_from,
struct AddressList * env_from,
struct ConfigSubset * sub )
static

Bounce an email message.

Parameters
fpHandle of message
mMailbox
eEmail
toAddress to bounce to
resent_fromAddress of new sender
env_fromEnvelope of original sender
subConfig Subset
Return values
0Success
-1Failure

Definition at line 815 of file sendlib.c.

818{
819 if (!e)
820 return -1;
821
822 int rc = 0;
823
824 struct Buffer *tempfile = buf_pool_get();
825 buf_mktemp(tempfile);
826 FILE *fp_tmp = mutt_file_fopen(buf_string(tempfile), "w");
827 if (fp_tmp)
828 {
830
831 const bool c_bounce_delivered = cs_subset_bool(sub, "bounce_delivered");
832 if (!c_bounce_delivered)
833 chflags |= CH_WEED_DELIVERED;
834
835 if (!mutt_file_seek(fp, e->offset, SEEK_SET))
836 {
837 (void) mutt_file_fclose(&fp_tmp);
838 return -1;
839 }
840 fprintf(fp_tmp, "Resent-From: %s\n", resent_from);
841
842 struct Buffer *date = buf_pool_get();
843 mutt_date_make_date(date, cs_subset_bool(sub, "local_date_header"));
844 fprintf(fp_tmp, "Resent-Date: %s\n", buf_string(date));
845 buf_pool_release(&date);
846
847 char *msgid_str = msgid_generate();
848 fprintf(fp_tmp, "Resent-Message-ID: %s\n", msgid_str);
849 FREE(&msgid_str);
850 mutt_addrlist_write_file(to, fp_tmp, "Resent-To");
851 mutt_copy_header(fp, e, fp_tmp, chflags, NULL, 0);
852 fputc('\n', fp_tmp);
853 mutt_file_copy_bytes(fp, fp_tmp, e->body->length);
854 if (mutt_file_fclose(&fp_tmp) != 0)
855 {
856 mutt_perror("%s", buf_string(tempfile));
857 unlink(buf_string(tempfile));
858 return -1;
859 }
860 const char *const c_smtp_url = cs_subset_string(sub, "smtp_url");
861 if (c_smtp_url)
862 {
863 rc = mutt_smtp_send(env_from, to, NULL, NULL, buf_string(tempfile),
864 (e->body->encoding == ENC_8BIT), sub);
865 }
866 else
867 {
868 rc = mutt_invoke_sendmail(m, env_from, to, NULL, NULL, buf_string(tempfile),
869 (e->body->encoding == ENC_8BIT), sub);
870 }
871 }
872
873 buf_pool_release(&tempfile);
874 return rc;
875}
void mutt_addrlist_write_file(const struct AddressList *al, FILE *fp, const char *header)
Wrapper for mutt_write_address()
Definition address.c:1261
int mutt_copy_header(FILE *fp_in, struct Email *e, FILE *fp_out, CopyHeaderFlags chflags, const char *prefix, int wraplen)
Copy Email header.
Definition copy_email.c:432
@ CH_WEED_DELIVERED
Weed eventual Delivered-To headers.
Definition copy_email.h:79
@ CH_NOQFROM
Ignore ">From " line.
Definition copy_email.h:81
int mutt_file_copy_bytes(FILE *fp_in, FILE *fp_out, size_t size)
Copy some content from one file to another.
Definition file.c:192
void mutt_date_make_date(struct Buffer *buf, bool local)
Write a date in RFC822 format to a buffer.
Definition date.c:400
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:299
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:1136
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_bounce_message()

int mutt_bounce_message ( FILE * fp,
struct Mailbox * m,
struct Email * e,
struct AddressList * to,
struct ConfigSubset * sub )

Bounce an email message.

Parameters
fpHandle of message
mMailbox
eEmail
toAddressList to bounce to
subConfig Subset
Return values
0Success
-1Failure

Definition at line 887 of file sendlib.c.

889{
890 if (!fp || !e || !to || TAILQ_EMPTY(to))
891 return -1;
892
893 const char *fqdn = mutt_fqdn(true, sub);
894 char *err = NULL;
895
896 struct Address *from = mutt_default_from(sub);
897 struct AddressList from_list = TAILQ_HEAD_INITIALIZER(from_list);
898 mutt_addrlist_append(&from_list, from);
899
900 /* mutt_default_from() does not use $real_name if the real name is not set
901 * in $from, so we add it here. The reason it is not added in
902 * mutt_default_from() is that during normal sending, we execute
903 * send-hooks and set the real_name last so that it can be changed based
904 * upon message criteria. */
905 if (!from->personal)
906 {
907 const char *const c_real_name = cs_subset_string(sub, "real_name");
908 if (c_real_name)
909 from->personal = buf_new(c_real_name);
910 }
911
912 mutt_addrlist_qualify(&from_list, fqdn);
913
914 rfc2047_encode_addrlist(&from_list, "Resent-From");
915 if (mutt_addrlist_to_intl(&from_list, &err))
916 {
917 mutt_error(_("Bad IDN %s while preparing resent-from"), err);
918 FREE(&err);
919 mutt_addrlist_clear(&from_list);
920 return -1;
921 }
922 struct Buffer *resent_from = buf_pool_get();
923 mutt_addrlist_write(&from_list, resent_from, false);
924
925 OptNewsSend = false;
926
927 /* prepare recipient list. idna conversion appears to happen before this
928 * function is called, since the user receives confirmation of the address
929 * list being bounced to. */
930 struct AddressList resent_to = TAILQ_HEAD_INITIALIZER(resent_to);
931 mutt_addrlist_copy(&resent_to, to, false);
932 rfc2047_encode_addrlist(&resent_to, "Resent-To");
933 int rc = bounce_message(fp, m, e, &resent_to, buf_string(resent_from), &from_list, sub);
934 mutt_addrlist_clear(&resent_to);
935 mutt_addrlist_clear(&from_list);
936 buf_pool_release(&resent_from);
937 return rc;
938}
void mutt_addrlist_copy(struct AddressList *dst, const struct AddressList *src, bool prune)
Copy a list of addresses into another list.
Definition address.c:776
void mutt_addrlist_qualify(struct AddressList *al, const char *host)
Expand local names in an Address list using a hostname.
Definition address.c:687
size_t mutt_addrlist_write(const struct AddressList *al, struct Buffer *buf, bool display)
Write an Address to a buffer.
Definition address.c:1219
int mutt_addrlist_to_intl(struct AddressList *al, char **err)
Convert an Address list to Punycode.
Definition address.c:1306
struct Buffer * buf_new(const char *str)
Allocate a new Buffer.
Definition buffer.c:311
bool OptNewsSend
(pseudo) used to change behavior when posting
Definition globals.c:54
#define TAILQ_HEAD_INITIALIZER(head)
Definition queue.h:694
void rfc2047_encode_addrlist(struct AddressList *al, const char *tag)
Encode any RFC2047 headers, where required, in an Address list.
Definition rfc2047.c:784
struct Address * mutt_default_from(struct ConfigSubset *sub)
Get a default 'from' Address.
Definition send.c:1405
const char * mutt_fqdn(bool may_hide_host, const struct ConfigSubset *sub)
Get the Fully-Qualified Domain Name.
Definition sendlib.c:717
static int bounce_message(FILE *fp, struct Mailbox *m, struct Email *e, struct AddressList *to, const char *resent_from, struct AddressList *env_from, struct ConfigSubset *sub)
Bounce an email message.
Definition sendlib.c:815
struct Buffer * personal
Real name of address.
Definition address.h:36
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ set_noconv_flags()

static void set_noconv_flags ( struct Body * b,
bool flag )
static

Set/reset the "x-mutt-noconv" flag.

Parameters
bBody of email
flagIf true, set the flag, otherwise remove it

Definition at line 945 of file sendlib.c.

946{
947 for (; b; b = b->next)
948 {
949 if ((b->type == TYPE_MESSAGE) || (b->type == TYPE_MULTIPART))
950 {
951 set_noconv_flags(b->parts, flag);
952 }
953 else if ((b->type == TYPE_TEXT) && b->noconv)
954 {
955 if (flag)
956 mutt_param_set(&b->parameter, "x-mutt-noconv", "yes");
957 else
958 mutt_param_delete(&b->parameter, "x-mutt-noconv");
959 }
960 }
961}
void mutt_param_set(struct ParameterList *pl, const char *attribute, const char *value)
Set a Parameter.
Definition parameter.c:111
static void set_noconv_flags(struct Body *b, bool flag)
Set/reset the "x-mutt-noconv" flag.
Definition sendlib.c:945
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_write_multiple_fcc()

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.

Parameters
[in]pathPath to mailboxes (comma separated)
[in]eEmail
[in]msgidMessage id
[in]postIf true, postpone message
[in]fccfcc setting to save (postpone only)
[out]finalpathFinal path of email
[in]subConfig Subset
Return values
0Success
-1Failure

Definition at line 975 of file sendlib.c.

977{
978 char fcc_tok[PATH_MAX] = { 0 };
979
980 mutt_str_copy(fcc_tok, path, sizeof(fcc_tok));
981
982 char *tok = strtok(fcc_tok, ",");
983 if (!tok)
984 return -1;
985
986 mutt_debug(LL_DEBUG1, "Fcc: initial mailbox = '%s'\n", tok);
987 /* expand_path already called above for the first token */
988 int status = mutt_write_fcc(tok, e, msgid, post, fcc, finalpath, sub);
989 if (status != 0)
990 return status;
991
992 struct Buffer *fcc_expanded = buf_pool_get();
993 while ((tok = strtok(NULL, ",")))
994 {
995 if (*tok == '\0')
996 continue;
997
998 /* Only call expand_path if tok has some data */
999 mutt_debug(LL_DEBUG1, "Fcc: additional mailbox token = '%s'\n", tok);
1000 buf_strcpy(fcc_expanded, tok);
1001 expand_path(fcc_expanded, false);
1002 mutt_debug(LL_DEBUG1, " Additional mailbox expanded = '%s'\n",
1003 buf_string(fcc_expanded));
1004 status = mutt_write_fcc(buf_string(fcc_expanded), e, msgid, post, fcc, finalpath, sub);
1005 if (status != 0)
1006 {
1007 buf_pool_release(&fcc_expanded);
1008 return status;
1009 }
1010 }
1011
1012 buf_pool_release(&fcc_expanded);
1013 return 0;
1014}
void expand_path(struct Buffer *buf, bool regex)
Create the canonical path.
Definition muttlib.c:122
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:1028
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_write_fcc()

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.

Parameters
[in]pathPath to mailbox
[in]eEmail
[in]msgidMessage id
[in]postIf true, postpone message, else fcc mode
[in]fccfcc setting to save (postpone only)
[out]finalpathFinal path of email
[in]subConfig Subset
Return values
0Success
-1Failure

Definition at line 1028 of file sendlib.c.

1030{
1031 struct Message *msg = NULL;
1032 struct Buffer *tempfile = NULL;
1033 FILE *fp_tmp = NULL;
1034 int rc = -1;
1035 bool need_mailbox_cleanup = false;
1036 struct stat st = { 0 };
1037 MsgOpenFlags onm_flags;
1038
1039 if (post)
1040 set_noconv_flags(e->body, true);
1041
1042#ifdef RECORD_FOLDER_HOOK
1043 exec_folder_hook(path, NULL);
1044#endif
1045 struct Mailbox *m_fcc = mx_path_resolve(path);
1046 bool old_append = m_fcc->append;
1047 if (!mx_mbox_open(m_fcc, MUTT_APPEND | MUTT_QUIET))
1048 {
1049 mutt_debug(LL_DEBUG1, "unable to open mailbox %s in append-mode, aborting\n", path);
1050 goto done;
1051 }
1052
1053 /* We need to add a Content-Length field to avoid problems where a line in
1054 * the message body begins with "From " */
1055 if ((m_fcc->type == MUTT_MMDF) || (m_fcc->type == MUTT_MBOX))
1056 {
1057 tempfile = buf_pool_get();
1058 buf_mktemp(tempfile);
1059 fp_tmp = mutt_file_fopen(buf_string(tempfile), "w+");
1060 if (!fp_tmp)
1061 {
1062 mutt_perror("%s", buf_string(tempfile));
1063 mx_mbox_close(m_fcc);
1064 goto done;
1065 }
1066 /* remember new mail status before appending message */
1067 need_mailbox_cleanup = true;
1068 stat(path, &st);
1069 }
1070
1071 e->read = !post; /* make sure to put it in the 'cur' directory (maildir) */
1072 onm_flags = MUTT_ADD_FROM;
1073 if (post)
1074 onm_flags |= MUTT_SET_DRAFT;
1075 msg = mx_msg_open_new(m_fcc, e, onm_flags);
1076 if (!msg)
1077 {
1078 mutt_file_fclose(&fp_tmp);
1079 mx_mbox_close(m_fcc);
1080 goto done;
1081 }
1082
1083 const bool c_crypt_protected_headers_read = cs_subset_bool(sub, "crypt_protected_headers_read");
1084
1085 /* post == 1 => postpone message.
1086 * post == 0 => Normal mode. */
1087 mutt_rfc822_write_header(msg->fp, e->env, e->body,
1089 c_crypt_protected_headers_read &&
1091 sub);
1092
1093 /* (postponement) if this was a reply of some sort, <msgid> contains the
1094 * Message-ID: of message replied to. Save it using a special X-Mutt-
1095 * header so it can be picked up if the message is recalled at a later
1096 * point in time. This will allow the message to be marked as replied if
1097 * the same mailbox is still open. */
1098 if (post && msgid)
1099 fprintf(msg->fp, "Mutt-References: %s\n", msgid);
1100
1101 /* (postponement) save the Fcc: using a special X-Mutt- header so that
1102 * it can be picked up when the message is recalled */
1103 if (post && fcc)
1104 fprintf(msg->fp, "Mutt-Fcc: %s\n", fcc);
1105
1106 if ((m_fcc->type == MUTT_MMDF) || (m_fcc->type == MUTT_MBOX))
1107 fprintf(msg->fp, "Status: RO\n");
1108
1109 /* (postponement) if the mail is to be signed or encrypted, save this info */
1110 if (((WithCrypto & APPLICATION_PGP) != 0) && post && (e->security & APPLICATION_PGP))
1111 {
1112 fputs("Mutt-PGP: ", msg->fp);
1113 if (e->security & SEC_ENCRYPT)
1114 fputc('E', msg->fp);
1115 if (e->security & SEC_OPPENCRYPT)
1116 fputc('O', msg->fp);
1117 if (e->security & SEC_SIGN)
1118 {
1119 fputc('S', msg->fp);
1120
1121 const char *const c_pgp_sign_as = cs_subset_string(sub, "pgp_sign_as");
1122 if (c_pgp_sign_as)
1123 fprintf(msg->fp, "<%s>", c_pgp_sign_as);
1124 }
1125 if (e->security & SEC_INLINE)
1126 fputc('I', msg->fp);
1127#ifdef USE_AUTOCRYPT
1128 if (e->security & SEC_AUTOCRYPT)
1129 fputc('A', msg->fp);
1131 fputc('Z', msg->fp);
1132#endif
1133 fputc('\n', msg->fp);
1134 }
1135
1136 /* (postponement) if the mail is to be signed or encrypted, save this info */
1137 if (((WithCrypto & APPLICATION_SMIME) != 0) && post && (e->security & APPLICATION_SMIME))
1138 {
1139 fputs("Mutt-SMIME: ", msg->fp);
1140 if (e->security & SEC_ENCRYPT)
1141 {
1142 fputc('E', msg->fp);
1143
1144 const char *const c_smime_encrypt_with = cs_subset_string(sub, "smime_encrypt_with");
1145 if (c_smime_encrypt_with)
1146 fprintf(msg->fp, "C<%s>", c_smime_encrypt_with);
1147 }
1148 if (e->security & SEC_OPPENCRYPT)
1149 fputc('O', msg->fp);
1150 if (e->security & SEC_SIGN)
1151 {
1152 fputc('S', msg->fp);
1153
1154 const char *const c_smime_sign_as = cs_subset_string(sub, "smime_sign_as");
1155 if (c_smime_sign_as)
1156 fprintf(msg->fp, "<%s>", c_smime_sign_as);
1157 }
1158 if (e->security & SEC_INLINE)
1159 fputc('I', msg->fp);
1160 fputc('\n', msg->fp);
1161 }
1162
1163 if (fp_tmp)
1164 {
1165 mutt_write_mime_body(e->body, fp_tmp, sub);
1166
1167 /* make sure the last line ends with a newline. Emacs doesn't ensure this
1168 * will happen, and it can cause problems parsing the mailbox later. */
1169 if (mutt_file_seek(fp_tmp, -1, SEEK_END) && (fgetc(fp_tmp) != '\n') &&
1170 mutt_file_seek(fp_tmp, 0, SEEK_END))
1171 {
1172 fputc('\n', fp_tmp);
1173 }
1174
1175 fflush(fp_tmp);
1176 if (ferror(fp_tmp))
1177 {
1178 mutt_debug(LL_DEBUG1, "%s: write failed\n", buf_string(tempfile));
1179 mutt_file_fclose(&fp_tmp);
1180 unlink(buf_string(tempfile));
1181 mx_msg_commit(m_fcc, msg); /* XXX really? */
1182 mx_msg_close(m_fcc, &msg);
1183 mx_mbox_close(m_fcc);
1184 goto done;
1185 }
1186
1187 /* count the number of lines */
1188 int lines = 0;
1189 char line_buf[1024] = { 0 };
1190 rewind(fp_tmp);
1191 while (fgets(line_buf, sizeof(line_buf), fp_tmp))
1192 lines++;
1193 fprintf(msg->fp, "Content-Length: " OFF_T_FMT "\n", (LOFF_T) ftello(fp_tmp));
1194 fprintf(msg->fp, "Lines: %d\n\n", lines);
1195
1196 /* copy the body and clean up */
1197 rewind(fp_tmp);
1198 rc = mutt_file_copy_stream(fp_tmp, msg->fp);
1199 if (mutt_file_fclose(&fp_tmp) != 0)
1200 rc = -1;
1201 /* if there was an error, leave the temp version */
1202 if (rc >= 0)
1203 {
1204 unlink(buf_string(tempfile));
1205 rc = 0;
1206 }
1207 }
1208 else
1209 {
1210 fputc('\n', msg->fp); /* finish off the header */
1211 rc = mutt_write_mime_body(e->body, msg->fp, sub);
1212 }
1213
1214 if (mx_msg_commit(m_fcc, msg) != 0)
1215 rc = -1;
1216 else if (finalpath)
1217 *finalpath = mutt_str_dup(msg->committed_path);
1218 mx_msg_close(m_fcc, &msg);
1219 mx_mbox_close(m_fcc);
1220
1221 if (!post && need_mailbox_cleanup)
1222 mailbox_restore_timestamp(path, &st);
1223
1224 if (post)
1225 set_noconv_flags(e->body, false);
1226
1227done:
1228 m_fcc->append = old_append;
1229 mailbox_free(&m_fcc);
1230
1231#ifdef RECORD_FOLDER_HOOK
1232 /* We ran a folder hook for the destination mailbox,
1233 * now we run it for the user's current mailbox */
1234 const struct Mailbox *m_cur = get_current_mailbox();
1235 if (m_cur)
1236 exec_folder_hook(m_cur->path, m_cur->desc);
1237#endif
1238
1239 if (fp_tmp)
1240 {
1241 mutt_file_fclose(&fp_tmp);
1242 unlink(buf_string(tempfile));
1243 }
1244 buf_pool_release(&tempfile);
1245
1246 return rc;
1247}
void mailbox_free(struct Mailbox **ptr)
Free a Mailbox.
Definition mailbox.c:90
@ MUTT_MMDF
'mmdf' Mailbox type
Definition mailbox.h:45
@ MUTT_MBOX
'mbox' Mailbox type
Definition mailbox.h:44
bool mutt_should_hide_protected_subject(struct Email *e)
Should NeoMutt hide the protected subject?
Definition crypt.c:1106
int mutt_file_copy_stream(FILE *fp_in, FILE *fp_out)
Copy the contents of one file into another.
Definition file.c:224
void exec_folder_hook(const char *path, const char *desc)
Perform a folder hook.
Definition exec.c:64
struct Mailbox * get_current_mailbox(void)
Get the current Mailbox.
Definition index.c:725
void mailbox_restore_timestamp(const char *path, struct stat *st)
Restore the timestamp of a mailbox.
bool mx_mbox_open(struct Mailbox *m, OpenMailboxFlags flags)
Open a mailbox and parse it.
Definition mx.c:285
struct Message * mx_msg_open_new(struct Mailbox *m, const struct Email *e, MsgOpenFlags flags)
Open a new message.
Definition mx.c:1044
int mx_msg_commit(struct Mailbox *m, struct Message *msg)
Commit a message to a folder - Wrapper for MxOps::msg_commit()
Definition mx.c:1164
struct Mailbox * mx_path_resolve(const char *path)
Get a Mailbox for a path.
Definition mx.c:1650
enum MxStatus mx_mbox_close(struct Mailbox *m)
Save changes and close mailbox.
Definition mx.c:595
uint8_t MsgOpenFlags
Definition mx.h:46
@ MUTT_ADD_FROM
add a From_ line
Definition mx.h:43
@ MUTT_SET_DRAFT
set the message draft flag
Definition mx.h:44
@ MUTT_QUIET
Do not print any messages.
Definition mxapi.h:46
@ MUTT_APPEND
Open mailbox for appending messages.
Definition mxapi.h:44
@ SEC_OPPENCRYPT
Opportunistic encrypt mode.
Definition lib.h:100
@ SEC_SIGN
Email is signed.
Definition lib.h:93
@ SEC_INLINE
Email has an inline signature.
Definition lib.h:99
@ SEC_AUTOCRYPT
(Autocrypt) Message will be, or was Autocrypt encrypt+signed
Definition lib.h:101
@ SEC_AUTOCRYPT_OVERRIDE
(Autocrypt) Indicates manual set/unset of encryption
Definition lib.h:102
int mutt_rfc822_write_header(FILE *fp, struct Envelope *env, struct Body *b, enum MuttWriteHeaderMode mode, bool privacy, bool hide_protected_subject, struct ConfigSubset *sub)
Write out one RFC822 header line.
Definition header.c:584
@ MUTT_WRITE_HEADER_FCC
fcc mode, like normal mode but for Bcc header
Definition header.h:39
@ MUTT_WRITE_HEADER_POSTPONE
A postponed Email, just the envelope info.
Definition header.h:40
bool read
Email is read.
Definition email.h:50
A mailbox.
Definition mailbox.h:81
bool append
Mailbox is opened in append mode.
Definition mailbox.h:111
enum MailboxType type
Mailbox type.
Definition mailbox.h:104
struct ConfigSubset * sub
Inherited config items.
Definition mailbox.h:85
char * committed_path
the final path generated by mx_msg_commit()
Definition message.h:37
+ Here is the call graph for this function:
+ Here is the caller graph for this function: