NeoMutt  2024-04-25-76-g20fe7b
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 <ctype.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 "copy.h"
#include "globals.h"
#include "handler.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.
 
static char * gen_msgid (void)
 Generate a random Message ID.
 
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

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

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

197{
198 struct Buffer *buf = NULL;
199 struct State state = { 0 };
200 struct stat st = { 0 };
201
202 for (; b; b = b->next)
203 {
204 if (b->type == TYPE_MULTIPART)
205 {
206 b->encoding = ENC_7BIT;
207 transform_to_7bit(b->parts, fp_in, sub);
208 }
209 else if (mutt_is_message_type(b->type, b->subtype))
210 {
211 mutt_message_to_7bit(b, fp_in, sub);
212 }
213 else
214 {
215 b->noconv = true;
216 b->force_charset = true;
217
218 /* Because of the potential recursion in message types, we
219 * restrict the lifetime of the buffer tightly */
220 buf = buf_pool_get();
221 buf_mktemp(buf);
222 state.fp_out = mutt_file_fopen(buf_string(buf), "w");
223 if (!state.fp_out)
224 {
225 mutt_perror("fopen");
226 buf_pool_release(&buf);
227 return;
228 }
229 state.fp_in = fp_in;
230 mutt_decode_attachment(b, &state);
231 mutt_file_fclose(&state.fp_out);
232 FREE(&b->d_filename);
233 b->d_filename = b->filename;
234 b->filename = buf_strdup(buf);
235 buf_pool_release(&buf);
236 b->unlink = true;
237 if (stat(b->filename, &st) == -1)
238 {
239 mutt_perror("stat");
240 return;
241 }
242 b->length = st.st_size;
243
244 mutt_update_encoding(b, sub);
245 if (b->encoding == ENC_8BIT)
247 else if (b->encoding == ENC_BINARY)
248 b->encoding = ENC_BASE64;
249 }
250 }
251}
char * buf_strdup(const struct Buffer *buf)
Copy a Buffer's string.
Definition: buffer.c:571
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:1493
#define mutt_perror(...)
Definition: logging2.h:93
void mutt_decode_attachment(const struct Body *b, struct State *state)
Decode an email's attachment.
Definition: handler.c:1905
#define FREE(x)
Definition: memory.h:45
@ 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:81
void buf_pool_release(struct Buffer **ptr)
Return a Buffer to the pool.
Definition: pool.c:94
void mutt_update_encoding(struct Body *b, struct ConfigSubset *sub)
Update the encoding type.
Definition: sendlib.c:422
static void transform_to_7bit(struct Body *b, FILE *fp_in, struct ConfigSubset *sub)
Convert MIME parts to 7-bit.
Definition: sendlib.c:196
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:259
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:36
Keep track when processing files.
Definition: state.h:48
FILE * fp_out
File to write to.
Definition: state.h:50
FILE * fp_in
File to read from.
Definition: state.h:49
#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 259 of file sendlib.c.

260{
261 struct Buffer *temp = buf_pool_get();
262 FILE *fp_in = NULL;
263 FILE *fp_out = NULL;
264 struct stat st = { 0 };
265
266 if (!b->filename && fp)
267 {
268 fp_in = fp;
269 }
270 else if (!b->filename || !(fp_in = mutt_file_fopen(b->filename, "r")))
271 {
272 mutt_error(_("Could not open %s"), b->filename ? b->filename : "(null)");
273 return;
274 }
275 else
276 {
277 b->offset = 0;
278 if (stat(b->filename, &st) == -1)
279 {
280 mutt_perror("stat");
281 mutt_file_fclose(&fp_in);
282 goto cleanup;
283 }
284 b->length = st.st_size;
285 }
286
287 /* Avoid buffer pool due to recursion */
288 buf_mktemp(temp);
289 fp_out = mutt_file_fopen(buf_string(temp), "w+");
290 if (!fp_out)
291 {
292 mutt_perror("fopen");
293 goto cleanup;
294 }
295
296 if (!mutt_file_seek(fp_in, b->offset, SEEK_SET))
297 {
298 goto cleanup;
299 }
300 b->parts = mutt_rfc822_parse_message(fp_in, b);
301
302 transform_to_7bit(b->parts, fp_in, sub);
303
304 mutt_copy_hdr(fp_in, fp_out, b->offset, b->offset + b->length,
305 CH_MIME | CH_NONEWLINE | CH_XMIT, NULL, 0);
306
307 fputs("MIME-Version: 1.0\n", fp_out);
308 mutt_write_mime_header(b->parts, fp_out, sub);
309 fputc('\n', fp_out);
310 mutt_write_mime_body(b->parts, fp_out, sub);
311
312 if (fp_in != fp)
313 mutt_file_fclose(&fp_in);
314 mutt_file_fclose(&fp_out);
315
316 b->encoding = ENC_7BIT;
317 FREE(&b->d_filename);
318 b->d_filename = b->filename;
319 if (b->filename && b->unlink)
320 unlink(b->filename);
321 b->filename = buf_strdup(temp);
322 b->unlink = true;
323 if (stat(b->filename, &st) == -1)
324 {
325 mutt_perror("stat");
326 goto cleanup;
327 }
328 b->length = st.st_size;
330 b->email->body = NULL;
331
332cleanup:
333 if (fp_in && (fp_in != fp))
334 mutt_file_fclose(&fp_in);
335
336 if (fp_out)
337 {
338 mutt_file_fclose(&fp_out);
340 }
341
342 buf_pool_release(&temp);
343}
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:108
#define CH_XMIT
Transmitting this message? (Ignore Lines: and Content-Length:)
Definition: copy.h:57
#define CH_NONEWLINE
Don't output terminating newline after the header.
Definition: copy.h:62
#define CH_MIME
Ignore MIME fields.
Definition: copy.h:63
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:1832
bool mutt_file_seek(FILE *fp, LOFF_T offset, int whence)
Wrapper for fseeko with error handling.
Definition: file.c:778
void mutt_file_unlink(const char *s)
Delete a file, carefully.
Definition: file.c:221
int mutt_write_mime_header(struct Body *b, FILE *fp, struct ConfigSubset *sub)
Create a MIME header.
Definition: header.c:756
int mutt_write_mime_body(struct Body *b, FILE *fp, struct ConfigSubset *sub)
Write a MIME part.
Definition: body.c:300
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: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 351 of file sendlib.c.

352{
353 const bool c_allow_8bit = cs_subset_bool(sub, "allow_8bit");
354 if (b->type == TYPE_TEXT)
355 {
356 const bool c_encode_from = cs_subset_bool(sub, "encode_from");
357 char send_charset[128] = { 0 };
358 char *chsname = mutt_body_get_charset(b, send_charset, sizeof(send_charset));
359 if ((info->lobin && !mutt_istr_startswith(chsname, "iso-2022")) ||
360 (info->linemax > 990) || (info->from && c_encode_from))
361 {
363 }
364 else if (info->hibin)
365 {
366 b->encoding = c_allow_8bit ? ENC_8BIT : ENC_QUOTED_PRINTABLE;
367 }
368 else
369 {
370 b->encoding = ENC_7BIT;
371 }
372 }
373 else if ((b->type == TYPE_MESSAGE) || (b->type == TYPE_MULTIPART))
374 {
375 if (info->lobin || info->hibin)
376 {
377 if (c_allow_8bit && !info->lobin)
378 b->encoding = ENC_8BIT;
379 else
380 mutt_message_to_7bit(b, NULL, sub);
381 }
382 else
383 {
384 b->encoding = ENC_7BIT;
385 }
386 }
387 else if ((b->type == TYPE_APPLICATION) && mutt_istr_equal(b->subtype, "pgp-keys"))
388 {
389 b->encoding = ENC_7BIT;
390 }
391 else
392 {
393 /* Determine which encoding is smaller */
394 if (1.33 * (float) (info->lobin + info->hibin + info->ascii) <
395 3.0 * (float) (info->lobin + info->hibin) + (float) info->ascii)
396 {
397 b->encoding = ENC_BASE64;
398 }
399 else
400 {
402 }
403 }
404}
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:132
@ 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:242
long hibin
8-bit characters
Definition: content.h:37
long ascii
Number of ascii chars.
Definition: content.h:41
bool from
Has a line beginning with "From "?
Definition: content.h:45
long linemax
Length of the longest line in the file.
Definition: content.h:42
long lobin
Unprintable 7-bit chars (eg., control chars)
Definition: content.h:38
+ 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 410 of file sendlib.c.

411{
412 b->stamp = mutt_date_now();
413}
time_t mutt_date_now(void)
Return the number of seconds since the Unix epoch.
Definition: date.c:456
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 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 422 of file sendlib.c.

423{
424 struct Content *info = NULL;
425 char chsbuf[256] = { 0 };
426
427 /* override noconv when it's us-ascii */
428 if (mutt_ch_is_us_ascii(mutt_body_get_charset(b, chsbuf, sizeof(chsbuf))))
429 b->noconv = false;
430
431 if (!b->force_charset && !b->noconv)
432 mutt_param_delete(&b->parameter, "charset");
433
434 info = mutt_get_content_info(b->filename, b, sub);
435 if (!info)
436 return;
437
438 set_encoding(b, info, sub);
440
441 FREE(&b->content);
442 b->content = info;
443}
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:188
#define mutt_ch_is_us_ascii(str)
Definition: charset.h:99
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:351
void mutt_stamp_attachment(struct Body *b)
Timestamp an Attachment.
Definition: sendlib.c:410
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:36
+ 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 454 of file sendlib.c.

456{
457 struct Body *body = NULL;
458 FILE *fp = NULL;
459 CopyMessageFlags cmflags;
461
462 const bool c_mime_forward_decode = cs_subset_bool(sub, "mime_forward_decode");
463 const bool c_forward_decrypt = cs_subset_bool(sub, "forward_decrypt");
464 if (WithCrypto)
465 {
466 if ((c_mime_forward_decode || c_forward_decrypt) && (e->security & SEC_ENCRYPT))
467 {
469 return NULL;
470 }
471 }
472
473 struct Buffer *buf = buf_pool_get();
474 buf_mktemp(buf);
475 fp = mutt_file_fopen_masked(buf_string(buf), "w+");
476 if (!fp)
477 {
478 buf_pool_release(&buf);
479 return NULL;
480 }
481
482 body = mutt_body_new();
483 body->type = TYPE_MESSAGE;
484 body->subtype = mutt_str_dup("rfc822");
485 body->filename = mutt_str_dup(buf_string(buf));
486 body->unlink = true;
487 body->use_disp = false;
488 body->disposition = DISP_INLINE;
489 body->noconv = true;
490
491 buf_pool_release(&buf);
492
493 struct Message *msg = mx_msg_open(m, e);
494 if (!msg)
495 {
496 mutt_body_free(&body);
498 return NULL;
499 }
501
502 CopyHeaderFlags chflags = CH_XMIT;
503 cmflags = MUTT_CM_NO_FLAGS;
504
505 /* If we are attaching a message, ignore `$mime_forward_decode` */
506 if (!attach_msg && c_mime_forward_decode)
507 {
508 chflags |= CH_MIME | CH_TXTPLAIN;
511 pgp &= ~PGP_ENCRYPT;
513 pgp &= ~SMIME_ENCRYPT;
514 }
515 else if ((WithCrypto != 0) && c_forward_decrypt && (e->security & SEC_ENCRYPT))
516 {
518 {
519 chflags |= CH_MIME | CH_NONEWLINE;
520 cmflags = MUTT_CM_DECODE_PGP;
521 pgp &= ~PGP_ENCRYPT;
522 }
523 else if (((WithCrypto & APPLICATION_PGP) != 0) &&
525 {
526 chflags |= CH_MIME | CH_TXTPLAIN;
528 pgp &= ~PGP_ENCRYPT;
529 }
530 else if (((WithCrypto & APPLICATION_SMIME) != 0) &&
532 {
533 chflags |= CH_MIME | CH_NONEWLINE;
534 cmflags = MUTT_CM_DECODE_SMIME;
535 pgp &= ~SMIME_ENCRYPT;
536 }
537 }
538
539 mutt_copy_message(fp, e, msg, cmflags, chflags, 0);
540 mx_msg_close(m, &msg);
541
542 fflush(fp);
543 rewind(fp);
544
545 body->email = email_new();
546 body->email->offset = 0;
547 /* we don't need the user headers here */
548 body->email->env = mutt_rfc822_read_header(fp, body->email, false, false);
549 if (WithCrypto)
550 body->email->security = pgp;
551 mutt_update_encoding(body, sub);
552 body->parts = body->email->body;
553
555
556 return body;
557}
void mutt_parse_mime_message(struct Email *e, FILE *fp)
Parse a MIME email.
Definition: attachments.c:597
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:907
#define MUTT_CM_DECODE_PGP
Used for decoding PGP messages.
Definition: copy.h:47
#define MUTT_CM_DECODE
Decode the message body into text/plain.
Definition: copy.h:40
#define MUTT_CM_CHARCONV
Perform character set conversions.
Definition: copy.h:44
#define MUTT_CM_DECODE_SMIME
Used for decoding S/MIME messages.
Definition: copy.h:48
uint32_t CopyHeaderFlags
Flags for mutt_copy_header(), e.g. CH_UPDATE.
Definition: copy.h:52
#define MUTT_CM_NO_FLAGS
No flags are set.
Definition: copy.h:37
#define CH_TXTPLAIN
Generate text/plain MIME headers.
Definition: copy.h:65
uint16_t CopyMessageFlags
Flags for mutt_copy_message(), e.g. MUTT_CM_NOHEADER.
Definition: copy.h:36
SecurityFlags mutt_is_application_smime(struct Body *b)
Does the message use S/MIME?
Definition: crypt.c:609
bool crypt_valid_passphrase(SecurityFlags flags)
Check that we have a usable passphrase, ask if not.
Definition: crypt.c:132
SecurityFlags mutt_is_multipart_encrypted(struct Body *b)
Does the message have encrypted parts?
Definition: crypt.c:443
SecurityFlags mutt_is_application_pgp(const struct Body *b)
Does the message use PGP?
Definition: crypt.c:548
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:80
struct Envelope * mutt_rfc822_read_header(FILE *fp, struct Email *e, bool user_hdrs, bool weed)
Parses an RFC822 header.
Definition: parse.c:1200
@ DISP_INLINE
Content is inline.
Definition: mime.h:62
char * mutt_str_dup(const char *str)
Copy a string, safely.
Definition: string.c:253
int mx_msg_close(struct Mailbox *m, struct Message **ptr)
Close a message.
Definition: mx.c:1180
struct Message * mx_msg_open(struct Mailbox *m, struct Email *e)
Return a stream pointer for a message.
Definition: mx.c:1134
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
#define mutt_file_fopen_masked(PATH, MODE)
Definition: neomutt.h:75
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 566 of file sendlib.c.

567{
568 FILE *fp = NULL, *fp_err = NULL;
569 char *buf = NULL;
570 size_t buflen;
571 pid_t pid;
572 struct Buffer *cmd = buf_pool_get();
573
574 const char *const c_mime_type_query_command = cs_subset_string(sub, "mime_type_query_command");
575
576 buf_file_expand_fmt_quote(cmd, c_mime_type_query_command, b->filename);
577
578 pid = filter_create(buf_string(cmd), NULL, &fp, &fp_err, EnvList);
579 if (pid < 0)
580 {
581 mutt_error(_("Error running \"%s\""), buf_string(cmd));
582 buf_pool_release(&cmd);
583 return;
584 }
585 buf_pool_release(&cmd);
586
587 buf = mutt_file_read_line(buf, &buflen, fp, NULL, MUTT_RL_NO_FLAGS);
588 if (buf)
589 {
590 if (strchr(buf, '/'))
592 FREE(&buf);
593 }
594
595 mutt_file_fclose(&fp);
596 mutt_file_fclose(&fp_err);
597 filter_wait(pid);
598}
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:463
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:808
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:1456
#define MUTT_RL_NO_FLAGS
No flags are set.
Definition: file.h:40
char ** EnvList
Private copy of the environment variables.
Definition: globals.c:78
int filter_wait(pid_t pid)
Wait for the exit of a process and return its status.
Definition: filter.c:220
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:209
+ 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 607 of file sendlib.c.

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

668{
669 char *tmp = NULL;
670 char *p = NULL;
671 int i;
672
673 const struct Slist *const c_send_charset = cs_subset_slist(sub, "send_charset");
674
675 struct ListNode *np = NULL;
676 STAILQ_FOREACH(np, h, entries)
677 {
678 p = strchr(NONULL(np->data), ':');
679 if (!p)
680 continue;
681
682 i = p - np->data;
683 p = mutt_str_skip_email_wsp(p + 1);
684 tmp = mutt_str_dup(p);
685
686 if (!tmp)
687 continue;
688
689 rfc2047_encode(&tmp, NULL, i + 2, c_send_charset);
690 mutt_mem_realloc(&np->data, i + 2 + mutt_str_len(tmp) + 1);
691
692 sprintf(np->data + i + 2, "%s", tmp);
693
694 FREE(&tmp);
695 }
696}
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
void mutt_mem_realloc(void *ptr, size_t size)
Resize a block of memory on the heap.
Definition: memory.c:115
char * mutt_str_skip_email_wsp(const char *s)
Skip over whitespace as defined by RFC5322.
Definition: string.c:608
#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:628
A List node for strings.
Definition: list.h:36
char * data
String.
Definition: list.h:37
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 707 of file sendlib.c.

708{
709 const char *const c_hostname = cs_subset_string(sub, "hostname");
710 if (!c_hostname || (c_hostname[0] == '@'))
711 return NULL;
712
713 const char *p = c_hostname;
714
715 const bool c_hidden_host = cs_subset_bool(sub, "hidden_host");
716 if (may_hide_host && c_hidden_host)
717 {
718 p = strchr(c_hostname, '.');
719 if (p)
720 p++;
721
722 // sanity check: don't hide the host if the fqdn is something like example.com
723 if (!p || !strchr(p, '.'))
724 p = c_hostname;
725 }
726
727 return p;
728}
+ 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 753 of file sendlib.c.

754{
755 const int ID_LEFT_LEN = 50;
756 const int ID_RIGHT_LEN = 12;
757 char rnd_id_left[ID_LEFT_LEN + 1];
758 char rnd_id_right[ID_RIGHT_LEN + 1];
759 char buf[128] = { 0 };
760
761 mutt_rand_base32(rnd_id_left, sizeof(rnd_id_left) - 1);
762 mutt_rand_base32(rnd_id_right, sizeof(rnd_id_right) - 1);
763 rnd_id_left[ID_LEFT_LEN] = 0;
764 rnd_id_right[ID_RIGHT_LEN] = 0;
765
766 snprintf(buf, sizeof(buf), "<%s@%s>", rnd_id_left, rnd_id_right);
767 return mutt_str_dup(buf);
768}
void mutt_rand_base32(char *buf, size_t buflen)
Fill a buffer with a base32-encoded random string.
Definition: random.c:106
+ 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 780 of file sendlib.c.

781{
782 if (final)
783 {
784 if (!TAILQ_EMPTY(&env->bcc) && TAILQ_EMPTY(&env->to) && TAILQ_EMPTY(&env->cc))
785 {
786 /* some MTA's will put an Apparently-To: header field showing the Bcc:
787 * recipients if there is no To: or Cc: field, so attempt to suppress
788 * it by using an empty To: field. */
789 struct Address *to = mutt_addr_new();
790 to->group = true;
791 mutt_addrlist_append(&env->to, to);
793
794 char buf[1024] = { 0 };
795 buf[0] = '\0';
796 mutt_addr_cat(buf, sizeof(buf), "undisclosed-recipients", AddressSpecials);
797
798 buf_strcpy(to->mailbox, buf);
799 }
800
801 mutt_set_followup_to(env, sub);
802
803 if (!env->message_id)
804 env->message_id = gen_msgid();
805 }
806
807 /* Take care of 8-bit => 7-bit conversion. */
809 encode_headers(&env->userhdrs, sub);
810}
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:708
void mutt_addrlist_append(struct AddressList *al, struct Address *a)
Append an Address to an AddressList.
Definition: address.c:1480
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:395
#define TAILQ_EMPTY(head)
Definition: queue.h:721
void rfc2047_encode_envelope(struct Envelope *env)
Encode the fields of an Envelope.
Definition: rfc2047.c:857
void mutt_set_followup_to(struct Envelope *env, struct ConfigSubset *sub)
Set followup-to field.
Definition: send.c:1337
static char * gen_msgid(void)
Generate a random Message ID.
Definition: sendlib.c:753
static void encode_headers(struct ListHead *h, struct ConfigSubset *sub)
RFC2047-encode a list of headers.
Definition: sendlib.c:667
An email address.
Definition: address.h:36
bool group
Group mailbox?
Definition: address.h:39
struct Buffer * mailbox
Mailbox and host address.
Definition: address.h:38
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 819 of file sendlib.c.

820{
821 struct ListNode *item = NULL;
822 STAILQ_FOREACH(item, &env->userhdrs, entries)
823 {
824 rfc2047_decode(&item->data);
825 }
826
828
829 /* back conversions */
831}
void mutt_addrlist_clear(struct AddressList *al)
Unlink and free all Address in an AddressList.
Definition: address.c:1460
void rfc2047_decode_envelope(struct Envelope *env)
Decode the fields of an Envelope.
Definition: rfc2047.c:832
void rfc2047_decode(char **pd)
Decode any RFC2047-encoded header fields.
Definition: rfc2047.c:661
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 845 of file sendlib.c.

848{
849 if (!e)
850 return -1;
851
852 int rc = 0;
853
854 struct Buffer *tempfile = buf_pool_get();
855 buf_mktemp(tempfile);
856 FILE *fp_tmp = mutt_file_fopen(buf_string(tempfile), "w");
857 if (fp_tmp)
858 {
860
861 const bool c_bounce_delivered = cs_subset_bool(sub, "bounce_delivered");
862 if (!c_bounce_delivered)
863 chflags |= CH_WEED_DELIVERED;
864
865 if (!mutt_file_seek(fp, e->offset, SEEK_SET))
866 {
867 (void) mutt_file_fclose(&fp_tmp);
868 return -1;
869 }
870 fprintf(fp_tmp, "Resent-From: %s\n", resent_from);
871
872 struct Buffer *date = buf_pool_get();
873 mutt_date_make_date(date, cs_subset_bool(sub, "local_date_header"));
874 fprintf(fp_tmp, "Resent-Date: %s\n", buf_string(date));
875 buf_pool_release(&date);
876
877 char *msgid_str = gen_msgid();
878 fprintf(fp_tmp, "Resent-Message-ID: %s\n", msgid_str);
879 FREE(&msgid_str);
880 mutt_addrlist_write_file(to, fp_tmp, "Resent-To");
881 mutt_copy_header(fp, e, fp_tmp, chflags, NULL, 0);
882 fputc('\n', fp_tmp);
883 mutt_file_copy_bytes(fp, fp_tmp, e->body->length);
884 if (mutt_file_fclose(&fp_tmp) != 0)
885 {
886 mutt_perror("%s", buf_string(tempfile));
887 unlink(buf_string(tempfile));
888 return -1;
889 }
890 const char *const c_smtp_url = cs_subset_string(sub, "smtp_url");
891 if (c_smtp_url)
892 {
893 rc = mutt_smtp_send(env_from, to, NULL, NULL, buf_string(tempfile),
894 (e->body->encoding == ENC_8BIT), sub);
895 }
896 else
897 {
898 rc = mutt_invoke_sendmail(m, env_from, to, NULL, NULL, buf_string(tempfile),
899 (e->body->encoding == ENC_8BIT), sub);
900 }
901 }
902
903 buf_pool_release(&tempfile);
904 return rc;
905}
void mutt_addrlist_write_file(const struct AddressList *al, FILE *fp, const char *header)
Wrapper for mutt_write_address()
Definition: address.c:1248
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:425
#define CH_WEED_DELIVERED
Weed eventual Delivered-To headers.
Definition: copy.h:67
#define CH_NOQFROM
Ignore ">From " line.
Definition: copy.h:69
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:257
void mutt_date_make_date(struct Buffer *buf, bool local)
Write a date in RFC822 format to a buffer.
Definition: date.c:397
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:300
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:1100
+ 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 917 of file sendlib.c.

919{
920 if (!fp || !e || !to || TAILQ_EMPTY(to))
921 return -1;
922
923 const char *fqdn = mutt_fqdn(true, sub);
924 char *err = NULL;
925
926 struct Address *from = mutt_default_from(sub);
927 struct AddressList from_list = TAILQ_HEAD_INITIALIZER(from_list);
928 mutt_addrlist_append(&from_list, from);
929
930 /* mutt_default_from() does not use $real_name if the real name is not set
931 * in $from, so we add it here. The reason it is not added in
932 * mutt_default_from() is that during normal sending, we execute
933 * send-hooks and set the real_name last so that it can be changed based
934 * upon message criteria. */
935 if (!from->personal)
936 {
937 const char *const c_real_name = cs_subset_string(sub, "real_name");
938 if (c_real_name)
939 from->personal = buf_new(c_real_name);
940 }
941
942 mutt_addrlist_qualify(&from_list, fqdn);
943
944 rfc2047_encode_addrlist(&from_list, "Resent-From");
945 if (mutt_addrlist_to_intl(&from_list, &err))
946 {
947 mutt_error(_("Bad IDN %s while preparing resent-from"), err);
948 FREE(&err);
949 mutt_addrlist_clear(&from_list);
950 return -1;
951 }
952 struct Buffer *resent_from = buf_pool_get();
953 mutt_addrlist_write(&from_list, resent_from, false);
954
955 OptNewsSend = false;
956
957 /* prepare recipient list. idna conversion appears to happen before this
958 * function is called, since the user receives confirmation of the address
959 * list being bounced to. */
960 struct AddressList resent_to = TAILQ_HEAD_INITIALIZER(resent_to);
961 mutt_addrlist_copy(&resent_to, to, false);
962 rfc2047_encode_addrlist(&resent_to, "Resent-To");
963 int rc = bounce_message(fp, m, e, &resent_to, buf_string(resent_from), &from_list, sub);
964 mutt_addrlist_clear(&resent_to);
965 mutt_addrlist_clear(&from_list);
966 buf_pool_release(&resent_from);
967 return rc;
968}
void mutt_addrlist_copy(struct AddressList *dst, const struct AddressList *src, bool prune)
Copy a list of addresses into another list.
Definition: address.c:765
void mutt_addrlist_qualify(struct AddressList *al, const char *host)
Expand local names in an Address list using a hostname.
Definition: address.c:680
size_t mutt_addrlist_write(const struct AddressList *al, struct Buffer *buf, bool display)
Write an Address to a buffer.
Definition: address.c:1206
int mutt_addrlist_to_intl(struct AddressList *al, char **err)
Convert an Address list to Punycode.
Definition: address.c:1293
struct Buffer * buf_new(const char *str)
Allocate a new Buffer.
Definition: buffer.c:304
bool OptNewsSend
(pseudo) used to change behavior when posting
Definition: globals.c:71
#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:766
struct Address * mutt_default_from(struct ConfigSubset *sub)
Get a default 'from' Address.
Definition: send.c:1461
const char * mutt_fqdn(bool may_hide_host, const struct ConfigSubset *sub)
Get the Fully-Qualified Domain Name.
Definition: sendlib.c:707
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:845
struct Buffer * 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 975 of file sendlib.c.

976{
977 for (; b; b = b->next)
978 {
979 if ((b->type == TYPE_MESSAGE) || (b->type == TYPE_MULTIPART))
980 {
981 set_noconv_flags(b->parts, flag);
982 }
983 else if ((b->type == TYPE_TEXT) && b->noconv)
984 {
985 if (flag)
986 mutt_param_set(&b->parameter, "x-mutt-noconv", "yes");
987 else
988 mutt_param_delete(&b->parameter, "x-mutt-noconv");
989 }
990 }
991}
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:975
+ 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 1005 of file sendlib.c.

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

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