NeoMutt  2023-03-22-27-g3cb248
Teaching an old dog new tricks
DOXYGEN
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 <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 "lib.h"
#include "attach/lib.h"
#include "convert/lib.h"
#include "ncrypt/lib.h"
#include "copy.h"
#include "globals.h"
#include "handler.h"
#include "mutt_mailbox.h"
#include "muttlib.h"
#include "mx.h"
+ Include dependency graph for sendlib.c:

Go to the source code of this file.

Functions

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

Detailed Description

Miscellaneous functions for sending an email.

Authors
  • Michael R. Elkins
  • Pietro Cerutti
  • R Primus

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 att,
const char *  path 
)

Find the MIME type for an attachment.

Parameters
attEmail with attachment
pathPath to attachment
Return values
numMIME type, 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 69 of file sendlib.c.

70{
71 FILE *fp = NULL;
72 char *p = NULL, *q = NULL, *ct = NULL;
73 char buf[PATH_MAX] = { 0 };
74 char subtype[256] = { 0 };
75 char xtype[256] = { 0 };
76 int sze, cur_sze = 0;
77 bool found_mimetypes = false;
78 enum ContentType type = TYPE_OTHER;
79
80 int szf = mutt_str_len(path);
81
82 for (int count = 0; count < 4; count++)
83 {
84 /* can't use strtok() because we use it in an inner loop below, so use
85 * a switch statement here instead. */
86 switch (count)
87 {
88 /* last file with last entry to match wins type/xtype */
89 case 0:
90 /* check default unix mimetypes location first */
91 mutt_str_copy(buf, "/etc/mime.types", sizeof(buf));
92 break;
93 case 1:
94 mutt_str_copy(buf, SYSCONFDIR "/mime.types", sizeof(buf));
95 break;
96 case 2:
97 mutt_str_copy(buf, PKGDATADIR "/mime.types", sizeof(buf));
98 break;
99 case 3:
100 snprintf(buf, sizeof(buf), "%s/.mime.types", NONULL(HomeDir));
101 break;
102 default:
103 mutt_debug(LL_DEBUG1, "Internal error, count = %d\n", count);
104 goto bye; /* shouldn't happen */
105 }
106
107 fp = fopen(buf, "r");
108 if (fp)
109 {
110 found_mimetypes = true;
111
112 while (fgets(buf, sizeof(buf) - 1, fp))
113 {
114 /* weed out any comments */
115 p = strchr(buf, '#');
116 if (p)
117 *p = '\0';
118
119 /* remove any leading space. */
120 ct = buf;
121 SKIPWS(ct);
122
123 /* position on the next field in this line */
124 p = strpbrk(ct, " \t");
125 if (!p)
126 continue;
127 *p++ = 0;
128 SKIPWS(p);
129
130 /* cycle through the file extensions */
131 while ((p = strtok(p, " \t\n")))
132 {
133 sze = mutt_str_len(p);
134 if ((sze > cur_sze) && (szf >= sze) && mutt_istr_equal(path + szf - sze, p) &&
135 ((szf == sze) || (path[szf - sze - 1] == '.')))
136 {
137 /* get the content-type */
138
139 p = strchr(ct, '/');
140 if (!p)
141 {
142 /* malformed line, just skip it. */
143 break;
144 }
145 *p++ = 0;
146
147 for (q = p; *q && !IS_SPACE(*q); q++)
148 ; // do nothing
149
150 mutt_strn_copy(subtype, p, q - p, sizeof(subtype));
151
152 type = mutt_check_mime_type(ct);
153 if (type == TYPE_OTHER)
154 mutt_str_copy(xtype, ct, sizeof(xtype));
155
156 cur_sze = sze;
157 }
158 p = NULL;
159 }
160 }
161 mutt_file_fclose(&fp);
162 }
163 }
164
165bye:
166
167 /* no mime.types file found */
168 if (!found_mimetypes)
169 {
170 mutt_error(_("Could not find any mime.types file"));
171 }
172
173 if ((type != TYPE_OTHER) || (*xtype != '\0'))
174 {
175 att->type = type;
176 mutt_str_replace(&att->subtype, subtype);
177 mutt_str_replace(&att->xtype, xtype);
178 }
179
180 return type;
181}
char * HomeDir
User's home directory.
Definition: globals.c:38
int mutt_file_fclose(FILE **fp)
Close a FILE handle (and NULL the pointer)
Definition: file.c:149
#define mutt_error(...)
Definition: logging.h:87
#define mutt_debug(LEVEL,...)
Definition: logging.h:84
@ LL_DEBUG1
Log at debug level 1.
Definition: logging.h:40
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:819
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:431
size_t mutt_str_len(const char *a)
Calculate the length of a string, safely.
Definition: string.c:567
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:652
char * mutt_str_replace(char **p, const char *s)
Replace one string with another.
Definition: string.c:326
#define PATH_MAX
Definition: mutt.h:41
enum ContentType mutt_check_mime_type(const char *s)
Check a MIME type string.
Definition: parse.c:325
#define NONULL(x)
Definition: string2.h:37
#define IS_SPACE(ch)
Definition: string2.h:38
#define SKIPWS(ch)
Definition: string2.h:46
char * xtype
content-type if x-unknown
Definition: body.h:61
char * subtype
content-type subtype
Definition: body.h:60
unsigned int type
content-type primary type, ContentType
Definition: body.h:40
+ 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 a,
FILE *  fp_in,
struct ConfigSubset sub 
)
static

Convert MIME parts to 7-bit.

Parameters
aBody of the email
fp_inFile to read
subConfig Subset

Definition at line 189 of file sendlib.c.

190{
191 struct Buffer *buf = NULL;
192 struct State state = { 0 };
193 struct stat st = { 0 };
194
195 for (; a; a = a->next)
196 {
197 if (a->type == TYPE_MULTIPART)
198 {
199 a->encoding = ENC_7BIT;
200 transform_to_7bit(a->parts, fp_in, sub);
201 }
202 else if (mutt_is_message_type(a->type, a->subtype))
203 {
204 mutt_message_to_7bit(a, fp_in, sub);
205 }
206 else
207 {
208 a->noconv = true;
209 a->force_charset = true;
210
211 /* Because of the potential recursion in message types, we
212 * restrict the lifetime of the buffer tightly */
213 buf = mutt_buffer_pool_get();
215 state.fp_out = mutt_file_fopen(mutt_buffer_string(buf), "w");
216 if (!state.fp_out)
217 {
218 mutt_perror("fopen");
220 return;
221 }
222 state.fp_in = fp_in;
223 mutt_decode_attachment(a, &state);
224 mutt_file_fclose(&state.fp_out);
225 FREE(&a->d_filename);
226 a->d_filename = a->filename;
229 a->unlink = true;
230 if (stat(a->filename, &st) == -1)
231 {
232 mutt_perror("stat");
233 return;
234 }
235 a->length = st.st_size;
236
237 mutt_update_encoding(a, sub);
238 if (a->encoding == ENC_8BIT)
240 else if (a->encoding == ENC_BINARY)
241 a->encoding = ENC_BASE64;
242 }
243 }
244}
char * mutt_buffer_strdup(const struct Buffer *buf)
Copy a Buffer's string.
Definition: buffer.c:485
static const char * mutt_buffer_string(const struct Buffer *buf)
Convert a buffer to a const char * "string".
Definition: buffer.h:78
FILE * mutt_file_fopen(const char *path, const char *mode)
Call fopen() safely.
Definition: file.c:634
#define mutt_perror(...)
Definition: logging.h:88
void mutt_decode_attachment(struct Body *b, struct State *state)
Decode an email's attachment.
Definition: handler.c:1889
#define FREE(x)
Definition: memory.h:43
@ 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
bool mutt_is_message_type(int type, const char *subtype)
Determine if a mime type matches a message or not.
Definition: parse.c:1450
void mutt_buffer_pool_release(struct Buffer **pbuf)
Free a Buffer from the pool.
Definition: pool.c:112
struct Buffer * mutt_buffer_pool_get(void)
Get a Buffer from the pool.
Definition: pool.c:101
void mutt_message_to_7bit(struct Body *a, FILE *fp, struct ConfigSubset *sub)
Convert an email's MIME parts to 7-bit.
Definition: sendlib.c:252
static void transform_to_7bit(struct Body *a, FILE *fp_in, struct ConfigSubset *sub)
Convert MIME parts to 7-bit.
Definition: sendlib.c:189
void mutt_update_encoding(struct Body *a, struct ConfigSubset *sub)
Update the encoding type.
Definition: sendlib.c:415
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:72
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:67
LOFF_T length
length (in bytes) of attachment
Definition: body.h:53
struct Body * next
next attachment in the list
Definition: body.h:71
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:58
String manipulation buffer.
Definition: buffer.h:34
Keep track when processing files.
Definition: state.h:47
FILE * fp_out
File to write to.
Definition: state.h:49
FILE * fp_in
File to read from.
Definition: state.h:48
#define mutt_buffer_mktemp(buf)
Definition: tmp.h:37
+ 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 a,
FILE *  fp,
struct ConfigSubset sub 
)

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

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

Definition at line 252 of file sendlib.c.

253{
254 struct Buffer temp = mutt_buffer_make(0);
255 FILE *fp_in = NULL;
256 FILE *fp_out = NULL;
257 struct stat st = { 0 };
258
259 if (!a->filename && fp)
260 {
261 fp_in = fp;
262 }
263 else if (!a->filename || !(fp_in = fopen(a->filename, "r")))
264 {
265 mutt_error(_("Could not open %s"), a->filename ? a->filename : "(null)");
266 return;
267 }
268 else
269 {
270 a->offset = 0;
271 if (stat(a->filename, &st) == -1)
272 {
273 mutt_perror("stat");
274 mutt_file_fclose(&fp_in);
275 goto cleanup;
276 }
277 a->length = st.st_size;
278 }
279
280 /* Avoid buffer pool due to recursion */
281 mutt_buffer_mktemp(&temp);
282 fp_out = mutt_file_fopen(mutt_buffer_string(&temp), "w+");
283 if (!fp_out)
284 {
285 mutt_perror("fopen");
286 goto cleanup;
287 }
288
289 if (!mutt_file_seek(fp_in, a->offset, SEEK_SET))
290 {
291 goto cleanup;
292 }
293 a->parts = mutt_rfc822_parse_message(fp_in, a);
294
295 transform_to_7bit(a->parts, fp_in, sub);
296
297 mutt_copy_hdr(fp_in, fp_out, a->offset, a->offset + a->length,
298 CH_MIME | CH_NONEWLINE | CH_XMIT, NULL, 0);
299
300 fputs("MIME-Version: 1.0\n", fp_out);
301 mutt_write_mime_header(a->parts, fp_out, sub);
302 fputc('\n', fp_out);
303 mutt_write_mime_body(a->parts, fp_out, sub);
304
305 if (fp_in != fp)
306 mutt_file_fclose(&fp_in);
307 mutt_file_fclose(&fp_out);
308
309 a->encoding = ENC_7BIT;
310 FREE(&a->d_filename);
311 a->d_filename = a->filename;
312 if (a->filename && a->unlink)
313 unlink(a->filename);
314 a->filename = mutt_buffer_strdup(&temp);
315 a->unlink = true;
316 if (stat(a->filename, &st) == -1)
317 {
318 mutt_perror("stat");
319 goto cleanup;
320 }
321 a->length = st.st_size;
323 a->email->body = NULL;
324
325cleanup:
326 if (fp_in && (fp_in != fp))
327 mutt_file_fclose(&fp_in);
328
329 if (fp_out)
330 {
331 mutt_file_fclose(&fp_out);
333 }
334
335 mutt_buffer_dealloc(&temp);
336}
struct Buffer mutt_buffer_make(size_t size)
Make a new buffer on the stack.
Definition: buffer.c:67
void mutt_buffer_dealloc(struct Buffer *buf)
Release the memory allocated by a buffer.
Definition: buffer.c:347
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.c:105
#define CH_XMIT
Transmitting this message? (Ignore Lines: and Content-Length:)
Definition: copy.h:55
#define CH_NONEWLINE
Don't output terminating newline after the header.
Definition: copy.h:60
#define CH_MIME
Ignore MIME fields.
Definition: copy.h:61
void mutt_body_free(struct Body **ptr)
Free a Body.
Definition: body.c:57
bool mutt_file_seek(FILE *fp, LOFF_T offset, int whence)
Wrapper for fseeko with error handling.
Definition: file.c:708
void mutt_file_unlink(const char *s)
Delete a file, carefully.
Definition: file.c:193
int mutt_write_mime_header(struct Body *a, FILE *fp, struct ConfigSubset *sub)
Create a MIME header.
Definition: header.c:750
struct Body * mutt_rfc822_parse_message(FILE *fp, struct Body *parent)
Parse a Message/RFC822 body.
Definition: parse.c:1760
int mutt_write_mime_body(struct Body *a, FILE *fp, struct ConfigSubset *sub)
Write a MIME part.
Definition: body.c:318
LOFF_T offset
offset where the actual data begins
Definition: body.h:52
struct Email * email
header information for message/rfc822
Definition: body.h:73
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:

◆ 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 344 of file sendlib.c.

345{
346 const bool c_allow_8bit = cs_subset_bool(sub, "allow_8bit");
347 if (b->type == TYPE_TEXT)
348 {
349 const bool c_encode_from = cs_subset_bool(sub, "encode_from");
350 char send_charset[128] = { 0 };
351 char *chsname = mutt_body_get_charset(b, send_charset, sizeof(send_charset));
352 if ((info->lobin && !mutt_istr_startswith(chsname, "iso-2022")) ||
353 (info->linemax > 990) || (info->from && c_encode_from))
354 {
356 }
357 else if (info->hibin)
358 {
359 b->encoding = c_allow_8bit ? ENC_8BIT : ENC_QUOTED_PRINTABLE;
360 }
361 else
362 {
363 b->encoding = ENC_7BIT;
364 }
365 }
366 else if ((b->type == TYPE_MESSAGE) || (b->type == TYPE_MULTIPART))
367 {
368 if (info->lobin || info->hibin)
369 {
370 if (c_allow_8bit && !info->lobin)
371 b->encoding = ENC_8BIT;
372 else
373 mutt_message_to_7bit(b, NULL, sub);
374 }
375 else
376 {
377 b->encoding = ENC_7BIT;
378 }
379 }
380 else if ((b->type == TYPE_APPLICATION) && mutt_istr_equal(b->subtype, "pgp-keys"))
381 {
382 b->encoding = ENC_7BIT;
383 }
384 else
385 {
386 /* Determine which encoding is smaller */
387 if (1.33 * (float) (info->lobin + info->hibin + info->ascii) <
388 3.0 * (float) (info->lobin + info->hibin) + (float) info->ascii)
389 {
390 b->encoding = ENC_BASE64;
391 }
392 else
393 {
395 }
396 }
397}
bool cs_subset_bool(const struct ConfigSubset *sub, const char *name)
Get a boolean config item by name.
Definition: helpers.c:73
char * mutt_body_get_charset(struct Body *b, char *buf, size_t buflen)
Get a body's character set.
Definition: body.c:131
@ 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:239
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 a)

Timestamp an Attachment.

Parameters
aAttachment

Definition at line 403 of file sendlib.c.

404{
405 a->stamp = mutt_date_now();
406}
time_t mutt_date_now(void)
Return the number of seconds since the Unix epoch.
Definition: date.c:432
time_t stamp
Time stamp of last encoding update.
Definition: body.h:76
+ 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 a,
struct ConfigSubset sub 
)

Update the encoding type.

Parameters
aBody to update
subConfig Subset

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

Definition at line 415 of file sendlib.c.

416{
417 struct Content *info = NULL;
418 char chsbuf[256] = { 0 };
419
420 /* override noconv when it's us-ascii */
421 if (mutt_ch_is_us_ascii(mutt_body_get_charset(a, chsbuf, sizeof(chsbuf))))
422 a->noconv = false;
423
424 if (!a->force_charset && !a->noconv)
425 mutt_param_delete(&a->parameter, "charset");
426
427 info = mutt_get_content_info(a->filename, a, sub);
428 if (!info)
429 return;
430
431 set_encoding(a, info, sub);
433
434 FREE(&a->content);
435 a->content = info;
436}
struct Content * mutt_get_content_info(const char *fname, struct Body *b, struct ConfigSubset *sub)
Analyze file to determine MIME encoding to use.
Definition: content_info.c:180
#define mutt_ch_is_us_ascii(str)
Definition: charset.h:96
void mutt_param_delete(struct ParameterList *pl, const char *attribute)
Delete a matching Parameter.
Definition: parameter.c:142
void mutt_stamp_attachment(struct Body *a)
Timestamp an Attachment.
Definition: sendlib.c:403
static void set_encoding(struct Body *b, struct Content *info, struct ConfigSubset *sub)
Determine which Content-Transfer-Encoding to use.
Definition: sendlib.c:344
struct ParameterList parameter
Parameters of the content-type.
Definition: body.h:62
struct Content * content
Detailed info about the content of the attachment.
Definition: body.h:69
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 447 of file sendlib.c.

449{
450 struct Body *body = NULL;
451 FILE *fp = NULL;
452 CopyMessageFlags cmflags;
454
455 const bool c_mime_forward_decode = cs_subset_bool(sub, "mime_forward_decode");
456 const bool c_forward_decrypt = cs_subset_bool(sub, "forward_decrypt");
457 if (WithCrypto)
458 {
459 if ((c_mime_forward_decode || c_forward_decrypt) && (e->security & SEC_ENCRYPT))
460 {
462 return NULL;
463 }
464 }
465
466 struct Buffer *buf = mutt_buffer_pool_get();
468 fp = mutt_file_fopen(mutt_buffer_string(buf), "w+");
469 if (!fp)
470 {
472 return NULL;
473 }
474
475 body = mutt_body_new();
476 body->type = TYPE_MESSAGE;
477 body->subtype = mutt_str_dup("rfc822");
479 body->unlink = true;
480 body->use_disp = false;
481 body->disposition = DISP_INLINE;
482 body->noconv = true;
483
485
486 struct Message *msg = mx_msg_open(m, e->msgno);
487 if (!msg)
488 {
489 mutt_body_free(&body);
491 return NULL;
492 }
494
495 CopyHeaderFlags chflags = CH_XMIT;
496 cmflags = MUTT_CM_NO_FLAGS;
497
498 /* If we are attaching a message, ignore `$mime_forward_decode` */
499 if (!attach_msg && c_mime_forward_decode)
500 {
501 chflags |= CH_MIME | CH_TXTPLAIN;
504 pgp &= ~PGP_ENCRYPT;
506 pgp &= ~SMIME_ENCRYPT;
507 }
508 else if ((WithCrypto != 0) && c_forward_decrypt && (e->security & SEC_ENCRYPT))
509 {
511 {
512 chflags |= CH_MIME | CH_NONEWLINE;
513 cmflags = MUTT_CM_DECODE_PGP;
514 pgp &= ~PGP_ENCRYPT;
515 }
516 else if (((WithCrypto & APPLICATION_PGP) != 0) &&
518 {
519 chflags |= CH_MIME | CH_TXTPLAIN;
521 pgp &= ~PGP_ENCRYPT;
522 }
523 else if (((WithCrypto & APPLICATION_SMIME) != 0) &&
525 {
526 chflags |= CH_MIME | CH_TXTPLAIN;
528 pgp &= ~SMIME_ENCRYPT;
529 }
530 }
531
532 mutt_copy_message(fp, e, msg, cmflags, chflags, 0);
533 mx_msg_close(m, &msg);
534
535 fflush(fp);
536 rewind(fp);
537
538 body->email = email_new();
539 body->email->offset = 0;
540 /* we don't need the user headers here */
541 body->email->env = mutt_rfc822_read_header(fp, body->email, false, false);
542 if (WithCrypto)
543 body->email->security = pgp;
544 mutt_update_encoding(body, sub);
545 body->parts = body->email->body;
546
548
549 return body;
550}
void mutt_parse_mime_message(struct Email *e, FILE *fp)
Parse a MIME email.
Definition: attachments.c:592
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:875
#define MUTT_CM_DECODE_PGP
Used for decoding PGP messages.
Definition: copy.h:45
#define MUTT_CM_DECODE
Decode the message body into text/plain.
Definition: copy.h:38
#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
#define CH_TXTPLAIN
Generate text/plain MIME headers.
Definition: copy.h:63
uint16_t CopyMessageFlags
Flags for mutt_copy_message(), e.g. MUTT_CM_NOHEADER.
Definition: copy.h:34
SecurityFlags mutt_is_application_pgp(struct Body *b)
Does the message use PGP?
Definition: crypt.c:541
SecurityFlags mutt_is_application_smime(struct Body *b)
Does the message use S/MIME?
Definition: crypt.c:598
bool crypt_valid_passphrase(SecurityFlags flags)
Check that we have a usable passphrase, ask if not.
Definition: crypt.c:133
SecurityFlags mutt_is_multipart_encrypted(struct Body *b)
Does the message have encrypted parts?
Definition: crypt.c:436
struct Body * mutt_body_new(void)
Create a new Body.
Definition: body.c:43
struct Email * email_new(void)
Create a new Email.
Definition: email.c:78
@ DISP_INLINE
Content is inline.
Definition: mime.h:62
char * mutt_str_dup(const char *str)
Copy a string, safely.
Definition: string.c:250
int mx_msg_close(struct Mailbox *m, struct Message **msg)
Close a message.
Definition: mx.c:1200
struct Message * mx_msg_open(struct Mailbox *m, int msgno)
Return a stream pointer for a message.
Definition: mx.c:1154
uint16_t SecurityFlags
Flags, e.g. SEC_ENCRYPT.
Definition: lib.h:76
#define APPLICATION_PGP
Use PGP to encrypt/sign.
Definition: lib.h:90
#define PGP_ENCRYPT
Definition: lib.h:96
#define APPLICATION_SMIME
Use SMIME to encrypt/sign.
Definition: lib.h:91
#define SEC_NO_FLAGS
No flags are set.
Definition: lib.h:77
#define SEC_ENCRYPT
Email is encrypted.
Definition: lib.h:78
#define SMIME_ENCRYPT
Definition: lib.h:102
#define WithCrypto
Definition: lib.h:116
struct Envelope * mutt_rfc822_read_header(FILE *fp, struct Email *e, bool user_hdrs, bool weed)
Parses an RFC822 header.
Definition: parse.c:1162
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:66
SecurityFlags security
bit 0-10: flags, bit 11,12: application, bit 13: traditional pgp See: ncrypt/lib.h pgplib....
Definition: email.h:41
LOFF_T offset
Where in the stream does this message begin?
Definition: email.h:69
int msgno
Number displayed to the user.
Definition: email.h:110
A local copy of an email.
Definition: mxapi.h:43
FILE * fp
pointer to the message data
Definition: mxapi.h:44
+ 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 att,
struct ConfigSubset sub 
)
static

Run an external command to determine the MIME type.

Parameters
attAttachment
subConfig Subset

The command in $mime_type_query_command is run.

Definition at line 559 of file sendlib.c.

560{
561 FILE *fp = NULL, *fp_err = NULL;
562 char *buf = NULL;
563 size_t buflen;
564 pid_t pid;
565 struct Buffer *cmd = mutt_buffer_pool_get();
566
567 const char *const c_mime_type_query_command = cs_subset_string(sub, "mime_type_query_command");
568
569 mutt_buffer_file_expand_fmt_quote(cmd, c_mime_type_query_command, att->filename);
570
571 pid = filter_create(mutt_buffer_string(cmd), NULL, &fp, &fp_err);
572 if (pid < 0)
573 {
574 mutt_error(_("Error running \"%s\""), mutt_buffer_string(cmd));
576 return;
577 }
579
580 buf = mutt_file_read_line(buf, &buflen, fp, NULL, MUTT_RL_NO_FLAGS);
581 if (buf)
582 {
583 if (strchr(buf, '/'))
584 mutt_parse_content_type(buf, att);
585 FREE(&buf);
586 }
587
588 mutt_file_fclose(&fp);
589 mutt_file_fclose(&fp_err);
590 filter_wait(pid);
591}
const char * cs_subset_string(const struct ConfigSubset *sub, const char *name)
Get a string config item by name.
Definition: helpers.c:317
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:738
void mutt_buffer_file_expand_fmt_quote(struct Buffer *dest, const char *fmt, const char *src)
Replace s in a string with a filename.
Definition: file.c:1475
#define MUTT_RL_NO_FLAGS
No flags are set.
Definition: file.h:39
int filter_wait(pid_t pid)
Wait for the exit of a process and return its status.
Definition: filter.c:217
pid_t filter_create(const char *cmd, FILE **fp_in, FILE **fp_out, FILE **fp_err)
Set up filter program.
Definition: filter.c:206
void mutt_parse_content_type(const char *s, struct Body *ct)
Parse a content type.
Definition: parse.c:426
+ 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 600 of file sendlib.c.

601{
602 if (!path || (path[0] == '\0'))
603 return NULL;
604
605 struct Body *att = mutt_body_new();
606 att->filename = mutt_str_dup(path);
607
608 const char *const c_mime_type_query_command = cs_subset_string(sub, "mime_type_query_command");
609 const bool c_mime_type_query_first = cs_subset_bool(sub, "mime_type_query_first");
610
611 if (c_mime_type_query_command && c_mime_type_query_first)
612 run_mime_type_query(att, sub);
613
614 /* Attempt to determine the appropriate content-type based on the filename
615 * suffix. */
616 if (!att->subtype)
617 mutt_lookup_mime_type(att, path);
618
619 if (!att->subtype && c_mime_type_query_command && !c_mime_type_query_first)
620 {
621 run_mime_type_query(att, sub);
622 }
623
624 struct Content *info = mutt_get_content_info(path, att, sub);
625 if (!info)
626 {
627 mutt_body_free(&att);
628 return NULL;
629 }
630
631 if (!att->subtype)
632 {
633 if ((info->nulbin == 0) &&
634 ((info->lobin == 0) || ((info->lobin + info->hibin + info->ascii) / info->lobin >= 10)))
635 {
636 /* Statistically speaking, there should be more than 10% "lobin"
637 * chars if this is really a binary file... */
638 att->type = TYPE_TEXT;
639 att->subtype = mutt_str_dup("plain");
640 }
641 else
642 {
643 att->type = TYPE_APPLICATION;
644 att->subtype = mutt_str_dup("octet-stream");
645 }
646 }
647
648 FREE(&info);
649 mutt_update_encoding(att, sub);
650 return att;
651}
enum ContentType mutt_lookup_mime_type(struct Body *att, const char *path)
Find the MIME type for an attachment.
Definition: sendlib.c:69
static void run_mime_type_query(struct Body *att, struct ConfigSubset *sub)
Run an external command to determine the MIME type.
Definition: sendlib.c:559
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 660 of file sendlib.c.

661{
662 char *tmp = NULL;
663 char *p = NULL;
664 int i;
665
666 const struct Slist *const c_send_charset = cs_subset_slist(sub, "send_charset");
667
668 struct ListNode *np = NULL;
669 STAILQ_FOREACH(np, h, entries)
670 {
671 p = strchr(np->data, ':');
672 if (!p)
673 continue;
674
675 i = p - np->data;
676 p = mutt_str_skip_email_wsp(p + 1);
677 tmp = mutt_str_dup(p);
678
679 if (!tmp)
680 continue;
681
682 rfc2047_encode(&tmp, NULL, i + 2, c_send_charset);
683 mutt_mem_realloc(&np->data, i + 2 + mutt_str_len(tmp) + 1);
684
685 sprintf(np->data + i + 2, "%s", tmp);
686
687 FREE(&tmp);
688 }
689}
const struct Slist * cs_subset_slist(const struct ConfigSubset *sub, const char *name)
Get a string-list config item by name.
Definition: helpers.c:268
void mutt_mem_realloc(void *ptr, size_t size)
Resize a block of memory on the heap.
Definition: memory.c:114
char * mutt_str_skip_email_wsp(const char *s)
Skip over whitespace as defined by RFC5322.
Definition: string.c:679
#define STAILQ_FOREACH(var, head, field)
Definition: queue.h:352
void rfc2047_encode(char **pd, const char *specials, int col, const struct Slist *charsets)
RFC-2047-encode a string.
Definition: rfc2047.c:625
A List node for strings.
Definition: list.h:35
char * data
String.
Definition: list.h:36
String list.
Definition: slist.h:47
+ 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 700 of file sendlib.c.

701{
702 const char *const c_hostname = cs_subset_string(sub, "hostname");
703 if (!c_hostname || (c_hostname[0] == '@'))
704 return NULL;
705
706 const char *p = c_hostname;
707
708 const bool c_hidden_host = cs_subset_bool(sub, "hidden_host");
709 if (may_hide_host && c_hidden_host)
710 {
711 p = strchr(c_hostname, '.');
712 if (p)
713 p++;
714
715 // sanity check: don't hide the host if the fqdn is something like example.com
716 if (!p || !strchr(p, '.'))
717 p = c_hostname;
718 }
719
720 return p;
721}
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ gen_msgid()

static char * gen_msgid ( void  )
static

Generate a random Message ID.

Return values
ptrMessage ID

The length of the message id is chosen such that it is maximal and fits in the recommended 78 character line length for the headers Message-ID:, References:, and In-Reply-To:, this leads to 62 available characters (excluding @ and >). Since we choose from 32 letters, we have 32^62 = 2^310 different message ids.

Examples:

Message-ID: <12345678901111111111222222222233333333334444444444@123456789011>
In-Reply-To: <12345678901111111111222222222233333333334444444444@123456789011>
References: <12345678901111111111222222222233333333334444444444@123456789011>

The distribution of the characters to left-of-@ and right-of-@ was arbitrary. The choice was made to put more into the left-id and shorten the right-id to slightly mimic a common length domain name.

Note
The caller should free the string

Definition at line 746 of file sendlib.c.

747{
748 const int ID_LEFT_LEN = 50;
749 const int ID_RIGHT_LEN = 12;
750 char rnd_id_left[ID_LEFT_LEN + 1];
751 char rnd_id_right[ID_RIGHT_LEN + 1];
752 char buf[128] = { 0 };
753
754 mutt_rand_base32(rnd_id_left, sizeof(rnd_id_left) - 1);
755 mutt_rand_base32(rnd_id_right, sizeof(rnd_id_right) - 1);
756 rnd_id_left[ID_LEFT_LEN] = 0;
757 rnd_id_right[ID_RIGHT_LEN] = 0;
758
759 snprintf(buf, sizeof(buf), "<%s@%s>", rnd_id_left, rnd_id_right);
760 return mutt_str_dup(buf);
761}
void mutt_rand_base32(char *buf, size_t buflen)
Fill a buffer with a base32-encoded random string.
Definition: random.c:102
+ 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 773 of file sendlib.c.

774{
775 if (final)
776 {
777 if (!TAILQ_EMPTY(&env->bcc) && TAILQ_EMPTY(&env->to) && TAILQ_EMPTY(&env->cc))
778 {
779 /* some MTA's will put an Apparently-To: header field showing the Bcc:
780 * recipients if there is no To: or Cc: field, so attempt to suppress
781 * it by using an empty To: field. */
782 struct Address *to = mutt_addr_new();
783 to->group = true;
784 mutt_addrlist_append(&env->to, to);
786
787 char buf[1024] = { 0 };
788 buf[0] = '\0';
789 mutt_addr_cat(buf, sizeof(buf), "undisclosed-recipients", AddressSpecials);
790
791 to->mailbox = mutt_str_dup(buf);
792 }
793
794 mutt_set_followup_to(env, sub);
795
796 if (!env->message_id)
797 env->message_id = gen_msgid();
798 }
799
800 /* Take care of 8-bit => 7-bit conversion. */
802 encode_headers(&env->userhdrs, sub);
803}
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:687
void mutt_addrlist_append(struct AddressList *al, struct Address *a)
Append an Address to an AddressList.
Definition: address.c:1463
struct Address * mutt_addr_new(void)
Create a new Address.
Definition: address.c:389
const char AddressSpecials[]
Characters with special meaning for email addresses.
Definition: address.c:42
#define TAILQ_EMPTY(head)
Definition: queue.h:721
void rfc2047_encode_envelope(struct Envelope *env)
Encode the fields of an Envelope.
Definition: rfc2047.c:820
void mutt_set_followup_to(struct Envelope *env, struct ConfigSubset *sub)
Set followup-to field.
Definition: send.c:1345
static char * gen_msgid(void)
Generate a random Message ID.
Definition: sendlib.c:746
static void encode_headers(struct ListHead *h, struct ConfigSubset *sub)
RFC2047-encode a list of headers.
Definition: sendlib.c:660
An email address.
Definition: address.h:36
bool group
Group mailbox?
Definition: address.h:39
char * mailbox
Mailbox and host address.
Definition: address.h:38
struct ListHead userhdrs
user defined headers
Definition: envelope.h:87
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 812 of file sendlib.c.

813{
814 struct ListNode *item = NULL;
815 STAILQ_FOREACH(item, &env->userhdrs, entries)
816 {
817 rfc2047_decode(&item->data);
818 }
819
821
822 /* back conversions */
824}
void mutt_addrlist_clear(struct AddressList *al)
Unlink and free all Address in an AddressList.
Definition: address.c:1443
void rfc2047_decode_envelope(struct Envelope *env)
Decode the fields of an Envelope.
Definition: rfc2047.c:800
void rfc2047_decode(char **pd)
Decode any RFC2047-encoded header fields.
Definition: rfc2047.c:655
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 838 of file sendlib.c.

841{
842 if (!e)
843 return -1;
844
845 int rc = 0;
846
847 struct Buffer *tempfile = mutt_buffer_pool_get();
848 mutt_buffer_mktemp(tempfile);
849 FILE *fp_tmp = mutt_file_fopen(mutt_buffer_string(tempfile), "w");
850 if (fp_tmp)
851 {
853
854 const bool c_bounce_delivered = cs_subset_bool(sub, "bounce_delivered");
855 if (!c_bounce_delivered)
856 chflags |= CH_WEED_DELIVERED;
857
858 if (!mutt_file_seek(fp, e->offset, SEEK_SET))
859 {
860 (void) mutt_file_fclose(&fp_tmp);
861 return -1;
862 }
863 fprintf(fp_tmp, "Resent-From: %s\n", resent_from);
864
865 struct Buffer *date = mutt_buffer_pool_get();
866 mutt_date_make_date(date, cs_subset_bool(sub, "local_date_header"));
867 fprintf(fp_tmp, "Resent-Date: %s\n", mutt_buffer_string(date));
869
870 char *msgid_str = gen_msgid();
871 fprintf(fp_tmp, "Resent-Message-ID: %s\n", msgid_str);
872 FREE(&msgid_str);
873 mutt_addrlist_write_file(to, fp_tmp, "Resent-To");
874 mutt_copy_header(fp, e, fp_tmp, chflags, NULL, 0);
875 fputc('\n', fp_tmp);
876 mutt_file_copy_bytes(fp, fp_tmp, e->body->length);
877 if (mutt_file_fclose(&fp_tmp) != 0)
878 {
880 unlink(mutt_buffer_string(tempfile));
881 return -1;
882 }
883#ifdef USE_SMTP
884 const char *const c_smtp_url = cs_subset_string(sub, "smtp_url");
885 if (c_smtp_url)
886 {
887 rc = mutt_smtp_send(env_from, to, NULL, NULL, mutt_buffer_string(tempfile),
888 (e->body->encoding == ENC_8BIT), sub);
889 }
890 else
891#endif
892 {
893 rc = mutt_invoke_sendmail(m, env_from, to, NULL, NULL, mutt_buffer_string(tempfile),
894 (e->body->encoding == ENC_8BIT), sub);
895 }
896 }
897
898 mutt_buffer_pool_release(&tempfile);
899 return rc;
900}
void mutt_addrlist_write_file(const struct AddressList *al, FILE *fp, const char *header)
Wrapper for mutt_write_address()
Definition: address.c:1234
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.c:415
#define CH_WEED_DELIVERED
Weed eventual Delivered-To headers.
Definition: copy.h:65
#define CH_NOQFROM
Ignore ">From " line.
Definition: copy.h:67
void mutt_date_make_date(struct Buffer *buf, bool local)
Write a date in RFC822 format to a buffer.
Definition: date.c:384
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:229
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:296
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:1096
+ 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 912 of file sendlib.c.

914{
915 if (!fp || !e || !to || TAILQ_EMPTY(to))
916 return -1;
917
918 const char *fqdn = mutt_fqdn(true, sub);
919 char *err = NULL;
920
921 struct Address *from = mutt_default_from(sub);
922 struct AddressList from_list = TAILQ_HEAD_INITIALIZER(from_list);
923 mutt_addrlist_append(&from_list, from);
924
925 /* mutt_default_from() does not use $real_name if the real name is not set
926 * in $from, so we add it here. The reason it is not added in
927 * mutt_default_from() is that during normal sending, we execute
928 * send-hooks and set the real_name last so that it can be changed based
929 * upon message criteria. */
930 if (!from->personal)
931 {
932 const char *const c_real_name = cs_subset_string(sub, "real_name");
933 from->personal = mutt_str_dup(c_real_name);
934 }
935
936 mutt_addrlist_qualify(&from_list, fqdn);
937
938 rfc2047_encode_addrlist(&from_list, "Resent-From");
939 if (mutt_addrlist_to_intl(&from_list, &err))
940 {
941 mutt_error(_("Bad IDN %s while preparing resent-from"), err);
942 FREE(&err);
943 mutt_addrlist_clear(&from_list);
944 return -1;
945 }
946 struct Buffer *resent_from = mutt_buffer_pool_get();
947 mutt_addrlist_write(&from_list, resent_from, false);
948
949#ifdef USE_NNTP
950 OptNewsSend = false;
951#endif
952
953 /* prepare recipient list. idna conversion appears to happen before this
954 * function is called, since the user receives confirmation of the address
955 * list being bounced to. */
956 struct AddressList resent_to = TAILQ_HEAD_INITIALIZER(resent_to);
957 mutt_addrlist_copy(&resent_to, to, false);
958 rfc2047_encode_addrlist(&resent_to, "Resent-To");
959 int rc = bounce_message(fp, m, e, &resent_to, mutt_buffer_string(resent_from),
960 &from_list, sub);
961 mutt_addrlist_clear(&resent_to);
962 mutt_addrlist_clear(&from_list);
963 mutt_buffer_pool_release(&resent_from);
964 return rc;
965}
void mutt_addrlist_copy(struct AddressList *dst, const struct AddressList *src, bool prune)
Copy a list of addresses into another list.
Definition: address.c:745
void mutt_addrlist_qualify(struct AddressList *al, const char *host)
Expand local names in an Address list using a hostname.
Definition: address.c:656
size_t mutt_addrlist_write(const struct AddressList *al, struct Buffer *buf, bool display)
Write an Address to a buffer.
Definition: address.c:1192
int mutt_addrlist_to_intl(struct AddressList *al, char **err)
Convert an Address list to Punycode.
Definition: address.c:1278
bool OptNewsSend
(pseudo) used to change behavior when posting
Definition: globals.c:79
#define TAILQ_HEAD_INITIALIZER(head)
Definition: queue.h:637
void rfc2047_encode_addrlist(struct AddressList *al, const char *tag)
Encode any RFC2047 headers, where required, in an Address list.
Definition: rfc2047.c:757
struct Address * mutt_default_from(struct ConfigSubset *sub)
Get a default 'from' Address.
Definition: send.c:1470
const char * mutt_fqdn(bool may_hide_host, const struct ConfigSubset *sub)
Get the Fully-Qualified Domain Name.
Definition: sendlib.c:700
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:838
char * personal
Real name of address.
Definition: address.h:37
+ 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 972 of file sendlib.c.

973{
974 for (; b; b = b->next)
975 {
976 if ((b->type == TYPE_MESSAGE) || (b->type == TYPE_MULTIPART))
977 {
978 set_noconv_flags(b->parts, flag);
979 }
980 else if ((b->type == TYPE_TEXT) && b->noconv)
981 {
982 if (flag)
983 mutt_param_set(&b->parameter, "x-mutt-noconv", "yes");
984 else
985 mutt_param_delete(&b->parameter, "x-mutt-noconv");
986 }
987 }
988}
void mutt_param_set(struct ParameterList *pl, const char *attribute, const char *value)
Set a Parameter.
Definition: parameter.c:110
static void set_noconv_flags(struct Body *b, bool flag)
Set/reset the "x-mutt-noconv" flag.
Definition: sendlib.c:972
+ 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 1002 of file sendlib.c.

1004{
1005 char fcc_tok[PATH_MAX] = { 0 };
1006 char fcc_expanded[PATH_MAX] = { 0 };
1007
1008 mutt_str_copy(fcc_tok, path, sizeof(fcc_tok));
1009
1010 char *tok = strtok(fcc_tok, ",");
1011 if (!tok)
1012 return -1;
1013
1014 mutt_debug(LL_DEBUG1, "Fcc: initial mailbox = '%s'\n", tok);
1015 /* mutt_expand_path already called above for the first token */
1016 int status = mutt_write_fcc(tok, e, msgid, post, fcc, finalpath, sub);
1017 if (status != 0)
1018 return status;
1019
1020 while ((tok = strtok(NULL, ",")))
1021 {
1022 if (*tok == '\0')
1023 continue;
1024
1025 /* Only call mutt_expand_path if tok has some data */
1026 mutt_debug(LL_DEBUG1, "Fcc: additional mailbox token = '%s'\n", tok);
1027 mutt_str_copy(fcc_expanded, tok, sizeof(fcc_expanded));
1028 mutt_expand_path(fcc_expanded, sizeof(fcc_expanded));
1029 mutt_debug(LL_DEBUG1, " Additional mailbox expanded = '%s'\n", fcc_expanded);
1030 status = mutt_write_fcc(fcc_expanded, e, msgid, post, fcc, finalpath, sub);
1031 if (status != 0)
1032 return status;
1033 }
1034
1035 return 0;
1036}
char * mutt_expand_path(char *buf, size_t buflen)
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:1050
+ 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 1050 of file sendlib.c.

1052{
1053 struct Message *msg = NULL;
1054 struct Buffer *tempfile = NULL;
1055 FILE *fp_tmp = NULL;
1056 int rc = -1;
1057 bool need_mailbox_cleanup = false;
1058 struct stat st = { 0 };
1059 MsgOpenFlags onm_flags;
1060
1061 if (post)
1062 set_noconv_flags(e->body, true);
1063
1064#ifdef RECORD_FOLDER_HOOK
1065 mutt_folder_hook(path, NULL);
1066#endif
1067 struct Mailbox *m_fcc = mx_path_resolve(path);
1068 bool old_append = m_fcc->append;
1069 if (!mx_mbox_open(m_fcc, MUTT_APPEND | MUTT_QUIET))
1070 {
1071 mutt_debug(LL_DEBUG1, "unable to open mailbox %s in append-mode, aborting\n", path);
1072 goto done;
1073 }
1074
1075 /* We need to add a Content-Length field to avoid problems where a line in
1076 * the message body begins with "From " */
1077 if ((m_fcc->type == MUTT_MMDF) || (m_fcc->type == MUTT_MBOX))
1078 {
1079 tempfile = mutt_buffer_pool_get();
1080 mutt_buffer_mktemp(tempfile);
1081 fp_tmp = mutt_file_fopen(mutt_buffer_string(tempfile), "w+");
1082 if (!fp_tmp)
1083 {
1085 mx_mbox_close(m_fcc);
1086 goto done;
1087 }
1088 /* remember new mail status before appending message */
1089 need_mailbox_cleanup = true;
1090 stat(path, &st);
1091 }
1092
1093 e->read = !post; /* make sure to put it in the 'cur' directory (maildir) */
1094 onm_flags = MUTT_ADD_FROM;
1095 if (post)
1096 onm_flags |= MUTT_SET_DRAFT;
1097 msg = mx_msg_open_new(m_fcc, e, onm_flags);
1098 if (!msg)
1099 {
1100 mutt_file_fclose(&fp_tmp);
1101 mx_mbox_close(m_fcc);
1102 goto done;
1103 }
1104
1105 const bool c_crypt_protected_headers_read = cs_subset_bool(sub, "crypt_protected_headers_read");
1106
1107 /* post == 1 => postpone message.
1108 * post == 0 => Normal mode. */
1109 mutt_rfc822_write_header(msg->fp, e->env, e->body,
1111 c_crypt_protected_headers_read &&
1113 sub);
1114
1115 /* (postponement) if this was a reply of some sort, <msgid> contains the
1116 * Message-ID: of message replied to. Save it using a special X-Mutt-
1117 * header so it can be picked up if the message is recalled at a later
1118 * point in time. This will allow the message to be marked as replied if
1119 * the same mailbox is still open. */
1120 if (post && msgid)
1121 fprintf(msg->fp, "Mutt-References: %s\n", msgid);
1122
1123 /* (postponement) save the Fcc: using a special X-Mutt- header so that
1124 * it can be picked up when the message is recalled */
1125 if (post && fcc)
1126 fprintf(msg->fp, "Mutt-Fcc: %s\n", fcc);
1127
1128 if ((m_fcc->type == MUTT_MMDF) || (m_fcc->type == MUTT_MBOX))
1129 fprintf(msg->fp, "Status: RO\n");
1130
1131 /* (postponement) if the mail is to be signed or encrypted, save this info */
1132 if (((WithCrypto & APPLICATION_PGP) != 0) && post && (e->security & APPLICATION_PGP))
1133 {
1134 fputs("Mutt-PGP: ", msg->fp);
1135 if (e->security & SEC_ENCRYPT)
1136 fputc('E', msg->fp);
1137 if (e->security & SEC_OPPENCRYPT)
1138 fputc('O', msg->fp);
1139 if (e->security & SEC_SIGN)
1140 {
1141 fputc('S', msg->fp);
1142
1143 const char *const c_pgp_sign_as = cs_subset_string(sub, "pgp_sign_as");
1144 if (c_pgp_sign_as)
1145 fprintf(msg->fp, "<%s>", c_pgp_sign_as);
1146 }
1147 if (e->security & SEC_INLINE)
1148 fputc('I', msg->fp);
1149#ifdef USE_AUTOCRYPT
1150 if (e->security & SEC_AUTOCRYPT)
1151 fputc('A', msg->fp);
1153 fputc('Z', msg->fp);
1154#endif
1155 fputc('\n', msg->fp);
1156 }
1157
1158 /* (postponement) if the mail is to be signed or encrypted, save this info */
1159 if (((WithCrypto & APPLICATION_SMIME) != 0) && post && (e->security & APPLICATION_SMIME))
1160 {
1161 fputs("Mutt-SMIME: ", msg->fp);
1162 if (e->security & SEC_ENCRYPT)
1163 {
1164 fputc('E', msg->fp);
1165
1166 const char *const c_smime_encrypt_with = cs_subset_string(sub, "smime_encrypt_with");
1167 if (c_smime_encrypt_with)
1168 fprintf(msg->fp, "C<%s>", c_smime_encrypt_with);
1169 }
1170 if (e->security & SEC_OPPENCRYPT)
1171 fputc('O', msg->fp);
1172 if (e->security & SEC_SIGN)
1173 {
1174 fputc('S', msg->fp);
1175
1176 const char *const c_smime_sign_as = cs_subset_string(sub, "smime_sign_as");
1177 if (c_smime_sign_as)
1178 fprintf(msg->fp, "<%s>", c_smime_sign_as);
1179 }
1180 if (e->security & SEC_INLINE)
1181 fputc('I', msg->fp);
1182 fputc('\n', msg->fp);
1183 }
1184
1185#ifdef MIXMASTER
1186 /* (postponement) if the mail is to be sent through a mixmaster
1187 * chain, save that information */
1188
1189 if (post && !STAILQ_EMPTY(&e->chain))
1190 {
1191 fputs("Mutt-Mix:", msg->fp);
1192 struct ListNode *p = NULL;
1193 STAILQ_FOREACH(p, &e->chain, entries)
1194 {
1195 fprintf(msg->fp, " %s", (char *) p->data);
1196 }
1197
1198 fputc('\n', msg->fp);
1199 }
1200#endif
1201
1202 if (fp_tmp)
1203 {
1204 mutt_write_mime_body(e->body, fp_tmp, sub);
1205
1206 /* make sure the last line ends with a newline. Emacs doesn't ensure this
1207 * will happen, and it can cause problems parsing the mailbox later. */
1208 if (mutt_file_seek(fp_tmp, -1, SEEK_END) && (fgetc(fp_tmp) != '\n') &&
1209 mutt_file_seek(fp_tmp, 0, SEEK_END))
1210 {
1211 fputc('\n', fp_tmp);
1212 }
1213
1214 fflush(fp_tmp);
1215 if (ferror(fp_tmp))
1216 {
1217 mutt_debug(LL_DEBUG1, "%s: write failed\n", mutt_buffer_string(tempfile));
1218 mutt_file_fclose(&fp_tmp);
1219 unlink(mutt_buffer_string(tempfile));
1220 mx_msg_commit(m_fcc, msg); /* XXX really? */
1221 mx_msg_close(m_fcc, &msg);
1222 mx_mbox_close(m_fcc);
1223 goto done;
1224 }
1225
1226 /* count the number of lines */
1227 int lines = 0;
1228 char line_buf[1024] = { 0 };
1229 rewind(fp_tmp);
1230 while (fgets(line_buf, sizeof(line_buf), fp_tmp))
1231 lines++;
1232 fprintf(msg->fp, "Content-Length: " OFF_T_FMT "\n", (LOFF_T) ftello(fp_tmp));
1233 fprintf(msg->fp, "Lines: %d\n\n", lines);
1234
1235 /* copy the body and clean up */
1236 rewind(fp_tmp);
1237 rc = mutt_file_copy_stream(fp_tmp, msg->fp);
1238 if (mutt_file_fclose(&fp_tmp) != 0)
1239 rc = -1;
1240 /* if there was an error, leave the temp version */
1241 if (rc >= 0)
1242 {
1243 unlink(mutt_buffer_string(tempfile));
1244 rc = 0;
1245 }
1246 }
1247 else
1248 {
1249 fputc('\n', msg->fp); /* finish off the header */
1250 rc = mutt_write_mime_body(e->body, msg->fp, sub);
1251 }
1252
1253 if (mx_msg_commit(m_fcc, msg) != 0)
1254 rc = -1;
1255 else if (finalpath)
1256 *finalpath = mutt_str_dup(msg->committed_path);
1257 mx_msg_close(m_fcc, &msg);
1258 mx_mbox_close(m_fcc);
1259
1260 if (!post && need_mailbox_cleanup)
1261 mutt_mailbox_cleanup(path, &st);
1262
1263 if (post)
1264 set_noconv_flags(e->body, false);
1265
1266done:
1267 m_fcc->append = old_append;
1268 mailbox_free(&m_fcc);
1269
1270#ifdef RECORD_FOLDER_HOOK
1271 /* We ran a folder hook for the destination mailbox,
1272 * now we run it for the user's current mailbox */
1273 const struct Mailbox *m_cur = get_current_mailbox();
1274 if (m_cur)
1275 mutt_folder_hook(m_cur->path, m_cur->desc);
1276#endif
1277
1278 if (fp_tmp)
1279 {
1280 mutt_file_fclose(&fp_tmp);
1281 unlink(mutt_buffer_string(tempfile));
1282 }
1283 mutt_buffer_pool_release(&tempfile);
1284
1285 return rc;
1286}
bool mutt_should_hide_protected_subject(struct Email *e)
Should NeoMutt hide the protected subject?
Definition: crypt.c:1079
int mutt_file_copy_stream(FILE *fp_in, FILE *fp_out)
Copy the contents of one file into another.
Definition: file.c:259
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:571
@ MUTT_WRITE_HEADER_FCC
fcc mode, like normal mode but for Bcc header
Definition: header.h:41
@ MUTT_WRITE_HEADER_POSTPONE
A postponed Email, just the envelope info.
Definition: header.h:42
void mutt_folder_hook(const char *path, const char *desc)
Perform a folder hook.
Definition: hook.c:587
struct Mailbox * get_current_mailbox(void)
Get the current Mailbox.
Definition: index.c:618
void mailbox_free(struct Mailbox **ptr)
Free a Mailbox.
Definition: mailbox.c:87
@ MUTT_MMDF
'mmdf' Mailbox type
Definition: mailbox.h:46
@ MUTT_MBOX
'mbox' Mailbox type
Definition: mailbox.h:45
void mutt_mailbox_cleanup(const char *path, struct stat *st)
Restore the timestamp of a mailbox.
Definition: mutt_mailbox.c:424
bool mx_mbox_open(struct Mailbox *m, OpenMailboxFlags flags)
Open a mailbox and parse it.
Definition: mx.c:305
struct Message * mx_msg_open_new(struct Mailbox *m, const struct Email *e, MsgOpenFlags flags)
Open a new message.
Definition: mx.c:1062
int mx_msg_commit(struct Mailbox *m, struct Message *msg)
Commit a message to a folder - Wrapper for MxOps::msg_commit()
Definition: mx.c:1179
struct Mailbox * mx_path_resolve(const char *path)
Get a Mailbox for a path.
Definition: mx.c:1684
enum MxStatus mx_mbox_close(struct Mailbox *m)
Save changes and close mailbox.
Definition: mx.c:616
uint8_t MsgOpenFlags
Flags for mx_msg_open_new(), e.g. MUTT_ADD_FROM.
Definition: mx.h:41
#define MUTT_ADD_FROM
add a From_ line
Definition: mx.h:43
#define MUTT_SET_DRAFT
set the message draft flag
Definition: mx.h:44
#define MUTT_APPEND
Open mailbox for appending messages.
Definition: mxapi.h:63
#define MUTT_QUIET
Do not print any messages.
Definition: mxapi.h:65
#define SEC_INLINE
Email has an inline signature.
Definition: lib.h:85
#define SEC_AUTOCRYPT
(Autocrypt) Message will be, or was Autocrypt encrypt+signed
Definition: lib.h:87
#define SEC_OPPENCRYPT
Opportunistic encrypt mode.
Definition: lib.h:86
#define SEC_AUTOCRYPT_OVERRIDE
(Autocrypt) Indicates manual set/unset of encryption
Definition: lib.h:88
#define SEC_SIGN
Email is signed.
Definition: lib.h:79
#define STAILQ_EMPTY(head)
Definition: queue.h:348
bool read
Email is read.
Definition: email.h:48
struct ListHead chain
Mixmaster chain.
Definition: email.h:89
A mailbox.
Definition: mailbox.h:79
bool append
Mailbox is opened in append mode.
Definition: mailbox.h:109
enum MailboxType type
Mailbox type.
Definition: mailbox.h:102
struct ConfigSubset * sub
Inherited config items.
Definition: mailbox.h:83
char * committed_path
the final path generated by mx_msg_commit()
Definition: mxapi.h:46
+ Here is the call graph for this function:
+ Here is the caller graph for this function: