NeoMutt
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 <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 *att, const char *path)
 Find the MIME type for an attachment.
 
static void transform_to_7bit (struct Body *a, FILE *fp_in, struct ConfigSubset *sub)
 Convert MIME parts to 7-bit.
 
void mutt_message_to_7bit (struct Body *a, 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 *a)
 Timestamp an Attachment.
 
void mutt_update_encoding (struct Body *a, 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 *att, 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
  • 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
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 74 of file sendlib.c.

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

195{
196 struct Buffer *buf = NULL;
197 struct State state = { 0 };
198 struct stat st = { 0 };
199
200 for (; a; a = a->next)
201 {
202 if (a->type == TYPE_MULTIPART)
203 {
204 a->encoding = ENC_7BIT;
205 transform_to_7bit(a->parts, fp_in, sub);
206 }
207 else if (mutt_is_message_type(a->type, a->subtype))
208 {
209 mutt_message_to_7bit(a, fp_in, sub);
210 }
211 else
212 {
213 a->noconv = true;
214 a->force_charset = true;
215
216 /* Because of the potential recursion in message types, we
217 * restrict the lifetime of the buffer tightly */
218 buf = buf_pool_get();
219 buf_mktemp(buf);
220 state.fp_out = mutt_file_fopen(buf_string(buf), "w");
221 if (!state.fp_out)
222 {
223 mutt_perror("fopen");
224 buf_pool_release(&buf);
225 return;
226 }
227 state.fp_in = fp_in;
228 mutt_decode_attachment(a, &state);
229 mutt_file_fclose(&state.fp_out);
230 FREE(&a->d_filename);
231 a->d_filename = a->filename;
232 a->filename = buf_strdup(buf);
233 buf_pool_release(&buf);
234 a->unlink = true;
235 if (stat(a->filename, &st) == -1)
236 {
237 mutt_perror("stat");
238 return;
239 }
240 a->length = st.st_size;
241
242 mutt_update_encoding(a, sub);
243 if (a->encoding == ENC_8BIT)
245 else if (a->encoding == ENC_BINARY)
246 a->encoding = ENC_BASE64;
247 }
248 }
249}
char * buf_strdup(const struct Buffer *buf)
Copy a Buffer's string.
Definition: buffer.c:542
static const char * buf_string(const struct Buffer *buf)
Convert a buffer to a const char * "string".
Definition: buffer.h:93
bool mutt_is_message_type(int type, const char *subtype)
Determine if a mime type matches a message or not.
Definition: parse.c:1482
FILE * mutt_file_fopen(const char *path, const char *mode)
Call fopen() safely.
Definition: file.c:636
#define mutt_perror(...)
Definition: logging2.h:93
void mutt_decode_attachment(struct Body *b, struct State *state)
Decode an email's attachment.
Definition: handler.c:1892
#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_message_to_7bit(struct Body *a, FILE *fp, struct ConfigSubset *sub)
Convert an email's MIME parts to 7-bit.
Definition: sendlib.c:257
static void transform_to_7bit(struct Body *a, FILE *fp_in, struct ConfigSubset *sub)
Convert MIME parts to 7-bit.
Definition: sendlib.c:194
void mutt_update_encoding(struct Body *a, struct ConfigSubset *sub)
Update the encoding type.
Definition: sendlib.c:420
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 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 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 257 of file sendlib.c.

258{
259 struct Buffer temp = buf_make(0);
260 FILE *fp_in = NULL;
261 FILE *fp_out = NULL;
262 struct stat st = { 0 };
263
264 if (!a->filename && fp)
265 {
266 fp_in = fp;
267 }
268 else if (!a->filename || !(fp_in = fopen(a->filename, "r")))
269 {
270 mutt_error(_("Could not open %s"), a->filename ? a->filename : "(null)");
271 return;
272 }
273 else
274 {
275 a->offset = 0;
276 if (stat(a->filename, &st) == -1)
277 {
278 mutt_perror("stat");
279 mutt_file_fclose(&fp_in);
280 goto cleanup;
281 }
282 a->length = st.st_size;
283 }
284
285 /* Avoid buffer pool due to recursion */
286 buf_mktemp(&temp);
287 fp_out = mutt_file_fopen(buf_string(&temp), "w+");
288 if (!fp_out)
289 {
290 mutt_perror("fopen");
291 goto cleanup;
292 }
293
294 if (!mutt_file_seek(fp_in, a->offset, SEEK_SET))
295 {
296 goto cleanup;
297 }
298 a->parts = mutt_rfc822_parse_message(fp_in, a);
299
300 transform_to_7bit(a->parts, fp_in, sub);
301
302 mutt_copy_hdr(fp_in, fp_out, a->offset, a->offset + a->length,
303 CH_MIME | CH_NONEWLINE | CH_XMIT, NULL, 0);
304
305 fputs("MIME-Version: 1.0\n", fp_out);
306 mutt_write_mime_header(a->parts, fp_out, sub);
307 fputc('\n', fp_out);
308 mutt_write_mime_body(a->parts, fp_out, sub);
309
310 if (fp_in != fp)
311 mutt_file_fclose(&fp_in);
312 mutt_file_fclose(&fp_out);
313
314 a->encoding = ENC_7BIT;
315 FREE(&a->d_filename);
316 a->d_filename = a->filename;
317 if (a->filename && a->unlink)
318 unlink(a->filename);
319 a->filename = buf_strdup(&temp);
320 a->unlink = true;
321 if (stat(a->filename, &st) == -1)
322 {
323 mutt_perror("stat");
324 goto cleanup;
325 }
326 a->length = st.st_size;
328 a->email->body = NULL;
329
330cleanup:
331 if (fp_in && (fp_in != fp))
332 mutt_file_fclose(&fp_in);
333
334 if (fp_out)
335 {
336 mutt_file_fclose(&fp_out);
338 }
339
340 buf_dealloc(&temp);
341}
void buf_dealloc(struct Buffer *buf)
Release the memory allocated by a buffer.
Definition: buffer.c:389
struct Buffer buf_make(size_t size)
Make a new buffer on the stack.
Definition: buffer.c:70
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:106
#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
struct Body * mutt_rfc822_parse_message(FILE *fp, struct Body *parent)
Parse a Message/RFC822 body.
Definition: parse.c:1794
bool mutt_file_seek(FILE *fp, LOFF_T offset, int whence)
Wrapper for fseeko with error handling.
Definition: file.c:733
void mutt_file_unlink(const char *s)
Delete a file, carefully.
Definition: file.c:196
int mutt_write_mime_header(struct Body *a, FILE *fp, struct ConfigSubset *sub)
Create a MIME header.
Definition: header.c:758
int mutt_write_mime_body(struct Body *a, FILE *fp, struct ConfigSubset *sub)
Write a MIME part.
Definition: body.c:301
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 349 of file sendlib.c.

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

409{
410 a->stamp = mutt_date_now();
411}
time_t mutt_date_now(void)
Return the number of seconds since the Unix epoch.
Definition: date.c:446
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 420 of file sendlib.c.

421{
422 struct Content *info = NULL;
423 char chsbuf[256] = { 0 };
424
425 /* override noconv when it's us-ascii */
426 if (mutt_ch_is_us_ascii(mutt_body_get_charset(a, chsbuf, sizeof(chsbuf))))
427 a->noconv = false;
428
429 if (!a->force_charset && !a->noconv)
430 mutt_param_delete(&a->parameter, "charset");
431
432 info = mutt_get_content_info(a->filename, a, sub);
433 if (!info)
434 return;
435
436 set_encoding(a, info, sub);
438
439 FREE(&a->content);
440 a->content = info;
441}
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:187
#define mutt_ch_is_us_ascii(str)
Definition: charset.h:97
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:408
static void set_encoding(struct Body *b, struct Content *info, struct ConfigSubset *sub)
Determine which Content-Transfer-Encoding to use.
Definition: sendlib.c:349
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 452 of file sendlib.c.

454{
455 struct Body *body = NULL;
456 FILE *fp = NULL;
457 CopyMessageFlags cmflags;
459
460 const bool c_mime_forward_decode = cs_subset_bool(sub, "mime_forward_decode");
461 const bool c_forward_decrypt = cs_subset_bool(sub, "forward_decrypt");
462 if (WithCrypto)
463 {
464 if ((c_mime_forward_decode || c_forward_decrypt) && (e->security & SEC_ENCRYPT))
465 {
467 return NULL;
468 }
469 }
470
471 struct Buffer *buf = buf_pool_get();
472 buf_mktemp(buf);
473 fp = mutt_file_fopen(buf_string(buf), "w+");
474 if (!fp)
475 {
476 buf_pool_release(&buf);
477 return NULL;
478 }
479
480 body = mutt_body_new();
481 body->type = TYPE_MESSAGE;
482 body->subtype = mutt_str_dup("rfc822");
483 body->filename = mutt_str_dup(buf_string(buf));
484 body->unlink = true;
485 body->use_disp = false;
486 body->disposition = DISP_INLINE;
487 body->noconv = true;
488
489 buf_pool_release(&buf);
490
491 struct Message *msg = mx_msg_open(m, e);
492 if (!msg)
493 {
494 mutt_body_free(&body);
496 return NULL;
497 }
499
500 CopyHeaderFlags chflags = CH_XMIT;
501 cmflags = MUTT_CM_NO_FLAGS;
502
503 /* If we are attaching a message, ignore `$mime_forward_decode` */
504 if (!attach_msg && c_mime_forward_decode)
505 {
506 chflags |= CH_MIME | CH_TXTPLAIN;
509 pgp &= ~PGP_ENCRYPT;
511 pgp &= ~SMIME_ENCRYPT;
512 }
513 else if ((WithCrypto != 0) && c_forward_decrypt && (e->security & SEC_ENCRYPT))
514 {
516 {
517 chflags |= CH_MIME | CH_NONEWLINE;
518 cmflags = MUTT_CM_DECODE_PGP;
519 pgp &= ~PGP_ENCRYPT;
520 }
521 else if (((WithCrypto & APPLICATION_PGP) != 0) &&
523 {
524 chflags |= CH_MIME | CH_TXTPLAIN;
526 pgp &= ~PGP_ENCRYPT;
527 }
528 else if (((WithCrypto & APPLICATION_SMIME) != 0) &&
530 {
531 chflags |= CH_MIME | CH_TXTPLAIN;
533 pgp &= ~SMIME_ENCRYPT;
534 }
535 }
536
537 mutt_copy_message(fp, e, msg, cmflags, chflags, 0);
538 mx_msg_close(m, &msg);
539
540 fflush(fp);
541 rewind(fp);
542
543 body->email = email_new();
544 body->email->offset = 0;
545 /* we don't need the user headers here */
546 body->email->env = mutt_rfc822_read_header(fp, body->email, false, false);
547 if (WithCrypto)
548 body->email->security = pgp;
549 mutt_update_encoding(body, sub);
550 body->parts = body->email->body;
551
553
554 return body;
555}
void mutt_parse_mime_message(struct Email *e, FILE *fp)
Parse a MIME email.
Definition: attachments.c:596
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:884
#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:537
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:135
SecurityFlags mutt_is_multipart_encrypted(struct Body *b)
Does the message have encrypted parts?
Definition: crypt.c:432
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
struct Envelope * mutt_rfc822_read_header(FILE *fp, struct Email *e, bool user_hdrs, bool weed)
Parses an RFC822 header.
Definition: parse.c:1170
@ DISP_INLINE
Content is inline.
Definition: mime.h:62
char * mutt_str_dup(const char *str)
Copy a string, safely.
Definition: string.c:251
int mx_msg_close(struct Mailbox *m, struct Message **ptr)
Close a message.
Definition: mx.c:1206
struct Message * mx_msg_open(struct Mailbox *m, struct Email *e)
Return a stream pointer for a message.
Definition: mx.c:1160
uint16_t SecurityFlags
Flags, e.g. SEC_ENCRYPT.
Definition: lib.h:77
#define APPLICATION_PGP
Use PGP to encrypt/sign.
Definition: lib.h:91
#define PGP_ENCRYPT
Definition: lib.h:97
#define APPLICATION_SMIME
Use SMIME to encrypt/sign.
Definition: lib.h:92
#define SEC_NO_FLAGS
No flags are set.
Definition: lib.h:78
#define SEC_ENCRYPT
Email is encrypted.
Definition: lib.h:79
#define SMIME_ENCRYPT
Definition: lib.h:103
#define WithCrypto
Definition: lib.h:117
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
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 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 564 of file sendlib.c.

565{
566 FILE *fp = NULL, *fp_err = NULL;
567 char *buf = NULL;
568 size_t buflen;
569 pid_t pid;
570 struct Buffer *cmd = buf_pool_get();
571
572 const char *const c_mime_type_query_command = cs_subset_string(sub, "mime_type_query_command");
573
574 buf_file_expand_fmt_quote(cmd, c_mime_type_query_command, att->filename);
575
576 pid = filter_create(buf_string(cmd), NULL, &fp, &fp_err, EnvList);
577 if (pid < 0)
578 {
579 mutt_error(_("Error running \"%s\""), buf_string(cmd));
580 buf_pool_release(&cmd);
581 return;
582 }
583 buf_pool_release(&cmd);
584
585 buf = mutt_file_read_line(buf, &buflen, fp, NULL, MUTT_RL_NO_FLAGS);
586 if (buf)
587 {
588 if (strchr(buf, '/'))
589 mutt_parse_content_type(buf, att);
590 FREE(&buf);
591 }
592
593 mutt_file_fclose(&fp);
594 mutt_file_fclose(&fp_err);
595 filter_wait(pid);
596}
const char * cs_subset_string(const struct ConfigSubset *sub, const char *name)
Get a string config item by name.
Definition: helpers.c:292
void mutt_parse_content_type(const char *s, struct Body *ct)
Parse a content type.
Definition: parse.c:426
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:763
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:1497
#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:218
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:207
char ** EnvList
Private copy of the environment variables.
Definition: globals.c:85
+ 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 605 of file sendlib.c.

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

666{
667 char *tmp = NULL;
668 char *p = NULL;
669 int i;
670
671 const struct Slist *const c_send_charset = cs_subset_slist(sub, "send_charset");
672
673 struct ListNode *np = NULL;
674 STAILQ_FOREACH(np, h, entries)
675 {
676 p = strchr(NONULL(np->data), ':');
677 if (!p)
678 continue;
679
680 i = p - np->data;
681 p = mutt_str_skip_email_wsp(p + 1);
682 tmp = mutt_str_dup(p);
683
684 if (!tmp)
685 continue;
686
687 rfc2047_encode(&tmp, NULL, i + 2, c_send_charset);
688 mutt_mem_realloc(&np->data, i + 2 + mutt_str_len(tmp) + 1);
689
690 sprintf(np->data + i + 2, "%s", tmp);
691
692 FREE(&tmp);
693 }
694}
const struct Slist * cs_subset_slist(const struct ConfigSubset *sub, const char *name)
Get a string-list config item by name.
Definition: helpers.c:243
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:680
#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:626
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 705 of file sendlib.c.

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

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

779{
780 if (final)
781 {
782 if (!TAILQ_EMPTY(&env->bcc) && TAILQ_EMPTY(&env->to) && TAILQ_EMPTY(&env->cc))
783 {
784 /* some MTA's will put an Apparently-To: header field showing the Bcc:
785 * recipients if there is no To: or Cc: field, so attempt to suppress
786 * it by using an empty To: field. */
787 struct Address *to = mutt_addr_new();
788 to->group = true;
789 mutt_addrlist_append(&env->to, to);
791
792 char buf[1024] = { 0 };
793 buf[0] = '\0';
794 mutt_addr_cat(buf, sizeof(buf), "undisclosed-recipients", AddressSpecials);
795
796 buf_strcpy(to->mailbox, buf);
797 }
798
799 mutt_set_followup_to(env, sub);
800
801 if (!env->message_id)
802 env->message_id = gen_msgid();
803 }
804
805 /* Take care of 8-bit => 7-bit conversion. */
807 encode_headers(&env->userhdrs, sub);
808}
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:705
void mutt_addrlist_append(struct AddressList *al, struct Address *a)
Append an Address to an AddressList.
Definition: address.c:1481
struct Address * mutt_addr_new(void)
Create a new Address.
Definition: address.c:399
const char AddressSpecials[]
Characters with special meaning for email addresses.
Definition: address.c:43
size_t buf_strcpy(struct Buffer *buf, const char *s)
Copy a string into a Buffer.
Definition: buffer.c:407
#define TAILQ_EMPTY(head)
Definition: queue.h:721
void rfc2047_encode_envelope(struct Envelope *env)
Encode the fields of an Envelope.
Definition: rfc2047.c:848
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:751
static void encode_headers(struct ListHead *h, struct ConfigSubset *sub)
RFC2047-encode a list of headers.
Definition: sendlib.c:665
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: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 817 of file sendlib.c.

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

846{
847 if (!e)
848 return -1;
849
850 int rc = 0;
851
852 struct Buffer *tempfile = buf_pool_get();
853 buf_mktemp(tempfile);
854 FILE *fp_tmp = mutt_file_fopen(buf_string(tempfile), "w");
855 if (fp_tmp)
856 {
858
859 const bool c_bounce_delivered = cs_subset_bool(sub, "bounce_delivered");
860 if (!c_bounce_delivered)
861 chflags |= CH_WEED_DELIVERED;
862
863 if (!mutt_file_seek(fp, e->offset, SEEK_SET))
864 {
865 (void) mutt_file_fclose(&fp_tmp);
866 return -1;
867 }
868 fprintf(fp_tmp, "Resent-From: %s\n", resent_from);
869
870 struct Buffer *date = buf_pool_get();
871 mutt_date_make_date(date, cs_subset_bool(sub, "local_date_header"));
872 fprintf(fp_tmp, "Resent-Date: %s\n", buf_string(date));
873 buf_pool_release(&date);
874
875 char *msgid_str = gen_msgid();
876 fprintf(fp_tmp, "Resent-Message-ID: %s\n", msgid_str);
877 FREE(&msgid_str);
878 mutt_addrlist_write_file(to, fp_tmp, "Resent-To");
879 mutt_copy_header(fp, e, fp_tmp, chflags, NULL, 0);
880 fputc('\n', fp_tmp);
881 mutt_file_copy_bytes(fp, fp_tmp, e->body->length);
882 if (mutt_file_fclose(&fp_tmp) != 0)
883 {
884 mutt_perror("%s", buf_string(tempfile));
885 unlink(buf_string(tempfile));
886 return -1;
887 }
888#ifdef USE_SMTP
889 const char *const c_smtp_url = cs_subset_string(sub, "smtp_url");
890 if (c_smtp_url)
891 {
892 rc = mutt_smtp_send(env_from, to, NULL, NULL, buf_string(tempfile),
893 (e->body->encoding == ENC_8BIT), sub);
894 }
895 else
896#endif
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:1249
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:423
#define CH_WEED_DELIVERED
Weed eventual Delivered-To headers.
Definition: copy.h:65
#define CH_NOQFROM
Ignore ">From " line.
Definition: copy.h:67
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:232
void mutt_date_make_date(struct Buffer *buf, bool local)
Write a date in RFC822 format to a buffer.
Definition: date.c:387
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:297
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:1107
+ 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#ifdef USE_NNTP
956 OptNewsSend = false;
957#endif
958
959 /* prepare recipient list. idna conversion appears to happen before this
960 * function is called, since the user receives confirmation of the address
961 * list being bounced to. */
962 struct AddressList resent_to = TAILQ_HEAD_INITIALIZER(resent_to);
963 mutt_addrlist_copy(&resent_to, to, false);
964 rfc2047_encode_addrlist(&resent_to, "Resent-To");
965 int rc = bounce_message(fp, m, e, &resent_to, buf_string(resent_from), &from_list, sub);
966 mutt_addrlist_clear(&resent_to);
967 mutt_addrlist_clear(&from_list);
968 buf_pool_release(&resent_from);
969 return rc;
970}
void mutt_addrlist_copy(struct AddressList *dst, const struct AddressList *src, bool prune)
Copy a list of addresses into another list.
Definition: address.c:762
void mutt_addrlist_qualify(struct AddressList *al, const char *host)
Expand local names in an Address list using a hostname.
Definition: address.c:677
size_t mutt_addrlist_write(const struct AddressList *al, struct Buffer *buf, bool display)
Write an Address to a buffer.
Definition: address.c:1207
int mutt_addrlist_to_intl(struct AddressList *al, char **err)
Convert an Address list to Punycode.
Definition: address.c:1294
struct Buffer * buf_new(const char *str)
Allocate a new Buffer.
Definition: buffer.c:316
bool OptNewsSend
(pseudo) used to change behavior when posting
Definition: globals.c:77
#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:762
struct Address * mutt_default_from(struct ConfigSubset *sub)
Get a default 'from' Address.
Definition: send.c:1463
const char * mutt_fqdn(bool may_hide_host, const struct ConfigSubset *sub)
Get the Fully-Qualified Domain Name.
Definition: sendlib.c:705
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:843
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 977 of file sendlib.c.

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

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

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