NeoMutt  2025-12-11-435-g4ac674
Teaching an old dog new tricks
DOXYGEN
Loading...
Searching...
No Matches
copy_email.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 "core/lib.h"
#include "gui/lib.h"
#include "mutt.h"
#include "copy_email.h"
#include "expando/lib.h"
#include "index/lib.h"
#include "ncrypt/lib.h"
#include "pager/lib.h"
#include "send/lib.h"
#include "body.h"
#include "email.h"
#include "envelope.h"
#include "from.h"
#include "handler.h"
#include "mime.h"
#include "module_data.h"
#include "mx.h"
#include "parse.h"
#include "rfc2047.h"
#include "tags.h"
#include "notmuch/lib.h"
#include "muttlib.h"
#include <libintl.h>
+ Include dependency graph for copy_email.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
  • Thomas Klausner

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_email.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 1088 of file copy_email.c.

1089{
1090 char *s = *h;
1091 size_t l;
1092 bool rp = false;
1093
1094 switch (mutt_tolower(*s))
1095 {
1096 case 'b':
1097 {
1098 if (!(l = mutt_istr_startswith(s, "bcc:")))
1099 return 0;
1100 break;
1101 }
1102 case 'c':
1103 {
1104 if (!(l = mutt_istr_startswith(s, "cc:")))
1105 return 0;
1106 break;
1107 }
1108 case 'f':
1109 {
1110 if (!(l = mutt_istr_startswith(s, "from:")))
1111 return 0;
1112 break;
1113 }
1114 case 'm':
1115 {
1116 if (!(l = mutt_istr_startswith(s, "mail-followup-to:")))
1117 return 0;
1118 break;
1119 }
1120 case 'r':
1121 {
1122 if ((l = mutt_istr_startswith(s, "return-path:")))
1123 {
1124 rp = true;
1125 break;
1126 }
1127 else if ((l = mutt_istr_startswith(s, "reply-to:")))
1128 {
1129 break;
1130 }
1131 return 0;
1132 }
1133 case 's':
1134 {
1135 if (!(l = mutt_istr_startswith(s, "sender:")))
1136 return 0;
1137 break;
1138 }
1139 case 't':
1140 {
1141 if (!(l = mutt_istr_startswith(s, "to:")))
1142 return 0;
1143 break;
1144 }
1145 default:
1146 return 0;
1147 }
1148
1149 struct AddressList al = TAILQ_HEAD_INITIALIZER(al);
1150 mutt_addrlist_parse(&al, s + l);
1151 if (TAILQ_EMPTY(&al))
1152 return 0;
1153
1156 struct Address *a = NULL;
1157 TAILQ_FOREACH(a, &al, entries)
1158 {
1159 if (a->personal)
1160 {
1162 }
1163 }
1164
1165 /* angle brackets for return path are mandated by RFC5322,
1166 * so leave Return-Path as-is */
1167 if (rp)
1168 {
1169 *h = mutt_str_dup(s);
1170 }
1171 else
1172 {
1173 struct Buffer buf = { 0 };
1174 (*h)[l - 1] = '\0';
1175 mutt_addrlist_write_wrap(&al, &buf, *h);
1176 buf_addch(&buf, '\n');
1177 *h = buf.data;
1178 }
1179
1181
1182 FREE(&s);
1183 return 1;
1184}
void mutt_addrlist_clear(struct AddressList *al)
Unlink and free all Address in an AddressList.
Definition address.c:1464
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:1193
int mutt_addrlist_to_local(struct AddressList *al)
Convert an Address list from Punycode.
Definition address.c:1382
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:126
#define FREE(x)
Free memory and set the pointer to NULL.
Definition memory.h:68
char * mutt_str_dup(const char *str)
Copy a string, safely.
Definition string.c:257
size_t mutt_istr_startswith(const char *str, const char *prefix)
Check whether a string starts with a prefix, ignoring case.
Definition string.c:246
#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:805
An email address.
Definition address.h:35
struct Buffer * personal
Real name of address.
Definition address.h:36
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 1026 of file copy_email.c.

1027{
1028 struct Body *part = NULL;
1029
1030 for (part = b->parts; part; part = part->next)
1031 {
1032 if (part->deleted || part->parts)
1033 {
1034 /* Copy till start of this part */
1035 if (mutt_file_copy_bytes(fp_in, fp_out, part->hdr_offset - ftello(fp_in)))
1036 {
1037 return -1;
1038 }
1039
1040 if (part->deleted)
1041 {
1042 /* If this is modified, count_delete_lines() needs to be changed too */
1043 fprintf(fp_out,
1044 "Content-Type: message/external-body; access-type=x-mutt-deleted;\n"
1045 "\texpiration=%s; length=" OFF_T_FMT "\n"
1046 "\n",
1047 quoted_date, part->length);
1048 if (ferror(fp_out))
1049 {
1050 return -1;
1051 }
1052
1053 /* Copy the original mime headers */
1054 if (mutt_file_copy_bytes(fp_in, fp_out, part->offset - ftello(fp_in)))
1055 {
1056 return -1;
1057 }
1058
1059 /* Skip the deleted body */
1060 if (!mutt_file_seek(fp_in, part->offset + part->length, SEEK_SET))
1061 {
1062 return -1;
1063 }
1064 }
1065 else
1066 {
1067 if (copy_delete_attach(part, fp_in, fp_out, quoted_date))
1068 {
1069 return -1;
1070 }
1071 }
1072 }
1073 }
1074
1075 /* Copy the last parts */
1076 if (mutt_file_copy_bytes(fp_in, fp_out, b->offset + b->length - ftello(fp_in)))
1077 return -1;
1078
1079 return 0;
1080}
static int copy_delete_attach(struct Body *b, FILE *fp_in, FILE *fp_out, const char *quoted_date)
Copy a message, deleting marked attachments.
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:192
bool mutt_file_seek(FILE *fp, LOFF_T offset, int whence)
Wrapper for fseeko with error handling.
Definition file.c:652
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 82 of file copy_email.c.

83{
84 const char **old = ARRAY_GET(headers, pos);
85 if (old && *old)
86 {
87 char *new_value = NULL;
88 mutt_str_asprintf(&new_value, "%s%s", *old, value);
89 FREE(old);
90 FREE(&value);
91 value = new_value;
92 }
93 ARRAY_SET(headers, pos, value);
94}
#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:805
+ 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 112 of file copy_email.c.

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

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

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

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

919{
920 if (!msg || !e->body)
921 {
922 return -1;
923 }
924 if (fp_out == msg->fp)
925 {
926 mutt_debug(LL_DEBUG1, "trying to read/write from/to the same FILE*!\n");
927 return -1;
928 }
929
930 int rc = mutt_copy_message_fp(fp_out, msg->fp, e, cmflags, chflags, wraplen);
931 if ((rc == 0) && (ferror(fp_out) || feof(fp_out)))
932 {
933 mutt_debug(LL_DEBUG1, "failed to detect EOF!\n");
934 rc = -1;
935 }
936 return rc;
937}
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_email.c:663
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 950 of file copy_email.c.

952{
953 char buf[256] = { 0 };
954 struct Message *msg = NULL;
955 int rc;
956
957 if (!mutt_file_seek(fp_in, e->offset, SEEK_SET))
958 return -1;
959 if (!fgets(buf, sizeof(buf), fp_in))
960 return -1;
961
962 msg = mx_msg_open_new(dest, e, is_from(buf, NULL, 0, NULL) ? MUTT_MSG_NO_FLAGS : MUTT_ADD_FROM);
963 if (!msg)
964 return -1;
965 if ((dest->type == MUTT_MBOX) || (dest->type == MUTT_MMDF))
966 chflags |= CH_FROM | CH_FORCE_FROM;
967 chflags |= ((dest->type == MUTT_MAILDIR) ? CH_NOSTATUS : CH_UPDATE);
968 rc = mutt_copy_message_fp(msg->fp, fp_in, e, cmflags, chflags, 0);
969 if (mx_msg_commit(dest, msg) != 0)
970 rc = -1;
971
972#ifdef USE_NOTMUCH
973 if (msg->committed_path && (dest->type == MUTT_MAILDIR) && (src->type == MUTT_NOTMUCH))
974 nm_update_filename(src, NULL, msg->committed_path, e);
975#endif
976
977 mx_msg_close(dest, &msg);
978 return rc;
979}
@ MUTT_NOTMUCH
'Notmuch' (virtual) Mailbox type
Definition mailbox.h:50
@ MUTT_MMDF
'mmdf' Mailbox type
Definition mailbox.h:45
@ MUTT_MBOX
'mbox' Mailbox type
Definition mailbox.h:44
@ MUTT_MAILDIR
'Maildir' Mailbox type
Definition mailbox.h:47
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:1808
int mx_msg_close(struct Mailbox *m, struct Message **ptr)
Close a message.
Definition mx.c:1182
struct Message * mx_msg_open_new(struct Mailbox *m, const struct Email *e, MsgOpenFlags flags)
Open a new message.
Definition mx.c:1041
int mx_msg_commit(struct Mailbox *m, struct Message *msg)
Commit a message to a folder - Wrapper for MxOps::msg_commit()
Definition mx.c:1161
#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:101
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 992 of file copy_email.c.

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