NeoMutt  2018-07-16 +952-a2da0a
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/mutt.h"
#include "config/lib.h"
#include "email/lib.h"
#include "mutt.h"
#include "copy.h"
#include "context.h"
#include "globals.h"
#include "handler.h"
#include "hdrline.h"
#include "mailbox.h"
#include "mutt_window.h"
#include "muttlib.h"
#include "mx.h"
#include "ncrypt/ncrypt.h"
#include "sendlib.h"
#include "state.h"
#include "notmuch/mutt_notmuch.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 *fpin, FILE *fpout, char *date)
 Copy a message, deleting marked attachments. More...
 
int mutt_copy_hdr (FILE *in, FILE *out, LOFF_T off_start, LOFF_T off_end, int flags, const char *prefix)
 Copy header from one file to another. More...
 
int mutt_copy_header (FILE *in, struct Email *e, FILE *out, int flags, const char *prefix)
 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 *fpout, FILE *fpin, struct Email *e, int flags, int chflags)
 make a copy of a message from a FILE pointer More...
 
int mutt_copy_message_ctx (FILE *fpout, struct Mailbox *src, struct Email *e, int flags, int chflags)
 Copy a message from a Context. More...
 
static int append_message (struct Mailbox *dest, FILE *fpin, struct Mailbox *src, struct Email *e, int flags, int chflags)
 appends a copy of the given message to a mailbox More...
 
int mutt_append_message (struct Mailbox *dest, struct Mailbox *src, struct Email *e, int cmflags, int chflags)
 Append a message. More...
 
static void format_address_header (char **h, struct Address *a)
 Write address headers to a buffer. More...
 

Detailed Description

Duplicate the structure of an entire email.

Authors
  • Michael R. Elkins

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

static int address_header_decode ( char **  h)
static

Parse an email's headers.

Parameters
hArray of header strings
Return values
0Success
1Failure

Definition at line 1009 of file copy.c.

1010 {
1011  char *s = *h;
1012  size_t l;
1013  bool rp = false;
1014 
1015  struct Address *a = NULL;
1016  struct Address *cur = NULL;
1017 
1018  switch (tolower((unsigned char) *s))
1019  {
1020  case 'b':
1021  {
1022  if (!(l = mutt_str_startswith(s, "bcc:", CASE_IGNORE)))
1023  return 0;
1024  break;
1025  }
1026  case 'c':
1027  {
1028  if (!(l = mutt_str_startswith(s, "cc:", CASE_IGNORE)))
1029  return 0;
1030  break;
1031  }
1032  case 'f':
1033  {
1034  if (!(l = mutt_str_startswith(s, "from:", CASE_IGNORE)))
1035  return 0;
1036  break;
1037  }
1038  case 'm':
1039  {
1040  if (!(l = mutt_str_startswith(s, "mail-followup-to:", CASE_IGNORE)))
1041  return 0;
1042  break;
1043  }
1044  case 'r':
1045  {
1046  if ((l = mutt_str_startswith(s, "return-path:", CASE_IGNORE)))
1047  {
1048  rp = true;
1049  break;
1050  }
1051  else if ((l = mutt_str_startswith(s, "reply-to:", CASE_IGNORE)))
1052  {
1053  break;
1054  }
1055  return 0;
1056  }
1057  case 's':
1058  {
1059  if (!(l = mutt_str_startswith(s, "sender:", CASE_IGNORE)))
1060  return 0;
1061  break;
1062  }
1063  case 't':
1064  {
1065  if (!(l = mutt_str_startswith(s, "to:", CASE_IGNORE)))
1066  return 0;
1067  break;
1068  }
1069  default:
1070  return 0;
1071  }
1072 
1073  a = mutt_addr_parse_list(a, s + l);
1074  if (!a)
1075  return 0;
1076 
1079  for (cur = a; cur; cur = cur->next)
1080  if (cur->personal)
1082 
1083  /* angle brackets for return path are mandated by RFC5322,
1084  * so leave Return-Path as-is */
1085  if (rp)
1086  *h = mutt_str_strdup(s);
1087  else
1088  {
1089  *h = mutt_mem_calloc(1, l + 2);
1090  mutt_str_strfcpy(*h, s, l + 1);
1091  format_address_header(h, a);
1092  }
1093 
1094  mutt_addr_free(&a);
1095 
1096  FREE(&s);
1097  return 1;
1098 }
void * mutt_mem_calloc(size_t nmemb, size_t size)
Allocate zeroed memory on the heap.
Definition: memory.c:51
An email address.
Definition: address.h:32
int mutt_addrlist_to_local(struct Address *a)
Convert an Address list from Punycode.
Definition: address.c:1249
static void format_address_header(char **h, struct Address *a)
Write address headers to a buffer.
Definition: copy.c:942
struct Address * mutt_addr_parse_list(struct Address *top, const char *s)
Parse a list of email addresses.
Definition: address.c:465
size_t mutt_str_strfcpy(char *dest, const char *src, size_t dsize)
Copy a string into a buffer (guaranteeing NUL-termination)
Definition: string.c:742
Ignore case when comparing strings.
Definition: string2.h:70
void mutt_str_dequote_comment(char *s)
Un-escape characters in an email address comment.
Definition: string.c:867
void rfc2047_decode_addrlist(struct Address *a)
Decode any RFC2047 headers in an Address list.
Definition: rfc2047.c:768
size_t mutt_str_startswith(const char *str, const char *prefix, enum CaseSensitivity cs)
Check whether a string starts with a prefix.
Definition: string.c:166
char * personal
real name of address
Definition: address.h:34
char * mutt_str_strdup(const char *str)
Copy a string, safely.
Definition: string.c:384
#define FREE(x)
Definition: memory.h:46
void mutt_addr_free(struct Address **p)
Free a list of Addresses.
Definition: address.c:446
struct Address * next
Definition: address.h:39

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

static int copy_delete_attach ( struct Body b,
FILE *  fpin,
FILE *  fpout,
char *  date 
)
static

Copy a message, deleting marked attachments.

Parameters
bEmail Body
fpinFILE pointer to read from
fpoutFILE pointer to write to
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 886 of file copy.c.

887 {
888  struct Body *part = NULL;
889 
890  for (part = b->parts; part; part = part->next)
891  {
892  if (part->deleted || part->parts)
893  {
894  /* Copy till start of this part */
895  if (mutt_file_copy_bytes(fpin, fpout, part->hdr_offset - ftello(fpin)))
896  return -1;
897 
898  if (part->deleted)
899  {
900  fprintf(
901  fpout,
902  "Content-Type: message/external-body; access-type=x-mutt-deleted;\n"
903  "\texpiration=%s; length=" OFF_T_FMT "\n"
904  "\n",
905  date + 5, part->length);
906  if (ferror(fpout))
907  return -1;
908 
909  /* Copy the original mime headers */
910  if (mutt_file_copy_bytes(fpin, fpout, part->offset - ftello(fpin)))
911  return -1;
912 
913  /* Skip the deleted body */
914  fseeko(fpin, part->offset + part->length, SEEK_SET);
915  }
916  else
917  {
918  if (copy_delete_attach(part, fpin, fpout, date))
919  return -1;
920  }
921  }
922  }
923 
924  /* Copy the last parts */
925  if (mutt_file_copy_bytes(fpin, fpout, b->offset + b->length - ftello(fpin)))
926  return -1;
927 
928  return 0;
929 }
LOFF_T offset
offset where the actual data begins
Definition: body.h:45
struct Body * next
next attachment in the list
Definition: body.h:57
The body of an email.
Definition: body.h:33
LOFF_T length
length (in bytes) of attachment
Definition: body.h:46
static int copy_delete_attach(struct Body *b, FILE *fpin, FILE *fpout, char *date)
Copy a message, deleting marked attachments.
Definition: copy.c:886
struct Body * parts
parts of a multipart or message/rfc822
Definition: body.h:58
bool deleted
attachment marked for deletion
Definition: body.h:75
long hdr_offset
offset in stream where the headers begin.
Definition: body.h:41
int mutt_file_copy_bytes(FILE *in, FILE *out, size_t size)
Copy some content from one file to another.
Definition: file.c:237

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

int mutt_copy_hdr ( FILE *  in,
FILE *  out,
LOFF_T  off_start,
LOFF_T  off_end,
int  flags,
const char *  prefix 
)

Copy header from one file to another.

Parameters
inFILE pointer to read from
outFILE pointer to write to
off_startOffset to start from
off_endOffset to finish at
flagsFlags (see below)
prefixPrefix for quoting headers
Return values
0Success
-1Failure

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

Definition at line 72 of file copy.c.

74 {
75  bool from = false;
76  bool this_is_from = false;
77  bool ignore = false;
78  char buf[LONG_STRING]; /* should be long enough to get most fields in one pass */
79  char *nl = NULL;
80  char **headers = NULL;
81  int hdr_count;
82  int x;
83  char *this_one = NULL;
84  size_t this_one_len = 0;
85  int error;
86 
87  if (off_start < 0)
88  return -1;
89 
90  if (ftello(in) != off_start)
91  if (fseeko(in, off_start, SEEK_SET) < 0)
92  return -1;
93 
94  buf[0] = '\n';
95  buf[1] = '\0';
96 
97  if ((flags & (CH_REORDER | CH_WEED | CH_MIME | CH_DECODE | CH_PREFIX | CH_WEED_DELIVERED)) == 0)
98  {
99  /* Without these flags to complicate things
100  * we can do a more efficient line to line copying
101  */
102  while (ftello(in) < off_end)
103  {
104  nl = strchr(buf, '\n');
105 
106  if (!fgets(buf, sizeof(buf), in))
107  break;
108 
109  /* Is it the beginning of a header? */
110  if (nl && buf[0] != ' ' && buf[0] != '\t')
111  {
112  ignore = true;
113  if (!from && mutt_str_startswith(buf, "From ", CASE_MATCH))
114  {
115  if ((flags & CH_FROM) == 0)
116  continue;
117  from = true;
118  }
119  else if ((flags & CH_NOQFROM) && mutt_str_startswith(buf, ">From ", CASE_IGNORE))
120  continue;
121 
122  else if (buf[0] == '\n' || (buf[0] == '\r' && buf[1] == '\n'))
123  break; /* end of header */
124 
125  if ((flags & (CH_UPDATE | CH_XMIT | CH_NOSTATUS)) &&
126  (mutt_str_startswith(buf, "Status:", CASE_IGNORE) ||
127  mutt_str_startswith(buf, "X-Status:", CASE_IGNORE)))
128  {
129  continue;
130  }
131  if ((flags & (CH_UPDATE_LEN | CH_XMIT | CH_NOLEN)) &&
132  (mutt_str_startswith(buf, "Content-Length:", CASE_IGNORE) ||
133  mutt_str_startswith(buf, "Lines:", CASE_IGNORE)))
134  {
135  continue;
136  }
137  if ((flags & CH_UPDATE_REFS) && mutt_str_startswith(buf, "References:", CASE_IGNORE))
138  continue;
139  if ((flags & CH_UPDATE_IRT) && mutt_str_startswith(buf, "In-Reply-To:", CASE_IGNORE))
140  continue;
141  if (flags & CH_UPDATE_LABEL && mutt_str_startswith(buf, "X-Label:", CASE_IGNORE))
142  continue;
143 
144  ignore = false;
145  }
146 
147  if (!ignore && fputs(buf, out) == EOF)
148  return -1;
149  }
150  return 0;
151  }
152 
153  hdr_count = 1;
154  x = 0;
155  error = false;
156 
157  /* We are going to read and collect the headers in an array
158  * so we are able to do re-ordering.
159  * First count the number of entries in the array
160  */
161  if (flags & CH_REORDER)
162  {
163  struct ListNode *np = NULL;
164  STAILQ_FOREACH(np, &HeaderOrderList, entries)
165  {
166  mutt_debug(3, "Reorder list: %s\n", np->data);
167  hdr_count++;
168  }
169  }
170 
171  mutt_debug(1, "WEED is %s\n", (flags & CH_WEED) ? "Set" : "Not");
172 
173  headers = mutt_mem_calloc(hdr_count, sizeof(char *));
174 
175  /* Read all the headers into the array */
176  while (ftello(in) < off_end)
177  {
178  nl = strchr(buf, '\n');
179 
180  /* Read a line */
181  if (!fgets(buf, sizeof(buf), in))
182  break;
183 
184  /* Is it the beginning of a header? */
185  if (nl && buf[0] != ' ' && buf[0] != '\t')
186  {
187  /* Do we have anything pending? */
188  if (this_one)
189  {
190  if (flags & CH_DECODE)
191  {
192  if (address_header_decode(&this_one) == 0)
193  rfc2047_decode(&this_one);
194  this_one_len = mutt_str_strlen(this_one);
195 
196  /* Convert CRLF line endings to LF */
197  if ((this_one_len > 2) && (this_one[this_one_len - 2] == '\r') &&
198  (this_one[this_one_len - 1] == '\n'))
199  {
200  this_one[this_one_len - 2] = '\n';
201  this_one[this_one_len - 1] = '\0';
202  }
203  }
204 
205  if (!headers[x])
206  headers[x] = this_one;
207  else
208  {
209  int hlen = mutt_str_strlen(headers[x]);
210 
211  mutt_mem_realloc(&headers[x], hlen + this_one_len + sizeof(char));
212  strcat(headers[x] + hlen, this_one);
213  FREE(&this_one);
214  }
215 
216  this_one = NULL;
217  }
218 
219  ignore = true;
220  this_is_from = false;
221  if (!from && mutt_str_startswith(buf, "From ", CASE_MATCH))
222  {
223  if ((flags & CH_FROM) == 0)
224  continue;
225  this_is_from = true;
226  from = true;
227  }
228  else if (buf[0] == '\n' || (buf[0] == '\r' && buf[1] == '\n'))
229  break; /* end of header */
230 
231  /* note: CH_FROM takes precedence over header weeding. */
232  if (!((flags & CH_FROM) && (flags & CH_FORCE_FROM) && this_is_from) &&
233  (flags & CH_WEED) && mutt_matches_ignore(buf))
234  {
235  continue;
236  }
237  if ((flags & CH_WEED_DELIVERED) && mutt_str_startswith(buf, "Delivered-To:", CASE_IGNORE))
238  {
239  continue;
240  }
241  if ((flags & (CH_UPDATE | CH_XMIT | CH_NOSTATUS)) &&
242  (mutt_str_startswith(buf, "Status:", CASE_IGNORE) ||
243  mutt_str_startswith(buf, "X-Status:", CASE_IGNORE)))
244  {
245  continue;
246  }
247  if ((flags & (CH_UPDATE_LEN | CH_XMIT | CH_NOLEN)) &&
248  (mutt_str_startswith(buf, "Content-Length:", CASE_IGNORE) ||
249  mutt_str_startswith(buf, "Lines:", CASE_IGNORE)))
250  {
251  continue;
252  }
253  if ((flags & CH_MIME))
254  {
255  if (mutt_str_startswith(buf, "mime-version:", CASE_IGNORE))
256  {
257  continue;
258  }
259  size_t plen = mutt_str_startswith(buf, "content-", CASE_IGNORE);
260  if ((plen != 0) && (mutt_str_startswith(buf + plen, "transfer-encoding:", CASE_IGNORE) ||
261  mutt_str_startswith(buf + plen, "type:", CASE_IGNORE)))
262  {
263  continue;
264  }
265  }
266  if ((flags & CH_UPDATE_REFS) && mutt_str_startswith(buf, "References:", CASE_IGNORE))
267  continue;
268  if ((flags & CH_UPDATE_IRT) && mutt_str_startswith(buf, "In-Reply-To:", CASE_IGNORE))
269  continue;
270 
271  /* Find x -- the array entry where this header is to be saved */
272  if (flags & CH_REORDER)
273  {
274  struct ListNode *np = NULL;
275  x = 0;
276  STAILQ_FOREACH(np, &HeaderOrderList, entries)
277  {
278  ++x;
279  if (mutt_str_startswith(buf, np->data, CASE_IGNORE))
280  {
281  mutt_debug(2, "Reorder: %s matches %s", np->data, buf);
282  break;
283  }
284  }
285  }
286 
287  ignore = false;
288  } /* If beginning of header */
289 
290  if (!ignore)
291  {
292  mutt_debug(2, "Reorder: x = %d; hdr_count = %d\n", x, hdr_count);
293  if (!this_one)
294  {
295  this_one = mutt_str_strdup(buf);
296  this_one_len = mutt_str_strlen(this_one);
297  }
298  else
299  {
300  size_t blen = mutt_str_strlen(buf);
301 
302  mutt_mem_realloc(&this_one, this_one_len + blen + sizeof(char));
303  strcat(this_one + this_one_len, buf);
304  this_one_len += blen;
305  }
306  }
307  } /* while (ftello (in) < off_end) */
308 
309  /* Do we have anything pending? -- XXX, same code as in above in the loop. */
310  if (this_one)
311  {
312  if (flags & CH_DECODE)
313  {
314  if (address_header_decode(&this_one) == 0)
315  rfc2047_decode(&this_one);
316  this_one_len = mutt_str_strlen(this_one);
317  }
318 
319  if (!headers[x])
320  headers[x] = this_one;
321  else
322  {
323  int hlen = mutt_str_strlen(headers[x]);
324 
325  mutt_mem_realloc(&headers[x], hlen + this_one_len + sizeof(char));
326  strcat(headers[x] + hlen, this_one);
327  FREE(&this_one);
328  }
329 
330  this_one = NULL;
331  }
332 
333  /* Now output the headers in order */
334  for (x = 0; x < hdr_count; x++)
335  {
336  if (headers[x])
337  {
338  /* We couldn't do the prefixing when reading because RFC2047
339  * decoding may have concatenated lines.
340  */
341 
342  if (flags & (CH_DECODE | CH_PREFIX))
343  {
344  if (mutt_write_one_header(out, 0, headers[x], (flags & CH_PREFIX) ? prefix : 0,
346  {
347  error = true;
348  break;
349  }
350  }
351  else
352  {
353  if (fputs(headers[x], out) == EOF)
354  {
355  error = true;
356  break;
357  }
358  }
359  }
360  }
361 
362  /* Free in a separate loop to be sure that all headers are freed
363  * in case of error. */
364  for (x = 0; x < hdr_count; x++)
365  FREE(&headers[x]);
366  FREE(&headers);
367 
368  if (error)
369  return -1;
370  return 0;
371 }
bool mutt_matches_ignore(const char *s)
Does the string match the ignore list.
Definition: parse.c:245
#define CH_MIME
ignore MIME fields
Definition: copy.h:56
void * mutt_mem_calloc(size_t nmemb, size_t size)
Allocate zeroed memory on the heap.
Definition: memory.c:51
void rfc2047_decode(char **pd)
Decode any RFC2047-encoded header fields.
Definition: rfc2047.c:649
static size_t plen
Length of cached packet.
Definition: pgppacket.c:38
WHERE short Wrap
Config: Width to wrap text in the pager.
Definition: globals.h:156
#define CH_FROM
retain the "From " message separator?
Definition: copy.h:51
int mutt_write_one_header(FILE *fp, const char *tag, const char *value, const char *pfx, int wraplen, int flags)
Write one header line to a file.
Definition: sendlib.c:2107
#define CH_NOSTATUS
suppress the status and x-status fields
Definition: copy.h:53
#define CH_UPDATE
update the status and x-status fields?
Definition: copy.h:47
Match case when comparing strings.
Definition: string2.h:69
size_t mutt_str_strlen(const char *a)
Calculate the length of a string, safely.
Definition: string.c:663
#define CH_UPDATE_REFS
update References:
Definition: copy.h:64
#define LONG_STRING
Definition: string2.h:36
#define CH_WEED_DELIVERED
weed eventual Delivered-To headers
Definition: copy.h:60
static int address_header_decode(char **h)
Parse an email&#39;s headers.
Definition: copy.c:1009
#define CH_WEED
weed the headers?
Definition: copy.h:48
void mutt_mem_realloc(void *ptr, size_t size)
Resize a block of memory on the heap.
Definition: memory.c:124
#define CH_FORCE_FROM
give CH_FROM precedence over CH_WEED?
Definition: copy.h:61
#define CH_UPDATE_LABEL
update X-Label: from hdr->env->x_label?
Definition: copy.h:66
#define CH_UPDATE_IRT
update In-Reply-To:
Definition: copy.h:63
struct MuttWindow * MuttIndexWindow
Index Window.
Definition: mutt_window.c:39
#define CH_REORDER
Re-order output of headers.
Definition: copy.h:54
#define CH_DECODE
do RFC1522 decoding?
Definition: copy.h:49
#define CH_XMIT
transmitting this message?
Definition: copy.h:50
Ignore case when comparing strings.
Definition: string2.h:70
#define CH_UPDATE_LEN
update Lines: and Content-Length:
Definition: copy.h:57
#define STAILQ_FOREACH(var, head, field)
Definition: queue.h:350
#define CH_NOLEN
don&#39;t write Content-Length: and Lines:
Definition: copy.h:59
size_t mutt_str_startswith(const char *str, const char *prefix, enum CaseSensitivity cs)
Check whether a string starts with a prefix.
Definition: string.c:166
#define CH_NOQFROM
ignore ">From " line
Definition: copy.h:62
char * data
Definition: list.h:35
char * mutt_str_strdup(const char *str)
Copy a string, safely.
Definition: string.c:384
#define FREE(x)
Definition: memory.h:46
#define mutt_debug(LEVEL,...)
Definition: logging.h:85
A List node for strings.
Definition: list.h:33
#define CH_PREFIX
use IndentString string?
Definition: copy.h:52
int mutt_window_wrap_cols(struct MuttWindow *win, short wrap)
Calculate the wrap column for a Window.
Definition: mutt_window.c:309

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

int mutt_copy_header ( FILE *  in,
struct Email e,
FILE *  out,
int  flags,
const char *  prefix 
)

Copy Email header.

Parameters
inFILE pointer to read from
eEmail
outFILE pointer to write to
flagsFlags, see below
prefixPrefix for quoting headers
Return values
0Success
-1Failure

flags:

prefix

  • string to use if CH_PREFIX is set

Definition at line 406 of file copy.c.

407 {
408  if (e->env)
409  {
410  flags |= (e->env->irt_changed ? CH_UPDATE_IRT : 0) |
411  (e->env->refs_changed ? CH_UPDATE_REFS : 0);
412  }
413 
414  if (mutt_copy_hdr(in, out, e->offset, e->content->offset, flags, prefix) == -1)
415  return -1;
416 
417  if (flags & CH_TXTPLAIN)
418  {
419  char chsbuf[SHORT_STRING];
420  char buffer[SHORT_STRING];
421  fputs("MIME-Version: 1.0\n", out);
422  fputs("Content-Transfer-Encoding: 8bit\n", out);
423  fputs("Content-Type: text/plain; charset=", out);
424  mutt_ch_canonical_charset(chsbuf, sizeof(chsbuf), Charset ? Charset : "us-ascii");
425  mutt_addr_cat(buffer, sizeof(buffer), chsbuf, MimeSpecials);
426  fputs(buffer, out);
427  fputc('\n', out);
428  }
429 
430  if ((flags & CH_UPDATE_IRT) && !STAILQ_EMPTY(&e->env->in_reply_to))
431  {
432  fputs("In-Reply-To:", out);
433  struct ListNode *np = NULL;
434  STAILQ_FOREACH(np, &e->env->in_reply_to, entries)
435  {
436  fputc(' ', out);
437  fputs(np->data, out);
438  }
439  fputc('\n', out);
440  }
441 
442  if ((flags & CH_UPDATE_REFS) && !STAILQ_EMPTY(&e->env->references))
443  {
444  fputs("References:", out);
445  mutt_write_references(&e->env->references, out, 0);
446  fputc('\n', out);
447  }
448 
449  if ((flags & CH_UPDATE) && (flags & CH_NOSTATUS) == 0)
450  {
451  if (e->old || e->read)
452  {
453  fputs("Status: ", out);
454  if (e->read)
455  fputs("RO", out);
456  else if (e->old)
457  fputc('O', out);
458  fputc('\n', out);
459  }
460 
461  if (e->flagged || e->replied)
462  {
463  fputs("X-Status: ", out);
464  if (e->replied)
465  fputc('A', out);
466  if (e->flagged)
467  fputc('F', out);
468  fputc('\n', out);
469  }
470  }
471 
472  if (flags & CH_UPDATE_LEN && (flags & CH_NOLEN) == 0)
473  {
474  fprintf(out, "Content-Length: " OFF_T_FMT "\n", e->content->length);
475  if (e->lines != 0 || e->content->length == 0)
476  fprintf(out, "Lines: %d\n", e->lines);
477  }
478 
479 #ifdef USE_NOTMUCH
480  if (flags & CH_VIRTUAL)
481  {
482  /* Add some fake headers based on notmuch data */
483  char *folder = nm_email_get_folder(e);
484  if (folder && !(Weed && mutt_matches_ignore("folder")))
485  {
486  char buf[LONG_STRING];
487  mutt_str_strfcpy(buf, folder, sizeof(buf));
488  mutt_pretty_mailbox(buf, sizeof(buf));
489 
490  fputs("Folder: ", out);
491  fputs(buf, out);
492  fputc('\n', out);
493  }
494  }
495 #endif
496  char *tags = driver_tags_get(&e->tags);
497  if (tags && !(Weed && mutt_matches_ignore("tags")))
498  {
499  fputs("Tags: ", out);
500  fputs(tags, out);
501  fputc('\n', out);
502  }
503  FREE(&tags);
504 
505  if (flags & CH_UPDATE_LABEL)
506  {
507  e->xlabel_changed = false;
508  if (e->env->x_label)
509  if (fprintf(out, "X-Label: %s\n", e->env->x_label) != 10 + strlen(e->env->x_label))
510  return -1;
511  }
512 
513  if ((flags & CH_NONEWLINE) == 0)
514  {
515  if (flags & CH_PREFIX)
516  fputs(prefix, out);
517  fputc('\n', out); /* add header terminator */
518  }
519 
520  if (ferror(out) || feof(out))
521  return -1;
522 
523  return 0;
524 }
bool mutt_matches_ignore(const char *s)
Does the string match the ignore list.
Definition: parse.c:245
bool xlabel_changed
editable - used for syncing
Definition: email.h:60
int lines
how many lines in the body of this message?
Definition: email.h:86
#define SHORT_STRING
Definition: string2.h:34
void mutt_pretty_mailbox(char *s, size_t buflen)
Shorten a mailbox path using &#39;~&#39; or &#39;=&#39;.
Definition: muttlib.c:606
bool refs_changed
References changed to break thread.
Definition: envelope.h:64
char * Charset
Config: Default character set for displaying text on screen.
Definition: charset.c:52
struct Body * content
list of MIME parts
Definition: email.h:92
LOFF_T offset
offset where the actual data begins
Definition: body.h:45
#define CH_NOSTATUS
suppress the status and x-status fields
Definition: copy.h:53
#define CH_UPDATE
update the status and x-status fields?
Definition: copy.h:47
struct TagHead tags
for drivers that support server tagging
Definition: email.h:109
#define CH_UPDATE_REFS
update References:
Definition: copy.h:64
#define LONG_STRING
Definition: string2.h:36
int mutt_copy_hdr(FILE *in, FILE *out, LOFF_T off_start, LOFF_T off_end, int flags, const char *prefix)
Copy header from one file to another.
Definition: copy.c:72
char * driver_tags_get(struct TagHead *head)
Get tags.
Definition: tags.c:150
bool read
Definition: email.h:49
struct ListHead in_reply_to
in-reply-to header content
Definition: envelope.h:60
char * nm_email_get_folder(struct Email *e)
Get the folder for a Email.
bool old
Definition: email.h:48
struct Envelope * env
envelope information
Definition: email.h:91
void mutt_ch_canonical_charset(char *buf, size_t buflen, const char *name)
Canonicalise the charset of a string.
Definition: charset.c:312
#define CH_VIRTUAL
write virtual header lines too
Definition: copy.h:67
bool Weed
Config: Filter headers when displaying/forwarding/printing/replying.
Definition: email_globals.c:38
#define CH_TXTPLAIN
generate text/plain MIME headers
Definition: copy.h:58
#define CH_UPDATE_LABEL
update X-Label: from hdr->env->x_label?
Definition: copy.h:66
void mutt_addr_cat(char *buf, size_t buflen, const char *value, const char *specials)
Copy a string and escape the specified characters.
Definition: address.c:681
#define CH_UPDATE_IRT
update In-Reply-To:
Definition: copy.h:63
LOFF_T length
length (in bytes) of attachment
Definition: body.h:46
bool irt_changed
In-Reply-To changed to link/break threads.
Definition: envelope.h:63
const char MimeSpecials[]
Characters that need special treatment in MIME.
Definition: mime.c:67
size_t mutt_str_strfcpy(char *dest, const char *src, size_t dsize)
Copy a string into a buffer (guaranteeing NUL-termination)
Definition: string.c:742
void mutt_write_references(const struct ListHead *r, FILE *f, size_t trim)
Add the message references to a list.
Definition: sendlib.c:1788
#define CH_UPDATE_LEN
update Lines: and Content-Length:
Definition: copy.h:57
#define STAILQ_FOREACH(var, head, field)
Definition: queue.h:350
#define CH_NOLEN
don&#39;t write Content-Length: and Lines:
Definition: copy.h:59
LOFF_T offset
where in the stream does this message begin?
Definition: email.h:85
char * data
Definition: list.h:35
bool flagged
marked important?
Definition: email.h:41
bool replied
Definition: email.h:52
#define FREE(x)
Definition: memory.h:46
#define STAILQ_EMPTY(head)
Definition: queue.h:346
struct ListHead references
message references (in reverse order)
Definition: envelope.h:59
A List node for strings.
Definition: list.h:33
char * x_label
Definition: envelope.h:50
#define CH_PREFIX
use IndentString string?
Definition: copy.h:52
#define CH_NONEWLINE
don&#39;t output terminating newline
Definition: copy.h:55

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

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

Count the number of lines and bytes to be deleted in this body

Definition at line 536 of file copy.c.

537 {
538  int dellines = 0;
539 
540  if (b->deleted)
541  {
542  fseeko(fp, b->offset, SEEK_SET);
543  for (long l = b->length; l; l--)
544  {
545  const int ch = getc(fp);
546  if (ch == EOF)
547  break;
548  if (ch == '\n')
549  dellines++;
550  }
551  dellines -= 3;
552  *length -= b->length - (84 + datelen);
553  /* Count the number of digits exceeding the first one to write the size */
554  for (long l = 10; b->length >= l; l *= 10)
555  (*length)++;
556  }
557  else
558  {
559  for (b = b->parts; b; b = b->next)
560  dellines += count_delete_lines(fp, b, length, datelen);
561  }
562  return dellines;
563 }
LOFF_T offset
offset where the actual data begins
Definition: body.h:45
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:536
struct Body * next
next attachment in the list
Definition: body.h:57
LOFF_T length
length (in bytes) of attachment
Definition: body.h:46
struct Body * parts
parts of a multipart or message/rfc822
Definition: body.h:58
bool deleted
attachment marked for deletion
Definition: body.h:75

+ Here is the caller graph for this function:

int mutt_copy_message_fp ( FILE *  fpout,
FILE *  fpin,
struct Email e,
int  flags,
int  chflags 
)

make a copy of a message from a FILE pointer

Parameters
fpoutWhere to write output
fpinWhere to get input
eEmail being copied
flagsSee below
chflagsFlags to mutt_copy_header()
Return values
0Success
-1Failure

Definition at line 584 of file copy.c.

585 {
586  struct Body *body = e->content;
587  char prefix[SHORT_STRING];
588  LOFF_T new_offset = -1;
589  int rc = 0;
590 
591  if (flags & MUTT_CM_PREFIX)
592  {
593  if (TextFlowed)
594  mutt_str_strfcpy(prefix, ">", sizeof(prefix));
595  else
596  mutt_make_string_flags(prefix, sizeof(prefix), NONULL(IndentString), Context, e, 0);
597  }
598 
599  if (e->xlabel_changed)
600  chflags |= CH_UPDATE_LABEL;
601 
602  if ((flags & MUTT_CM_NOHEADER) == 0)
603  {
604  if (flags & MUTT_CM_PREFIX)
605  chflags |= CH_PREFIX;
606 
607  else if (e->attach_del && (chflags & CH_UPDATE_LEN))
608  {
609  int new_lines;
610  LOFF_T new_length = body->length;
611  char date[SHORT_STRING];
612 
613  mutt_date_make_date(date, sizeof(date));
614  int dlen = mutt_str_strlen(date);
615  if (dlen == 0)
616  return -1;
617 
618  date[5] = '\"';
619  date[dlen - 1] = '\"';
620 
621  /* Count the number of lines and bytes to be deleted */
622  fseeko(fpin, body->offset, SEEK_SET);
623  new_lines = e->lines - count_delete_lines(fpin, body, &new_length, dlen);
624 
625  /* Copy the headers */
626  if (mutt_copy_header(fpin, e, fpout, chflags | CH_NOLEN | CH_NONEWLINE, NULL))
627  return -1;
628  fprintf(fpout, "Content-Length: " OFF_T_FMT "\n", new_length);
629  if (new_lines <= 0)
630  new_lines = 0;
631  else
632  fprintf(fpout, "Lines: %d\n", new_lines);
633 
634  putc('\n', fpout);
635  if (ferror(fpout) || feof(fpout))
636  return -1;
637  new_offset = ftello(fpout);
638 
639  /* Copy the body */
640  if (fseeko(fpin, body->offset, SEEK_SET) < 0)
641  return -1;
642  if (copy_delete_attach(body, fpin, fpout, date))
643  return -1;
644 
645  LOFF_T fail = ((ftello(fpout) - new_offset) - new_length);
646  if (fail)
647  {
648  mutt_error(ngettext("The length calculation was wrong by %ld byte",
649  "The length calculation was wrong by %ld bytes", fail),
650  fail);
651  new_length += fail;
652  }
653 
654  /* Update original message if we are sync'ing a mailfolder */
655  if (flags & MUTT_CM_UPDATE)
656  {
657  e->attach_del = false;
658  e->lines = new_lines;
659  body->offset = new_offset;
660 
661  /* update the total size of the mailbox to reflect this deletion */
662  Context->mailbox->size -= body->length - new_length;
663  /* if the message is visible, update the visible size of the mailbox as well. */
664  if (Context->mailbox->v2r[e->msgno] != -1)
665  Context->vsize -= body->length - new_length;
666 
667  body->length = new_length;
668  mutt_body_free(&body->parts);
669  }
670 
671  return 0;
672  }
673 
674  if (mutt_copy_header(fpin, e, fpout, chflags, (chflags & CH_PREFIX) ? prefix : NULL) == -1)
675  {
676  return -1;
677  }
678 
679  new_offset = ftello(fpout);
680  }
681 
682  if (flags & MUTT_CM_DECODE)
683  {
684  /* now make a text/plain version of the message */
685  struct State s = { 0 };
686  s.fpin = fpin;
687  s.fpout = fpout;
688  if (flags & MUTT_CM_PREFIX)
689  s.prefix = prefix;
690  if (flags & MUTT_CM_DISPLAY)
691  s.flags |= MUTT_DISPLAY;
692  if (flags & MUTT_CM_PRINTING)
693  s.flags |= MUTT_PRINTING;
694  if (flags & MUTT_CM_WEED)
695  s.flags |= MUTT_WEED;
696  if (flags & MUTT_CM_CHARCONV)
697  s.flags |= MUTT_CHARCONV;
698  if (flags & MUTT_CM_REPLYING)
699  s.flags |= MUTT_REPLYING;
700 
701  if ((WithCrypto != 0) && flags & MUTT_CM_VERIFY)
702  s.flags |= MUTT_VERIFY;
703 
704  rc = mutt_body_handler(body, &s);
705  }
706  else if ((WithCrypto != 0) && (flags & MUTT_CM_DECODE_CRYPT) && (e->security & ENCRYPT))
707  {
708  struct Body *cur = NULL;
709  FILE *fp = NULL;
710 
711  if (((WithCrypto & APPLICATION_PGP) != 0) && (flags & MUTT_CM_DECODE_PGP) &&
712  (e->security & APPLICATION_PGP) && e->content->type == TYPE_MULTIPART)
713  {
714  if (crypt_pgp_decrypt_mime(fpin, &fp, e->content, &cur))
715  return -1;
716  fputs("MIME-Version: 1.0\n", fpout);
717  }
718 
719  if (((WithCrypto & APPLICATION_SMIME) != 0) && (flags & MUTT_CM_DECODE_SMIME) &&
720  (e->security & APPLICATION_SMIME) && e->content->type == TYPE_APPLICATION)
721  {
722  if (crypt_smime_decrypt_mime(fpin, &fp, e->content, &cur))
723  return -1;
724  }
725 
726  if (!cur)
727  {
728  mutt_error(_("No decryption engine available for message"));
729  return -1;
730  }
731 
732  mutt_write_mime_header(cur, fpout);
733  fputc('\n', fpout);
734 
735  if (fseeko(fp, cur->offset, SEEK_SET) < 0)
736  return -1;
737  if (mutt_file_copy_bytes(fp, fpout, cur->length) == -1)
738  {
739  mutt_file_fclose(&fp);
740  mutt_body_free(&cur);
741  return -1;
742  }
743  mutt_body_free(&cur);
744  mutt_file_fclose(&fp);
745  }
746  else
747  {
748  if (fseeko(fpin, body->offset, SEEK_SET) < 0)
749  return -1;
750  if (flags & MUTT_CM_PREFIX)
751  {
752  int c;
753  size_t bytes = body->length;
754 
755  fputs(prefix, fpout);
756 
757  while ((c = fgetc(fpin)) != EOF && bytes--)
758  {
759  fputc(c, fpout);
760  if (c == '\n')
761  {
762  fputs(prefix, fpout);
763  }
764  }
765  }
766  else if (mutt_file_copy_bytes(fpin, fpout, body->length) == -1)
767  return -1;
768  }
769 
770  if ((flags & MUTT_CM_UPDATE) && (flags & MUTT_CM_NOHEADER) == 0 && new_offset != -1)
771  {
772  body->offset = new_offset;
773  mutt_body_free(&body->parts);
774  }
775 
776  return rc;
777 }
#define MUTT_CM_DECODE_CRYPT
Definition: copy.h:43
The "current" mailbox.
Definition: context.h:36
bool xlabel_changed
editable - used for syncing
Definition: email.h:60
#define MUTT_DISPLAY
output is displayed to the user
Definition: state.h:40
int lines
how many lines in the body of this message?
Definition: email.h:86
#define NONULL(x)
Definition: string2.h:39
#define SHORT_STRING
Definition: string2.h:34
off_t size
Definition: mailbox.h:82
int mutt_copy_header(FILE *in, struct Email *e, FILE *out, int flags, const char *prefix)
Copy Email header.
Definition: copy.c:406
#define MUTT_CHARCONV
Do character set conversions.
Definition: state.h:44
unsigned int security
bit 0-8: flags, bit 9,10: application.
Definition: email.h:37
#define MUTT_CM_UPDATE
update structs on sync
Definition: copy.h:36
bool attach_del
has an attachment marked for deletion
Definition: email.h:47
struct Body * content
list of MIME parts
Definition: email.h:92
#define MUTT_CM_WEED
weed message/rfc822 attachment headers
Definition: copy.h:37
char * prefix
Definition: state.h:35
LOFF_T offset
offset where the actual data begins
Definition: body.h:45
#define _(a)
Definition: message.h:28
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:536
size_t mutt_str_strlen(const char *a)
Calculate the length of a string, safely.
Definition: string.c:663
#define MUTT_PRINTING
are we printing? - MUTT_DISPLAY "light"
Definition: state.h:45
int mutt_write_mime_header(struct Body *a, FILE *f)
Create a MIME header.
Definition: sendlib.c:359
#define MUTT_CM_PRINTING
printing the message - display light
Definition: copy.h:39
int crypt_pgp_decrypt_mime(FILE *a, FILE **b, struct Body *c, struct Body **d)
Wrapper for CryptModuleSpecs::decrypt_mime()
Definition: cryptglue.c:192
#define MUTT_CM_REPLYING
replying the message
Definition: copy.h:40
char * mutt_date_make_date(char *buf, size_t buflen)
Write a date in RFC822 format to a buffer.
Definition: date.c:380
The body of an email.
Definition: body.h:33
WHERE bool TextFlowed
Config: Generate &#39;format=flowed&#39; messages.
Definition: globals.h:259
FILE * fpout
Definition: state.h:34
int flags
Definition: state.h:36
struct Mailbox * mailbox
Definition: context.h:50
#define MUTT_CM_DISPLAY
output is displayed to the user
Definition: copy.h:35
off_t vsize
Definition: context.h:38
#define ENCRYPT
Definition: ncrypt.h:119
#define CH_UPDATE_LABEL
update X-Label: from hdr->env->x_label?
Definition: copy.h:66
#define MUTT_CM_PREFIX
quote the message
Definition: copy.h:33
LOFF_T length
length (in bytes) of attachment
Definition: body.h:46
#define MUTT_CM_DECODE
decode the message body into text/plain
Definition: copy.h:34
#define MUTT_VERIFY
perform signature verification
Definition: state.h:41
#define MUTT_CM_CHARCONV
perform character set conversions
Definition: copy.h:38
static int copy_delete_attach(struct Body *b, FILE *fpin, FILE *fpout, char *date)
Copy a message, deleting marked attachments.
Definition: copy.c:886
struct Body * parts
parts of a multipart or message/rfc822
Definition: body.h:58
size_t mutt_str_strfcpy(char *dest, const char *src, size_t dsize)
Copy a string into a buffer (guaranteeing NUL-termination)
Definition: string.c:742
#define MUTT_WEED
weed headers even when not in display mode
Definition: state.h:43
#define CH_UPDATE_LEN
update Lines: and Content-Length:
Definition: copy.h:57
#define MUTT_CM_VERIFY
do signature verification
Definition: copy.h:44
#define CH_NOLEN
don&#39;t write Content-Length: and Lines:
Definition: copy.h:59
FILE * fpin
Definition: state.h:33
unsigned int type
content-type primary type
Definition: body.h:67
#define APPLICATION_PGP
Definition: ncrypt.h:129
#define MUTT_CM_DECODE_SMIME
used for decoding S/MIME messages
Definition: copy.h:42
int * v2r
mapping from virtual to real msgno
Definition: mailbox.h:95
void mutt_body_free(struct Body **p)
Free a Body.
Definition: body.c:56
Type: &#39;multipart/*&#39;.
Definition: mime.h:37
int mutt_file_fclose(FILE **f)
Close a FILE handle (and NULL the pointer)
Definition: file.c:149
#define mutt_error(...)
Definition: logging.h:88
void mutt_make_string_flags(char *buf, size_t buflen, const char *s, struct Context *ctx, struct Email *e, enum FormatFlag flags)
Create formatted strings using mailbox expandos.
Definition: hdrline.c:1454
#define MUTT_CM_DECODE_PGP
used for decoding PGP messages
Definition: copy.h:41
#define MUTT_REPLYING
are we replying?
Definition: state.h:46
Keep track when processing files.
Definition: state.h:31
int mutt_body_handler(struct Body *b, struct State *s)
Handler for the Body of an email.
Definition: handler.c:1502
#define MUTT_CM_NOHEADER
flags to mutt_copy_message
Definition: copy.h:32
int mutt_file_copy_bytes(FILE *in, FILE *out, size_t size)
Copy some content from one file to another.
Definition: file.c:237
int crypt_smime_decrypt_mime(FILE *a, FILE **b, struct Body *c, struct Body **d)
Wrapper for CryptModuleSpecs::decrypt_mime()
Definition: cryptglue.c:373
#define WithCrypto
Definition: ncrypt.h:154
#define CH_PREFIX
use IndentString string?
Definition: copy.h:52
Type: &#39;application/*&#39;.
Definition: mime.h:33
#define CH_NONEWLINE
don&#39;t output terminating newline
Definition: copy.h:55
int msgno
number displayed to the user
Definition: email.h:88
#define APPLICATION_SMIME
Definition: ncrypt.h:130
WHERE char * IndentString
Config: String used to indent &#39;reply&#39; text.
Definition: globals.h:138

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

int mutt_copy_message_ctx ( FILE *  fpout,
struct Mailbox src,
struct Email e,
int  flags,
int  chflags 
)

Copy a message from a Context.

Parameters
fpoutFILE pointer to write to
srcSource mailbox
eEmail
flagsFlags, see: mutt_copy_message_fp()
chflagsHeader flags, see: mutt_copy_header()
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 792 of file copy.c.

794 {
795  struct Message *msg = mx_msg_open(src, e->msgno);
796  if (!msg)
797  return -1;
798  if (!e->content)
799  return -1;
800  int r = mutt_copy_message_fp(fpout, msg->fp, e, flags, chflags);
801  if ((r == 0) && (ferror(fpout) || feof(fpout)))
802  {
803  mutt_debug(1, "failed to detect EOF!\n");
804  r = -1;
805  }
806  mx_msg_close(src, &msg);
807  return r;
808 }
struct Body * content
list of MIME parts
Definition: email.h:92
int mx_msg_close(struct Mailbox *m, struct Message **msg)
Close a message.
Definition: mx.c:1187
int mutt_copy_message_fp(FILE *fpout, FILE *fpin, struct Email *e, int flags, int chflags)
make a copy of a message from a FILE pointer
Definition: copy.c:584
A local copy of an email.
Definition: mx.h:81
struct Message::@0 flags
FILE * fp
pointer to the message data
Definition: mx.h:83
#define mutt_debug(LEVEL,...)
Definition: logging.h:85
struct Message * mx_msg_open(struct Mailbox *m, int msgno)
return a stream pointer for a message
Definition: mx.c:1139
int msgno
number displayed to the user
Definition: email.h:88

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

static int append_message ( struct Mailbox dest,
FILE *  fpin,
struct Mailbox src,
struct Email e,
int  flags,
int  chflags 
)
static

appends a copy of the given message to a mailbox

Parameters
destdestination mailbox
fpinwhere to get input
srcsource mailbox
eEmail being copied
flagsmutt_open_copy_message() flags
chflagsmutt_copy_header() flags
Return values
0Success
-1Error

Definition at line 821 of file copy.c.

823 {
824  char buf[STRING];
825  struct Message *msg = NULL;
826  int r;
827 
828  if (fseeko(fpin, e->offset, SEEK_SET) < 0)
829  return -1;
830  if (!fgets(buf, sizeof(buf), fpin))
831  return -1;
832 
833  msg = mx_msg_open_new(dest, e, is_from(buf, NULL, 0, NULL) ? 0 : MUTT_ADD_FROM);
834  if (!msg)
835  return -1;
836  if (dest->magic == MUTT_MBOX || dest->magic == MUTT_MMDF)
837  chflags |= CH_FROM | CH_FORCE_FROM;
838  chflags |= (dest->magic == MUTT_MAILDIR ? CH_NOSTATUS : CH_UPDATE);
839  r = mutt_copy_message_fp(msg->fp, fpin, e, flags, chflags);
840  if (mx_msg_commit(dest, msg) != 0)
841  r = -1;
842 
843 #ifdef USE_NOTMUCH
844  if (msg->committed_path && dest->magic == MUTT_MAILDIR && src->magic == MUTT_NOTMUCH)
845  nm_update_filename(src, NULL, msg->committed_path, e);
846 #endif
847 
848  mx_msg_close(dest, &msg);
849  return r;
850 }
&#39;Notmuch&#39; (virtual) Mailbox type
Definition: magic.h:43
&#39;Maildir&#39; Mailbox type
Definition: magic.h:40
&#39;mmdf&#39; Mailbox type
Definition: magic.h:38
#define CH_FROM
retain the "From " message separator?
Definition: copy.h:51
#define CH_NOSTATUS
suppress the status and x-status fields
Definition: copy.h:53
#define CH_UPDATE
update the status and x-status fields?
Definition: copy.h:47
int mx_msg_close(struct Mailbox *m, struct Message **msg)
Close a message.
Definition: mx.c:1187
enum MailboxType magic
mailbox type
Definition: mailbox.h:99
struct Message * mx_msg_open_new(struct Mailbox *m, struct Email *e, int flags)
Open a new message.
Definition: mx.c:1053
int nm_update_filename(struct Mailbox *m, const char *old, const char *new, struct Email *e)
Change the filename.
int mutt_copy_message_fp(FILE *fpout, FILE *fpin, struct Email *e, int flags, int chflags)
make a copy of a message from a FILE pointer
Definition: copy.c:584
#define CH_FORCE_FROM
give CH_FROM precedence over CH_WEED?
Definition: copy.h:61
&#39;mbox&#39; Mailbox type
Definition: magic.h:37
A local copy of an email.
Definition: mx.h:81
struct Message::@0 flags
LOFF_T offset
where in the stream does this message begin?
Definition: email.h:85
char * committed_path
the final path generated by mx_msg_commit()
Definition: mx.h:85
#define STRING
Definition: string2.h:35
int mx_msg_commit(struct Mailbox *m, struct Message *msg)
Commit a message to a folder - Wrapper for MxOps::msg_commit()
Definition: mx.c:1166
FILE * fp
pointer to the message data
Definition: mx.h:83
bool is_from(const char *s, char *path, size_t pathlen, time_t *tp)
Is a string a &#39;From&#39; header line?
Definition: from.c:49
#define MUTT_ADD_FROM
add a From_ line
Definition: mx.h:64

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

int mutt_append_message ( struct Mailbox dest,
struct Mailbox src,
struct Email e,
int  cmflags,
int  chflags 
)

Append a message.

Parameters
destDestination Mailbox
srcSource Mailbox
eEmail
cmflagsmutt_open_copy_message() flags
chflagsmutt_copy_header() flags
Return values
0Success
-1Failure

Definition at line 862 of file copy.c.

864 {
865  struct Message *msg = mx_msg_open(src, e->msgno);
866  if (!msg)
867  return -1;
868  int r = append_message(dest, msg->fp, src, e, cmflags, chflags);
869  mx_msg_close(src, &msg);
870  return r;
871 }
int mx_msg_close(struct Mailbox *m, struct Message **msg)
Close a message.
Definition: mx.c:1187
A local copy of an email.
Definition: mx.h:81
FILE * fp
pointer to the message data
Definition: mx.h:83
struct Message * mx_msg_open(struct Mailbox *m, int msgno)
return a stream pointer for a message
Definition: mx.c:1139
static int append_message(struct Mailbox *dest, FILE *fpin, struct Mailbox *src, struct Email *e, int flags, int chflags)
appends a copy of the given message to a mailbox
Definition: copy.c:821
int msgno
number displayed to the user
Definition: email.h:88

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

static void format_address_header ( char **  h,
struct Address a 
)
static

Write address headers to a buffer.

Parameters
hArray of header strings
aEmail Address

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

TODO fix that.

Definition at line 942 of file copy.c.

943 {
944  char buf[HUGE_STRING];
945  char cbuf[STRING];
946  char c2buf[STRING];
947  char *p = NULL;
948  size_t linelen, buflen, plen;
949 
950  linelen = mutt_str_strlen(*h);
951  plen = linelen;
952  buflen = linelen + 3;
953 
954  mutt_mem_realloc(h, buflen);
955  for (int count = 0; a; a = a->next, count++)
956  {
957  struct Address *tmp = a->next;
958  a->next = NULL;
959  *buf = '\0';
960  *cbuf = '\0';
961  *c2buf = '\0';
962  const size_t l = mutt_addr_write(buf, sizeof(buf), a, false);
963  a->next = tmp;
964 
965  if (count && linelen + l > 74)
966  {
967  strcpy(cbuf, "\n\t");
968  linelen = l + 8;
969  }
970  else
971  {
972  if (a->mailbox)
973  {
974  strcpy(cbuf, " ");
975  linelen++;
976  }
977  linelen += l;
978  }
979  if (!a->group && a->next && a->next->mailbox)
980  {
981  linelen++;
982  buflen++;
983  strcpy(c2buf, ",");
984  }
985 
986  const size_t cbuflen = mutt_str_strlen(cbuf);
987  const size_t c2buflen = mutt_str_strlen(c2buf);
988  buflen += l + cbuflen + c2buflen;
989  mutt_mem_realloc(h, buflen);
990  p = *h;
991  strcat(p + plen, cbuf);
992  plen += cbuflen;
993  strcat(p + plen, buf);
994  plen += l;
995  strcat(p + plen, c2buf);
996  plen += c2buflen;
997  }
998 
999  /* Space for this was allocated in the beginning of this function. */
1000  strcat(p + plen, "\n");
1001 }
static size_t plen
Length of cached packet.
Definition: pgppacket.c:38
An email address.
Definition: address.h:32
char * mailbox
mailbox and host address
Definition: address.h:35
size_t mutt_str_strlen(const char *a)
Calculate the length of a string, safely.
Definition: string.c:663
size_t mutt_addr_write(char *buf, size_t buflen, struct Address *addr, bool display)
Write an Address to a buffer.
Definition: address.c:1146
void mutt_mem_realloc(void *ptr, size_t size)
Resize a block of memory on the heap.
Definition: memory.c:124
#define HUGE_STRING
Definition: string2.h:37
#define STRING
Definition: string2.h:35
bool group
group mailbox?
Definition: address.h:36
struct Address * next
Definition: address.h:39

+ Here is the call graph for this function:

+ Here is the caller graph for this function: