NeoMutt  2024-03-23-147-g885fbc
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 *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 75 of file sendlib.c.

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

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

259{
260 struct Buffer *temp = buf_pool_get();
261 FILE *fp_in = NULL;
262 FILE *fp_out = NULL;
263 struct stat st = { 0 };
264
265 if (!b->filename && fp)
266 {
267 fp_in = fp;
268 }
269 else if (!b->filename || !(fp_in = mutt_file_fopen(b->filename, "r")))
270 {
271 mutt_error(_("Could not open %s"), b->filename ? b->filename : "(null)");
272 return;
273 }
274 else
275 {
276 b->offset = 0;
277 if (stat(b->filename, &st) == -1)
278 {
279 mutt_perror("stat");
280 mutt_file_fclose(&fp_in);
281 goto cleanup;
282 }
283 b->length = st.st_size;
284 }
285
286 /* Avoid buffer pool due to recursion */
287 buf_mktemp(temp);
288 fp_out = mutt_file_fopen(buf_string(temp), "w+");
289 if (!fp_out)
290 {
291 mutt_perror("fopen");
292 goto cleanup;
293 }
294
295 if (!mutt_file_seek(fp_in, b->offset, SEEK_SET))
296 {
297 goto cleanup;
298 }
299 b->parts = mutt_rfc822_parse_message(fp_in, b);
300
301 transform_to_7bit(b->parts, fp_in, sub);
302
303 mutt_copy_hdr(fp_in, fp_out, b->offset, b->offset + b->length,
304 CH_MIME | CH_NONEWLINE | CH_XMIT, NULL, 0);
305
306 fputs("MIME-Version: 1.0\n", fp_out);
307 mutt_write_mime_header(b->parts, fp_out, sub);
308 fputc('\n', fp_out);
309 mutt_write_mime_body(b->parts, fp_out, sub);
310
311 if (fp_in != fp)
312 mutt_file_fclose(&fp_in);
313 mutt_file_fclose(&fp_out);
314
315 b->encoding = ENC_7BIT;
316 FREE(&b->d_filename);
317 b->d_filename = b->filename;
318 if (b->filename && b->unlink)
319 unlink(b->filename);
320 b->filename = buf_strdup(temp);
321 b->unlink = true;
322 if (stat(b->filename, &st) == -1)
323 {
324 mutt_perror("stat");
325 goto cleanup;
326 }
327 b->length = st.st_size;
329 b->email->body = NULL;
330
331cleanup:
332 if (fp_in && (fp_in != fp))
333 mutt_file_fclose(&fp_in);
334
335 if (fp_out)
336 {
337 mutt_file_fclose(&fp_out);
339 }
340
341 buf_pool_release(&temp);
342}
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:775
void mutt_file_unlink(const char *s)
Delete a file, carefully.
Definition: file.c:220
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 350 of file sendlib.c.

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

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

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

455{
456 struct Body *body = NULL;
457 FILE *fp = NULL;
458 CopyMessageFlags cmflags;
460
461 const bool c_mime_forward_decode = cs_subset_bool(sub, "mime_forward_decode");
462 const bool c_forward_decrypt = cs_subset_bool(sub, "forward_decrypt");
463 if (WithCrypto)
464 {
465 if ((c_mime_forward_decode || c_forward_decrypt) && (e->security & SEC_ENCRYPT))
466 {
468 return NULL;
469 }
470 }
471
472 struct Buffer *buf = buf_pool_get();
473 buf_mktemp(buf);
474 fp = mutt_file_fopen(buf_string(buf), "w+");
475 if (!fp)
476 {
477 buf_pool_release(&buf);
478 return NULL;
479 }
480
481 body = mutt_body_new();
482 body->type = TYPE_MESSAGE;
483 body->subtype = mutt_str_dup("rfc822");
484 body->filename = mutt_str_dup(buf_string(buf));
485 body->unlink = true;
486 body->use_disp = false;
487 body->disposition = DISP_INLINE;
488 body->noconv = true;
489
490 buf_pool_release(&buf);
491
492 struct Message *msg = mx_msg_open(m, e);
493 if (!msg)
494 {
495 mutt_body_free(&body);
497 return NULL;
498 }
500
501 CopyHeaderFlags chflags = CH_XMIT;
502 cmflags = MUTT_CM_NO_FLAGS;
503
504 /* If we are attaching a message, ignore `$mime_forward_decode` */
505 if (!attach_msg && c_mime_forward_decode)
506 {
507 chflags |= CH_MIME | CH_TXTPLAIN;
510 pgp &= ~PGP_ENCRYPT;
512 pgp &= ~SMIME_ENCRYPT;
513 }
514 else if ((WithCrypto != 0) && c_forward_decrypt && (e->security & SEC_ENCRYPT))
515 {
517 {
518 chflags |= CH_MIME | CH_NONEWLINE;
519 cmflags = MUTT_CM_DECODE_PGP;
520 pgp &= ~PGP_ENCRYPT;
521 }
522 else if (((WithCrypto & APPLICATION_PGP) != 0) &&
524 {
525 chflags |= CH_MIME | CH_TXTPLAIN;
527 pgp &= ~PGP_ENCRYPT;
528 }
529 else if (((WithCrypto & APPLICATION_SMIME) != 0) &&
531 {
532 chflags |= CH_MIME | CH_NONEWLINE;
533 cmflags = MUTT_CM_DECODE_SMIME;
534 pgp &= ~SMIME_ENCRYPT;
535 }
536 }
537
538 mutt_copy_message(fp, e, msg, cmflags, chflags, 0);
539 mx_msg_close(m, &msg);
540
541 fflush(fp);
542 rewind(fp);
543
544 body->email = email_new();
545 body->email->offset = 0;
546 /* we don't need the user headers here */
547 body->email->env = mutt_rfc822_read_header(fp, body->email, false, false);
548 if (WithCrypto)
549 body->email->security = pgp;
550 mutt_update_encoding(body, sub);
551 body->parts = body->email->body;
552
554
555 return body;
556}
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:595
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:429
SecurityFlags mutt_is_application_pgp(const struct Body *b)
Does the message use PGP?
Definition: crypt.c:534
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:1178
struct Message * mx_msg_open(struct Mailbox *m, struct Email *e)
Return a stream pointer for a message.
Definition: mx.c:1132
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
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 565 of file sendlib.c.

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

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

667{
668 char *tmp = NULL;
669 char *p = NULL;
670 int i;
671
672 const struct Slist *const c_send_charset = cs_subset_slist(sub, "send_charset");
673
674 struct ListNode *np = NULL;
675 STAILQ_FOREACH(np, h, entries)
676 {
677 p = strchr(NONULL(np->data), ':');
678 if (!p)
679 continue;
680
681 i = p - np->data;
682 p = mutt_str_skip_email_wsp(p + 1);
683 tmp = mutt_str_dup(p);
684
685 if (!tmp)
686 continue;
687
688 rfc2047_encode(&tmp, NULL, i + 2, c_send_charset);
689 mutt_mem_realloc(&np->data, i + 2 + mutt_str_len(tmp) + 1);
690
691 sprintf(np->data + i + 2, "%s", tmp);
692
693 FREE(&tmp);
694 }
695}
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:657
#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:629
A List node for strings.
Definition: list.h:35
char * data
String.
Definition: list.h:36
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 706 of file sendlib.c.

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

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

780{
781 if (final)
782 {
783 if (!TAILQ_EMPTY(&env->bcc) && TAILQ_EMPTY(&env->to) && TAILQ_EMPTY(&env->cc))
784 {
785 /* some MTA's will put an Apparently-To: header field showing the Bcc:
786 * recipients if there is no To: or Cc: field, so attempt to suppress
787 * it by using an empty To: field. */
788 struct Address *to = mutt_addr_new();
789 to->group = true;
790 mutt_addrlist_append(&env->to, to);
792
793 char buf[1024] = { 0 };
794 buf[0] = '\0';
795 mutt_addr_cat(buf, sizeof(buf), "undisclosed-recipients", AddressSpecials);
796
797 buf_strcpy(to->mailbox, buf);
798 }
799
800 mutt_set_followup_to(env, sub);
801
802 if (!env->message_id)
803 env->message_id = gen_msgid();
804 }
805
806 /* Take care of 8-bit => 7-bit conversion. */
808 encode_headers(&env->userhdrs, sub);
809}
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:394
#define TAILQ_EMPTY(head)
Definition: queue.h:721
void rfc2047_encode_envelope(struct Envelope *env)
Encode the fields of an Envelope.
Definition: rfc2047.c:858
void mutt_set_followup_to(struct Envelope *env, struct ConfigSubset *sub)
Set followup-to field.
Definition: send.c:1341
static char * gen_msgid(void)
Generate a random Message ID.
Definition: sendlib.c:752
static void encode_headers(struct ListHead *h, struct ConfigSubset *sub)
RFC2047-encode a list of headers.
Definition: sendlib.c:666
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 818 of file sendlib.c.

819{
820 struct ListNode *item = NULL;
821 STAILQ_FOREACH(item, &env->userhdrs, entries)
822 {
823 rfc2047_decode(&item->data);
824 }
825
827
828 /* back conversions */
830}
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:833
void rfc2047_decode(char **pd)
Decode any RFC2047-encoded header fields.
Definition: rfc2047.c:662
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 844 of file sendlib.c.

847{
848 if (!e)
849 return -1;
850
851 int rc = 0;
852
853 struct Buffer *tempfile = buf_pool_get();
854 buf_mktemp(tempfile);
855 FILE *fp_tmp = mutt_file_fopen(buf_string(tempfile), "w");
856 if (fp_tmp)
857 {
859
860 const bool c_bounce_delivered = cs_subset_bool(sub, "bounce_delivered");
861 if (!c_bounce_delivered)
862 chflags |= CH_WEED_DELIVERED;
863
864 if (!mutt_file_seek(fp, e->offset, SEEK_SET))
865 {
866 (void) mutt_file_fclose(&fp_tmp);
867 return -1;
868 }
869 fprintf(fp_tmp, "Resent-From: %s\n", resent_from);
870
871 struct Buffer *date = buf_pool_get();
872 mutt_date_make_date(date, cs_subset_bool(sub, "local_date_header"));
873 fprintf(fp_tmp, "Resent-Date: %s\n", buf_string(date));
874 buf_pool_release(&date);
875
876 char *msgid_str = gen_msgid();
877 fprintf(fp_tmp, "Resent-Message-ID: %s\n", msgid_str);
878 FREE(&msgid_str);
879 mutt_addrlist_write_file(to, fp_tmp, "Resent-To");
880 mutt_copy_header(fp, e, fp_tmp, chflags, NULL, 0);
881 fputc('\n', fp_tmp);
882 mutt_file_copy_bytes(fp, fp_tmp, e->body->length);
883 if (mutt_file_fclose(&fp_tmp) != 0)
884 {
885 mutt_perror("%s", buf_string(tempfile));
886 unlink(buf_string(tempfile));
887 return -1;
888 }
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 {
897 rc = mutt_invoke_sendmail(m, env_from, to, NULL, NULL, buf_string(tempfile),
898 (e->body->encoding == ENC_8BIT), sub);
899 }
900 }
901
902 buf_pool_release(&tempfile);
903 return rc;
904}
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:256
void mutt_date_make_date(struct Buffer *buf, bool local)
Write a date in RFC822 format to a buffer.
Definition: date.c:396
int mutt_invoke_sendmail(struct Mailbox *m, struct AddressList *from, struct AddressList *to, struct AddressList *cc, struct AddressList *bcc, const char *msg, bool eightbit, struct ConfigSubset *sub)
Run sendmail.
Definition: sendmail.c:299
int mutt_smtp_send(const struct AddressList *from, const struct AddressList *to, const struct AddressList *cc, const struct AddressList *bcc, const char *msgfile, bool eightbit, struct ConfigSubset *sub)
Send a message using SMTP.
Definition: smtp.c: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 916 of file sendlib.c.

918{
919 if (!fp || !e || !to || TAILQ_EMPTY(to))
920 return -1;
921
922 const char *fqdn = mutt_fqdn(true, sub);
923 char *err = NULL;
924
925 struct Address *from = mutt_default_from(sub);
926 struct AddressList from_list = TAILQ_HEAD_INITIALIZER(from_list);
927 mutt_addrlist_append(&from_list, from);
928
929 /* mutt_default_from() does not use $real_name if the real name is not set
930 * in $from, so we add it here. The reason it is not added in
931 * mutt_default_from() is that during normal sending, we execute
932 * send-hooks and set the real_name last so that it can be changed based
933 * upon message criteria. */
934 if (!from->personal)
935 {
936 const char *const c_real_name = cs_subset_string(sub, "real_name");
937 if (c_real_name)
938 from->personal = buf_new(c_real_name);
939 }
940
941 mutt_addrlist_qualify(&from_list, fqdn);
942
943 rfc2047_encode_addrlist(&from_list, "Resent-From");
944 if (mutt_addrlist_to_intl(&from_list, &err))
945 {
946 mutt_error(_("Bad IDN %s while preparing resent-from"), err);
947 FREE(&err);
948 mutt_addrlist_clear(&from_list);
949 return -1;
950 }
951 struct Buffer *resent_from = buf_pool_get();
952 mutt_addrlist_write(&from_list, resent_from, false);
953
954 OptNewsSend = false;
955
956 /* prepare recipient list. idna conversion appears to happen before this
957 * function is called, since the user receives confirmation of the address
958 * list being bounced to. */
959 struct AddressList resent_to = TAILQ_HEAD_INITIALIZER(resent_to);
960 mutt_addrlist_copy(&resent_to, to, false);
961 rfc2047_encode_addrlist(&resent_to, "Resent-To");
962 int rc = bounce_message(fp, m, e, &resent_to, buf_string(resent_from), &from_list, sub);
963 mutt_addrlist_clear(&resent_to);
964 mutt_addrlist_clear(&from_list);
965 buf_pool_release(&resent_from);
966 return rc;
967}
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:303
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:767
struct Address * mutt_default_from(struct ConfigSubset *sub)
Get a default 'from' Address.
Definition: send.c:1465
const char * mutt_fqdn(bool may_hide_host, const struct ConfigSubset *sub)
Get the Fully-Qualified Domain Name.
Definition: sendlib.c:706
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:844
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 974 of file sendlib.c.

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

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

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