NeoMutt  2025-09-05-7-geaa2bd
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 <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, int pos, char *value)
 Add a header to a Headers array.
 
int mutt_copy_hdr (FILE *fp_in, FILE *fp_out, LOFF_T off_start, LOFF_T off_end, CopyHeaderFlags chflags, const char *prefix, int wraplen)
 Copy header from one file to another.
 
int mutt_copy_header (FILE *fp_in, struct Email *e, FILE *fp_out, CopyHeaderFlags chflags, const char *prefix, int wraplen)
 Copy Email header.
 
static int count_delete_lines (FILE *fp, struct Body *b, LOFF_T *length, size_t datelen)
 Count lines to be deleted in this email body.
 
int mutt_copy_message_fp (FILE *fp_out, FILE *fp_in, struct Email *e, CopyMessageFlags cmflags, CopyHeaderFlags chflags, int wraplen)
 Make a copy of a message from a FILE pointer.
 
int mutt_copy_message (FILE *fp_out, struct Email *e, struct Message *msg, CopyMessageFlags cmflags, CopyHeaderFlags chflags, int wraplen)
 Copy a message from a Mailbox.
 
static int append_message (struct Mailbox *dest, FILE *fp_in, struct Mailbox *src, struct Email *e, CopyMessageFlags cmflags, CopyHeaderFlags chflags)
 Appends a copy of the given message to a mailbox.
 
int mutt_append_message (struct Mailbox *m_dst, struct Mailbox *m_src, struct Email *e, struct Message *msg, CopyMessageFlags cmflags, CopyHeaderFlags chflags)
 Append a message.
 

Detailed Description

Duplicate the structure of an entire email.

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

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

1082{
1083 char *s = *h;
1084 size_t l;
1085 bool rp = false;
1086
1087 switch (mutt_tolower(*s))
1088 {
1089 case 'b':
1090 {
1091 if (!(l = mutt_istr_startswith(s, "bcc:")))
1092 return 0;
1093 break;
1094 }
1095 case 'c':
1096 {
1097 if (!(l = mutt_istr_startswith(s, "cc:")))
1098 return 0;
1099 break;
1100 }
1101 case 'f':
1102 {
1103 if (!(l = mutt_istr_startswith(s, "from:")))
1104 return 0;
1105 break;
1106 }
1107 case 'm':
1108 {
1109 if (!(l = mutt_istr_startswith(s, "mail-followup-to:")))
1110 return 0;
1111 break;
1112 }
1113 case 'r':
1114 {
1115 if ((l = mutt_istr_startswith(s, "return-path:")))
1116 {
1117 rp = true;
1118 break;
1119 }
1120 else if ((l = mutt_istr_startswith(s, "reply-to:")))
1121 {
1122 break;
1123 }
1124 return 0;
1125 }
1126 case 's':
1127 {
1128 if (!(l = mutt_istr_startswith(s, "sender:")))
1129 return 0;
1130 break;
1131 }
1132 case 't':
1133 {
1134 if (!(l = mutt_istr_startswith(s, "to:")))
1135 return 0;
1136 break;
1137 }
1138 default:
1139 return 0;
1140 }
1141
1142 struct AddressList al = TAILQ_HEAD_INITIALIZER(al);
1143 mutt_addrlist_parse(&al, s + l);
1144 if (TAILQ_EMPTY(&al))
1145 return 0;
1146
1149 struct Address *a = NULL;
1150 TAILQ_FOREACH(a, &al, entries)
1151 {
1152 if (a->personal)
1153 {
1155 }
1156 }
1157
1158 /* angle brackets for return path are mandated by RFC5322,
1159 * so leave Return-Path as-is */
1160 if (rp)
1161 {
1162 *h = mutt_str_dup(s);
1163 }
1164 else
1165 {
1166 struct Buffer buf = { 0 };
1167 (*h)[l - 1] = '\0';
1168 mutt_addrlist_write_wrap(&al, &buf, *h);
1169 buf_addch(&buf, '\n');
1170 *h = buf.data;
1171 }
1172
1174
1175 FREE(&s);
1176 return 1;
1177}
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
int mutt_tolower(int arg)
Wrapper for tolower(3)
Definition: ctype.c:125
#define FREE(x)
Definition: memory.h:62
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 1019 of file copy.c.

1020{
1021 struct Body *part = NULL;
1022
1023 for (part = b->parts; part; part = part->next)
1024 {
1025 if (part->deleted || part->parts)
1026 {
1027 /* Copy till start of this part */
1028 if (mutt_file_copy_bytes(fp_in, fp_out, part->hdr_offset - ftello(fp_in)))
1029 {
1030 return -1;
1031 }
1032
1033 if (part->deleted)
1034 {
1035 /* If this is modified, count_delete_lines() needs to be changed too */
1036 fprintf(fp_out,
1037 "Content-Type: message/external-body; access-type=x-mutt-deleted;\n"
1038 "\texpiration=%s; length=" OFF_T_FMT "\n"
1039 "\n",
1040 quoted_date, part->length);
1041 if (ferror(fp_out))
1042 {
1043 return -1;
1044 }
1045
1046 /* Copy the original mime headers */
1047 if (mutt_file_copy_bytes(fp_in, fp_out, part->offset - ftello(fp_in)))
1048 {
1049 return -1;
1050 }
1051
1052 /* Skip the deleted body */
1053 if (!mutt_file_seek(fp_in, part->offset + part->length, SEEK_SET))
1054 {
1055 return -1;
1056 }
1057 }
1058 else
1059 {
1060 if (copy_delete_attach(part, fp_in, fp_out, quoted_date))
1061 {
1062 return -1;
1063 }
1064 }
1065 }
1066 }
1067
1068 /* Copy the last parts */
1069 if (mutt_file_copy_bytes(fp_in, fp_out, b->offset + b->length - ftello(fp_in)))
1070 return -1;
1071
1072 return 0;
1073}
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:1019
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,
int  pos,
char *  value 
)
static

Add a header to a Headers array.

Parameters
headersHeaders array
posPosition to insert new header
valueText to insert

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

Definition at line 76 of file copy.c.

77{
78 char **old = ARRAY_GET(headers, pos);
79 if (old && *old)
80 {
81 char *new_value = NULL;
82 mutt_str_asprintf(&new_value, "%s%s", *old, value);
83 FREE(old);
84 FREE(&value);
85 value = new_value;
86 }
87 ARRAY_SET(headers, pos, value);
88}
#define ARRAY_SET(head, idx, elem)
Set an element in the array.
Definition: array.h: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:802
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_copy_hdr()

int mutt_copy_hdr ( FILE *  fp_in,
FILE *  fp_out,
LOFF_T  off_start,
LOFF_T  off_end,
CopyHeaderFlags  chflags,
const char *  prefix,
int  wraplen 
)

Copy header from one file to another.

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

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

Definition at line 106 of file copy.c.

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

◆ mutt_copy_header()

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

Copy Email header.

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

Definition at line 423 of file copy.c.

425{
426 char *temp_hdr = NULL;
427 const bool c_weed = (chflags & CH_UPDATE) ? false : cs_subset_bool(NeoMutt->sub, "weed");
428
429 if (e->env)
430 {
431 chflags |= ((e->env->changed & MUTT_ENV_CHANGED_IRT) ? CH_UPDATE_IRT : 0) |
435 }
436
437 if (mutt_copy_hdr(fp_in, fp_out, e->offset, e->body->offset, chflags, prefix, wraplen) == -1)
438 return -1;
439
440 if (chflags & CH_TXTPLAIN)
441 {
442 char chsbuf[128] = { 0 };
443 char buf[128] = { 0 };
444 fputs("MIME-Version: 1.0\n", fp_out);
445 fputs("Content-Transfer-Encoding: 8bit\n", fp_out);
446 fputs("Content-Type: text/plain; charset=", fp_out);
447 const char *const c_charset = cc_charset();
448 mutt_ch_canonical_charset(chsbuf, sizeof(chsbuf), c_charset ? c_charset : "us-ascii");
449 mutt_addr_cat(buf, sizeof(buf), chsbuf, MimeSpecials);
450 fputs(buf, fp_out);
451 fputc('\n', fp_out);
452 }
453
454 if ((chflags & CH_UPDATE_IRT) && !STAILQ_EMPTY(&e->env->in_reply_to) &&
455 !(c_weed && mutt_matches_ignore("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 !(c_weed && mutt_matches_ignore("References")))
469 {
470 fputs("References:", fp_out);
471 mutt_write_references(&e->env->references, fp_out, 0);
472 fputc('\n', fp_out);
473 }
474
475 if ((chflags & CH_UPDATE) && ((chflags & CH_NOSTATUS) == 0))
476 {
477 if ((e->old || e->read))
478 {
479 fputs("Status: ", fp_out);
480 if (e->read)
481 fputs("RO", fp_out);
482 else if (e->old)
483 fputc('O', fp_out);
484 fputc('\n', fp_out);
485 }
486
487 if ((e->flagged || e->replied))
488 {
489 fputs("X-Status: ", fp_out);
490 if (e->replied)
491 fputc('A', fp_out);
492 if (e->flagged)
493 fputc('F', fp_out);
494 fputc('\n', fp_out);
495 }
496 }
497
498 if (chflags & CH_UPDATE_LEN && ((chflags & CH_NOLEN) == 0) &&
499 !(c_weed && mutt_matches_ignore("Content-Length")))
500 {
501 fprintf(fp_out, "Content-Length: " OFF_T_FMT "\n", e->body->length);
502 if ((e->lines != 0) || (e->body->length == 0))
503 fprintf(fp_out, "Lines: %d\n", e->lines);
504 }
505
506#ifdef USE_NOTMUCH
507 if (chflags & CH_VIRTUAL)
508 {
509 /* Add some fake headers based on notmuch data */
510 char *folder = nm_email_get_folder(e);
511 if (folder && !(c_weed && mutt_matches_ignore("Folder")))
512 {
513 char buf[1024] = { 0 };
514 mutt_str_copy(buf, folder, sizeof(buf));
515 mutt_pretty_mailbox(buf, sizeof(buf));
516
517 fputs("Folder: ", fp_out);
518 fputs(buf, fp_out);
519 fputc('\n', fp_out);
520 }
521 }
522#endif
523
524 struct Buffer *tags = buf_pool_get();
525 driver_tags_get(&e->tags, tags);
526 if (!buf_is_empty(tags) && !(c_weed && mutt_matches_ignore("Tags")))
527 {
528 fputs("Tags: ", fp_out);
529 fputs(buf_string(tags), fp_out);
530 fputc('\n', fp_out);
531 }
532 buf_pool_release(&tags);
533
534 const struct Slist *const c_send_charset = cs_subset_slist(NeoMutt->sub, "send_charset");
535 const short c_wrap = cs_subset_number(NeoMutt->sub, "wrap");
536 if ((chflags & CH_UPDATE_LABEL) && e->env->x_label &&
537 !(c_weed && mutt_matches_ignore("X-Label")))
538 {
539 temp_hdr = e->env->x_label;
540 /* env->x_label isn't currently stored with direct references elsewhere.
541 * Mailbox->label_hash strdups the keys. But to be safe, encode a copy */
542 if (!(chflags & CH_DECODE))
543 {
544 temp_hdr = mutt_str_dup(temp_hdr);
545 rfc2047_encode(&temp_hdr, NULL, sizeof("X-Label:"), c_send_charset);
546 }
547 if (mutt_write_one_header(fp_out, "X-Label", temp_hdr, (chflags & CH_PREFIX) ? prefix : 0,
548 mutt_window_wrap_cols(wraplen, c_wrap), chflags,
549 NeoMutt->sub) == -1)
550 {
551 return -1;
552 }
553 if (!(chflags & CH_DECODE))
554 FREE(&temp_hdr);
555 }
556
557 if ((chflags & CH_UPDATE_SUBJECT) && e->env->subject &&
558 !(c_weed && mutt_matches_ignore("Subject")))
559 {
560 temp_hdr = e->env->subject;
561 /* env->subject is directly referenced in Mailbox->subj_hash, so we
562 * have to be careful not to encode (and thus free) that memory. */
563 if (!(chflags & CH_DECODE))
564 {
565 temp_hdr = mutt_str_dup(temp_hdr);
566 rfc2047_encode(&temp_hdr, NULL, sizeof("Subject:"), c_send_charset);
567 }
568 if (mutt_write_one_header(fp_out, "Subject", temp_hdr, (chflags & CH_PREFIX) ? prefix : 0,
569 mutt_window_wrap_cols(wraplen, c_wrap), chflags,
570 NeoMutt->sub) == -1)
571 {
572 return -1;
573 }
574 if (!(chflags & CH_DECODE))
575 FREE(&temp_hdr);
576 }
577
578 if ((chflags & CH_NONEWLINE) == 0)
579 {
580 if (chflags & CH_PREFIX)
581 fputs(prefix, fp_out);
582 fputc('\n', fp_out); /* add header terminator */
583 }
584
585 if (ferror(fp_out) || feof(fp_out))
586 return -1;
587
588 return 0;
589}
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:439
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:106
#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:580
char * nm_email_get_folder(struct Email *e)
Get the folder for a Email.
Definition: notmuch.c:1491
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 602 of file copy.c.

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

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

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

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

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