NeoMutt  2024-04-25-89-g194907
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 "expando/lib.h"
#include "index/lib.h"
#include "ncrypt/lib.h"
#include "pager/lib.h"
#include "send/lib.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
  • Richard Russon
  • Pietro Cerutti
  • Dennis Schön

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

1079{
1080 char *s = *h;
1081 size_t l;
1082 bool rp = false;
1083
1084 switch (tolower((unsigned char) *s))
1085 {
1086 case 'b':
1087 {
1088 if (!(l = mutt_istr_startswith(s, "bcc:")))
1089 return 0;
1090 break;
1091 }
1092 case 'c':
1093 {
1094 if (!(l = mutt_istr_startswith(s, "cc:")))
1095 return 0;
1096 break;
1097 }
1098 case 'f':
1099 {
1100 if (!(l = mutt_istr_startswith(s, "from:")))
1101 return 0;
1102 break;
1103 }
1104 case 'm':
1105 {
1106 if (!(l = mutt_istr_startswith(s, "mail-followup-to:")))
1107 return 0;
1108 break;
1109 }
1110 case 'r':
1111 {
1112 if ((l = mutt_istr_startswith(s, "return-path:")))
1113 {
1114 rp = true;
1115 break;
1116 }
1117 else if ((l = mutt_istr_startswith(s, "reply-to:")))
1118 {
1119 break;
1120 }
1121 return 0;
1122 }
1123 case 's':
1124 {
1125 if (!(l = mutt_istr_startswith(s, "sender:")))
1126 return 0;
1127 break;
1128 }
1129 case 't':
1130 {
1131 if (!(l = mutt_istr_startswith(s, "to:")))
1132 return 0;
1133 break;
1134 }
1135 default:
1136 return 0;
1137 }
1138
1139 struct AddressList al = TAILQ_HEAD_INITIALIZER(al);
1140 mutt_addrlist_parse(&al, s + l);
1141 if (TAILQ_EMPTY(&al))
1142 return 0;
1143
1146 struct Address *a = NULL;
1147 TAILQ_FOREACH(a, &al, entries)
1148 {
1149 if (a->personal)
1150 {
1152 }
1153 }
1154
1155 /* angle brackets for return path are mandated by RFC5322,
1156 * so leave Return-Path as-is */
1157 if (rp)
1158 {
1159 *h = mutt_str_dup(s);
1160 }
1161 else
1162 {
1163 struct Buffer buf = { 0 };
1164 (*h)[l - 1] = '\0';
1165 mutt_addrlist_write_wrap(&al, &buf, *h);
1166 buf_addch(&buf, '\n');
1167 *h = buf.data;
1168 }
1169
1171
1172 FREE(&s);
1173 return 1;
1174}
void mutt_addrlist_clear(struct AddressList *al)
Unlink and free all Address in an AddressList.
Definition: address.c:1460
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:1189
int mutt_addrlist_to_local(struct AddressList *al)
Convert an Address list from Punycode.
Definition: address.c:1378
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
#define FREE(x)
Definition: memory.h:45
char * mutt_str_dup(const char *str)
Copy a string, safely.
Definition: string.c:253
size_t mutt_istr_startswith(const char *str, const char *prefix)
Check whether a string starts with a prefix, ignoring case.
Definition: string.c:242
#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:801
An email address.
Definition: address.h:36
struct Buffer * personal
Real name of address.
Definition: address.h:37
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 1016 of file copy.c.

1017{
1018 struct Body *part = NULL;
1019
1020 for (part = b->parts; part; part = part->next)
1021 {
1022 if (part->deleted || part->parts)
1023 {
1024 /* Copy till start of this part */
1025 if (mutt_file_copy_bytes(fp_in, fp_out, part->hdr_offset - ftello(fp_in)))
1026 {
1027 return -1;
1028 }
1029
1030 if (part->deleted)
1031 {
1032 /* If this is modified, count_delete_lines() needs to be changed too */
1033 fprintf(fp_out,
1034 "Content-Type: message/external-body; access-type=x-mutt-deleted;\n"
1035 "\texpiration=%s; length=" OFF_T_FMT "\n"
1036 "\n",
1037 quoted_date, part->length);
1038 if (ferror(fp_out))
1039 {
1040 return -1;
1041 }
1042
1043 /* Copy the original mime headers */
1044 if (mutt_file_copy_bytes(fp_in, fp_out, part->offset - ftello(fp_in)))
1045 {
1046 return -1;
1047 }
1048
1049 /* Skip the deleted body */
1050 if (!mutt_file_seek(fp_in, part->offset + part->length, SEEK_SET))
1051 {
1052 return -1;
1053 }
1054 }
1055 else
1056 {
1057 if (copy_delete_attach(part, fp_in, fp_out, quoted_date))
1058 {
1059 return -1;
1060 }
1061 }
1062 }
1063 }
1064
1065 /* Copy the last parts */
1066 if (mutt_file_copy_bytes(fp_in, fp_out, b->offset + b->length - ftello(fp_in)))
1067 return -1;
1068
1069 return 0;
1070}
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:1016
int mutt_file_copy_bytes(FILE *fp_in, FILE *fp_out, size_t size)
Copy some content from one file to another.
Definition: file.c:257
bool mutt_file_seek(FILE *fp, LOFF_T offset, int whence)
Wrapper for fseeko with error handling.
Definition: file.c:778
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 78 of file copy.c.

79{
80 char **old = ARRAY_GET(headers, pos);
81 if (old && *old)
82 {
83 char *new_value = NULL;
84 mutt_str_asprintf(&new_value, "%s%s", *old, value);
85 FREE(old);
86 FREE(&value);
87 value = new_value;
88 }
89 ARRAY_SET(headers, pos, value);
90}
#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:803
+ 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 108 of file copy.c.

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

427{
428 char *temp_hdr = NULL;
429
430 if (e->env)
431 {
432 chflags |= ((e->env->changed & MUTT_ENV_CHANGED_IRT) ? CH_UPDATE_IRT : 0) |
436 }
437
438 if (mutt_copy_hdr(fp_in, fp_out, e->offset, e->body->offset, chflags, prefix, wraplen) == -1)
439 return -1;
440
441 if (chflags & CH_TXTPLAIN)
442 {
443 char chsbuf[128] = { 0 };
444 char buf[128] = { 0 };
445 fputs("MIME-Version: 1.0\n", fp_out);
446 fputs("Content-Transfer-Encoding: 8bit\n", fp_out);
447 fputs("Content-Type: text/plain; charset=", fp_out);
448 const char *const c_charset = cc_charset();
449 mutt_ch_canonical_charset(chsbuf, sizeof(chsbuf), c_charset ? c_charset : "us-ascii");
450 mutt_addr_cat(buf, sizeof(buf), chsbuf, MimeSpecials);
451 fputs(buf, fp_out);
452 fputc('\n', fp_out);
453 }
454
455 if ((chflags & CH_UPDATE_IRT) && !STAILQ_EMPTY(&e->env->in_reply_to))
456 {
457 fputs("In-Reply-To:", fp_out);
458 struct ListNode *np = NULL;
459 STAILQ_FOREACH(np, &e->env->in_reply_to, entries)
460 {
461 fputc(' ', fp_out);
462 fputs(np->data, fp_out);
463 }
464 fputc('\n', fp_out);
465 }
466
467 if ((chflags & CH_UPDATE_REFS) && !STAILQ_EMPTY(&e->env->references))
468 {
469 fputs("References:", fp_out);
470 mutt_write_references(&e->env->references, fp_out, 0);
471 fputc('\n', fp_out);
472 }
473
474 if ((chflags & CH_UPDATE) && ((chflags & CH_NOSTATUS) == 0))
475 {
476 if (e->old || e->read)
477 {
478 fputs("Status: ", fp_out);
479 if (e->read)
480 fputs("RO", fp_out);
481 else if (e->old)
482 fputc('O', fp_out);
483 fputc('\n', fp_out);
484 }
485
486 if (e->flagged || e->replied)
487 {
488 fputs("X-Status: ", fp_out);
489 if (e->replied)
490 fputc('A', fp_out);
491 if (e->flagged)
492 fputc('F', fp_out);
493 fputc('\n', fp_out);
494 }
495 }
496
497 if (chflags & CH_UPDATE_LEN && ((chflags & CH_NOLEN) == 0))
498 {
499 fprintf(fp_out, "Content-Length: " OFF_T_FMT "\n", e->body->length);
500 if ((e->lines != 0) || (e->body->length == 0))
501 fprintf(fp_out, "Lines: %d\n", e->lines);
502 }
503
504 const bool c_weed = cs_subset_bool(NeoMutt->sub, "weed");
505#ifdef USE_NOTMUCH
506 if (chflags & CH_VIRTUAL)
507 {
508 /* Add some fake headers based on notmuch data */
509 char *folder = nm_email_get_folder(e);
510 if (folder && !(c_weed && mutt_matches_ignore("folder")))
511 {
512 char buf[1024] = { 0 };
513 mutt_str_copy(buf, folder, sizeof(buf));
514 mutt_pretty_mailbox(buf, sizeof(buf));
515
516 fputs("Folder: ", fp_out);
517 fputs(buf, fp_out);
518 fputc('\n', fp_out);
519 }
520 }
521#endif
522
523 struct Buffer *tags = buf_pool_get();
524 driver_tags_get(&e->tags, tags);
525 if (!buf_is_empty(tags) && !(c_weed && mutt_matches_ignore("tags")))
526 {
527 fputs("Tags: ", fp_out);
528 fputs(buf_string(tags), fp_out);
529 fputc('\n', fp_out);
530 }
531 buf_pool_release(&tags);
532
533 const struct Slist *const c_send_charset = cs_subset_slist(NeoMutt->sub, "send_charset");
534 const short c_wrap = cs_subset_number(NeoMutt->sub, "wrap");
535 if ((chflags & CH_UPDATE_LABEL) && e->env->x_label)
536 {
537 temp_hdr = e->env->x_label;
538 /* env->x_label isn't currently stored with direct references elsewhere.
539 * Mailbox->label_hash strdups the keys. But to be safe, encode a copy */
540 if (!(chflags & CH_DECODE))
541 {
542 temp_hdr = mutt_str_dup(temp_hdr);
543 rfc2047_encode(&temp_hdr, NULL, sizeof("X-Label:"), c_send_charset);
544 }
545 if (mutt_write_one_header(fp_out, "X-Label", temp_hdr, (chflags & CH_PREFIX) ? prefix : 0,
546 mutt_window_wrap_cols(wraplen, c_wrap), chflags,
547 NeoMutt->sub) == -1)
548 {
549 return -1;
550 }
551 if (!(chflags & CH_DECODE))
552 FREE(&temp_hdr);
553 }
554
555 if ((chflags & CH_UPDATE_SUBJECT) && e->env->subject)
556 {
557 temp_hdr = e->env->subject;
558 /* env->subject is directly referenced in Mailbox->subj_hash, so we
559 * have to be careful not to encode (and thus free) that memory. */
560 if (!(chflags & CH_DECODE))
561 {
562 temp_hdr = mutt_str_dup(temp_hdr);
563 rfc2047_encode(&temp_hdr, NULL, sizeof("Subject:"), c_send_charset);
564 }
565 if (mutt_write_one_header(fp_out, "Subject", temp_hdr, (chflags & CH_PREFIX) ? prefix : 0,
566 mutt_window_wrap_cols(wraplen, c_wrap), chflags,
567 NeoMutt->sub) == -1)
568 {
569 return -1;
570 }
571 if (!(chflags & CH_DECODE))
572 FREE(&temp_hdr);
573 }
574
575 if ((chflags & CH_NONEWLINE) == 0)
576 {
577 if (chflags & CH_PREFIX)
578 fputs(prefix, fp_out);
579 fputc('\n', fp_out); /* add header terminator */
580 }
581
582 if (ferror(fp_out) || feof(fp_out))
583 return -1;
584
585 return 0;
586}
void mutt_addr_cat(char *buf, size_t buflen, const char *value, const char *specials)
Copy a string and wrap it in quotes if it contains special characters.
Definition: address.c:708
bool buf_is_empty(const struct Buffer *buf)
Is the Buffer empty?
Definition: buffer.c:291
static const char * buf_string(const struct Buffer *buf)
Convert a buffer to a const char * "string".
Definition: buffer.h:96
void mutt_pretty_mailbox(char *buf, size_t buflen)
Shorten a mailbox path using '~' or '='.
Definition: muttlib.c:440
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.
Definition: config_cache.c:116
int mutt_copy_hdr(FILE *fp_in, FILE *fp_out, LOFF_T off_start, LOFF_T off_end, CopyHeaderFlags chflags, const char *prefix, int wraplen)
Copy header from one file to another.
Definition: copy.c:108
#define CH_NONEWLINE
Don't output terminating newline after the header.
Definition: copy.h:62
#define CH_TXTPLAIN
Generate text/plain MIME headers.
Definition: copy.h:65
#define CH_VIRTUAL
Write virtual header lines too.
Definition: copy.h:75
#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:519
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:374
size_t mutt_str_copy(char *dest, const char *src, size_t dsize)
Copy a string into a buffer (guaranteeing NUL-termination)
Definition: string.c:581
char * nm_email_get_folder(struct Email *e)
Get the folder for a Email.
Definition: notmuch.c:1469
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 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:628
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
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 * 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:164
+ 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 599 of file copy.c.

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

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

909{
910 if (!msg || !e->body)
911 {
912 return -1;
913 }
914 if (fp_out == msg->fp)
915 {
916 mutt_debug(LL_DEBUG1, "trying to read/write from/to the same FILE*!\n");
917 return -1;
918 }
919
920 int rc = mutt_copy_message_fp(fp_out, msg->fp, e, cmflags, chflags, wraplen);
921 if ((rc == 0) && (ferror(fp_out) || feof(fp_out)))
922 {
923 mutt_debug(LL_DEBUG1, "failed to detect EOF!\n");
924 rc = -1;
925 }
926 return rc;
927}
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:653
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 940 of file copy.c.

942{
943 char buf[256] = { 0 };
944 struct Message *msg = NULL;
945 int rc;
946
947 if (!mutt_file_seek(fp_in, e->offset, SEEK_SET))
948 return -1;
949 if (!fgets(buf, sizeof(buf), fp_in))
950 return -1;
951
952 msg = mx_msg_open_new(dest, e, is_from(buf, NULL, 0, NULL) ? MUTT_MSG_NO_FLAGS : MUTT_ADD_FROM);
953 if (!msg)
954 return -1;
955 if ((dest->type == MUTT_MBOX) || (dest->type == MUTT_MMDF))
956 chflags |= CH_FROM | CH_FORCE_FROM;
957 chflags |= ((dest->type == MUTT_MAILDIR) ? CH_NOSTATUS : CH_UPDATE);
958 rc = mutt_copy_message_fp(msg->fp, fp_in, e, cmflags, chflags, 0);
959 if (mx_msg_commit(dest, msg) != 0)
960 rc = -1;
961
962#ifdef USE_NOTMUCH
963 if (msg->committed_path && (dest->type == MUTT_MAILDIR) && (src->type == MUTT_NOTMUCH))
964 nm_update_filename(src, NULL, msg->committed_path, e);
965#endif
966
967 mx_msg_close(dest, &msg);
968 return rc;
969}
@ 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
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:1763
int mx_msg_close(struct Mailbox *m, struct Message **ptr)
Close a message.
Definition: mx.c:1180
struct Message * mx_msg_open_new(struct Mailbox *m, const struct Email *e, MsgOpenFlags flags)
Open a new message.
Definition: mx.c:1040
int mx_msg_commit(struct Mailbox *m, struct Message *msg)
Commit a message to a folder - Wrapper for MxOps::msg_commit()
Definition: mx.c:1159
#define MUTT_ADD_FROM
add a From_ line
Definition: mx.h:39
#define MUTT_MSG_NO_FLAGS
No flags are set.
Definition: mx.h:38
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 982 of file copy.c.

985{
986 if (!e)
987 return -1;
988
989 const bool own_msg = !msg;
990 if (own_msg && !(msg = mx_msg_open(m_src, e)))
991 {
992 return -1;
993 }
994
995 int rc = append_message(m_dst, msg->fp, m_src, e, cmflags, chflags);
996 if (own_msg)
997 {
998 mx_msg_close(m_src, &msg);
999 }
1000 return rc;
1001}
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:940
struct Message * mx_msg_open(struct Mailbox *m, struct Email *e)
Return a stream pointer for a message.
Definition: mx.c:1134
+ Here is the call graph for this function:
+ Here is the caller graph for this function: