NeoMutt  2025-12-11-911-gd8d604
Teaching an old dog new tricks
DOXYGEN
Loading...
Searching...
No Matches
copy_email.c File Reference

Duplicate the structure of an entire email. More...

#include "config.h"
#include <inttypes.h>
#include <locale.h>
#include <stdbool.h>
#include <string.h>
#include "mutt/lib.h"
#include "address/lib.h"
#include "config/lib.h"
#include "core/lib.h"
#include "gui/lib.h"
#include "mutt.h"
#include "copy_email.h"
#include "expando/lib.h"
#include "index/lib.h"
#include "ncrypt/lib.h"
#include "pager/lib.h"
#include "send/lib.h"
#include "body.h"
#include "email.h"
#include "envelope.h"
#include "from.h"
#include "handler.h"
#include "mime.h"
#include "module_data.h"
#include "mx.h"
#include "parse.h"
#include "rfc2047.h"
#include "tags.h"
#include "notmuch/lib.h"
#include "muttlib.h"
#include <libintl.h>
+ Include dependency graph for copy_email.c:

Go to the source code of this file.

Functions

static int address_header_decode (char **h)
 Parse an email's headers.
 
static int copy_delete_attach (struct Body *b, FILE *fp_in, FILE *fp_out, const char *quoted_date)
 Copy a message, deleting marked attachments.
 
static void add_one_header (struct StringArray *headers, int pos, char *value)
 Add a header to a Headers array.
 
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.
 
int mutt_copy_header (FILE *fp_in, struct Email *e, FILE *fp_out, CopyHeaderFlags chflags, const char *prefix, int wraplen)
 Copy Email header.
 
static int count_delete_lines (FILE *fp, struct Body *b, LOFF_T *length, size_t datelen)
 Count lines to be deleted in this email body.
 
int mutt_copy_message_fp (FILE *fp_out, FILE *fp_in, struct Email *e, CopyMessageFlags cmflags, CopyHeaderFlags chflags, int wraplen)
 Make a copy of a message from a FILE pointer.
 
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.
 
static int append_message (struct Mailbox *dest, FILE *fp_in, struct Mailbox *src, struct Email *e, CopyMessageFlags cmflags, CopyHeaderFlags chflags)
 Appends a copy of the given message to a mailbox.
 
int mutt_append_message (struct Mailbox *m_dst, struct Mailbox *m_src, struct Email *e, struct Message *msg, CopyMessageFlags cmflags, CopyHeaderFlags chflags)
 Append a message.
 

Detailed Description

Duplicate the structure of an entire email.

Authors
  • Michael R. Elkins
  • Richard Russon
  • Pietro Cerutti
  • Dennis Schön
  • Thomas Klausner

This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.

You should have received a copy of the GNU General Public License along with this program. If not, see http://www.gnu.org/licenses/.

Definition in file copy_email.c.

Function Documentation

◆ address_header_decode()

static int address_header_decode ( char ** h)
static

Parse an email's headers.

Parameters
[out]hArray of header strings
Return values
0Success
1Failure

Definition at line 1091 of file copy_email.c.

1092{
1093 char *s = *h;
1094 size_t l;
1095 bool rp = false;
1096
1097 switch (mutt_tolower(*s))
1098 {
1099 case 'b':
1100 {
1101 if (!(l = mutt_istr_startswith(s, "bcc:")))
1102 return 0;
1103 break;
1104 }
1105 case 'c':
1106 {
1107 if (!(l = mutt_istr_startswith(s, "cc:")))
1108 return 0;
1109 break;
1110 }
1111 case 'f':
1112 {
1113 if (!(l = mutt_istr_startswith(s, "from:")))
1114 return 0;
1115 break;
1116 }
1117 case 'm':
1118 {
1119 if (!(l = mutt_istr_startswith(s, "mail-followup-to:")))
1120 return 0;
1121 break;
1122 }
1123 case 'r':
1124 {
1125 if ((l = mutt_istr_startswith(s, "return-path:")))
1126 {
1127 rp = true;
1128 break;
1129 }
1130 else if ((l = mutt_istr_startswith(s, "reply-to:")))
1131 {
1132 break;
1133 }
1134 return 0;
1135 }
1136 case 's':
1137 {
1138 if (!(l = mutt_istr_startswith(s, "sender:")))
1139 return 0;
1140 break;
1141 }
1142 case 't':
1143 {
1144 if (!(l = mutt_istr_startswith(s, "to:")))
1145 return 0;
1146 break;
1147 }
1148 default:
1149 return 0;
1150 }
1151
1152 struct AddressList al = TAILQ_HEAD_INITIALIZER(al);
1153 mutt_addrlist_parse(&al, s + l);
1154 if (TAILQ_EMPTY(&al))
1155 return 0;
1156
1159 struct Address *a = NULL;
1160 TAILQ_FOREACH(a, &al, entries)
1161 {
1162 if (a->personal)
1163 {
1165 }
1166 }
1167
1168 /* angle brackets for return path are mandated by RFC5322,
1169 * so leave Return-Path as-is */
1170 if (rp)
1171 {
1172 *h = mutt_str_dup(s);
1173 }
1174 else
1175 {
1176 struct Buffer buf = { 0 };
1177 (*h)[l - 1] = '\0';
1178 mutt_addrlist_write_wrap(&al, &buf, *h);
1179 buf_addch(&buf, '\n');
1180 *h = buf.data;
1181 }
1182
1184
1185 FREE(&s);
1186 return 1;
1187}
void mutt_addrlist_clear(struct AddressList *al)
Unlink and free all Address in an AddressList.
Definition address.c:1469
size_t mutt_addrlist_write_wrap(const struct AddressList *al, struct Buffer *buf, const char *header)
Write an AddressList to a buffer, perform line wrapping.
Definition address.c:1198
int mutt_addrlist_to_local(struct AddressList *al)
Convert an Address list from Punycode.
Definition address.c:1387
int mutt_addrlist_parse(struct AddressList *al, const char *s)
Parse a list of email addresses.
Definition address.c:480
void buf_dequote_comment(struct Buffer *buf)
Un-escape characters in an email address comment.
Definition buffer.c:434
size_t buf_addch(struct Buffer *buf, char c)
Add a single character to a Buffer.
Definition buffer.c:241
int mutt_tolower(int arg)
Wrapper for tolower(3)
Definition ctype.c:126
#define FREE(x)
Free memory and set the pointer to NULL.
Definition memory.h:68
char * mutt_str_dup(const char *str)
Copy a string, safely.
Definition string.c:257
size_t mutt_istr_startswith(const char *str, const char *prefix)
Check whether a string starts with a prefix, ignoring case.
Definition string.c:246
#define TAILQ_FOREACH(var, head, field)
Definition queue.h:782
#define TAILQ_HEAD_INITIALIZER(head)
Definition queue.h:694
#define TAILQ_EMPTY(head)
Definition queue.h:778
void rfc2047_decode_addrlist(struct AddressList *al)
Decode any RFC2047 headers in an Address list.
Definition rfc2047.c:809
An email address.
Definition address.h:35
struct Buffer * personal
Real name of address.
Definition address.h:36
String manipulation buffer.
Definition buffer.h:36
char * data
Pointer to data.
Definition buffer.h:37
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ copy_delete_attach()

static int copy_delete_attach ( struct Body * b,
FILE * fp_in,
FILE * fp_out,
const char * quoted_date )
static

Copy a message, deleting marked attachments.

Parameters
bEmail Body
fp_inFILE pointer to read from
fp_outFILE pointer to write to
quoted_dateDate stamp
Return values
0Success
-1Failure

This function copies a message body, while deleting in_the_copy any attachments which are marked for deletion. Nothing is changed in the original message – this is left to the caller.

Definition at line 1029 of file copy_email.c.

1030{
1031 struct Body *part = NULL;
1032
1033 for (part = b->parts; part; part = part->next)
1034 {
1035 if (part->deleted || part->parts)
1036 {
1037 /* Copy till start of this part */
1038 if (mutt_file_copy_bytes(fp_in, fp_out, part->hdr_offset - ftello(fp_in)) != 0)
1039 {
1040 return -1;
1041 }
1042
1043 if (part->deleted)
1044 {
1045 /* If this is modified, count_delete_lines() needs to be changed too */
1046 fprintf(fp_out,
1047 "Content-Type: message/external-body; access-type=x-mutt-deleted;\n"
1048 "\texpiration=%s; length=" OFF_T_FMT "\n"
1049 "\n",
1050 quoted_date, part->length);
1051 if (ferror(fp_out))
1052 {
1053 return -1;
1054 }
1055
1056 /* Copy the original mime headers */
1057 if (mutt_file_copy_bytes(fp_in, fp_out, part->offset - ftello(fp_in)) != 0)
1058 {
1059 return -1;
1060 }
1061
1062 /* Skip the deleted body */
1063 if (!mutt_file_seek(fp_in, part->offset + part->length, SEEK_SET))
1064 {
1065 return -1;
1066 }
1067 }
1068 else
1069 {
1070 if (copy_delete_attach(part, fp_in, fp_out, quoted_date))
1071 {
1072 return -1;
1073 }
1074 }
1075 }
1076 }
1077
1078 /* Copy the last parts */
1079 if (mutt_file_copy_bytes(fp_in, fp_out, b->offset + b->length - ftello(fp_in)) != 0)
1080 return -1;
1081
1082 return 0;
1083}
static int copy_delete_attach(struct Body *b, FILE *fp_in, FILE *fp_out, const char *quoted_date)
Copy a message, deleting marked attachments.
int mutt_file_copy_bytes(FILE *fp_in, FILE *fp_out, size_t size)
Copy some content from one file to another.
Definition file.c:192
bool mutt_file_seek(FILE *fp, LOFF_T offset, int whence)
Wrapper for fseeko with error handling.
Definition file.c:648
The body of an email.
Definition body.h:36
struct Body * parts
parts of a multipart or message/rfc822
Definition body.h:73
LOFF_T offset
offset where the actual data begins
Definition body.h:52
bool deleted
Attachment marked for deletion.
Definition body.h:88
LOFF_T length
length (in bytes) of attachment
Definition body.h:53
struct Body * next
next attachment in the list
Definition body.h:72
long hdr_offset
Offset in stream where the headers begin.
Definition body.h:81
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ add_one_header()

static void add_one_header ( struct StringArray * headers,
int pos,
char * value )
static

Add a header to a Headers array.

Parameters
headersHeaders array
posPosition to insert new header
valueText to insert

If a header already exists in that position, the new text will be concatenated on the old.

Definition at line 82 of file copy_email.c.

83{
84 const char **old = ARRAY_GET(headers, pos);
85 if (old && *old)
86 {
87 char *new_value = NULL;
88 mutt_str_asprintf(&new_value, "%s%s", *old, value);
89 FREE(old);
90 FREE(&value);
91 value = new_value;
92 }
93 ARRAY_SET(headers, pos, value);
94}
#define ARRAY_SET(head, idx, elem)
Set an element in the array.
Definition array.h:123
#define ARRAY_GET(head, idx)
Return the element at index.
Definition array.h:109
int mutt_str_asprintf(char **strp, const char *fmt,...)
Definition string.c:808
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_copy_hdr()

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.

Parameters
fp_inFILE pointer to read from
fp_outFILE pointer to write to
off_startOffset to start from
off_endOffset to finish at
chflagsFlags, see CopyHeaderFlags
prefixPrefix for quoting headers
wraplenWidth to wrap at (when chflags & CH_DISPLAY)
Return values
0Success
-1Failure

Ok, the only reason for not merging this with mutt_copy_header() below is to avoid creating a Email structure in message_handler(). Also, this one will wrap headers much more aggressively than the other one.

Definition at line 112 of file copy_email.c.

114{
115 bool from = false;
116 bool this_is_from = false;
117 bool ignore = false;
118 char buf[1024] = { 0 }; /* should be long enough to get most fields in one pass */
119 char *nl = NULL;
120 struct StringArray headers = ARRAY_HEAD_INITIALIZER;
121 int hdr_count;
122 int x;
123 char *this_one = NULL;
124 size_t this_one_len = 0;
125
126 if (off_start < 0)
127 return -1;
128
129 if (ftello(fp_in) != off_start)
130 if (!mutt_file_seek(fp_in, off_start, SEEK_SET))
131 return -1;
132
133 buf[0] = '\n';
134 buf[1] = '\0';
135
136 if ((chflags & (CH_REORDER | CH_WEED | CH_MIME | CH_DECODE | CH_PREFIX | CH_WEED_DELIVERED)) == 0)
137 {
138 /* Without these flags to complicate things
139 * we can do a more efficient line to line copying */
140 while (ftello(fp_in) < off_end)
141 {
142 nl = strchr(buf, '\n');
143
144 if (!fgets(buf, sizeof(buf), fp_in))
145 break;
146
147 /* Convert CRLF line endings to LF */
148 const size_t line_len = strlen(buf);
149 if ((line_len > 2) && (buf[line_len - 2] == '\r') && (buf[line_len - 1] == '\n'))
150 {
151 buf[line_len - 2] = '\n';
152 buf[line_len - 1] = '\0';
153 }
154
155 /* Is it the beginning of a header? */
156 if (nl && (buf[0] != ' ') && (buf[0] != '\t'))
157 {
158 ignore = true;
159 if (!from && mutt_str_startswith(buf, "From "))
160 {
161 if ((chflags & CH_FROM) == 0)
162 continue;
163 from = true;
164 }
165 else if ((chflags & CH_NOQFROM) && mutt_istr_startswith(buf, ">From "))
166 {
167 continue;
168 }
169 else if ((buf[0] == '\n') || ((buf[0] == '\r') && (buf[1] == '\n')))
170 {
171 break; /* end of header */
172 }
173
174 if ((chflags & (CH_UPDATE | CH_XMIT | CH_NOSTATUS)) &&
175 (mutt_istr_startswith(buf, "Status:") || mutt_istr_startswith(buf, "X-Status:")))
176 {
177 continue;
178 }
179 if ((chflags & (CH_UPDATE_LEN | CH_XMIT | CH_NOLEN)) &&
180 (mutt_istr_startswith(buf, "Content-Length:") ||
181 mutt_istr_startswith(buf, "Lines:")))
182 {
183 continue;
184 }
185 if ((chflags & CH_UPDATE_REFS) && mutt_istr_startswith(buf, "References:"))
186 {
187 continue;
188 }
189 if ((chflags & CH_UPDATE_IRT) && mutt_istr_startswith(buf, "In-Reply-To:"))
190 {
191 continue;
192 }
193 if (chflags & CH_UPDATE_LABEL && mutt_istr_startswith(buf, "X-Label:"))
194 continue;
195 if ((chflags & CH_UPDATE_SUBJECT) && mutt_istr_startswith(buf, "Subject:"))
196 {
197 continue;
198 }
199
200 ignore = false;
201 }
202
203 if (!ignore && (fputs(buf, fp_out) == EOF))
204 return -1;
205 }
206 return 0;
207 }
208
209 hdr_count = 1;
210 x = 0;
211
213 ASSERT(mod_data);
214
215 /* We are going to read and collect the headers in an array
216 * so we are able to do re-ordering.
217 * First count the number of entries in the array */
218 if (chflags & CH_REORDER)
219 {
220 struct ListNode *np = NULL;
221 STAILQ_FOREACH(np, &mod_data->header_order, entries)
222 {
223 mutt_debug(LL_DEBUG3, "Reorder list: %s\n", np->data);
224 hdr_count++;
225 }
226 }
227
228 mutt_debug(LL_DEBUG1, "WEED is %sset\n", (chflags & CH_WEED) ? "" : "not ");
229
230 ARRAY_RESERVE(&headers, hdr_count);
231
232 /* Read all the headers into the array */
233 while (ftello(fp_in) < off_end)
234 {
235 nl = strchr(buf, '\n');
236
237 /* Read a line */
238 if (!fgets(buf, sizeof(buf), fp_in))
239 break;
240
241 /* Is it the beginning of a header? */
242 if (nl && (buf[0] != ' ') && (buf[0] != '\t'))
243 {
244 /* Do we have anything pending? */
245 if (this_one)
246 {
247 if (chflags & CH_DECODE)
248 {
249 if (address_header_decode(&this_one) == 0)
250 rfc2047_decode(&this_one);
251 this_one_len = mutt_str_len(this_one);
252 }
253
254 add_one_header(&headers, x, this_one);
255 this_one = NULL;
256 }
257
258 ignore = true;
259 this_is_from = false;
260 if (!from && mutt_str_startswith(buf, "From "))
261 {
262 if ((chflags & CH_FROM) == 0)
263 continue;
264 this_is_from = true;
265 from = true;
266 }
267 else if ((buf[0] == '\n') || ((buf[0] == '\r') && (buf[1] == '\n')))
268 {
269 break; /* end of header */
270 }
271
272 /* note: CH_FROM takes precedence over header weeding. */
273 if (!((chflags & CH_FROM) && (chflags & CH_FORCE_FROM) && this_is_from) &&
274 (chflags & CH_WEED) && mutt_matches_ignore(buf))
275 {
276 continue;
277 }
278 if ((chflags & CH_WEED_DELIVERED) && mutt_istr_startswith(buf, "Delivered-To:"))
279 {
280 continue;
281 }
282 if ((chflags & (CH_UPDATE | CH_XMIT | CH_NOSTATUS)) &&
283 (mutt_istr_startswith(buf, "Status:") || mutt_istr_startswith(buf, "X-Status:")))
284 {
285 continue;
286 }
287 if ((chflags & (CH_UPDATE_LEN | CH_XMIT | CH_NOLEN)) &&
288 (mutt_istr_startswith(buf, "Content-Length:") || mutt_istr_startswith(buf, "Lines:")))
289 {
290 continue;
291 }
292 if ((chflags & CH_MIME))
293 {
294 if (mutt_istr_startswith(buf, "mime-version:"))
295 {
296 continue;
297 }
298 size_t plen = mutt_istr_startswith(buf, "content-");
299 if ((plen != 0) && (mutt_istr_startswith(buf + plen, "transfer-encoding:") ||
300 mutt_istr_startswith(buf + plen, "type:")))
301 {
302 continue;
303 }
304 }
305 if ((chflags & CH_UPDATE_REFS) && mutt_istr_startswith(buf, "References:"))
306 {
307 continue;
308 }
309 if ((chflags & CH_UPDATE_IRT) && mutt_istr_startswith(buf, "In-Reply-To:"))
310 {
311 continue;
312 }
313 if ((chflags & CH_UPDATE_LABEL) && mutt_istr_startswith(buf, "X-Label:"))
314 continue;
315 if ((chflags & CH_UPDATE_SUBJECT) && mutt_istr_startswith(buf, "Subject:"))
316 {
317 continue;
318 }
319
320 /* Find x -- the array entry where this header is to be saved */
321 if (chflags & CH_REORDER)
322 {
323 struct ListNode *np = NULL;
324 x = 0;
325 int match = -1;
326 size_t match_len = 0;
327
328 STAILQ_FOREACH(np, &mod_data->header_order, entries)
329 {
330 size_t hdr_order_len = mutt_str_len(np->data);
331 if (mutt_istrn_equal(buf, np->data, hdr_order_len))
332 {
333 if ((match == -1) || (hdr_order_len > match_len))
334 {
335 match = x;
336 match_len = hdr_order_len;
337 }
338 mutt_debug(LL_DEBUG2, "Reorder: %s matches %s\n", np->data, buf);
339 }
340 x++;
341 }
342 if (match != -1)
343 x = match;
344 }
345
346 ignore = false;
347 } /* If beginning of header */
348
349 if (!ignore)
350 {
351 mutt_debug(LL_DEBUG2, "Reorder: x = %d; hdr_count = %d\n", x, hdr_count);
352 if (this_one)
353 {
354 size_t blen = mutt_str_len(buf);
355
356 MUTT_MEM_REALLOC(&this_one, this_one_len + blen + 1, char);
357 mutt_strn_copy(this_one + this_one_len, buf, blen, blen + 1);
358 this_one_len += blen;
359 }
360 else
361 {
362 this_one = mutt_str_dup(buf);
363 this_one_len = mutt_str_len(this_one);
364 }
365 }
366 } /* while (ftello (fp_in) < off_end) */
367
368 /* Do we have anything pending? -- XXX, same code as in above in the loop. */
369 if (this_one)
370 {
371 if (chflags & CH_DECODE)
372 {
373 if (address_header_decode(&this_one) == 0)
374 rfc2047_decode(&this_one);
375 this_one_len = mutt_str_len(this_one);
376 }
377
378 add_one_header(&headers, x, this_one);
379 this_one = NULL;
380 }
381
382 /* Now output the headers in order */
383 bool error = false;
384 const char **hp = NULL;
385 const short c_wrap = cs_subset_number(NeoMutt->sub, "wrap");
386
387 ARRAY_FOREACH(hp, &headers)
388 {
389 if (!error && hp && *hp)
390 {
391 /* We couldn't do the prefixing when reading because RFC2047
392 * decoding may have concatenated lines. */
393 if (chflags & (CH_DECODE | CH_PREFIX))
394 {
395 const char *pre = (chflags & CH_PREFIX) ? prefix : NULL;
396 wraplen = mutt_window_wrap_cols(wraplen, c_wrap);
397
398 if (mutt_write_one_header(fp_out, 0, *hp, pre, wraplen, chflags, NeoMutt->sub) == -1)
399 {
400 error = true;
401 }
402 }
403 else
404 {
405 if (fputs(*hp, fp_out) == EOF)
406 {
407 error = true;
408 }
409 }
410 }
411
412 FREE(hp);
413 }
414 ARRAY_FREE(&headers);
415
416 if (error)
417 return -1;
418 return 0;
419}
#define ARRAY_FOREACH(elem, head)
Iterate over all elements of the array.
Definition array.h:223
#define ARRAY_RESERVE(head, n)
Reserve memory for the array.
Definition array.h:191
#define ARRAY_FREE(head)
Release all memory.
Definition array.h:209
#define ARRAY_HEAD_INITIALIZER
Static initializer for arrays.
Definition array.h:58
short cs_subset_number(const struct ConfigSubset *sub, const char *name)
Get a number config item by name.
Definition helpers.c:143
static int address_header_decode(char **h)
Parse an email's headers.
static void add_one_header(struct StringArray *headers, int pos, char *value)
Add a header to a Headers array.
Definition copy_email.c:82
@ CH_UPDATE
Update the status and x-status fields?
Definition copy_email.h:66
@ CH_XMIT
Transmitting this message? (Ignore Lines: and Content-Length:)
Definition copy_email.h:69
@ CH_WEED_DELIVERED
Weed eventual Delivered-To headers.
Definition copy_email.h:79
@ CH_UPDATE_LEN
Update Lines: and Content-Length:
Definition copy_email.h:76
@ CH_WEED
Weed the headers?
Definition copy_email.h:67
@ CH_FROM
Retain the "From " message separator?
Definition copy_email.h:70
@ CH_UPDATE_LABEL
Update X-Label: from email->env->x_label?
Definition copy_email.h:85
@ CH_UPDATE_IRT
Update In-Reply-To:
Definition copy_email.h:82
@ CH_NOSTATUS
Suppress the status and x-status fields.
Definition copy_email.h:72
@ CH_UPDATE_REFS
Update References:
Definition copy_email.h:83
@ CH_MIME
Ignore MIME fields.
Definition copy_email.h:75
@ CH_PREFIX
Quote header using $indent_string string?
Definition copy_email.h:71
@ CH_NOLEN
Don't write Content-Length: and Lines:
Definition copy_email.h:78
@ CH_UPDATE_SUBJECT
Update Subject: protected header update.
Definition copy_email.h:86
@ CH_DECODE
Do RFC2047 header decoding.
Definition copy_email.h:68
@ CH_NOQFROM
Ignore ">From " line.
Definition copy_email.h:81
@ CH_FORCE_FROM
Give CH_FROM precedence over CH_WEED?
Definition copy_email.h:80
@ CH_REORDER
Re-order output of headers (specified by 'header-order')
Definition copy_email.h:73
bool mutt_matches_ignore(const char *s)
Does the string match the ignore list.
Definition parse.c:320
#define mutt_debug(LEVEL,...)
Definition logging2.h:91
@ LL_DEBUG3
Log at debug level 3.
Definition logging2.h:47
@ LL_DEBUG2
Log at debug level 2.
Definition logging2.h:46
@ LL_DEBUG1
Log at debug level 1.
Definition logging2.h:45
#define MUTT_MEM_REALLOC(pptr, n, type)
Definition memory.h:55
@ MODULE_ID_EMAIL
ModuleEmail, Email code
Definition module_api.h:64
char * mutt_strn_copy(char *dest, const char *src, size_t len, size_t dsize)
Copy a sub-string into a buffer.
Definition string.c:364
size_t mutt_str_startswith(const char *str, const char *prefix)
Check whether a string starts with a prefix.
Definition string.c:234
size_t mutt_str_len(const char *a)
Calculate the length of a string, safely.
Definition string.c:503
bool mutt_istrn_equal(const char *a, const char *b, size_t num)
Check for equality of two strings ignoring case (to a maximum), safely.
Definition string.c:457
int mutt_window_wrap_cols(int width, short wrap)
Calculate the wrap column for a given screen width.
void * neomutt_get_module_data(struct NeoMutt *n, enum ModuleId id)
Get the private data for a Module.
Definition neomutt.c:663
#define STAILQ_FOREACH(var, head, field)
Definition queue.h:390
void rfc2047_decode(char **pd)
Decode any RFC2047-encoded header fields.
Definition rfc2047.c:669
int mutt_write_one_header(FILE *fp, const char *tag, const char *value, const char *pfx, int wraplen, CopyHeaderFlags chflags, struct ConfigSubset *sub)
Write one header line to a file.
Definition header.c:424
#define ASSERT(COND)
Definition signal2.h:59
Email private Module data.
Definition module_data.h:32
struct ListHead header_order
List of header fields in the order they should be displayed.
Definition module_data.h:36
A List node for strings.
Definition list.h:37
char * data
String.
Definition list.h:38
Container for Accounts, Notifications.
Definition neomutt.h:41
struct ConfigSubset * sub
Inherited config items.
Definition neomutt.h:49
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_copy_header()

int mutt_copy_header ( FILE * fp_in,
struct Email * e,
FILE * fp_out,
CopyHeaderFlags chflags,
const char * prefix,
int wraplen )

Copy Email header.

Parameters
fp_inFILE pointer to read from
eEmail
fp_outFILE pointer to write to
chflagsSee CopyHeaderFlags
prefixPrefix for quoting headers (if CH_PREFIX is set)
wraplenWidth to wrap at (when chflags & CH_DISPLAY)
Return values
0Success
-1Failure

Definition at line 432 of file copy_email.c.

434{
435 char *temp_hdr = NULL;
436 const bool c_weed = (chflags & CH_UPDATE) ? false : cs_subset_bool(NeoMutt->sub, "weed");
437
438 if (e->env)
439 {
440 chflags |= ((e->env->changed & MUTT_ENV_CHANGED_IRT) ? CH_UPDATE_IRT : 0) |
441 ((e->env->changed & MUTT_ENV_CHANGED_REFS) ? CH_UPDATE_REFS : 0) |
442 ((e->env->changed & MUTT_ENV_CHANGED_XLABEL) ? CH_UPDATE_LABEL : 0) |
443 ((e->env->changed & MUTT_ENV_CHANGED_SUBJECT) ? CH_UPDATE_SUBJECT : 0);
444 }
445
446 if (mutt_copy_hdr(fp_in, fp_out, e->offset, e->body->offset, chflags, prefix, wraplen) == -1)
447 return -1;
448
449 if (chflags & CH_TXTPLAIN)
450 {
451 char chsbuf[128] = { 0 };
452 char buf[128] = { 0 };
453 fputs("MIME-Version: 1.0\n", fp_out);
454 fputs("Content-Transfer-Encoding: 8bit\n", fp_out);
455 fputs("Content-Type: text/plain; charset=", fp_out);
456 const char *const c_charset = cc_charset();
457 mutt_ch_canonical_charset(chsbuf, sizeof(chsbuf), c_charset ? c_charset : "us-ascii");
458 mutt_addr_cat(buf, sizeof(buf), chsbuf, MimeSpecials);
459 fputs(buf, fp_out);
460 fputc('\n', fp_out);
461 }
462
463 if ((chflags & CH_UPDATE_IRT) && !STAILQ_EMPTY(&e->env->in_reply_to) &&
464 !(c_weed && mutt_matches_ignore("In-Reply-To")))
465 {
466 fputs("In-Reply-To:", fp_out);
467 struct ListNode *np = NULL;
468 STAILQ_FOREACH(np, &e->env->in_reply_to, entries)
469 {
470 fputc(' ', fp_out);
471 fputs(np->data, fp_out);
472 }
473 fputc('\n', fp_out);
474 }
475
476 if ((chflags & CH_UPDATE_REFS) && !STAILQ_EMPTY(&e->env->references) &&
477 !(c_weed && mutt_matches_ignore("References")))
478 {
479 fputs("References:", fp_out);
480 mutt_write_references(&e->env->references, fp_out, 0);
481 fputc('\n', fp_out);
482 }
483
484 if ((chflags & CH_UPDATE) && ((chflags & CH_NOSTATUS) == 0))
485 {
486 if ((e->old || e->read))
487 {
488 fputs("Status: ", fp_out);
489 if (e->read)
490 fputs("RO", fp_out);
491 else if (e->old)
492 fputc('O', fp_out);
493 fputc('\n', fp_out);
494 }
495
496 if ((e->flagged || e->replied))
497 {
498 fputs("X-Status: ", fp_out);
499 if (e->replied)
500 fputc('A', fp_out);
501 if (e->flagged)
502 fputc('F', fp_out);
503 fputc('\n', fp_out);
504 }
505 }
506
507 if (chflags & CH_UPDATE_LEN && ((chflags & CH_NOLEN) == 0) &&
508 !(c_weed && mutt_matches_ignore("Content-Length")))
509 {
510 fprintf(fp_out, "Content-Length: " OFF_T_FMT "\n", e->body->length);
511 if ((e->lines != 0) || (e->body->length == 0))
512 fprintf(fp_out, "Lines: %d\n", e->lines);
513 }
514
515#ifdef USE_NOTMUCH
516 if (chflags & CH_VIRTUAL)
517 {
518 /* Add some fake headers based on notmuch data */
519 char *folder = nm_email_get_folder(e);
520 if (folder && !(c_weed && mutt_matches_ignore("Folder")))
521 {
522 struct Buffer *buf = buf_pool_get();
523 buf_strcpy(buf, folder);
524 pretty_mailbox(buf);
525 fprintf(fp_out, "Folder: %s\n", buf->data);
526 buf_pool_release(&buf);
527 }
528 }
529#endif
530
531 struct Buffer *tags = buf_pool_get();
532 driver_tags_get(&e->tags, tags);
533 if (!buf_is_empty(tags) && !(c_weed && mutt_matches_ignore("Tags")))
534 {
535 fputs("Tags: ", fp_out);
536 fputs(buf_string(tags), fp_out);
537 fputc('\n', fp_out);
538 }
539 buf_pool_release(&tags);
540
541 const struct Slist *const c_send_charset = cs_subset_slist(NeoMutt->sub, "send_charset");
542 const short c_wrap = cs_subset_number(NeoMutt->sub, "wrap");
543 if ((chflags & CH_UPDATE_LABEL) && e->env->x_label &&
544 !(c_weed && mutt_matches_ignore("X-Label")))
545 {
546 temp_hdr = e->env->x_label;
547 /* env->x_label isn't currently stored with direct references elsewhere.
548 * Mailbox->label_hash strdups the keys. But to be safe, encode a copy */
549 if (!(chflags & CH_DECODE))
550 {
551 temp_hdr = mutt_str_dup(temp_hdr);
552 rfc2047_encode(&temp_hdr, NULL, sizeof("X-Label:"), c_send_charset);
553 }
554 if (mutt_write_one_header(fp_out, "X-Label", temp_hdr, (chflags & CH_PREFIX) ? prefix : 0,
555 mutt_window_wrap_cols(wraplen, c_wrap), chflags,
556 NeoMutt->sub) == -1)
557 {
558 return -1;
559 }
560 if (!(chflags & CH_DECODE))
561 FREE(&temp_hdr);
562 }
563
564 if ((chflags & CH_UPDATE_SUBJECT) && e->env->subject &&
565 !(c_weed && mutt_matches_ignore("Subject")))
566 {
567 temp_hdr = e->env->subject;
568 /* env->subject is directly referenced in Mailbox->subj_hash, so we
569 * have to be careful not to encode (and thus free) that memory. */
570 if (!(chflags & CH_DECODE))
571 {
572 temp_hdr = mutt_str_dup(temp_hdr);
573 rfc2047_encode(&temp_hdr, NULL, sizeof("Subject:"), c_send_charset);
574 }
575 if (mutt_write_one_header(fp_out, "Subject", temp_hdr, (chflags & CH_PREFIX) ? prefix : 0,
576 mutt_window_wrap_cols(wraplen, c_wrap), chflags,
577 NeoMutt->sub) == -1)
578 {
579 return -1;
580 }
581 if (!(chflags & CH_DECODE))
582 FREE(&temp_hdr);
583 }
584
585 if ((chflags & CH_NONEWLINE) == 0)
586 {
587 if (chflags & CH_PREFIX)
588 fputs(prefix, fp_out);
589 fputc('\n', fp_out); /* add header terminator */
590 }
591
592 if (ferror(fp_out) || feof(fp_out))
593 return -1;
594
595 return 0;
596}
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:713
bool buf_is_empty(const struct Buffer *buf)
Is the Buffer empty?
Definition buffer.c:291
size_t buf_strcpy(struct Buffer *buf, const char *s)
Copy a string into a Buffer.
Definition buffer.c:395
static const char * buf_string(const struct Buffer *buf)
Convert a buffer to a const char * "string".
Definition buffer.h:96
const struct Slist * cs_subset_slist(const struct ConfigSubset *sub, const char *name)
Get a string-list config item by name.
Definition helpers.c:242
bool cs_subset_bool(const struct ConfigSubset *sub, const char *name)
Get a boolean config item by name.
Definition helpers.c:47
const char * cc_charset(void)
Get the cached value of $charset.
int mutt_copy_hdr(FILE *fp_in, FILE *fp_out, LOFF_T off_start, LOFF_T off_end, CopyHeaderFlags chflags, const char *prefix, int wraplen)
Copy header from one file to another.
Definition copy_email.c:112
@ CH_VIRTUAL
Write virtual header lines too.
Definition copy_email.h:87
@ CH_TXTPLAIN
Generate text/plain MIME headers.
Definition copy_email.h:77
@ CH_NONEWLINE
Don't output terminating newline after the header.
Definition copy_email.h:74
const char MimeSpecials[]
Characters that need special treatment in MIME.
Definition mime.c:69
void mutt_ch_canonical_charset(char *buf, size_t buflen, const char *name)
Canonicalise the charset of a string.
Definition charset.c:360
void pretty_mailbox(struct Buffer *buf)
Shorten a mailbox path using '~' or '='.
Definition muttlib.c:428
char * nm_email_get_folder(struct Email *e)
Get the folder for a Email.
Definition notmuch.c:1505
struct Buffer * buf_pool_get(void)
Get a Buffer from the pool.
Definition pool.c:91
void buf_pool_release(struct Buffer **ptr)
Return a Buffer to the pool.
Definition pool.c:111
#define STAILQ_EMPTY(head)
Definition queue.h:382
void rfc2047_encode(char **pd, const char *specials, int col, const struct Slist *charsets)
RFC-2047-encode a string.
Definition rfc2047.c:636
void mutt_write_references(const struct ListHead *r, FILE *fp, size_t trim)
Add the message references to a list.
Definition header.c:520
bool read
Email is read.
Definition email.h:50
struct Envelope * env
Envelope information.
Definition email.h:68
int lines
How many lines in the body of this message?
Definition email.h:62
struct Body * body
List of MIME parts.
Definition email.h:69
bool old
Email is seen, but unread.
Definition email.h:49
LOFF_T offset
Where in the stream does this message begin?
Definition email.h:71
bool flagged
Marked important?
Definition email.h:47
bool replied
Email has been replied to.
Definition email.h:51
struct TagList tags
For drivers that support server tagging.
Definition email.h:72
char *const subject
Email's subject.
Definition envelope.h:70
struct ListHead references
message references (in reverse order)
Definition envelope.h:83
struct ListHead in_reply_to
in-reply-to header content
Definition envelope.h:84
char * x_label
X-Label.
Definition envelope.h:76
String list.
Definition slist.h:37
void driver_tags_get(struct TagList *tl, struct Buffer *tags)
Get tags all tags separated by space.
Definition tags.c:165
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ count_delete_lines()

static int count_delete_lines ( FILE * fp,
struct Body * b,
LOFF_T * length,
size_t datelen )
static

Count lines to be deleted in this email body.

Parameters
fpFILE pointer to read from
bEmail Body
lengthNumber of bytes to be deleted
datelenLength of the date
Return values
numNumber of lines to be deleted
-1on error

Count the number of lines and bytes to be deleted in this body

Definition at line 609 of file copy_email.c.

610{
611 int dellines = 0;
612
613 if (b->deleted)
614 {
615 if (!mutt_file_seek(fp, b->offset, SEEK_SET))
616 {
617 return -1;
618 }
619 for (long l = b->length; l; l--)
620 {
621 const int ch = getc(fp);
622 if (ch == EOF)
623 break;
624 if (ch == '\n')
625 dellines++;
626 }
627 /* 3 and 89 come from the added header of three lines in
628 * copy_delete_attach(). 89 is the size of the header(including
629 * the newlines, tabs, and a single digit length), not including
630 * the date length. */
631 dellines -= 3;
632 *length -= b->length - (89 + datelen);
633 /* Count the number of digits exceeding the first one to write the size */
634 for (long l = 10; b->length >= l; l *= 10)
635 (*length)++;
636 }
637 else
638 {
639 for (b = b->parts; b; b = b->next)
640 {
641 const int del = count_delete_lines(fp, b, length, datelen);
642 if (del == -1)
643 {
644 return -1;
645 }
646 dellines += del;
647 }
648 }
649 return dellines;
650}
static int count_delete_lines(FILE *fp, struct Body *b, LOFF_T *length, size_t datelen)
Count lines to be deleted in this email body.
Definition copy_email.c:609
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_copy_message_fp()

int mutt_copy_message_fp ( FILE * fp_out,
FILE * fp_in,
struct Email * e,
CopyMessageFlags cmflags,
CopyHeaderFlags chflags,
int wraplen )

Make a copy of a message from a FILE pointer.

Parameters
fp_outWhere to write output
fp_inWhere to get input
eEmail being copied
cmflagsFlags, see CopyMessageFlags
chflagsFlags, see CopyHeaderFlags
wraplenWidth to wrap at (when chflags & CH_DISPLAY)
Return values
0Success
-1Failure

Definition at line 663 of file copy_email.c.

665{
666 struct Body *body = e->body;
667 struct Buffer *prefix = buf_pool_get();
668 LOFF_T new_offset = -1;
669 int rc = 0;
670
671 if (cmflags & MUTT_CM_PREFIX)
672 {
673 const bool c_text_flowed = cs_subset_bool(NeoMutt->sub, "text_flowed");
674 if (c_text_flowed)
675 {
676 buf_strcpy(prefix, ">");
677 }
678 else
679 {
680 const char *const c_attribution_locale = cs_subset_string(NeoMutt->sub, "attribution_locale");
681 const struct Expando *c_indent_string = cs_subset_expando(NeoMutt->sub, "indent_string");
682 struct Mailbox *m_cur = get_current_mailbox();
683 setlocale(LC_TIME, NONULL(c_attribution_locale));
684 mutt_make_string(prefix, -1, c_indent_string, m_cur, -1, e, MUTT_FORMAT_NONE, NULL);
685 setlocale(LC_TIME, "");
686 }
687 }
688
689 if ((cmflags & MUTT_CM_NOHEADER) == 0)
690 {
691 if (cmflags & MUTT_CM_PREFIX)
692 {
693 chflags |= CH_PREFIX;
694 }
695 else if (e->attach_del && (chflags & CH_UPDATE_LEN))
696 {
697 int new_lines;
698 int rc_attach_del = -1;
699 LOFF_T new_length = body->length;
700 struct Buffer *quoted_date = NULL;
701
702 quoted_date = buf_pool_get();
703 buf_addch(quoted_date, '"');
704 mutt_date_make_date(quoted_date, cs_subset_bool(NeoMutt->sub, "local_date_header"));
705 buf_addch(quoted_date, '"');
706
707 /* Count the number of lines and bytes to be deleted */
708 if (!mutt_file_seek(fp_in, body->offset, SEEK_SET))
709 {
710 goto attach_del_cleanup;
711 }
712 const int del = count_delete_lines(fp_in, body, &new_length, buf_len(quoted_date));
713 if (del == -1)
714 {
715 goto attach_del_cleanup;
716 }
717 new_lines = e->lines - del;
718
719 /* Copy the headers */
720 if (mutt_copy_header(fp_in, e, fp_out, chflags | CH_NOLEN | CH_NONEWLINE,
721 NULL, wraplen) != 0)
722 {
723 goto attach_del_cleanup;
724 }
725 fprintf(fp_out, "Content-Length: " OFF_T_FMT "\n", new_length);
726 if (new_lines <= 0)
727 new_lines = 0;
728 else
729 fprintf(fp_out, "Lines: %d\n", new_lines);
730
731 putc('\n', fp_out);
732 if (ferror(fp_out) || feof(fp_out))
733 goto attach_del_cleanup;
734 new_offset = ftello(fp_out);
735
736 /* Copy the body */
737 if (!mutt_file_seek(fp_in, body->offset, SEEK_SET))
738 goto attach_del_cleanup;
739 if (copy_delete_attach(body, fp_in, fp_out, buf_string(quoted_date)))
740 goto attach_del_cleanup;
741
742 buf_pool_release(&quoted_date);
743
744 LOFF_T fail = ((ftello(fp_out) - new_offset) - new_length);
745 if (fail)
746 {
747 mutt_error(ngettext("The length calculation was wrong by %ld byte",
748 "The length calculation was wrong by %ld bytes", fail),
749 (long) fail);
750 new_length += fail;
751 }
752
753 /* Update original message if we are sync'ing a mailfolder */
754 if (cmflags & MUTT_CM_UPDATE)
755 {
756 e->attach_del = false;
757 e->lines = new_lines;
758 body->offset = new_offset;
759
760 body->length = new_length;
761 mutt_body_free(&body->parts);
762 }
763
764 rc_attach_del = 0;
765
766 attach_del_cleanup:
767 buf_pool_release(&quoted_date);
768 rc = rc_attach_del;
769 goto done;
770 }
771
772 if (mutt_copy_header(fp_in, e, fp_out, chflags,
773 (chflags & CH_PREFIX) ? buf_string(prefix) : NULL, wraplen) == -1)
774 {
775 rc = -1;
776 goto done;
777 }
778
779 new_offset = ftello(fp_out);
780 }
781
782 if (cmflags & MUTT_CM_DECODE)
783 {
784 /* now make a text/plain version of the message */
785 struct State state = { 0 };
786 state.fp_in = fp_in;
787 state.fp_out = fp_out;
788 if (cmflags & MUTT_CM_PREFIX)
789 state.prefix = buf_string(prefix);
790 if (cmflags & MUTT_CM_DISPLAY)
791 {
792 state.flags |= STATE_DISPLAY;
793 state.wraplen = wraplen;
794 const char *const c_pager = pager_get_pager(NeoMutt->sub);
795 if (!c_pager)
796 state.flags |= STATE_PAGER;
797 }
798 if (cmflags & MUTT_CM_PRINTING)
799 state.flags |= STATE_PRINTING;
800 if (cmflags & MUTT_CM_WEED)
801 state.flags |= STATE_WEED;
802 if (cmflags & MUTT_CM_CHARCONV)
803 state.flags |= STATE_CHARCONV;
804 if (cmflags & MUTT_CM_REPLYING)
805 state.flags |= STATE_REPLYING;
806
807 if ((WithCrypto != 0) && cmflags & MUTT_CM_VERIFY)
808 state.flags |= STATE_VERIFY;
809
810 rc = mutt_body_handler(body, &state);
811 }
812 else if ((WithCrypto != 0) && (cmflags & MUTT_CM_DECODE_CRYPT) && (e->security & SEC_ENCRYPT))
813 {
814 struct Body *cur = NULL;
815 FILE *fp = NULL;
816
817 if (((WithCrypto & APPLICATION_PGP) != 0) && (cmflags & MUTT_CM_DECODE_PGP) &&
819 {
820 if (crypt_pgp_decrypt_mime(fp_in, &fp, e->body, &cur))
821 {
822 rc = 1;
823 goto done;
824 }
825 fputs("MIME-Version: 1.0\n", fp_out);
826 }
827
828 if (((WithCrypto & APPLICATION_SMIME) != 0) && (cmflags & MUTT_CM_DECODE_SMIME) &&
830 {
831 if (crypt_smime_decrypt_mime(fp_in, &fp, e->body, &cur))
832 {
833 rc = 1;
834 goto done;
835 }
836 }
837
838 if (!cur)
839 {
840 mutt_error(_("No decryption engine available for message"));
841 rc = 1;
842 goto done;
843 }
844
845 mutt_write_mime_header(cur, fp_out, NeoMutt->sub);
846 fputc('\n', fp_out);
847
848 if (!mutt_file_seek(fp, cur->offset, SEEK_SET))
849 {
850 rc = 1;
851 goto done;
852 }
853
854 if (mutt_file_copy_bytes(fp, fp_out, cur->length) == -1)
855 {
856 mutt_file_fclose(&fp);
857 mutt_body_free(&cur);
858 rc = 1;
859 goto done;
860 }
861 mutt_body_free(&cur);
862 mutt_file_fclose(&fp);
863 }
864 else
865 {
866 if (!mutt_file_seek(fp_in, body->offset, SEEK_SET))
867 {
868 rc = 1;
869 goto done;
870 }
871 if (cmflags & MUTT_CM_PREFIX)
872 {
873 int c;
874 size_t bytes = body->length;
875
876 fputs(buf_string(prefix), fp_out);
877
878 while (((c = fgetc(fp_in)) != EOF) && bytes--)
879 {
880 fputc(c, fp_out);
881 if (c == '\n')
882 {
883 fputs(buf_string(prefix), fp_out);
884 }
885 }
886 }
887 else if (mutt_file_copy_bytes(fp_in, fp_out, body->length) == -1)
888 {
889 rc = 1;
890 goto done;
891 }
892 }
893
894 if ((cmflags & MUTT_CM_UPDATE) && ((cmflags & MUTT_CM_NOHEADER) == 0) &&
895 (new_offset != -1))
896 {
897 body->offset = new_offset;
898 mutt_body_free(&body->parts);
899 }
900
901done:
902 buf_pool_release(&prefix);
903 return rc;
904}
size_t buf_len(const struct Buffer *buf)
Calculate the length of a Buffer.
Definition buffer.c:491
const char * cs_subset_string(const struct ConfigSubset *sub, const char *name)
Get a string config item by name.
Definition helpers.c:291
const struct Expando * cs_subset_expando(const struct ConfigSubset *sub, const char *name)
Get an Expando config item by name.
int mutt_copy_header(FILE *fp_in, struct Email *e, FILE *fp_out, CopyHeaderFlags chflags, const char *prefix, int wraplen)
Copy Email header.
Definition copy_email.c:432
@ MUTT_CM_PREFIX
Quote the header and body.
Definition copy_email.h:43
@ MUTT_CM_REPLYING
Replying the message.
Definition copy_email.h:50
@ MUTT_CM_DECODE_SMIME
Used for decoding S/MIME messages.
Definition copy_email.h:52
@ MUTT_CM_DECODE_PGP
Used for decoding PGP messages.
Definition copy_email.h:51
@ MUTT_CM_DECODE
Decode the message body into text/plain.
Definition copy_email.h:44
@ MUTT_CM_NOHEADER
Don't copy the message header.
Definition copy_email.h:42
@ MUTT_CM_PRINTING
Printing the message - display light.
Definition copy_email.h:49
@ MUTT_CM_CHARCONV
Perform character set conversions.
Definition copy_email.h:48
@ MUTT_CM_UPDATE
Update structs on sync.
Definition copy_email.h:46
@ MUTT_CM_DISPLAY
Output is displayed to the user.
Definition copy_email.h:45
@ MUTT_CM_VERIFY
Do signature verification.
Definition copy_email.h:53
@ MUTT_CM_WEED
Weed message/rfc822 attachment headers.
Definition copy_email.h:47
#define MUTT_CM_DECODE_CRYPT
Combination flag for decoding any kind of cryptography (PGP or S/MIME)
Definition copy_email.h:58
int crypt_pgp_decrypt_mime(FILE *fp_in, FILE **fp_out, struct Body *b, struct Body **b_dec)
Wrapper for CryptModuleSpecs::decrypt_mime()
Definition cryptglue.c:237
int crypt_smime_decrypt_mime(FILE *fp_in, FILE **fp_out, struct Body *b, struct Body **b_dec)
Wrapper for CryptModuleSpecs::decrypt_mime()
Definition cryptglue.c:510
int mutt_make_string(struct Buffer *buf, size_t max_cols, const struct Expando *exp, struct Mailbox *m, int inpgr, struct Email *e, MuttFormatFlags flags, const char *progress)
Create formatted strings using mailbox expandos.
Definition dlg_index.c:824
void mutt_body_free(struct Body **ptr)
Free a Body.
Definition body.c:58
#define mutt_file_fclose(FP)
Definition file.h:144
#define mutt_error(...)
Definition logging2.h:94
int mutt_body_handler(struct Body *b, struct State *state)
Handler for the Body of an email.
Definition handler.c:1664
struct Mailbox * get_current_mailbox(void)
Get the current Mailbox.
Definition index.c:726
@ TYPE_MULTIPART
Type: 'multipart/*'.
Definition mime.h:37
@ TYPE_APPLICATION
Type: 'application/*'.
Definition mime.h:33
void mutt_date_make_date(struct Buffer *buf, bool local)
Write a date in RFC822 format to a buffer.
Definition date.c:398
#define _(a)
Definition message.h:28
@ STATE_CHARCONV
Do character set conversions.
Definition state.h:41
@ STATE_PRINTING
Are we printing? - STATE_DISPLAY "light".
Definition state.h:42
@ STATE_REPLYING
Are we replying?
Definition state.h:43
@ STATE_PAGER
Output will be displayed in the Pager.
Definition state.h:46
@ STATE_VERIFY
Perform signature verification.
Definition state.h:38
@ STATE_WEED
Weed headers even when not in display mode.
Definition state.h:40
@ STATE_DISPLAY
Output is displayed to the user.
Definition state.h:37
@ SEC_ENCRYPT
Email is encrypted.
Definition lib.h:92
#define APPLICATION_PGP
Use PGP to encrypt/sign.
Definition lib.h:106
#define APPLICATION_SMIME
Use SMIME to encrypt/sign.
Definition lib.h:107
#define WithCrypto
Definition lib.h:132
const char * pager_get_pager(struct ConfigSubset *sub)
Get the value of $pager.
Definition config.c:111
@ MUTT_FORMAT_NONE
No flags are set.
Definition render.h:37
int mutt_write_mime_header(struct Body *b, FILE *fp, struct ConfigSubset *sub)
Create a MIME header.
Definition header.c:757
#define NONULL(x)
Definition string2.h:44
unsigned int type
content-type primary type, ContentType
Definition body.h:40
SecurityFlags security
bit 0-10: flags, bit 11,12: application, bit 13: traditional pgp See: ncrypt/lib.h pgplib....
Definition email.h:43
bool attach_del
Has an attachment marked for deletion.
Definition email.h:99
Parsed Expando trees.
Definition expando.h:41
A mailbox.
Definition mailbox.h:81
Keep track when processing files.
Definition state.h:54
int wraplen
Width to wrap lines to (when flags & STATE_DISPLAY)
Definition state.h:59
StateFlags flags
Flags, e.g. STATE_DISPLAY.
Definition state.h:58
FILE * fp_out
File to write to.
Definition state.h:56
FILE * fp_in
File to read from.
Definition state.h:55
const char * prefix
String to add to the beginning of each output line.
Definition state.h:57
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_copy_message()

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.

Parameters
fp_outFILE pointer to write to
eEmail
msgMessage
cmflagsFlags, see CopyMessageFlags
chflagsFlags, see CopyHeaderFlags
wraplenWidth to wrap at (when chflags & CH_DISPLAY)
Return values
0Success
-1Failure

should be made to return -1 on fatal errors, and 1 on non-fatal errors like partial decode, where it is worth displaying as much as possible

Definition at line 920 of file copy_email.c.

922{
923 if (!msg || !e->body)
924 {
925 return -1;
926 }
927 if (fp_out == msg->fp)
928 {
929 mutt_debug(LL_DEBUG1, "trying to read/write from/to the same FILE*!\n");
930 return -1;
931 }
932
933 int rc = mutt_copy_message_fp(fp_out, msg->fp, e, cmflags, chflags, wraplen);
934 if ((rc == 0) && (ferror(fp_out) || feof(fp_out)))
935 {
936 mutt_debug(LL_DEBUG1, "failed to detect EOF!\n");
937 rc = -1;
938 }
939 return rc;
940}
int mutt_copy_message_fp(FILE *fp_out, FILE *fp_in, struct Email *e, CopyMessageFlags cmflags, CopyHeaderFlags chflags, int wraplen)
Make a copy of a message from a FILE pointer.
Definition copy_email.c:663
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:

◆ append_message()

static int append_message ( struct Mailbox * dest,
FILE * fp_in,
struct Mailbox * src,
struct Email * e,
CopyMessageFlags cmflags,
CopyHeaderFlags chflags )
static

Appends a copy of the given message to a mailbox.

Parameters
destdestination mailbox
fp_inwhere to get input
srcsource mailbox
eEmail being copied
cmflagsFlags, see CopyMessageFlags
chflagsFlags, see CopyHeaderFlags
Return values
0Success
-1Error

Definition at line 953 of file copy_email.c.

955{
956 char buf[256] = { 0 };
957 struct Message *msg = NULL;
958 int rc;
959
960 if (!mutt_file_seek(fp_in, e->offset, SEEK_SET))
961 return -1;
962 if (!fgets(buf, sizeof(buf), fp_in))
963 return -1;
964
965 msg = mx_msg_open_new(dest, e, is_from(buf, NULL, 0, NULL) ? MUTT_MSG_NONE : MUTT_ADD_FROM);
966 if (!msg)
967 return -1;
968 if ((dest->type == MUTT_MBOX) || (dest->type == MUTT_MMDF))
969 chflags |= CH_FROM | CH_FORCE_FROM;
970 chflags |= ((dest->type == MUTT_MAILDIR) ? CH_NOSTATUS : CH_UPDATE);
971 rc = mutt_copy_message_fp(msg->fp, fp_in, e, cmflags, chflags, 0);
972 if (mx_msg_commit(dest, msg) != 0)
973 rc = -1;
974
975#ifdef USE_NOTMUCH
976 if (msg->committed_path && (dest->type == MUTT_MAILDIR) && (src->type == MUTT_NOTMUCH))
977 nm_update_filename(src, NULL, msg->committed_path, e);
978#endif
979
980 mx_msg_close(dest, &msg);
981 return rc;
982}
@ MUTT_NOTMUCH
'Notmuch' (virtual) Mailbox type
Definition mailbox.h:50
@ MUTT_MMDF
'mmdf' Mailbox type
Definition mailbox.h:45
@ MUTT_MBOX
'mbox' Mailbox type
Definition mailbox.h:44
@ MUTT_MAILDIR
'Maildir' Mailbox type
Definition mailbox.h:47
bool is_from(const char *s, char *path, size_t pathlen, time_t *tp)
Is a string a 'From' header line?
Definition from.c:49
int nm_update_filename(struct Mailbox *m, const char *old_file, const char *new_file, struct Email *e)
Change the filename.
Definition notmuch.c:1811
int mx_msg_close(struct Mailbox *m, struct Message **ptr)
Close a message.
Definition mx.c:1182
struct Message * mx_msg_open_new(struct Mailbox *m, const struct Email *e, MsgOpenFlags flags)
Open a new message.
Definition mx.c:1041
int mx_msg_commit(struct Mailbox *m, struct Message *msg)
Commit a message to a folder - Wrapper for MxOps::msg_commit()
Definition mx.c:1161
@ MUTT_ADD_FROM
add a From_ line
Definition mx.h:43
@ MUTT_MSG_NONE
No flags are set.
Definition mx.h:42
enum MailboxType type
Mailbox type.
Definition mailbox.h:104
A local copy of an email.
Definition message.h:34
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:

◆ mutt_append_message()

int mutt_append_message ( struct Mailbox * m_dst,
struct Mailbox * m_src,
struct Email * e,
struct Message * msg,
CopyMessageFlags cmflags,
CopyHeaderFlags chflags )

Append a message.

Parameters
m_dstDestination Mailbox
m_srcSource Mailbox
eEmail
msgMessage
cmflagsFlags, see CopyMessageFlags
chflagsFlags, see CopyHeaderFlags
Return values
0Success
-1Failure

Definition at line 995 of file copy_email.c.

998{
999 if (!e)
1000 return -1;
1001
1002 const bool own_msg = !msg;
1003 if (own_msg && !(msg = mx_msg_open(m_src, e)))
1004 {
1005 return -1;
1006 }
1007
1008 int rc = append_message(m_dst, msg->fp, m_src, e, cmflags, chflags);
1009 if (own_msg)
1010 {
1011 mx_msg_close(m_src, &msg);
1012 }
1013 return rc;
1014}
static int append_message(struct Mailbox *dest, FILE *fp_in, struct Mailbox *src, struct Email *e, CopyMessageFlags cmflags, CopyHeaderFlags chflags)
Appends a copy of the given message to a mailbox.
Definition copy_email.c:953
struct Message * mx_msg_open(struct Mailbox *m, struct Email *e)
Return a stream pointer for a message.
Definition mx.c:1136
+ Here is the call graph for this function:
+ Here is the caller graph for this function: