NeoMutt  2025-01-09-81-g753ae0
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 "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 1082 of file copy.c.

1083{
1084 char *s = *h;
1085 size_t l;
1086 bool rp = false;
1087
1088 switch (tolower((unsigned char) *s))
1089 {
1090 case 'b':
1091 {
1092 if (!(l = mutt_istr_startswith(s, "bcc:")))
1093 return 0;
1094 break;
1095 }
1096 case 'c':
1097 {
1098 if (!(l = mutt_istr_startswith(s, "cc:")))
1099 return 0;
1100 break;
1101 }
1102 case 'f':
1103 {
1104 if (!(l = mutt_istr_startswith(s, "from:")))
1105 return 0;
1106 break;
1107 }
1108 case 'm':
1109 {
1110 if (!(l = mutt_istr_startswith(s, "mail-followup-to:")))
1111 return 0;
1112 break;
1113 }
1114 case 'r':
1115 {
1116 if ((l = mutt_istr_startswith(s, "return-path:")))
1117 {
1118 rp = true;
1119 break;
1120 }
1121 else if ((l = mutt_istr_startswith(s, "reply-to:")))
1122 {
1123 break;
1124 }
1125 return 0;
1126 }
1127 case 's':
1128 {
1129 if (!(l = mutt_istr_startswith(s, "sender:")))
1130 return 0;
1131 break;
1132 }
1133 case 't':
1134 {
1135 if (!(l = mutt_istr_startswith(s, "to:")))
1136 return 0;
1137 break;
1138 }
1139 default:
1140 return 0;
1141 }
1142
1143 struct AddressList al = TAILQ_HEAD_INITIALIZER(al);
1144 mutt_addrlist_parse(&al, s + l);
1145 if (TAILQ_EMPTY(&al))
1146 return 0;
1147
1150 struct Address *a = NULL;
1151 TAILQ_FOREACH(a, &al, entries)
1152 {
1153 if (a->personal)
1154 {
1156 }
1157 }
1158
1159 /* angle brackets for return path are mandated by RFC5322,
1160 * so leave Return-Path as-is */
1161 if (rp)
1162 {
1163 *h = mutt_str_dup(s);
1164 }
1165 else
1166 {
1167 struct Buffer buf = { 0 };
1168 (*h)[l - 1] = '\0';
1169 mutt_addrlist_write_wrap(&al, &buf, *h);
1170 buf_addch(&buf, '\n');
1171 *h = buf.data;
1172 }
1173
1175
1176 FREE(&s);
1177 return 1;
1178}
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:55
char * mutt_str_dup(const char *str)
Copy a string, safely.
Definition: string.c:254
size_t mutt_istr_startswith(const char *str, const char *prefix)
Check whether a string starts with a prefix, ignoring case.
Definition: string.c:243
#define TAILQ_FOREACH(var, head, field)
Definition: queue.h:782
#define TAILQ_HEAD_INITIALIZER(head)
Definition: queue.h:694
#define TAILQ_EMPTY(head)
Definition: queue.h:778
void rfc2047_decode_addrlist(struct AddressList *al)
Decode any RFC2047 headers in an Address list.
Definition: rfc2047.c: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 1020 of file copy.c.

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

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

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

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

426{
427 char *temp_hdr = NULL;
428 const bool c_weed = cs_subset_bool(NeoMutt->sub, "weed");
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 !(c_weed && mutt_matches_ignore("In-Reply-To")))
457 {
458 fputs("In-Reply-To:", fp_out);
459 struct ListNode *np = NULL;
460 STAILQ_FOREACH(np, &e->env->in_reply_to, entries)
461 {
462 fputc(' ', fp_out);
463 fputs(np->data, fp_out);
464 }
465 fputc('\n', fp_out);
466 }
467
468 if ((chflags & CH_UPDATE_REFS) && !STAILQ_EMPTY(&e->env->references) &&
469 !(c_weed && mutt_matches_ignore("References")))
470 {
471 fputs("References:", fp_out);
472 mutt_write_references(&e->env->references, fp_out, 0);
473 fputc('\n', fp_out);
474 }
475
476 if ((chflags & CH_UPDATE) && ((chflags & CH_NOSTATUS) == 0))
477 {
478 if ((e->old || e->read) && !(c_weed && mutt_matches_ignore("Status")))
479 {
480 fputs("Status: ", fp_out);
481 if (e->read)
482 fputs("RO", fp_out);
483 else if (e->old)
484 fputc('O', fp_out);
485 fputc('\n', fp_out);
486 }
487
488 if ((e->flagged || e->replied) && !(c_weed && mutt_matches_ignore("X-Status")))
489 {
490 fputs("X-Status: ", fp_out);
491 if (e->replied)
492 fputc('A', fp_out);
493 if (e->flagged)
494 fputc('F', fp_out);
495 fputc('\n', fp_out);
496 }
497 }
498
499 if (chflags & CH_UPDATE_LEN && ((chflags & CH_NOLEN) == 0) &&
500 !(c_weed && mutt_matches_ignore("Content-Length")))
501 {
502 fprintf(fp_out, "Content-Length: " OFF_T_FMT "\n", e->body->length);
503 if ((e->lines != 0) || (e->body->length == 0))
504 fprintf(fp_out, "Lines: %d\n", e->lines);
505 }
506
507#ifdef USE_NOTMUCH
508 if (chflags & CH_VIRTUAL)
509 {
510 /* Add some fake headers based on notmuch data */
511 char *folder = nm_email_get_folder(e);
512 if (folder && !(c_weed && mutt_matches_ignore("Folder")))
513 {
514 char buf[1024] = { 0 };
515 mutt_str_copy(buf, folder, sizeof(buf));
516 mutt_pretty_mailbox(buf, sizeof(buf));
517
518 fputs("Folder: ", fp_out);
519 fputs(buf, fp_out);
520 fputc('\n', fp_out);
521 }
522 }
523#endif
524
525 struct Buffer *tags = buf_pool_get();
526 driver_tags_get(&e->tags, tags);
527 if (!buf_is_empty(tags) && !(c_weed && mutt_matches_ignore("Tags")))
528 {
529 fputs("Tags: ", fp_out);
530 fputs(buf_string(tags), fp_out);
531 fputc('\n', fp_out);
532 }
533 buf_pool_release(&tags);
534
535 const struct Slist *const c_send_charset = cs_subset_slist(NeoMutt->sub, "send_charset");
536 const short c_wrap = cs_subset_number(NeoMutt->sub, "wrap");
537 if ((chflags & CH_UPDATE_LABEL) && e->env->x_label &&
538 !(c_weed && mutt_matches_ignore("X-Label")))
539 {
540 temp_hdr = e->env->x_label;
541 /* env->x_label isn't currently stored with direct references elsewhere.
542 * Mailbox->label_hash strdups the keys. But to be safe, encode a copy */
543 if (!(chflags & CH_DECODE))
544 {
545 temp_hdr = mutt_str_dup(temp_hdr);
546 rfc2047_encode(&temp_hdr, NULL, sizeof("X-Label:"), c_send_charset);
547 }
548 if (mutt_write_one_header(fp_out, "X-Label", temp_hdr, (chflags & CH_PREFIX) ? prefix : 0,
549 mutt_window_wrap_cols(wraplen, c_wrap), chflags,
550 NeoMutt->sub) == -1)
551 {
552 return -1;
553 }
554 if (!(chflags & CH_DECODE))
555 FREE(&temp_hdr);
556 }
557
558 if ((chflags & CH_UPDATE_SUBJECT) && e->env->subject &&
559 !(c_weed && mutt_matches_ignore("Subject")))
560 {
561 temp_hdr = e->env->subject;
562 /* env->subject is directly referenced in Mailbox->subj_hash, so we
563 * have to be careful not to encode (and thus free) that memory. */
564 if (!(chflags & CH_DECODE))
565 {
566 temp_hdr = mutt_str_dup(temp_hdr);
567 rfc2047_encode(&temp_hdr, NULL, sizeof("Subject:"), c_send_charset);
568 }
569 if (mutt_write_one_header(fp_out, "Subject", temp_hdr, (chflags & CH_PREFIX) ? prefix : 0,
570 mutt_window_wrap_cols(wraplen, c_wrap), chflags,
571 NeoMutt->sub) == -1)
572 {
573 return -1;
574 }
575 if (!(chflags & CH_DECODE))
576 FREE(&temp_hdr);
577 }
578
579 if ((chflags & CH_NONEWLINE) == 0)
580 {
581 if (chflags & CH_PREFIX)
582 fputs(prefix, fp_out);
583 fputc('\n', fp_out); /* add header terminator */
584 }
585
586 if (ferror(fp_out) || feof(fp_out))
587 return -1;
588
589 return 0;
590}
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:107
#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:582
char * nm_email_get_folder(struct Email *e)
Get the folder for a Email.
Definition: notmuch.c:1488
struct Buffer * buf_pool_get(void)
Get a Buffer from the pool.
Definition: pool.c:82
void buf_pool_release(struct Buffer **ptr)
Return a Buffer to the pool.
Definition: pool.c:96
#define STAILQ_EMPTY(head)
Definition: queue.h:382
void rfc2047_encode(char **pd, const char *specials, int col, const struct Slist *charsets)
RFC-2047-encode a string.
Definition: rfc2047.c: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 603 of file copy.c.

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

659{
660 struct Body *body = e->body;
661 struct Buffer *prefix = buf_pool_get();
662 LOFF_T new_offset = -1;
663 int rc = 0;
664
665 if (cmflags & MUTT_CM_PREFIX)
666 {
667 const bool c_text_flowed = cs_subset_bool(NeoMutt->sub, "text_flowed");
668 if (c_text_flowed)
669 {
670 buf_strcpy(prefix, ">");
671 }
672 else
673 {
674 const char *const c_attribution_locale = cs_subset_string(NeoMutt->sub, "attribution_locale");
675 const struct Expando *c_indent_string = cs_subset_expando(NeoMutt->sub, "indent_string");
676 struct Mailbox *m_cur = get_current_mailbox();
677 setlocale(LC_TIME, NONULL(c_attribution_locale));
678 mutt_make_string(prefix, -1, c_indent_string, m_cur, -1, e, MUTT_FORMAT_NO_FLAGS, NULL);
679 setlocale(LC_TIME, "");
680 }
681 }
682
683 if ((cmflags & MUTT_CM_NOHEADER) == 0)
684 {
685 if (cmflags & MUTT_CM_PREFIX)
686 {
687 chflags |= CH_PREFIX;
688 }
689 else if (e->attach_del && (chflags & CH_UPDATE_LEN))
690 {
691 int new_lines;
692 int rc_attach_del = -1;
693 LOFF_T new_length = body->length;
694 struct Buffer *quoted_date = NULL;
695
696 quoted_date = buf_pool_get();
697 buf_addch(quoted_date, '"');
698 mutt_date_make_date(quoted_date, cs_subset_bool(NeoMutt->sub, "local_date_header"));
699 buf_addch(quoted_date, '"');
700
701 /* Count the number of lines and bytes to be deleted */
702 if (!mutt_file_seek(fp_in, body->offset, SEEK_SET))
703 {
704 goto attach_del_cleanup;
705 }
706 const int del = count_delete_lines(fp_in, body, &new_length, buf_len(quoted_date));
707 if (del == -1)
708 {
709 goto attach_del_cleanup;
710 }
711 new_lines = e->lines - del;
712
713 /* Copy the headers */
714 if (mutt_copy_header(fp_in, e, fp_out, chflags | CH_NOLEN | CH_NONEWLINE, NULL, wraplen))
715 goto attach_del_cleanup;
716 fprintf(fp_out, "Content-Length: " OFF_T_FMT "\n", new_length);
717 if (new_lines <= 0)
718 new_lines = 0;
719 else
720 fprintf(fp_out, "Lines: %d\n", new_lines);
721
722 putc('\n', fp_out);
723 if (ferror(fp_out) || feof(fp_out))
724 goto attach_del_cleanup;
725 new_offset = ftello(fp_out);
726
727 /* Copy the body */
728 if (!mutt_file_seek(fp_in, body->offset, SEEK_SET))
729 goto attach_del_cleanup;
730 if (copy_delete_attach(body, fp_in, fp_out, buf_string(quoted_date)))
731 goto attach_del_cleanup;
732
733 buf_pool_release(&quoted_date);
734
735 LOFF_T fail = ((ftello(fp_out) - new_offset) - new_length);
736 if (fail)
737 {
738 mutt_error(ngettext("The length calculation was wrong by %ld byte",
739 "The length calculation was wrong by %ld bytes", fail),
740 (long) fail);
741 new_length += fail;
742 }
743
744 /* Update original message if we are sync'ing a mailfolder */
745 if (cmflags & MUTT_CM_UPDATE)
746 {
747 e->attach_del = false;
748 e->lines = new_lines;
749 body->offset = new_offset;
750
751 body->length = new_length;
752 mutt_body_free(&body->parts);
753 }
754
755 rc_attach_del = 0;
756
757 attach_del_cleanup:
758 buf_pool_release(&quoted_date);
759 rc = rc_attach_del;
760 goto done;
761 }
762
763 if (mutt_copy_header(fp_in, e, fp_out, chflags,
764 (chflags & CH_PREFIX) ? buf_string(prefix) : NULL, wraplen) == -1)
765 {
766 rc = -1;
767 goto done;
768 }
769
770 new_offset = ftello(fp_out);
771 }
772
773 if (cmflags & MUTT_CM_DECODE)
774 {
775 /* now make a text/plain version of the message */
776 struct State state = { 0 };
777 state.fp_in = fp_in;
778 state.fp_out = fp_out;
779 if (cmflags & MUTT_CM_PREFIX)
780 state.prefix = buf_string(prefix);
781 if (cmflags & MUTT_CM_DISPLAY)
782 {
783 state.flags |= STATE_DISPLAY;
784 state.wraplen = wraplen;
785 const char *const c_pager = pager_get_pager(NeoMutt->sub);
786 if (!c_pager)
787 state.flags |= STATE_PAGER;
788 }
789 if (cmflags & MUTT_CM_PRINTING)
790 state.flags |= STATE_PRINTING;
791 if (cmflags & MUTT_CM_WEED)
792 state.flags |= STATE_WEED;
793 if (cmflags & MUTT_CM_CHARCONV)
794 state.flags |= STATE_CHARCONV;
795 if (cmflags & MUTT_CM_REPLYING)
796 state.flags |= STATE_REPLYING;
797
798 if ((WithCrypto != 0) && cmflags & MUTT_CM_VERIFY)
799 state.flags |= STATE_VERIFY;
800
801 rc = mutt_body_handler(body, &state);
802 }
803 else if ((WithCrypto != 0) && (cmflags & MUTT_CM_DECODE_CRYPT) && (e->security & SEC_ENCRYPT))
804 {
805 struct Body *cur = NULL;
806 FILE *fp = NULL;
807
808 if (((WithCrypto & APPLICATION_PGP) != 0) && (cmflags & MUTT_CM_DECODE_PGP) &&
810 {
811 if (crypt_pgp_decrypt_mime(fp_in, &fp, e->body, &cur))
812 {
813 rc = 1;
814 goto done;
815 }
816 fputs("MIME-Version: 1.0\n", fp_out);
817 }
818
819 if (((WithCrypto & APPLICATION_SMIME) != 0) && (cmflags & MUTT_CM_DECODE_SMIME) &&
821 {
822 if (crypt_smime_decrypt_mime(fp_in, &fp, e->body, &cur))
823 {
824 rc = 1;
825 goto done;
826 }
827 }
828
829 if (!cur)
830 {
831 mutt_error(_("No decryption engine available for message"));
832 rc = 1;
833 goto done;
834 }
835
836 mutt_write_mime_header(cur, fp_out, NeoMutt->sub);
837 fputc('\n', fp_out);
838
839 if (!mutt_file_seek(fp, cur->offset, SEEK_SET))
840 {
841 rc = 1;
842 goto done;
843 }
844
845 if (mutt_file_copy_bytes(fp, fp_out, cur->length) == -1)
846 {
847 mutt_file_fclose(&fp);
848 mutt_body_free(&cur);
849 rc = 1;
850 goto done;
851 }
852 mutt_body_free(&cur);
853 mutt_file_fclose(&fp);
854 }
855 else
856 {
857 if (!mutt_file_seek(fp_in, body->offset, SEEK_SET))
858 {
859 rc = 1;
860 goto done;
861 }
862 if (cmflags & MUTT_CM_PREFIX)
863 {
864 int c;
865 size_t bytes = body->length;
866
867 fputs(buf_string(prefix), fp_out);
868
869 while (((c = fgetc(fp_in)) != EOF) && bytes--)
870 {
871 fputc(c, fp_out);
872 if (c == '\n')
873 {
874 fputs(buf_string(prefix), fp_out);
875 }
876 }
877 }
878 else if (mutt_file_copy_bytes(fp_in, fp_out, body->length) == -1)
879 {
880 rc = 1;
881 goto done;
882 }
883 }
884
885 if ((cmflags & MUTT_CM_UPDATE) && ((cmflags & MUTT_CM_NOHEADER) == 0) &&
886 (new_offset != -1))
887 {
888 body->offset = new_offset;
889 mutt_body_free(&body->parts);
890 }
891
892done:
893 buf_pool_release(&prefix);
894 return rc;
895}
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:361
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:424
#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
int mutt_make_string(struct Buffer *buf, size_t max_cols, const struct Expando *exp, struct Mailbox *m, int inpgr, struct Email *e, MuttFormatFlags flags, const char *progress)
Create formatted strings using mailbox expandos.
Definition: dlg_index.c:803
void mutt_body_free(struct Body **ptr)
Free a Body.
Definition: body.c:58
#define mutt_file_fclose(FP)
Definition: file.h:139
#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:1633
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:721
@ 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:96
#define APPLICATION_SMIME
Use SMIME to encrypt/sign.
Definition: lib.h:97
#define SEC_ENCRYPT
Email is encrypted.
Definition: lib.h:84
#define WithCrypto
Definition: lib.h:122
const char * pager_get_pager(struct ConfigSubset *sub)
Get the value of $pager.
Definition: config.c:111
#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:99
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 911 of file copy.c.

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

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

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