NeoMutt  2022-04-29-215-gc12b98
Teaching an old dog new tricks
DOXYGEN
copy.c File Reference

Duplicate the structure of an entire email. More...

#include "config.h"
#include <ctype.h>
#include <inttypes.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 "index/lib.h"
#include "ncrypt/lib.h"
#include "send/lib.h"
#include "format_flags.h"
#include "handler.h"
#include "hdrline.h"
#include "mutt_globals.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. More...
 
static int copy_delete_attach (struct Body *b, FILE *fp_in, FILE *fp_out, const char *quoted_date)
 Copy a message, deleting marked attachments. More...
 
 ARRAY_HEAD (Headers, char *)
 
static void add_one_header (struct Headers *headers, size_t pos, char *value)
 Add a header to a Headers array. More...
 
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. More...
 
int mutt_copy_header (FILE *fp_in, struct Email *e, FILE *fp_out, CopyHeaderFlags chflags, const char *prefix, int wraplen)
 Copy Email header. More...
 
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. More...
 
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. More...
 
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. More...
 
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. More...
 
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. More...
 
static void format_address_header (char **h, struct AddressList *al)
 Write address headers to a buffer. More...
 

Detailed Description

Duplicate the structure of an entire email.

Authors
  • Michael R. Elkins
  • Pietro Cerutti

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

1104{
1105 char *s = *h;
1106 size_t l;
1107 bool rp = false;
1108
1109 switch (tolower((unsigned char) *s))
1110 {
1111 case 'b':
1112 {
1113 if (!(l = mutt_istr_startswith(s, "bcc:")))
1114 return 0;
1115 break;
1116 }
1117 case 'c':
1118 {
1119 if (!(l = mutt_istr_startswith(s, "cc:")))
1120 return 0;
1121 break;
1122 }
1123 case 'f':
1124 {
1125 if (!(l = mutt_istr_startswith(s, "from:")))
1126 return 0;
1127 break;
1128 }
1129 case 'm':
1130 {
1131 if (!(l = mutt_istr_startswith(s, "mail-followup-to:")))
1132 return 0;
1133 break;
1134 }
1135 case 'r':
1136 {
1137 if ((l = mutt_istr_startswith(s, "return-path:")))
1138 {
1139 rp = true;
1140 break;
1141 }
1142 else if ((l = mutt_istr_startswith(s, "reply-to:")))
1143 {
1144 break;
1145 }
1146 return 0;
1147 }
1148 case 's':
1149 {
1150 if (!(l = mutt_istr_startswith(s, "sender:")))
1151 return 0;
1152 break;
1153 }
1154 case 't':
1155 {
1156 if (!(l = mutt_istr_startswith(s, "to:")))
1157 return 0;
1158 break;
1159 }
1160 default:
1161 return 0;
1162 }
1163
1164 struct AddressList al = TAILQ_HEAD_INITIALIZER(al);
1165 mutt_addrlist_parse(&al, s + l);
1166 if (TAILQ_EMPTY(&al))
1167 return 0;
1168
1171 struct Address *a = NULL;
1172 TAILQ_FOREACH(a, &al, entries)
1173 {
1174 if (a->personal)
1175 {
1177 }
1178 }
1179
1180 /* angle brackets for return path are mandated by RFC5322,
1181 * so leave Return-Path as-is */
1182 if (rp)
1183 *h = mutt_str_dup(s);
1184 else
1185 {
1186 *h = mutt_mem_calloc(1, l + 2);
1187 mutt_str_copy(*h, s, l + 1);
1188 format_address_header(h, &al);
1189 }
1190
1192
1193 FREE(&s);
1194 return 1;
1195}
void mutt_addrlist_clear(struct AddressList *al)
Unlink and free all Address in an AddressList.
Definition: address.c:1470
int mutt_addrlist_to_local(struct AddressList *al)
Convert an Address list from Punycode.
Definition: address.c:1388
int mutt_addrlist_parse(struct AddressList *al, const char *s)
Parse a list of email addresses.
Definition: address.c:458
static void format_address_header(char **h, struct AddressList *al)
Write address headers to a buffer.
Definition: copy.c:1037
void * mutt_mem_calloc(size_t nmemb, size_t size)
Allocate zeroed memory on the heap.
Definition: memory.c:50
#define FREE(x)
Definition: memory.h:43
void mutt_str_dequote_comment(char *str)
Un-escape characters in an email address comment.
Definition: string.c:775
char * mutt_str_dup(const char *str)
Copy a string, safely.
Definition: string.c:250
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:652
size_t mutt_istr_startswith(const char *str, const char *prefix)
Check whether a string starts with a prefix, ignoring case.
Definition: string.c:239
#define TAILQ_FOREACH(var, head, field)
Definition: queue.h:725
#define TAILQ_HEAD_INITIALIZER(head)
Definition: queue.h:637
#define TAILQ_EMPTY(head)
Definition: queue.h:721
void rfc2047_decode_addrlist(struct AddressList *al)
Decode any RFC2047 headers in an Address list.
Definition: rfc2047.c:771
An email address.
Definition: address.h:36
char * personal
Real name of address.
Definition: address.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 970 of file copy.c.

971{
972 struct Body *part = NULL;
973
974 for (part = b->parts; part; part = part->next)
975 {
976 if (part->deleted || part->parts)
977 {
978 /* Copy till start of this part */
979 if (mutt_file_copy_bytes(fp_in, fp_out, part->hdr_offset - ftello(fp_in)))
980 {
981 return -1;
982 }
983
984 if (part->deleted)
985 {
986 /* If this is modified, count_delete_lines() needs to be changed too */
987 fprintf(fp_out,
988 "Content-Type: message/external-body; access-type=x-mutt-deleted;\n"
989 "\texpiration=%s; length=" OFF_T_FMT "\n"
990 "\n",
991 quoted_date, part->length);
992 if (ferror(fp_out))
993 {
994 return -1;
995 }
996
997 /* Copy the original mime headers */
998 if (mutt_file_copy_bytes(fp_in, fp_out, part->offset - ftello(fp_in)))
999 {
1000 return -1;
1001 }
1002
1003 /* Skip the deleted body */
1004 if (!mutt_file_seek(fp_in, part->offset + part->length, SEEK_SET))
1005 {
1006 return -1;
1007 }
1008 }
1009 else
1010 {
1011 if (copy_delete_attach(part, fp_in, fp_out, quoted_date))
1012 {
1013 return -1;
1014 }
1015 }
1016 }
1017 }
1018
1019 /* Copy the last parts */
1020 if (mutt_file_copy_bytes(fp_in, fp_out, b->offset + b->length - ftello(fp_in)))
1021 return -1;
1022
1023 return 0;
1024}
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:970
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:230
bool mutt_file_seek(FILE *fp, LOFF_T offset, int whence)
Wrapper for fseeko with error handling.
Definition: file.c:690
The body of an email.
Definition: body.h:36
struct Body * parts
parts of a multipart or message/rfc822
Definition: body.h:72
LOFF_T offset
offset where the actual data begins
Definition: body.h:52
bool deleted
Attachment marked for deletion.
Definition: body.h:87
LOFF_T length
length (in bytes) of attachment
Definition: body.h:53
struct Body * next
next attachment in the list
Definition: body.h:71
long hdr_offset
Offset in stream where the headers begin.
Definition: body.h:80
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ ARRAY_HEAD()

ARRAY_HEAD ( Headers  ,
char *   
)

◆ add_one_header()

static void add_one_header ( struct Headers *  headers,
size_t  pos,
char *  value 
)
static

Add a header to a Headers array.

Parameters
headersHeaders array
posPosition to insert new header
valueText to insert

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

Definition at line 74 of file copy.c.

75{
76 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:122
#define ARRAY_GET(head, idx)
Return the element at index.
Definition: array.h:108
int mutt_str_asprintf(char **strp, const char *fmt,...)
Definition: string.c:1031
+ 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 Headers 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 continue;
151 else if ((buf[0] == '\n') || ((buf[0] == '\r') && (buf[1] == '\n')))
152 break; /* end of header */
153
154 if ((chflags & (CH_UPDATE | CH_XMIT | CH_NOSTATUS)) &&
155 (mutt_istr_startswith(buf, "Status:") || mutt_istr_startswith(buf, "X-Status:")))
156 {
157 continue;
158 }
159 if ((chflags & (CH_UPDATE_LEN | CH_XMIT | CH_NOLEN)) &&
160 (mutt_istr_startswith(buf, "Content-Length:") ||
161 mutt_istr_startswith(buf, "Lines:")))
162 {
163 continue;
164 }
165 if ((chflags & CH_UPDATE_REFS) && mutt_istr_startswith(buf, "References:"))
166 {
167 continue;
168 }
169 if ((chflags & CH_UPDATE_IRT) && mutt_istr_startswith(buf, "In-Reply-To:"))
170 {
171 continue;
172 }
173 if (chflags & CH_UPDATE_LABEL && mutt_istr_startswith(buf, "X-Label:"))
174 continue;
175 if ((chflags & CH_UPDATE_SUBJECT) && mutt_istr_startswith(buf, "Subject:"))
176 {
177 continue;
178 }
179
180 ignore = false;
181 }
182
183 if (!ignore && (fputs(buf, fp_out) == EOF))
184 return -1;
185 }
186 return 0;
187 }
188
189 hdr_count = 1;
190 x = 0;
191
192 /* We are going to read and collect the headers in an array
193 * so we are able to do re-ordering.
194 * First count the number of entries in the array */
195 if (chflags & CH_REORDER)
196 {
197 struct ListNode *np = NULL;
198 STAILQ_FOREACH(np, &HeaderOrderList, entries)
199 {
200 mutt_debug(LL_DEBUG3, "Reorder list: %s\n", np->data);
201 hdr_count++;
202 }
203 }
204
205 mutt_debug(LL_DEBUG1, "WEED is %sset\n", (chflags & CH_WEED) ? "" : "not ");
206
207 ARRAY_RESERVE(&headers, hdr_count);
208
209 /* Read all the headers into the array */
210 while (ftello(fp_in) < off_end)
211 {
212 nl = strchr(buf, '\n');
213
214 /* Read a line */
215 if (!fgets(buf, sizeof(buf), fp_in))
216 break;
217
218 /* Is it the beginning of a header? */
219 if (nl && (buf[0] != ' ') && (buf[0] != '\t'))
220 {
221 /* Do we have anything pending? */
222 if (this_one)
223 {
224 if (chflags & CH_DECODE)
225 {
226 if (address_header_decode(&this_one) == 0)
227 rfc2047_decode(&this_one);
228 this_one_len = mutt_str_len(this_one);
229
230 /* Convert CRLF line endings to LF */
231 if ((this_one_len > 2) && (this_one[this_one_len - 2] == '\r') &&
232 (this_one[this_one_len - 1] == '\n'))
233 {
234 this_one[this_one_len - 2] = '\n';
235 this_one[this_one_len - 1] = '\0';
236 }
237 }
238
239 add_one_header(&headers, x, this_one);
240 this_one = NULL;
241 }
242
243 ignore = true;
244 this_is_from = false;
245 if (!from && mutt_str_startswith(buf, "From "))
246 {
247 if ((chflags & CH_FROM) == 0)
248 continue;
249 this_is_from = true;
250 from = true;
251 }
252 else if ((buf[0] == '\n') || ((buf[0] == '\r') && (buf[1] == '\n')))
253 break; /* end of header */
254
255 /* note: CH_FROM takes precedence over header weeding. */
256 if (!((chflags & CH_FROM) && (chflags & CH_FORCE_FROM) && this_is_from) &&
257 (chflags & CH_WEED) && mutt_matches_ignore(buf))
258 {
259 continue;
260 }
261 if ((chflags & CH_WEED_DELIVERED) && mutt_istr_startswith(buf, "Delivered-To:"))
262 {
263 continue;
264 }
265 if ((chflags & (CH_UPDATE | CH_XMIT | CH_NOSTATUS)) &&
266 (mutt_istr_startswith(buf, "Status:") || mutt_istr_startswith(buf, "X-Status:")))
267 {
268 continue;
269 }
270 if ((chflags & (CH_UPDATE_LEN | CH_XMIT | CH_NOLEN)) &&
271 (mutt_istr_startswith(buf, "Content-Length:") || mutt_istr_startswith(buf, "Lines:")))
272 {
273 continue;
274 }
275 if ((chflags & CH_MIME))
276 {
277 if (mutt_istr_startswith(buf, "mime-version:"))
278 {
279 continue;
280 }
281 size_t plen = mutt_istr_startswith(buf, "content-");
282 if ((plen != 0) && (mutt_istr_startswith(buf + plen, "transfer-encoding:") ||
283 mutt_istr_startswith(buf + plen, "type:")))
284 {
285 continue;
286 }
287 }
288 if ((chflags & CH_UPDATE_REFS) && mutt_istr_startswith(buf, "References:"))
289 {
290 continue;
291 }
292 if ((chflags & CH_UPDATE_IRT) && mutt_istr_startswith(buf, "In-Reply-To:"))
293 {
294 continue;
295 }
296 if ((chflags & CH_UPDATE_LABEL) && mutt_istr_startswith(buf, "X-Label:"))
297 continue;
298 if ((chflags & CH_UPDATE_SUBJECT) && mutt_istr_startswith(buf, "Subject:"))
299 {
300 continue;
301 }
302
303 /* Find x -- the array entry where this header is to be saved */
304 if (chflags & CH_REORDER)
305 {
306 struct ListNode *np = NULL;
307 x = 0;
308 int match = -1;
309 size_t match_len = 0;
310
311 STAILQ_FOREACH(np, &HeaderOrderList, entries)
312 {
313 x++;
314 size_t hdr_order_len = mutt_str_len(np->data);
315 if (mutt_istrn_equal(buf, np->data, hdr_order_len))
316 {
317 if ((match == -1) || (hdr_order_len > match_len))
318 {
319 match = x;
320 match_len = hdr_order_len;
321 }
322 mutt_debug(LL_DEBUG2, "Reorder: %s matches %s", np->data, buf);
323 }
324 }
325 if (match != -1)
326 x = match;
327 }
328
329 ignore = false;
330 } /* If beginning of header */
331
332 if (!ignore)
333 {
334 mutt_debug(LL_DEBUG2, "Reorder: x = %d; hdr_count = %d\n", x, hdr_count);
335 if (this_one)
336 {
337 size_t blen = mutt_str_len(buf);
338
339 mutt_mem_realloc(&this_one, this_one_len + blen + sizeof(char));
340 strcat(this_one + this_one_len, buf);
341 this_one_len += blen;
342 }
343 else
344 {
345 this_one = mutt_str_dup(buf);
346 this_one_len = mutt_str_len(this_one);
347 }
348 }
349 } /* while (ftello (fp_in) < off_end) */
350
351 /* Do we have anything pending? -- XXX, same code as in above in the loop. */
352 if (this_one)
353 {
354 if (chflags & CH_DECODE)
355 {
356 if (address_header_decode(&this_one) == 0)
357 rfc2047_decode(&this_one);
358 this_one_len = mutt_str_len(this_one);
359 }
360
361 add_one_header(&headers, x, this_one);
362 this_one = NULL;
363 }
364
365 /* Now output the headers in order */
366 bool error = false;
367 char **hp = NULL;
368 ARRAY_FOREACH(hp, &headers)
369 {
370 if (!error && hp && *hp)
371 {
372 /* We couldn't do the prefixing when reading because RFC2047
373 * decoding may have concatenated lines. */
374 if (chflags & (CH_DECODE | CH_PREFIX))
375 {
376 const char *pre = (chflags & CH_PREFIX) ? prefix : NULL;
377 const short c_wrap = cs_subset_number(NeoMutt->sub, "wrap");
378 wraplen = mutt_window_wrap_cols(wraplen, c_wrap);
379
380 if (mutt_write_one_header(fp_out, 0, *hp, pre, wraplen, chflags, NeoMutt->sub) == -1)
381 {
382 error = true;
383 }
384 }
385 else
386 {
387 if (fputs(*hp, fp_out) == EOF)
388 {
389 error = true;
390 }
391 }
392 }
393
394 FREE(hp);
395 }
396 ARRAY_FREE(&headers);
397
398 if (error)
399 return -1;
400 return 0;
401}
#define ARRAY_RESERVE(head, num)
Reserve memory for the array.
Definition: array.h:188
#define ARRAY_FOREACH(elem, head)
Iterate over all elements of the array.
Definition: array.h:211
#define ARRAY_FREE(head)
Release all memory.
Definition: array.h:203
#define ARRAY_HEAD_INITIALIZER
Static initializer for arrays.
Definition: array.h:57
short cs_subset_number(const struct ConfigSubset *sub, const char *name)
Get a number config item by name.
Definition: helpers.c:169
static int address_header_decode(char **h)
Parse an email's headers.
Definition: copy.c:1103
static void add_one_header(struct Headers *headers, size_t pos, char *value)
Add a header to a Headers array.
Definition: copy.c:74
#define CH_DECODE
Do RFC2047 header decoding.
Definition: copy.h:54
#define CH_XMIT
Transmitting this message? (Ignore Lines: and Content-Length:)
Definition: copy.h:55
#define CH_PREFIX
Quote header using $indent_string string?
Definition: copy.h:57
#define CH_UPDATE
Update the status and x-status fields?
Definition: copy.h:52
#define CH_NOSTATUS
Suppress the status and x-status fields.
Definition: copy.h:58
#define CH_FROM
Retain the "From " message separator?
Definition: copy.h:56
#define CH_WEED_DELIVERED
Weed eventual Delivered-To headers.
Definition: copy.h:65
#define CH_UPDATE_LABEL
Update X-Label: from email->env->x_label?
Definition: copy.h:71
#define CH_WEED
Weed the headers?
Definition: copy.h:53
#define CH_REORDER
Re-order output of headers (specified by 'hdr_order')
Definition: copy.h:59
#define CH_MIME
Ignore MIME fields.
Definition: copy.h:61
#define CH_UPDATE_REFS
Update References:
Definition: copy.h:69
#define CH_NOQFROM
Ignore ">From " line.
Definition: copy.h:67
#define CH_UPDATE_LEN
Update Lines: and Content-Length:
Definition: copy.h:62
#define CH_UPDATE_IRT
Update In-Reply-To:
Definition: copy.h:68
#define CH_FORCE_FROM
Give CH_FROM precedence over CH_WEED?
Definition: copy.h:66
#define CH_UPDATE_SUBJECT
Update Subject: protected header update.
Definition: copy.h:72
#define CH_NOLEN
Don't write Content-Length: and Lines:
Definition: copy.h:64
#define mutt_debug(LEVEL,...)
Definition: logging.h:84
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:420
@ LL_DEBUG3
Log at debug level 3.
Definition: logging.h:42
@ LL_DEBUG2
Log at debug level 2.
Definition: logging.h:41
@ LL_DEBUG1
Log at debug level 1.
Definition: logging.h:40
void mutt_mem_realloc(void *ptr, size_t size)
Resize a block of memory on the heap.
Definition: memory.c:114
size_t mutt_str_startswith(const char *str, const char *prefix)
Check whether a string starts with a prefix.
Definition: string.c:227
size_t mutt_str_len(const char *a)
Calculate the length of a string, safely.
Definition: string.c:567
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:524
struct ListHead HeaderOrderList
List of header fields in the order they should be displayed.
Definition: mutt_globals.h:62
int mutt_window_wrap_cols(int width, short wrap)
Calculate the wrap column for a given screen width.
Definition: mutt_window.c:365
bool mutt_matches_ignore(const char *s)
Does the string match the ignore list.
Definition: parse.c:313
static size_t plen
Length of cached packet.
Definition: pgppacket.c:39
#define STAILQ_FOREACH(var, head, field)
Definition: queue.h:352
void rfc2047_decode(char **pd)
Decode any RFC2047-encoded header fields.
Definition: rfc2047.c:649
A List node for strings.
Definition: list.h:35
char * data
String.
Definition: list.h:36
Container for Accounts, Notifications.
Definition: neomutt.h:37
struct ConfigSubset * sub
Inherited config items.
Definition: neomutt.h:39
+ 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 414 of file copy.c.

416{
417 char *temp_hdr = NULL;
418
419 if (e->env)
420 {
421 chflags |= ((e->env->changed & MUTT_ENV_CHANGED_IRT) ? CH_UPDATE_IRT : 0) |
425 }
426
427 if (mutt_copy_hdr(fp_in, fp_out, e->offset, e->body->offset, chflags, prefix, wraplen) == -1)
428 return -1;
429
430 if (chflags & CH_TXTPLAIN)
431 {
432 char chsbuf[128] = { 0 };
433 char buf[128] = { 0 };
434 fputs("MIME-Version: 1.0\n", fp_out);
435 fputs("Content-Transfer-Encoding: 8bit\n", fp_out);
436 fputs("Content-Type: text/plain; charset=", fp_out);
437 const char *const c_charset = cs_subset_string(NeoMutt->sub, "charset");
438 mutt_ch_canonical_charset(chsbuf, sizeof(chsbuf), c_charset ? c_charset : "us-ascii");
439 mutt_addr_cat(buf, sizeof(buf), chsbuf, MimeSpecials);
440 fputs(buf, fp_out);
441 fputc('\n', fp_out);
442 }
443
444 if ((chflags & CH_UPDATE_IRT) && !STAILQ_EMPTY(&e->env->in_reply_to))
445 {
446 fputs("In-Reply-To:", fp_out);
447 struct ListNode *np = NULL;
448 STAILQ_FOREACH(np, &e->env->in_reply_to, entries)
449 {
450 fputc(' ', fp_out);
451 fputs(np->data, fp_out);
452 }
453 fputc('\n', fp_out);
454 }
455
456 if ((chflags & CH_UPDATE_REFS) && !STAILQ_EMPTY(&e->env->references))
457 {
458 fputs("References:", fp_out);
459 mutt_write_references(&e->env->references, fp_out, 0);
460 fputc('\n', fp_out);
461 }
462
463 if ((chflags & CH_UPDATE) && ((chflags & CH_NOSTATUS) == 0))
464 {
465 if (e->old || e->read)
466 {
467 fputs("Status: ", fp_out);
468 if (e->read)
469 fputs("RO", fp_out);
470 else if (e->old)
471 fputc('O', fp_out);
472 fputc('\n', fp_out);
473 }
474
475 if (e->flagged || e->replied)
476 {
477 fputs("X-Status: ", fp_out);
478 if (e->replied)
479 fputc('A', fp_out);
480 if (e->flagged)
481 fputc('F', fp_out);
482 fputc('\n', fp_out);
483 }
484 }
485
486 if (chflags & CH_UPDATE_LEN && ((chflags & CH_NOLEN) == 0))
487 {
488 fprintf(fp_out, "Content-Length: " OFF_T_FMT "\n", e->body->length);
489 if ((e->lines != 0) || (e->body->length == 0))
490 fprintf(fp_out, "Lines: %d\n", e->lines);
491 }
492
493 const bool c_weed = cs_subset_bool(NeoMutt->sub, "weed");
494#ifdef USE_NOTMUCH
495 if (chflags & CH_VIRTUAL)
496 {
497 /* Add some fake headers based on notmuch data */
498 char *folder = nm_email_get_folder(e);
499 if (folder && !(c_weed && mutt_matches_ignore("folder")))
500 {
501 char buf[1024] = { 0 };
502 mutt_str_copy(buf, folder, sizeof(buf));
503 mutt_pretty_mailbox(buf, sizeof(buf));
504
505 fputs("Folder: ", fp_out);
506 fputs(buf, fp_out);
507 fputc('\n', fp_out);
508 }
509 }
510#endif
511 char *tags = driver_tags_get(&e->tags);
512 if (tags && !(c_weed && mutt_matches_ignore("tags")))
513 {
514 fputs("Tags: ", fp_out);
515 fputs(tags, fp_out);
516 fputc('\n', fp_out);
517 }
518 FREE(&tags);
519
520 const struct Slist *const c_send_charset = cs_subset_slist(NeoMutt->sub, "send_charset");
521 const short c_wrap = cs_subset_number(NeoMutt->sub, "wrap");
522 if ((chflags & CH_UPDATE_LABEL) && e->env->x_label)
523 {
524 temp_hdr = e->env->x_label;
525 /* env->x_label isn't currently stored with direct references elsewhere.
526 * Mailbox->label_hash strdups the keys. But to be safe, encode a copy */
527 if (!(chflags & CH_DECODE))
528 {
529 temp_hdr = mutt_str_dup(temp_hdr);
530 rfc2047_encode(&temp_hdr, NULL, sizeof("X-Label:"), c_send_charset);
531 }
532 if (mutt_write_one_header(fp_out, "X-Label", temp_hdr, (chflags & CH_PREFIX) ? prefix : 0,
533 mutt_window_wrap_cols(wraplen, c_wrap), chflags,
534 NeoMutt->sub) == -1)
535 {
536 return -1;
537 }
538 if (!(chflags & CH_DECODE))
539 FREE(&temp_hdr);
540 }
541
542 if ((chflags & CH_UPDATE_SUBJECT) && e->env->subject)
543 {
544 temp_hdr = e->env->subject;
545 /* env->subject is directly referenced in Mailbox->subj_hash, so we
546 * have to be careful not to encode (and thus free) that memory. */
547 if (!(chflags & CH_DECODE))
548 {
549 temp_hdr = mutt_str_dup(temp_hdr);
550 rfc2047_encode(&temp_hdr, NULL, sizeof("Subject:"), c_send_charset);
551 }
552 if (mutt_write_one_header(fp_out, "Subject", temp_hdr, (chflags & CH_PREFIX) ? prefix : 0,
553 mutt_window_wrap_cols(wraplen, c_wrap), chflags,
554 NeoMutt->sub) == -1)
555 {
556 return -1;
557 }
558 if (!(chflags & CH_DECODE))
559 FREE(&temp_hdr);
560 }
561
562 if ((chflags & CH_NONEWLINE) == 0)
563 {
564 if (chflags & CH_PREFIX)
565 fputs(prefix, fp_out);
566 fputc('\n', fp_out); /* add header terminator */
567 }
568
569 if (ferror(fp_out) || feof(fp_out))
570 return -1;
571
572 return 0;
573}
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:681
const char * cs_subset_string(const struct ConfigSubset *sub, const char *name)
Get a string config item by name.
Definition: helpers.c:317
const struct Slist * cs_subset_slist(const struct ConfigSubset *sub, const char *name)
Get a string-list config item by name.
Definition: helpers.c:268
bool cs_subset_bool(const struct ConfigSubset *sub, const char *name)
Get a boolean config item by name.
Definition: helpers.c:73
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:60
#define CH_TXTPLAIN
Generate text/plain MIME headers.
Definition: copy.h:63
#define CH_VIRTUAL
Write virtual header lines too.
Definition: copy.h:73
void mutt_pretty_mailbox(char *buf, size_t buflen)
Shorten a mailbox path using '~' or '='.
Definition: muttlib.c:522
#define MUTT_ENV_CHANGED_SUBJECT
Protected header update.
Definition: envelope.h:37
#define MUTT_ENV_CHANGED_XLABEL
X-Label edited.
Definition: envelope.h:36
#define MUTT_ENV_CHANGED_IRT
In-Reply-To changed to link/break threads.
Definition: envelope.h:34
#define MUTT_ENV_CHANGED_REFS
References changed to break thread.
Definition: envelope.h:35
void mutt_write_references(const struct ListHead *r, FILE *fp, size_t trim)
Add the message references to a list.
Definition: header.c:514
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:351
char * nm_email_get_folder(struct Email *e)
Get the folder for a Email.
Definition: notmuch.c:1449
#define STAILQ_EMPTY(head)
Definition: queue.h:348
void rfc2047_encode(char **pd, const char *specials, int col, const struct Slist *charsets)
RFC-2047-encode a string.
Definition: rfc2047.c:619
bool read
Email is read.
Definition: email.h:48
struct Envelope * env
Envelope information.
Definition: email.h:66
int lines
How many lines in the body of this message?
Definition: email.h:60
struct Body * body
List of MIME parts.
Definition: email.h:67
bool old
Email is seen, but unread.
Definition: email.h:47
LOFF_T offset
Where in the stream does this message begin?
Definition: email.h:69
bool flagged
Marked important?
Definition: email.h:45
bool replied
Email has been replied to.
Definition: email.h:49
struct TagList tags
For drivers that support server tagging.
Definition: email.h:70
unsigned char changed
Changed fields, e.g. MUTT_ENV_CHANGED_SUBJECT.
Definition: envelope.h:92
struct ListHead references
message references (in reverse order)
Definition: envelope.h:85
struct ListHead in_reply_to
in-reply-to header content
Definition: envelope.h:86
char * subject
Email's subject.
Definition: envelope.h:70
char * x_label
X-Label.
Definition: envelope.h:76
String list.
Definition: slist.h:47
char * driver_tags_get(struct TagList *list)
Get tags.
Definition: tags.c:145
+ 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 586 of file copy.c.

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

642{
643 struct Body *body = e->body;
644 char prefix[128] = { 0 };
645 LOFF_T new_offset = -1;
646 int rc = 0;
647
648 if (cmflags & MUTT_CM_PREFIX)
649 {
650 const bool c_text_flowed = cs_subset_bool(NeoMutt->sub, "text_flowed");
651 if (c_text_flowed)
652 mutt_str_copy(prefix, ">", sizeof(prefix));
653 else
654 {
655 const char *const c_indent_string = cs_subset_string(NeoMutt->sub, "indent_string");
656 struct Mailbox *m_cur = get_current_mailbox();
657 mutt_make_string(prefix, sizeof(prefix), wraplen, NONULL(c_indent_string),
658 m_cur, -1, e, MUTT_FORMAT_NO_FLAGS, NULL);
659 }
660 }
661
662 if ((cmflags & MUTT_CM_NOHEADER) == 0)
663 {
664 if (cmflags & MUTT_CM_PREFIX)
665 chflags |= CH_PREFIX;
666 else if (e->attach_del && (chflags & CH_UPDATE_LEN))
667 {
668 int new_lines;
669 int rc_attach_del = -1;
670 LOFF_T new_length = body->length;
671 struct Buffer *quoted_date = NULL;
672
673 quoted_date = mutt_buffer_pool_get();
674 mutt_buffer_addch(quoted_date, '"');
675 mutt_date_make_date(quoted_date, cs_subset_bool(NeoMutt->sub, "local_date_header"));
676 mutt_buffer_addch(quoted_date, '"');
677
678 /* Count the number of lines and bytes to be deleted */
679 if (!mutt_file_seek(fp_in, body->offset, SEEK_SET))
680 {
681 goto attach_del_cleanup;
682 }
683 const int del = count_delete_lines(fp_in, body, &new_length,
684 mutt_buffer_len(quoted_date));
685 if (del == -1)
686 {
687 goto attach_del_cleanup;
688 }
689 new_lines = e->lines - del;
690
691 /* Copy the headers */
692 if (mutt_copy_header(fp_in, e, fp_out, chflags | CH_NOLEN | CH_NONEWLINE, NULL, wraplen))
693 goto attach_del_cleanup;
694 fprintf(fp_out, "Content-Length: " OFF_T_FMT "\n", new_length);
695 if (new_lines <= 0)
696 new_lines = 0;
697 else
698 fprintf(fp_out, "Lines: %d\n", new_lines);
699
700 putc('\n', fp_out);
701 if (ferror(fp_out) || feof(fp_out))
702 goto attach_del_cleanup;
703 new_offset = ftello(fp_out);
704
705 /* Copy the body */
706 if (!mutt_file_seek(fp_in, body->offset, SEEK_SET))
707 goto attach_del_cleanup;
708 if (copy_delete_attach(body, fp_in, fp_out, mutt_buffer_string(quoted_date)))
709 goto attach_del_cleanup;
710
711 mutt_buffer_pool_release(&quoted_date);
712
713 LOFF_T fail = ((ftello(fp_out) - new_offset) - new_length);
714 if (fail)
715 {
716 mutt_error(ngettext("The length calculation was wrong by %ld byte",
717 "The length calculation was wrong by %ld bytes", fail),
718 fail);
719 new_length += fail;
720 }
721
722 /* Update original message if we are sync'ing a mailfolder */
723 if (cmflags & MUTT_CM_UPDATE)
724 {
725 e->attach_del = false;
726 e->lines = new_lines;
727 body->offset = new_offset;
728
729 body->length = new_length;
730 mutt_body_free(&body->parts);
731 }
732
733 rc_attach_del = 0;
734
735 attach_del_cleanup:
736 mutt_buffer_pool_release(&quoted_date);
737 return rc_attach_del;
738 }
739
740 if (mutt_copy_header(fp_in, e, fp_out, chflags,
741 (chflags & CH_PREFIX) ? prefix : NULL, wraplen) == -1)
742 {
743 return -1;
744 }
745
746 new_offset = ftello(fp_out);
747 }
748
749 if (cmflags & MUTT_CM_DECODE)
750 {
751 /* now make a text/plain version of the message */
752 struct State s = { 0 };
753 s.fp_in = fp_in;
754 s.fp_out = fp_out;
755 if (cmflags & MUTT_CM_PREFIX)
756 s.prefix = prefix;
757 if (cmflags & MUTT_CM_DISPLAY)
758 {
759 s.flags |= MUTT_DISPLAY;
760 s.wraplen = wraplen;
761 }
762 if (cmflags & MUTT_CM_PRINTING)
763 s.flags |= MUTT_PRINTING;
764 if (cmflags & MUTT_CM_WEED)
765 s.flags |= MUTT_WEED;
766 if (cmflags & MUTT_CM_CHARCONV)
767 s.flags |= MUTT_CHARCONV;
768 if (cmflags & MUTT_CM_REPLYING)
769 s.flags |= MUTT_REPLYING;
770
771 if ((WithCrypto != 0) && cmflags & MUTT_CM_VERIFY)
772 s.flags |= MUTT_VERIFY;
773
774 rc = mutt_body_handler(body, &s);
775 }
776 else if ((WithCrypto != 0) && (cmflags & MUTT_CM_DECODE_CRYPT) && (e->security & SEC_ENCRYPT))
777 {
778 struct Body *cur = NULL;
779 FILE *fp = NULL;
780
781 if (((WithCrypto & APPLICATION_PGP) != 0) && (cmflags & MUTT_CM_DECODE_PGP) &&
783 {
784 if (crypt_pgp_decrypt_mime(fp_in, &fp, e->body, &cur))
785 return -1;
786 fputs("MIME-Version: 1.0\n", fp_out);
787 }
788
789 if (((WithCrypto & APPLICATION_SMIME) != 0) && (cmflags & MUTT_CM_DECODE_SMIME) &&
791 {
792 if (crypt_smime_decrypt_mime(fp_in, &fp, e->body, &cur))
793 return -1;
794 }
795
796 if (!cur)
797 {
798 mutt_error(_("No decryption engine available for message"));
799 return -1;
800 }
801
802 mutt_write_mime_header(cur, fp_out, NeoMutt->sub);
803 fputc('\n', fp_out);
804
805 if (!mutt_file_seek(fp, cur->offset, SEEK_SET))
806 return -1;
807 if (mutt_file_copy_bytes(fp, fp_out, cur->length) == -1)
808 {
809 mutt_file_fclose(&fp);
810 mutt_body_free(&cur);
811 return -1;
812 }
813 mutt_body_free(&cur);
814 mutt_file_fclose(&fp);
815 }
816 else
817 {
818 if (!mutt_file_seek(fp_in, body->offset, SEEK_SET))
819 return -1;
820 if (cmflags & MUTT_CM_PREFIX)
821 {
822 int c;
823 size_t bytes = body->length;
824
825 fputs(prefix, fp_out);
826
827 while (((c = fgetc(fp_in)) != EOF) && bytes--)
828 {
829 fputc(c, fp_out);
830 if (c == '\n')
831 {
832 fputs(prefix, fp_out);
833 }
834 }
835 }
836 else if (mutt_file_copy_bytes(fp_in, fp_out, body->length) == -1)
837 return -1;
838 }
839
840 if ((cmflags & MUTT_CM_UPDATE) && ((cmflags & MUTT_CM_NOHEADER) == 0) &&
841 (new_offset != -1))
842 {
843 body->offset = new_offset;
844 mutt_body_free(&body->parts);
845 }
846
847 return rc;
848}
size_t mutt_buffer_len(const struct Buffer *buf)
Calculate the length of a Buffer.
Definition: buffer.c:371
size_t mutt_buffer_addch(struct Buffer *buf, char c)
Add a single character to a Buffer.
Definition: buffer.c:248
static const char * mutt_buffer_string(const struct Buffer *buf)
Convert a buffer to a const char * "string".
Definition: buffer.h:77
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:414
#define MUTT_CM_WEED
Weed message/rfc822 attachment headers.
Definition: copy.h:41
#define MUTT_CM_REPLYING
Replying the message.
Definition: copy.h:44
#define MUTT_CM_PREFIX
Quote the header and body.
Definition: copy.h:37
#define MUTT_CM_UPDATE
Update structs on sync.
Definition: copy.h:40
#define MUTT_CM_VERIFY
Do signature verification.
Definition: copy.h:47
#define MUTT_CM_DECODE_PGP
Used for decoding PGP messages.
Definition: copy.h:45
#define MUTT_CM_DECODE
Decode the message body into text/plain.
Definition: copy.h:38
#define MUTT_CM_CHARCONV
Perform character set conversions.
Definition: copy.h:42
#define MUTT_CM_DECODE_SMIME
Used for decoding S/MIME messages.
Definition: copy.h:46
#define MUTT_CM_PRINTING
Printing the message - display light.
Definition: copy.h:43
#define MUTT_CM_DECODE_CRYPT
Definition: copy.h:48
#define MUTT_CM_NOHEADER
Don't copy the message header.
Definition: copy.h:36
#define MUTT_CM_DISPLAY
Output is displayed to the user.
Definition: copy.h:39
int crypt_smime_decrypt_mime(FILE *fp_in, FILE **fp_out, struct Body *b, struct Body **cur)
Wrapper for CryptModuleSpecs::decrypt_mime()
Definition: cryptglue.c:433
int crypt_pgp_decrypt_mime(FILE *fp_in, FILE **fp_out, struct Body *b, struct Body **cur)
Wrapper for CryptModuleSpecs::decrypt_mime()
Definition: cryptglue.c:211
void mutt_date_make_date(struct Buffer *buf, bool local)
Write a date in RFC822 format to a buffer.
Definition: date.c:380
void mutt_body_free(struct Body **ptr)
Free a Body.
Definition: body.c:57
int mutt_file_fclose(FILE **fp)
Close a FILE handle (and NULL the pointer)
Definition: file.c:152
#define MUTT_FORMAT_NO_FLAGS
No flags are set.
Definition: format_flags.h:30
#define mutt_error(...)
Definition: logging.h:87
int mutt_body_handler(struct Body *b, struct State *s)
Handler for the Body of an email.
Definition: handler.c:1597
void mutt_make_string(char *buf, size_t buflen, int cols, const char *s, struct Mailbox *m, int inpgr, struct Email *e, MuttFormatFlags flags, const char *progress)
Create formatted strings using mailbox expandos.
Definition: hdrline.c:1405
int mutt_write_mime_header(struct Body *a, FILE *fp, struct ConfigSubset *sub)
Create a MIME header.
Definition: header.c:760
struct Mailbox * get_current_mailbox(void)
Get the current Mailbox.
Definition: index.c:624
@ TYPE_MULTIPART
Type: 'multipart/*'.
Definition: mime.h:37
@ TYPE_APPLICATION
Type: 'application/*'.
Definition: mime.h:33
#define _(a)
Definition: message.h:28
#define MUTT_WEED
Weed headers even when not in display mode.
Definition: state.h:35
#define MUTT_VERIFY
Perform signature verification.
Definition: state.h:33
#define MUTT_CHARCONV
Do character set conversions.
Definition: state.h:36
#define MUTT_DISPLAY
Output is displayed to the user.
Definition: state.h:32
#define MUTT_REPLYING
Are we replying?
Definition: state.h:38
#define MUTT_PRINTING
Are we printing? - MUTT_DISPLAY "light".
Definition: state.h:37
#define APPLICATION_PGP
Use PGP to encrypt/sign.
Definition: lib.h:90
#define APPLICATION_SMIME
Use SMIME to encrypt/sign.
Definition: lib.h:91
#define SEC_ENCRYPT
Email is encrypted.
Definition: lib.h:78
#define WithCrypto
Definition: lib.h:116
void mutt_buffer_pool_release(struct Buffer **pbuf)
Free a Buffer from the pool.
Definition: pool.c:112
struct Buffer * mutt_buffer_pool_get(void)
Get a Buffer from the pool.
Definition: pool.c:101
#define NONULL(x)
Definition: string2.h:37
unsigned int type
content-type primary type, ContentType
Definition: body.h:40
String manipulation buffer.
Definition: buffer.h:34
SecurityFlags security
bit 0-10: flags, bit 11,12: application, bit 13: traditional pgp See: ncrypt/lib.h pgplib....
Definition: email.h:41
bool attach_del
Has an attachment marked for deletion.
Definition: email.h:99
A mailbox.
Definition: mailbox.h:79
Keep track when processing files.
Definition: state.h:46
int wraplen
Width to wrap lines to (when flags & MUTT_DISPLAY)
Definition: state.h:51
StateFlags flags
Flags, e.g. MUTT_DISPLAY.
Definition: state.h:50
FILE * fp_out
File to write to.
Definition: state.h:48
char * prefix
String to add to the beginning of each output line.
Definition: state.h:49
FILE * fp_in
File to read from.
Definition: state.h:47
+ 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 864 of file copy.c.

866{
867 if (!msg || !e->body)
868 {
869 return -1;
870 }
871 if (fp_out == msg->fp)
872 {
873 mutt_debug(LL_DEBUG1, "trying to read/write from/to the same FILE*!\n");
874 return -1;
875 }
876
877 int rc = mutt_copy_message_fp(fp_out, msg->fp, e, cmflags, chflags, wraplen);
878 if ((rc == 0) && (ferror(fp_out) || feof(fp_out)))
879 {
880 mutt_debug(LL_DEBUG1, "failed to detect EOF!\n");
881 rc = -1;
882 }
883 return rc;
884}
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:640
FILE * fp
pointer to the message data
Definition: mxapi.h:44
+ 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 897 of file copy.c.

899{
900 char buf[256] = { 0 };
901 struct Message *msg = NULL;
902 int rc;
903
904 if (!mutt_file_seek(fp_in, e->offset, SEEK_SET))
905 return -1;
906 if (!fgets(buf, sizeof(buf), fp_in))
907 return -1;
908
909 msg = mx_msg_open_new(dest, e, is_from(buf, NULL, 0, NULL) ? MUTT_MSG_NO_FLAGS : MUTT_ADD_FROM);
910 if (!msg)
911 return -1;
912 if ((dest->type == MUTT_MBOX) || (dest->type == MUTT_MMDF))
913 chflags |= CH_FROM | CH_FORCE_FROM;
914 chflags |= ((dest->type == MUTT_MAILDIR) ? CH_NOSTATUS : CH_UPDATE);
915 rc = mutt_copy_message_fp(msg->fp, fp_in, e, cmflags, chflags, 0);
916 if (mx_msg_commit(dest, msg) != 0)
917 rc = -1;
918
919#ifdef USE_NOTMUCH
920 if (msg->committed_path && (dest->type == MUTT_MAILDIR) && (src->type == MUTT_NOTMUCH))
921 nm_update_filename(src, NULL, msg->committed_path, e);
922#endif
923
924 mx_msg_close(dest, &msg);
925 return rc;
926}
bool is_from(const char *s, char *path, size_t pathlen, time_t *tp)
Is a string a 'From' header line?
Definition: from.c:48
@ 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
int mx_msg_close(struct Mailbox *m, struct Message **msg)
Close a message.
Definition: mx.c:1193
struct Message * mx_msg_open_new(struct Mailbox *m, const struct Email *e, MsgOpenFlags flags)
Open a new message.
Definition: mx.c:1057
int mx_msg_commit(struct Mailbox *m, struct Message *msg)
Commit a message to a folder - Wrapper for MxOps::msg_commit()
Definition: mx.c:1172
#define MUTT_ADD_FROM
add a From_ line
Definition: mx.h:43
#define MUTT_MSG_NO_FLAGS
No flags are set.
Definition: mx.h:42
int nm_update_filename(struct Mailbox *m, const char *old_file, const char *new_file, struct Email *e)
Change the filename.
Definition: notmuch.c:1736
enum MailboxType type
Mailbox type.
Definition: mailbox.h:102
A local copy of an email.
Definition: mxapi.h:43
char * committed_path
the final path generated by mx_msg_commit()
Definition: mxapi.h:46
+ 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 939 of file copy.c.

942{
943 const bool own_msg = !msg;
944 if (own_msg && !(msg = mx_msg_open(m_src, e->msgno)))
945 {
946 return -1;
947 }
948
949 int rc = append_message(m_dst, msg->fp, m_src, e, cmflags, chflags);
950 if (own_msg)
951 {
952 mx_msg_close(m_src, &msg);
953 }
954 return rc;
955}
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:897
struct Message * mx_msg_open(struct Mailbox *m, int msgno)
Return a stream pointer for a message.
Definition: mx.c:1147
int msgno
Number displayed to the user.
Definition: email.h:111
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ format_address_header()

static void format_address_header ( char **  h,
struct AddressList *  al 
)
static

Write address headers to a buffer.

Parameters
[out]hArray of header strings
[in]alAddressList

This function is the equivalent of mutt_addrlist_write_file(), but writes to a buffer instead of writing to a stream. mutt_addrlist_write_file could be re-used if we wouldn't store all the decoded headers in a huge array, first.

TODO fix that.

Definition at line 1037 of file copy.c.

1038{
1039 char buf[8192] = { 0 };
1040 char cbuf[256] = { 0 };
1041 char c2buf[256];
1042 char *p = NULL;
1043 size_t linelen, buflen, plen;
1044
1045 linelen = mutt_str_len(*h);
1046 plen = linelen;
1047 buflen = linelen + 3;
1048
1049 mutt_mem_realloc(h, buflen);
1050 struct Address *first = TAILQ_FIRST(al);
1051 struct Address *a = NULL;
1052 TAILQ_FOREACH(a, al, entries)
1053 {
1054 *buf = '\0';
1055 *cbuf = '\0';
1056 *c2buf = '\0';
1057 const size_t l = mutt_addr_write(buf, sizeof(buf), a, false);
1058
1059 if (a != first && (linelen + l > 74))
1060 {
1061 strcpy(cbuf, "\n\t");
1062 linelen = l + 8;
1063 }
1064 else
1065 {
1066 if (a->mailbox)
1067 {
1068 strcpy(cbuf, " ");
1069 linelen++;
1070 }
1071 linelen += l;
1072 }
1073 if (!a->group && TAILQ_NEXT(a, entries) && TAILQ_NEXT(a, entries)->mailbox)
1074 {
1075 linelen++;
1076 buflen++;
1077 strcpy(c2buf, ",");
1078 }
1079
1080 const size_t cbuflen = mutt_str_len(cbuf);
1081 const size_t c2buflen = mutt_str_len(c2buf);
1082 buflen += l + cbuflen + c2buflen;
1083 mutt_mem_realloc(h, buflen);
1084 p = *h;
1085 strcat(p + plen, cbuf);
1086 plen += cbuflen;
1087 strcat(p + plen, buf);
1088 plen += l;
1089 strcat(p + plen, c2buf);
1090 plen += c2buflen;
1091 }
1092
1093 /* Space for this was allocated in the beginning of this function. */
1094 strcat(p + plen, "\n");
1095}
size_t mutt_addr_write(char *buf, size_t buflen, struct Address *addr, bool display)
Write a single Address to a buffer.
Definition: address.c:1025
#define TAILQ_FIRST(head)
Definition: queue.h:723
#define TAILQ_NEXT(elm, field)
Definition: queue.h:832
bool group
Group mailbox?
Definition: address.h:39
char * mailbox
Mailbox and host address.
Definition: address.h:38
+ Here is the call graph for this function:
+ Here is the caller graph for this function: