NeoMutt  2023-11-03-107-g582dc1
Teaching an old dog new tricks
DOXYGEN
Loading...
Searching...
No Matches
copy.c File Reference

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

#include "config.h"
#include <ctype.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 "email/lib.h"
#include "core/lib.h"
#include "gui/lib.h"
#include "mutt.h"
#include "copy.h"
#include "index/lib.h"
#include "ncrypt/lib.h"
#include "pager/lib.h"
#include "send/lib.h"
#include "format_flags.h"
#include "globals.h"
#include "handler.h"
#include "hdrline.h"
#include "mx.h"
#include "notmuch/lib.h"
#include "muttlib.h"
#include <libintl.h>
+ Include dependency graph for copy.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.
 
 ARRAY_HEAD (HeaderArray, char *)
 
static void add_one_header (struct HeaderArray *headers, size_t 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
  • Pietro Cerutti

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.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 1055 of file copy.c.

1056{
1057 char *s = *h;
1058 size_t l;
1059 bool rp = false;
1060
1061 switch (tolower((unsigned char) *s))
1062 {
1063 case 'b':
1064 {
1065 if (!(l = mutt_istr_startswith(s, "bcc:")))
1066 return 0;
1067 break;
1068 }
1069 case 'c':
1070 {
1071 if (!(l = mutt_istr_startswith(s, "cc:")))
1072 return 0;
1073 break;
1074 }
1075 case 'f':
1076 {
1077 if (!(l = mutt_istr_startswith(s, "from:")))
1078 return 0;
1079 break;
1080 }
1081 case 'm':
1082 {
1083 if (!(l = mutt_istr_startswith(s, "mail-followup-to:")))
1084 return 0;
1085 break;
1086 }
1087 case 'r':
1088 {
1089 if ((l = mutt_istr_startswith(s, "return-path:")))
1090 {
1091 rp = true;
1092 break;
1093 }
1094 else if ((l = mutt_istr_startswith(s, "reply-to:")))
1095 {
1096 break;
1097 }
1098 return 0;
1099 }
1100 case 's':
1101 {
1102 if (!(l = mutt_istr_startswith(s, "sender:")))
1103 return 0;
1104 break;
1105 }
1106 case 't':
1107 {
1108 if (!(l = mutt_istr_startswith(s, "to:")))
1109 return 0;
1110 break;
1111 }
1112 default:
1113 return 0;
1114 }
1115
1116 struct AddressList al = TAILQ_HEAD_INITIALIZER(al);
1117 mutt_addrlist_parse(&al, s + l);
1118 if (TAILQ_EMPTY(&al))
1119 return 0;
1120
1123 struct Address *a = NULL;
1124 TAILQ_FOREACH(a, &al, entries)
1125 {
1126 if (a->personal)
1127 {
1129 }
1130 }
1131
1132 /* angle brackets for return path are mandated by RFC5322,
1133 * so leave Return-Path as-is */
1134 if (rp)
1135 {
1136 *h = mutt_str_dup(s);
1137 }
1138 else
1139 {
1140 struct Buffer buf = { 0 };
1141 (*h)[l - 1] = '\0';
1142 mutt_addrlist_write_wrap(&al, &buf, *h);
1143 buf_addch(&buf, '\n');
1144 *h = buf.data;
1145 }
1146
1148
1149 FREE(&s);
1150 return 1;
1151}
void mutt_addrlist_clear(struct AddressList *al)
Unlink and free all Address in an AddressList.
Definition: address.c:1461
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:1190
int mutt_addrlist_to_local(struct AddressList *al)
Convert an Address list from Punycode.
Definition: address.c:1379
int mutt_addrlist_parse(struct AddressList *al, const char *s)
Parse a list of email addresses.
Definition: address.c:478
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:253
#define FREE(x)
Definition: memory.h:45
char * mutt_str_dup(const char *str)
Copy a string, safely.
Definition: string.c:251
size_t mutt_istr_startswith(const char *str, const char *prefix)
Check whether a string starts with a prefix, ignoring case.
Definition: string.c:240
#define TAILQ_FOREACH(var, head, field)
Definition: queue.h:725
#define TAILQ_HEAD_INITIALIZER(head)
Definition: queue.h:637
#define TAILQ_EMPTY(head)
Definition: queue.h:721
void rfc2047_decode_addrlist(struct AddressList *al)
Decode any RFC2047 headers in an Address list.
Definition: rfc2047.c:797
An email address.
Definition: address.h:36
struct Buffer * personal
Real name of address.
Definition: address.h:37
String manipulation buffer.
Definition: buffer.h:34
char * data
Pointer to data.
Definition: buffer.h:35
+ 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 993 of file copy.c.

994{
995 struct Body *part = NULL;
996
997 for (part = b->parts; part; part = part->next)
998 {
999 if (part->deleted || part->parts)
1000 {
1001 /* Copy till start of this part */
1002 if (mutt_file_copy_bytes(fp_in, fp_out, part->hdr_offset - ftello(fp_in)))
1003 {
1004 return -1;
1005 }
1006
1007 if (part->deleted)
1008 {
1009 /* If this is modified, count_delete_lines() needs to be changed too */
1010 fprintf(fp_out,
1011 "Content-Type: message/external-body; access-type=x-mutt-deleted;\n"
1012 "\texpiration=%s; length=" OFF_T_FMT "\n"
1013 "\n",
1014 quoted_date, part->length);
1015 if (ferror(fp_out))
1016 {
1017 return -1;
1018 }
1019
1020 /* Copy the original mime headers */
1021 if (mutt_file_copy_bytes(fp_in, fp_out, part->offset - ftello(fp_in)))
1022 {
1023 return -1;
1024 }
1025
1026 /* Skip the deleted body */
1027 if (!mutt_file_seek(fp_in, part->offset + part->length, SEEK_SET))
1028 {
1029 return -1;
1030 }
1031 }
1032 else
1033 {
1034 if (copy_delete_attach(part, fp_in, fp_out, quoted_date))
1035 {
1036 return -1;
1037 }
1038 }
1039 }
1040 }
1041
1042 /* Copy the last parts */
1043 if (mutt_file_copy_bytes(fp_in, fp_out, b->offset + b->length - ftello(fp_in)))
1044 return -1;
1045
1046 return 0;
1047}
static int copy_delete_attach(struct Body *b, FILE *fp_in, FILE *fp_out, const char *quoted_date)
Copy a message, deleting marked attachments.
Definition: copy.c:993
int mutt_file_copy_bytes(FILE *fp_in, FILE *fp_out, size_t size)
Copy some content from one file to another.
Definition: file.c:232
bool mutt_file_seek(FILE *fp, LOFF_T offset, int whence)
Wrapper for fseeko with error handling.
Definition: file.c:733
The body of an email.
Definition: body.h:36
struct Body * parts
parts of a multipart or message/rfc822
Definition: body.h:72
LOFF_T offset
offset where the actual data begins
Definition: body.h:52
bool deleted
Attachment marked for deletion.
Definition: body.h:87
LOFF_T length
length (in bytes) of attachment
Definition: body.h:53
struct Body * next
next attachment in the list
Definition: body.h:71
long hdr_offset
Offset in stream where the headers begin.
Definition: body.h:80
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ ARRAY_HEAD()

ARRAY_HEAD ( HeaderArray  ,
char *   
)

◆ add_one_header()

static void add_one_header ( struct HeaderArray *  headers,
size_t  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 76 of file copy.c.

77{
78 char **old = ARRAY_GET(headers, pos);
79 if (old && *old)
80 {
81 char *new_value = NULL;
82 mutt_str_asprintf(&new_value, "%s%s", *old, value);
83 FREE(old);
84 FREE(&value);
85 value = new_value;
86 }
87 ARRAY_SET(headers, pos, value);
88}
#define ARRAY_SET(head, idx, elem)
Set an element in the array.
Definition: array.h:122
#define ARRAY_GET(head, idx)
Return the element at index.
Definition: array.h:108
int mutt_str_asprintf(char **strp, const char *fmt,...)
Definition: string.c:966
+ 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 106 of file copy.c.

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

425{
426 char *temp_hdr = NULL;
427
428 if (e->env)
429 {
430 chflags |= ((e->env->changed & MUTT_ENV_CHANGED_IRT) ? CH_UPDATE_IRT : 0) |
434 }
435
436 if (mutt_copy_hdr(fp_in, fp_out, e->offset, e->body->offset, chflags, prefix, wraplen) == -1)
437 return -1;
438
439 if (chflags & CH_TXTPLAIN)
440 {
441 char chsbuf[128] = { 0 };
442 char buf[128] = { 0 };
443 fputs("MIME-Version: 1.0\n", fp_out);
444 fputs("Content-Transfer-Encoding: 8bit\n", fp_out);
445 fputs("Content-Type: text/plain; charset=", fp_out);
446 const char *const c_charset = cc_charset();
447 mutt_ch_canonical_charset(chsbuf, sizeof(chsbuf), c_charset ? c_charset : "us-ascii");
448 mutt_addr_cat(buf, sizeof(buf), chsbuf, MimeSpecials);
449 fputs(buf, fp_out);
450 fputc('\n', fp_out);
451 }
452
453 if ((chflags & CH_UPDATE_IRT) && !STAILQ_EMPTY(&e->env->in_reply_to))
454 {
455 fputs("In-Reply-To:", fp_out);
456 struct ListNode *np = NULL;
457 STAILQ_FOREACH(np, &e->env->in_reply_to, entries)
458 {
459 fputc(' ', fp_out);
460 fputs(np->data, fp_out);
461 }
462 fputc('\n', fp_out);
463 }
464
465 if ((chflags & CH_UPDATE_REFS) && !STAILQ_EMPTY(&e->env->references))
466 {
467 fputs("References:", fp_out);
468 mutt_write_references(&e->env->references, fp_out, 0);
469 fputc('\n', fp_out);
470 }
471
472 if ((chflags & CH_UPDATE) && ((chflags & CH_NOSTATUS) == 0))
473 {
474 if (e->old || e->read)
475 {
476 fputs("Status: ", fp_out);
477 if (e->read)
478 fputs("RO", fp_out);
479 else if (e->old)
480 fputc('O', fp_out);
481 fputc('\n', fp_out);
482 }
483
484 if (e->flagged || e->replied)
485 {
486 fputs("X-Status: ", fp_out);
487 if (e->replied)
488 fputc('A', fp_out);
489 if (e->flagged)
490 fputc('F', fp_out);
491 fputc('\n', fp_out);
492 }
493 }
494
495 if (chflags & CH_UPDATE_LEN && ((chflags & CH_NOLEN) == 0))
496 {
497 fprintf(fp_out, "Content-Length: " OFF_T_FMT "\n", e->body->length);
498 if ((e->lines != 0) || (e->body->length == 0))
499 fprintf(fp_out, "Lines: %d\n", e->lines);
500 }
501
502 const bool c_weed = cs_subset_bool(NeoMutt->sub, "weed");
503#ifdef USE_NOTMUCH
504 if (chflags & CH_VIRTUAL)
505 {
506 /* Add some fake headers based on notmuch data */
507 char *folder = nm_email_get_folder(e);
508 if (folder && !(c_weed && mutt_matches_ignore("folder")))
509 {
510 char buf[1024] = { 0 };
511 mutt_str_copy(buf, folder, sizeof(buf));
512 mutt_pretty_mailbox(buf, sizeof(buf));
513
514 fputs("Folder: ", fp_out);
515 fputs(buf, fp_out);
516 fputc('\n', fp_out);
517 }
518 }
519#endif
520 char *tags = driver_tags_get(&e->tags);
521 if (tags && !(c_weed && mutt_matches_ignore("tags")))
522 {
523 fputs("Tags: ", fp_out);
524 fputs(tags, fp_out);
525 fputc('\n', fp_out);
526 }
527 FREE(&tags);
528
529 const struct Slist *const c_send_charset = cs_subset_slist(NeoMutt->sub, "send_charset");
530 const short c_wrap = cs_subset_number(NeoMutt->sub, "wrap");
531 if ((chflags & CH_UPDATE_LABEL) && e->env->x_label)
532 {
533 temp_hdr = e->env->x_label;
534 /* env->x_label isn't currently stored with direct references elsewhere.
535 * Mailbox->label_hash strdups the keys. But to be safe, encode a copy */
536 if (!(chflags & CH_DECODE))
537 {
538 temp_hdr = mutt_str_dup(temp_hdr);
539 rfc2047_encode(&temp_hdr, NULL, sizeof("X-Label:"), c_send_charset);
540 }
541 if (mutt_write_one_header(fp_out, "X-Label", temp_hdr, (chflags & CH_PREFIX) ? prefix : 0,
542 mutt_window_wrap_cols(wraplen, c_wrap), chflags,
543 NeoMutt->sub) == -1)
544 {
545 return -1;
546 }
547 if (!(chflags & CH_DECODE))
548 FREE(&temp_hdr);
549 }
550
551 if ((chflags & CH_UPDATE_SUBJECT) && e->env->subject)
552 {
553 temp_hdr = e->env->subject;
554 /* env->subject is directly referenced in Mailbox->subj_hash, so we
555 * have to be careful not to encode (and thus free) that memory. */
556 if (!(chflags & CH_DECODE))
557 {
558 temp_hdr = mutt_str_dup(temp_hdr);
559 rfc2047_encode(&temp_hdr, NULL, sizeof("Subject:"), c_send_charset);
560 }
561 if (mutt_write_one_header(fp_out, "Subject", temp_hdr, (chflags & CH_PREFIX) ? prefix : 0,
562 mutt_window_wrap_cols(wraplen, c_wrap), chflags,
563 NeoMutt->sub) == -1)
564 {
565 return -1;
566 }
567 if (!(chflags & CH_DECODE))
568 FREE(&temp_hdr);
569 }
570
571 if ((chflags & CH_NONEWLINE) == 0)
572 {
573 if (chflags & CH_PREFIX)
574 fputs(prefix, fp_out);
575 fputc('\n', fp_out); /* add header terminator */
576 }
577
578 if (ferror(fp_out) || feof(fp_out))
579 return -1;
580
581 return 0;
582}
void mutt_addr_cat(char *buf, size_t buflen, const char *value, const char *specials)
Copy a string and wrap it in quotes if it contains special characters.
Definition: address.c:705
void mutt_pretty_mailbox(char *buf, size_t buflen)
Shorten a mailbox path using '~' or '='.
Definition: muttlib.c:477
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
bool cs_subset_bool(const struct ConfigSubset *sub, const char *name)
Get a boolean config item by name.
Definition: helpers.c:48
const char * cc_charset(void)
Get the cached value of $charset.
Definition: config_cache.c:115
int mutt_copy_hdr(FILE *fp_in, FILE *fp_out, LOFF_T off_start, LOFF_T off_end, CopyHeaderFlags chflags, const char *prefix, int wraplen)
Copy header from one file to another.
Definition: copy.c:106
#define CH_NONEWLINE
Don't output terminating newline after the header.
Definition: copy.h:60
#define CH_TXTPLAIN
Generate text/plain MIME headers.
Definition: copy.h:63
#define CH_VIRTUAL
Write virtual header lines too.
Definition: copy.h:73
#define MUTT_ENV_CHANGED_SUBJECT
Protected header update.
Definition: envelope.h:37
#define MUTT_ENV_CHANGED_XLABEL
X-Label edited.
Definition: envelope.h:36
#define MUTT_ENV_CHANGED_IRT
In-Reply-To changed to link/break threads.
Definition: envelope.h:34
#define MUTT_ENV_CHANGED_REFS
References changed to break thread.
Definition: envelope.h:35
void mutt_write_references(const struct ListHead *r, FILE *fp, size_t trim)
Add the message references to a list.
Definition: header.c:517
const char MimeSpecials[]
Characters that need special treatment in MIME.
Definition: mime.c:67
void mutt_ch_canonical_charset(char *buf, size_t buflen, const char *name)
Canonicalise the charset of a string.
Definition: charset.c:371
size_t mutt_str_copy(char *dest, const char *src, size_t dsize)
Copy a string into a buffer (guaranteeing NUL-termination)
Definition: string.c:653
char * nm_email_get_folder(struct Email *e)
Get the folder for a Email.
Definition: notmuch.c:1459
#define STAILQ_EMPTY(head)
Definition: queue.h:348
void rfc2047_encode(char **pd, const char *specials, int col, const struct Slist *charsets)
RFC-2047-encode a string.
Definition: rfc2047.c:626
bool read
Email is read.
Definition: email.h:48
struct Envelope * env
Envelope information.
Definition: email.h:66
int lines
How many lines in the body of this message?
Definition: email.h:60
struct Body * body
List of MIME parts.
Definition: email.h:67
bool old
Email is seen, but unread.
Definition: email.h:47
LOFF_T offset
Where in the stream does this message begin?
Definition: email.h:69
bool flagged
Marked important?
Definition: email.h:45
bool replied
Email has been replied to.
Definition: email.h:49
struct TagList tags
For drivers that support server tagging.
Definition: email.h:70
unsigned char changed
Changed fields, e.g. MUTT_ENV_CHANGED_SUBJECT.
Definition: envelope.h:90
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 * subject
Email's subject.
Definition: envelope.h:70
char * x_label
X-Label.
Definition: envelope.h:76
String list.
Definition: slist.h:47
char * driver_tags_get(struct TagList *list)
Get tags.
Definition: tags.c:145
+ 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 595 of file copy.c.

596{
597 int dellines = 0;
598
599 if (b->deleted)
600 {
601 if (!mutt_file_seek(fp, b->offset, SEEK_SET))
602 {
603 return -1;
604 }
605 for (long l = b->length; l; l--)
606 {
607 const int ch = getc(fp);
608 if (ch == EOF)
609 break;
610 if (ch == '\n')
611 dellines++;
612 }
613 /* 3 and 89 come from the added header of three lines in
614 * copy_delete_attach(). 89 is the size of the header(including
615 * the newlines, tabs, and a single digit length), not including
616 * the date length. */
617 dellines -= 3;
618 *length -= b->length - (89 + datelen);
619 /* Count the number of digits exceeding the first one to write the size */
620 for (long l = 10; b->length >= l; l *= 10)
621 (*length)++;
622 }
623 else
624 {
625 for (b = b->parts; b; b = b->next)
626 {
627 const int del = count_delete_lines(fp, b, length, datelen);
628 if (del == -1)
629 {
630 return -1;
631 }
632 dellines += del;
633 }
634 }
635 return dellines;
636}
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.c:595
+ 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 649 of file copy.c.

651{
652 struct Body *body = e->body;
653 char prefix[128] = { 0 };
654 LOFF_T new_offset = -1;
655 int rc = 0;
656
657 if (cmflags & MUTT_CM_PREFIX)
658 {
659 const bool c_text_flowed = cs_subset_bool(NeoMutt->sub, "text_flowed");
660 if (c_text_flowed)
661 {
662 mutt_str_copy(prefix, ">", sizeof(prefix));
663 }
664 else
665 {
666 const char *const c_attribution_locale = cs_subset_string(NeoMutt->sub, "attribution_locale");
667 const char *const c_indent_string = cs_subset_string(NeoMutt->sub, "indent_string");
668 struct Mailbox *m_cur = get_current_mailbox();
669 setlocale(LC_TIME, NONULL(c_attribution_locale));
670 mutt_make_string(prefix, sizeof(prefix), wraplen, NONULL(c_indent_string),
671 m_cur, -1, e, MUTT_FORMAT_NO_FLAGS, NULL);
672 setlocale(LC_TIME, "");
673 }
674 }
675
676 if ((cmflags & MUTT_CM_NOHEADER) == 0)
677 {
678 if (cmflags & MUTT_CM_PREFIX)
679 {
680 chflags |= CH_PREFIX;
681 }
682 else if (e->attach_del && (chflags & CH_UPDATE_LEN))
683 {
684 int new_lines;
685 int rc_attach_del = -1;
686 LOFF_T new_length = body->length;
687 struct Buffer *quoted_date = NULL;
688
689 quoted_date = buf_pool_get();
690 buf_addch(quoted_date, '"');
691 mutt_date_make_date(quoted_date, cs_subset_bool(NeoMutt->sub, "local_date_header"));
692 buf_addch(quoted_date, '"');
693
694 /* Count the number of lines and bytes to be deleted */
695 if (!mutt_file_seek(fp_in, body->offset, SEEK_SET))
696 {
697 goto attach_del_cleanup;
698 }
699 const int del = count_delete_lines(fp_in, body, &new_length, buf_len(quoted_date));
700 if (del == -1)
701 {
702 goto attach_del_cleanup;
703 }
704 new_lines = e->lines - del;
705
706 /* Copy the headers */
707 if (mutt_copy_header(fp_in, e, fp_out, chflags | CH_NOLEN | CH_NONEWLINE, NULL, wraplen))
708 goto attach_del_cleanup;
709 fprintf(fp_out, "Content-Length: " OFF_T_FMT "\n", new_length);
710 if (new_lines <= 0)
711 new_lines = 0;
712 else
713 fprintf(fp_out, "Lines: %d\n", new_lines);
714
715 putc('\n', fp_out);
716 if (ferror(fp_out) || feof(fp_out))
717 goto attach_del_cleanup;
718 new_offset = ftello(fp_out);
719
720 /* Copy the body */
721 if (!mutt_file_seek(fp_in, body->offset, SEEK_SET))
722 goto attach_del_cleanup;
723 if (copy_delete_attach(body, fp_in, fp_out, buf_string(quoted_date)))
724 goto attach_del_cleanup;
725
726 buf_pool_release(&quoted_date);
727
728 LOFF_T fail = ((ftello(fp_out) - new_offset) - new_length);
729 if (fail)
730 {
731 mutt_error(ngettext("The length calculation was wrong by %ld byte",
732 "The length calculation was wrong by %ld bytes", fail),
733 fail);
734 new_length += fail;
735 }
736
737 /* Update original message if we are sync'ing a mailfolder */
738 if (cmflags & MUTT_CM_UPDATE)
739 {
740 e->attach_del = false;
741 e->lines = new_lines;
742 body->offset = new_offset;
743
744 body->length = new_length;
745 mutt_body_free(&body->parts);
746 }
747
748 rc_attach_del = 0;
749
750 attach_del_cleanup:
751 buf_pool_release(&quoted_date);
752 return rc_attach_del;
753 }
754
755 if (mutt_copy_header(fp_in, e, fp_out, chflags,
756 (chflags & CH_PREFIX) ? prefix : NULL, wraplen) == -1)
757 {
758 return -1;
759 }
760
761 new_offset = ftello(fp_out);
762 }
763
764 if (cmflags & MUTT_CM_DECODE)
765 {
766 /* now make a text/plain version of the message */
767 struct State state = { 0 };
768 state.fp_in = fp_in;
769 state.fp_out = fp_out;
770 if (cmflags & MUTT_CM_PREFIX)
771 state.prefix = prefix;
772 if (cmflags & MUTT_CM_DISPLAY)
773 {
774 state.flags |= STATE_DISPLAY;
775 state.wraplen = wraplen;
776 const char *const c_pager = pager_get_pager(NeoMutt->sub);
777 if (!c_pager)
778 state.flags |= STATE_PAGER;
779 }
780 if (cmflags & MUTT_CM_PRINTING)
781 state.flags |= STATE_PRINTING;
782 if (cmflags & MUTT_CM_WEED)
783 state.flags |= STATE_WEED;
784 if (cmflags & MUTT_CM_CHARCONV)
785 state.flags |= STATE_CHARCONV;
786 if (cmflags & MUTT_CM_REPLYING)
787 state.flags |= STATE_REPLYING;
788
789 if ((WithCrypto != 0) && cmflags & MUTT_CM_VERIFY)
790 state.flags |= STATE_VERIFY;
791
792 rc = mutt_body_handler(body, &state);
793 }
794 else if ((WithCrypto != 0) && (cmflags & MUTT_CM_DECODE_CRYPT) && (e->security & SEC_ENCRYPT))
795 {
796 struct Body *cur = NULL;
797 FILE *fp = NULL;
798
799 if (((WithCrypto & APPLICATION_PGP) != 0) && (cmflags & MUTT_CM_DECODE_PGP) &&
801 {
802 if (crypt_pgp_decrypt_mime(fp_in, &fp, e->body, &cur))
803 return -1;
804 fputs("MIME-Version: 1.0\n", fp_out);
805 }
806
807 if (((WithCrypto & APPLICATION_SMIME) != 0) && (cmflags & MUTT_CM_DECODE_SMIME) &&
809 {
810 if (crypt_smime_decrypt_mime(fp_in, &fp, e->body, &cur))
811 return -1;
812 }
813
814 if (!cur)
815 {
816 mutt_error(_("No decryption engine available for message"));
817 return -1;
818 }
819
820 mutt_write_mime_header(cur, fp_out, NeoMutt->sub);
821 fputc('\n', fp_out);
822
823 if (!mutt_file_seek(fp, cur->offset, SEEK_SET))
824 return -1;
825 if (mutt_file_copy_bytes(fp, fp_out, cur->length) == -1)
826 {
827 mutt_file_fclose(&fp);
828 mutt_body_free(&cur);
829 return -1;
830 }
831 mutt_body_free(&cur);
832 mutt_file_fclose(&fp);
833 }
834 else
835 {
836 if (!mutt_file_seek(fp_in, body->offset, SEEK_SET))
837 return -1;
838 if (cmflags & MUTT_CM_PREFIX)
839 {
840 int c;
841 size_t bytes = body->length;
842
843 fputs(prefix, fp_out);
844
845 while (((c = fgetc(fp_in)) != EOF) && bytes--)
846 {
847 fputc(c, fp_out);
848 if (c == '\n')
849 {
850 fputs(prefix, fp_out);
851 }
852 }
853 }
854 else if (mutt_file_copy_bytes(fp_in, fp_out, body->length) == -1)
855 {
856 return -1;
857 }
858 }
859
860 if ((cmflags & MUTT_CM_UPDATE) && ((cmflags & MUTT_CM_NOHEADER) == 0) &&
861 (new_offset != -1))
862 {
863 body->offset = new_offset;
864 mutt_body_free(&body->parts);
865 }
866
867 return rc;
868}
size_t buf_len(const struct Buffer *buf)
Calculate the length of a Buffer.
Definition: buffer.c:466
static const char * buf_string(const struct Buffer *buf)
Convert a buffer to a const char * "string".
Definition: buffer.h:93
const char * cs_subset_string(const struct ConfigSubset *sub, const char *name)
Get a string config item by name.
Definition: helpers.c:292
int mutt_copy_header(FILE *fp_in, struct Email *e, FILE *fp_out, CopyHeaderFlags chflags, const char *prefix, int wraplen)
Copy Email header.
Definition: copy.c:423
#define MUTT_CM_WEED
Weed message/rfc822 attachment headers.
Definition: copy.h:41
#define MUTT_CM_REPLYING
Replying the message.
Definition: copy.h:44
#define MUTT_CM_PREFIX
Quote the header and body.
Definition: copy.h:37
#define MUTT_CM_UPDATE
Update structs on sync.
Definition: copy.h:40
#define MUTT_CM_VERIFY
Do signature verification.
Definition: copy.h:47
#define MUTT_CM_DECODE_PGP
Used for decoding PGP messages.
Definition: copy.h:45
#define MUTT_CM_DECODE
Decode the message body into text/plain.
Definition: copy.h:38
#define MUTT_CM_CHARCONV
Perform character set conversions.
Definition: copy.h:42
#define MUTT_CM_DECODE_SMIME
Used for decoding S/MIME messages.
Definition: copy.h:46
#define MUTT_CM_PRINTING
Printing the message - display light.
Definition: copy.h:43
#define MUTT_CM_DECODE_CRYPT
Definition: copy.h:48
#define MUTT_CM_NOHEADER
Don't copy the message header.
Definition: copy.h:36
#define MUTT_CM_DISPLAY
Output is displayed to the user.
Definition: copy.h:39
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:211
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:433
void mutt_body_free(struct Body **ptr)
Free a Body.
Definition: body.c:57
int mutt_file_fclose(FILE **fp)
Close a FILE handle (and NULL the pointer)
Definition: file.c:152
#define MUTT_FORMAT_NO_FLAGS
No flags are set.
Definition: format_flags.h:30
#define mutt_error(...)
Definition: logging2.h:92
int mutt_body_handler(struct Body *b, struct State *state)
Handler for the Body of an email.
Definition: handler.c:1624
void mutt_make_string(char *buf, size_t buflen, int cols, const char *s, struct Mailbox *m, int inpgr, struct Email *e, MuttFormatFlags flags, const char *progress)
Create formatted strings using mailbox expandos.
Definition: hdrline.c:1422
int mutt_write_mime_header(struct Body *b, FILE *fp, struct ConfigSubset *sub)
Create a MIME header.
Definition: header.c:754
struct Mailbox * get_current_mailbox(void)
Get the current Mailbox.
Definition: index.c:662
@ 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:387
#define _(a)
Definition: message.h:28
#define STATE_PAGER
Output will be displayed in the Pager.
Definition: state.h:41
#define STATE_WEED
Weed headers even when not in display mode.
Definition: state.h:35
#define STATE_DISPLAY
Output is displayed to the user.
Definition: state.h:32
#define STATE_REPLYING
Are we replying?
Definition: state.h:38
#define STATE_VERIFY
Perform signature verification.
Definition: state.h:33
#define STATE_CHARCONV
Do character set conversions.
Definition: state.h:36
#define STATE_PRINTING
Are we printing? - STATE_DISPLAY "light".
Definition: state.h:37
#define APPLICATION_PGP
Use PGP to encrypt/sign.
Definition: lib.h:91
#define APPLICATION_SMIME
Use SMIME to encrypt/sign.
Definition: lib.h:92
#define SEC_ENCRYPT
Email is encrypted.
Definition: lib.h:79
#define WithCrypto
Definition: lib.h:117
const char * pager_get_pager(struct ConfigSubset *sub)
Get the value of $pager.
Definition: config.c:103
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
#define NONULL(x)
Definition: string2.h:37
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:41
bool attach_del
Has an attachment marked for deletion.
Definition: email.h:100
A mailbox.
Definition: mailbox.h:79
Keep track when processing files.
Definition: state.h:47
int wraplen
Width to wrap lines to (when flags & STATE_DISPLAY)
Definition: state.h:52
StateFlags flags
Flags, e.g. STATE_DISPLAY.
Definition: state.h:51
FILE * fp_out
File to write to.
Definition: state.h:49
char * prefix
String to add to the beginning of each output line.
Definition: state.h:50
FILE * fp_in
File to read from.
Definition: state.h:48
+ 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 884 of file copy.c.

886{
887 if (!msg || !e->body)
888 {
889 return -1;
890 }
891 if (fp_out == msg->fp)
892 {
893 mutt_debug(LL_DEBUG1, "trying to read/write from/to the same FILE*!\n");
894 return -1;
895 }
896
897 int rc = mutt_copy_message_fp(fp_out, msg->fp, e, cmflags, chflags, wraplen);
898 if ((rc == 0) && (ferror(fp_out) || feof(fp_out)))
899 {
900 mutt_debug(LL_DEBUG1, "failed to detect EOF!\n");
901 rc = -1;
902 }
903 return rc;
904}
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.c:649
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 917 of file copy.c.

919{
920 char buf[256] = { 0 };
921 struct Message *msg = NULL;
922 int rc;
923
924 if (!mutt_file_seek(fp_in, e->offset, SEEK_SET))
925 return -1;
926 if (!fgets(buf, sizeof(buf), fp_in))
927 return -1;
928
929 msg = mx_msg_open_new(dest, e, is_from(buf, NULL, 0, NULL) ? MUTT_MSG_NO_FLAGS : MUTT_ADD_FROM);
930 if (!msg)
931 return -1;
932 if ((dest->type == MUTT_MBOX) || (dest->type == MUTT_MMDF))
933 chflags |= CH_FROM | CH_FORCE_FROM;
934 chflags |= ((dest->type == MUTT_MAILDIR) ? CH_NOSTATUS : CH_UPDATE);
935 rc = mutt_copy_message_fp(msg->fp, fp_in, e, cmflags, chflags, 0);
936 if (mx_msg_commit(dest, msg) != 0)
937 rc = -1;
938
939#ifdef USE_NOTMUCH
940 if (msg->committed_path && (dest->type == MUTT_MAILDIR) && (src->type == MUTT_NOTMUCH))
941 nm_update_filename(src, NULL, msg->committed_path, e);
942#endif
943
944 mx_msg_close(dest, &msg);
945 return rc;
946}
bool is_from(const char *s, char *path, size_t pathlen, time_t *tp)
Is a string a 'From' header line?
Definition: from.c:48
@ MUTT_NOTMUCH
'Notmuch' (virtual) Mailbox type
Definition: mailbox.h:51
@ MUTT_MMDF
'mmdf' Mailbox type
Definition: mailbox.h:46
@ MUTT_MBOX
'mbox' Mailbox type
Definition: mailbox.h:45
@ MUTT_MAILDIR
'Maildir' Mailbox type
Definition: mailbox.h:48
int mx_msg_close(struct Mailbox *m, struct Message **ptr)
Close a message.
Definition: mx.c:1185
struct Message * mx_msg_open_new(struct Mailbox *m, const struct Email *e, MsgOpenFlags flags)
Open a new message.
Definition: mx.c:1034
int mx_msg_commit(struct Mailbox *m, struct Message *msg)
Commit a message to a folder - Wrapper for MxOps::msg_commit()
Definition: mx.c:1164
#define MUTT_ADD_FROM
add a From_ line
Definition: mx.h:40
#define MUTT_MSG_NO_FLAGS
No flags are set.
Definition: mx.h:39
int nm_update_filename(struct Mailbox *m, const char *old_file, const char *new_file, struct Email *e)
Change the filename.
Definition: notmuch.c:1749
enum MailboxType type
Mailbox type.
Definition: mailbox.h:102
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 959 of file copy.c.

962{
963 if (!e)
964 return -1;
965
966 const bool own_msg = !msg;
967 if (own_msg && !(msg = mx_msg_open(m_src, e)))
968 {
969 return -1;
970 }
971
972 int rc = append_message(m_dst, msg->fp, m_src, e, cmflags, chflags);
973 if (own_msg)
974 {
975 mx_msg_close(m_src, &msg);
976 }
977 return rc;
978}
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.c:917
struct Message * mx_msg_open(struct Mailbox *m, struct Email *e)
Return a stream pointer for a message.
Definition: mx.c:1139
+ Here is the call graph for this function:
+ Here is the caller graph for this function: