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

Detailed Description

Duplicate the structure of an entire email.

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

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

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

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

◆ add_one_header()

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

Add a header to a Headers array.

Parameters
headersHeaders array
posPosition to insert new header
valueText to insert

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

Definition at line 74 of file copy.c.

75{
76 const char **old = ARRAY_GET(headers, pos);
77 if (old && *old)
78 {
79 char *new_value = NULL;
80 mutt_str_asprintf(&new_value, "%s%s", *old, value);
81 FREE(old);
82 FREE(&value);
83 value = new_value;
84 }
85 ARRAY_SET(headers, pos, value);
86}
#define ARRAY_SET(head, idx, elem)
Set an element in the array.
Definition array.h:123
#define ARRAY_GET(head, idx)
Return the element at index.
Definition array.h:109
int mutt_str_asprintf(char **strp, const char *fmt,...)
Definition string.c:803
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_copy_hdr()

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

Copy header from one file to another.

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

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

Definition at line 104 of file copy.c.

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

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

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

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

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

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

986{
987 if (!e)
988 return -1;
989
990 const bool own_msg = !msg;
991 if (own_msg && !(msg = mx_msg_open(m_src, e)))
992 {
993 return -1;
994 }
995
996 int rc = append_message(m_dst, msg->fp, m_src, e, cmflags, chflags);
997 if (own_msg)
998 {
999 mx_msg_close(m_src, &msg);
1000 }
1001 return rc;
1002}
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:941
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: