NeoMutt  2020-06-26-89-g172cd3
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 "email/lib.h"
#include "core/lib.h"
#include "gui/lib.h"
#include "mutt.h"
#include "copy.h"
#include "context.h"
#include "handler.h"
#include "hdrline.h"
#include "mutt_globals.h"
#include "mx.h"
#include "state.h"
#include "ncrypt/lib.h"
#include "send/lib.h"
#include "muttlib.h"
#include "notmuch/lib.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, char *date)
 Copy a message, deleting marked attachments. 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 Mailbox *m, struct Email *e, 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 *dest, struct Mailbox *src, struct Email *e, 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 1037 of file copy.c.

1038 {
1039  char *s = *h;
1040  size_t l;
1041  bool rp = false;
1042 
1043  switch (tolower((unsigned char) *s))
1044  {
1045  case 'b':
1046  {
1047  if (!(l = mutt_istr_startswith(s, "bcc:")))
1048  return 0;
1049  break;
1050  }
1051  case 'c':
1052  {
1053  if (!(l = mutt_istr_startswith(s, "cc:")))
1054  return 0;
1055  break;
1056  }
1057  case 'f':
1058  {
1059  if (!(l = mutt_istr_startswith(s, "from:")))
1060  return 0;
1061  break;
1062  }
1063  case 'm':
1064  {
1065  if (!(l = mutt_istr_startswith(s, "mail-followup-to:")))
1066  return 0;
1067  break;
1068  }
1069  case 'r':
1070  {
1071  if ((l = mutt_istr_startswith(s, "return-path:")))
1072  {
1073  rp = true;
1074  break;
1075  }
1076  else if ((l = mutt_istr_startswith(s, "reply-to:")))
1077  {
1078  break;
1079  }
1080  return 0;
1081  }
1082  case 's':
1083  {
1084  if (!(l = mutt_istr_startswith(s, "sender:")))
1085  return 0;
1086  break;
1087  }
1088  case 't':
1089  {
1090  if (!(l = mutt_istr_startswith(s, "to:")))
1091  return 0;
1092  break;
1093  }
1094  default:
1095  return 0;
1096  }
1097 
1098  struct AddressList al = TAILQ_HEAD_INITIALIZER(al);
1099  mutt_addrlist_parse(&al, s + l);
1100  if (TAILQ_EMPTY(&al))
1101  return 0;
1102 
1105  struct Address *a = NULL;
1106  TAILQ_FOREACH(a, &al, entries)
1107  {
1108  if (a->personal)
1109  {
1111  }
1112  }
1113 
1114  /* angle brackets for return path are mandated by RFC5322,
1115  * so leave Return-Path as-is */
1116  if (rp)
1117  *h = mutt_str_dup(s);
1118  else
1119  {
1120  *h = mutt_mem_calloc(1, l + 2);
1121  mutt_str_copy(*h, s, l + 1);
1122  format_address_header(h, &al);
1123  }
1124 
1125  mutt_addrlist_clear(&al);
1126 
1127  FREE(&s);
1128  return 1;
1129 }
void * mutt_mem_calloc(size_t nmemb, size_t size)
Allocate zeroed memory on the heap.
Definition: memory.c:50
static void format_address_header(char **h, struct AddressList *al)
Write address headers to a buffer.
Definition: copy.c:971
void rfc2047_decode_addrlist(struct AddressList *al)
Decode any RFC2047 headers in an Address list.
Definition: rfc2047.c:758
#define TAILQ_FOREACH(var, head, field)
Definition: queue.h:718
int mutt_addrlist_parse(struct AddressList *al, const char *s)
Parse a list of email addresses.
Definition: address.c:458
int mutt_addrlist_to_local(struct AddressList *al)
Convert an Address list from Punycode.
Definition: address.c:1379
void mutt_addrlist_clear(struct AddressList *al)
Unlink and free all Address in an AddressList.
Definition: address.c:1461
char * mutt_str_dup(const char *str)
Copy a string, safely.
Definition: string.c:375
An email address.
Definition: address.h:34
void mutt_str_dequote_comment(char *s)
Un-escape characters in an email address comment.
Definition: string.c:844
size_t mutt_istr_startswith(const char *str, const char *prefix)
Check whether a string starts with a prefix, ignoring case.
Definition: string.c:177
char * personal
Real name of address.
Definition: address.h:36
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:721
#define FREE(x)
Definition: memory.h:40
#define TAILQ_EMPTY(head)
Definition: queue.h:714
#define TAILQ_HEAD_INITIALIZER(head)
Definition: queue.h:630
+ 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,
char *  date 
)
static

Copy a message, deleting marked attachments.

Parameters
bEmail Body
fp_inFILE pointer to read from
fp_outFILE 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 915 of file copy.c.

916 {
917  struct Body *part = NULL;
918 
919  for (part = b->parts; part; part = part->next)
920  {
921  if (part->deleted || part->parts)
922  {
923  /* Copy till start of this part */
924  if (mutt_file_copy_bytes(fp_in, fp_out, part->hdr_offset - ftello(fp_in)))
925  return -1;
926 
927  if (part->deleted)
928  {
929  fprintf(
930  fp_out,
931  "Content-Type: message/external-body; access-type=x-mutt-deleted;\n"
932  "\texpiration=%s; length=" OFF_T_FMT "\n"
933  "\n",
934  date + 5, part->length);
935  if (ferror(fp_out))
936  return -1;
937 
938  /* Copy the original mime headers */
939  if (mutt_file_copy_bytes(fp_in, fp_out, part->offset - ftello(fp_in)))
940  return -1;
941 
942  /* Skip the deleted body */
943  fseeko(fp_in, part->offset + part->length, SEEK_SET);
944  }
945  else
946  {
947  if (copy_delete_attach(part, fp_in, fp_out, date))
948  return -1;
949  }
950  }
951  }
952 
953  /* Copy the last parts */
954  if (mutt_file_copy_bytes(fp_in, fp_out, b->offset + b->length - ftello(fp_in)))
955  return -1;
956 
957  return 0;
958 }
static int copy_delete_attach(struct Body *b, FILE *fp_in, FILE *fp_out, char *date)
Copy a message, deleting marked attachments.
Definition: copy.c:915
LOFF_T offset
offset where the actual data begins
Definition: body.h:44
struct Body * next
next attachment in the list
Definition: body.h:53
The body of an email.
Definition: body.h:34
LOFF_T length
length (in bytes) of attachment
Definition: body.h:45
struct Body * parts
parts of a multipart or message/rfc822
Definition: body.h:54
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:241
bool deleted
Attachment marked for deletion.
Definition: body.h:71
long hdr_offset
Offset in stream where the headers begin.
Definition: body.h:42
+ 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 77 of file copy.c.

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

401 {
402  char *temp_hdr = NULL;
403 
404  if (e->env)
405  {
406  chflags |= ((e->env->changed & MUTT_ENV_CHANGED_IRT) ? CH_UPDATE_IRT : 0) |
410  }
411 
412  if (mutt_copy_hdr(fp_in, fp_out, e->offset, e->content->offset, chflags,
413  prefix, wraplen) == -1)
414  return -1;
415 
416  if (chflags & CH_TXTPLAIN)
417  {
418  char chsbuf[128];
419  char buf[128];
420  fputs("MIME-Version: 1.0\n", fp_out);
421  fputs("Content-Transfer-Encoding: 8bit\n", fp_out);
422  fputs("Content-Type: text/plain; charset=", fp_out);
423  mutt_ch_canonical_charset(chsbuf, sizeof(chsbuf), C_Charset ? C_Charset : "us-ascii");
424  mutt_addr_cat(buf, sizeof(buf), chsbuf, MimeSpecials);
425  fputs(buf, fp_out);
426  fputc('\n', fp_out);
427  }
428 
429  if ((chflags & CH_UPDATE_IRT) && !STAILQ_EMPTY(&e->env->in_reply_to))
430  {
431  fputs("In-Reply-To:", fp_out);
432  struct ListNode *np = NULL;
433  STAILQ_FOREACH(np, &e->env->in_reply_to, entries)
434  {
435  fputc(' ', fp_out);
436  fputs(np->data, fp_out);
437  }
438  fputc('\n', fp_out);
439  }
440 
441  if ((chflags & CH_UPDATE_REFS) && !STAILQ_EMPTY(&e->env->references))
442  {
443  fputs("References:", fp_out);
444  mutt_write_references(&e->env->references, fp_out, 0, NeoMutt->sub);
445  fputc('\n', fp_out);
446  }
447 
448  if ((chflags & CH_UPDATE) && ((chflags & CH_NOSTATUS) == 0))
449  {
450  if (e->old || e->read)
451  {
452  fputs("Status: ", fp_out);
453  if (e->read)
454  fputs("RO", fp_out);
455  else if (e->old)
456  fputc('O', fp_out);
457  fputc('\n', fp_out);
458  }
459 
460  if (e->flagged || e->replied)
461  {
462  fputs("X-Status: ", fp_out);
463  if (e->replied)
464  fputc('A', fp_out);
465  if (e->flagged)
466  fputc('F', fp_out);
467  fputc('\n', fp_out);
468  }
469  }
470 
471  if (chflags & CH_UPDATE_LEN && ((chflags & CH_NOLEN) == 0))
472  {
473  fprintf(fp_out, "Content-Length: " OFF_T_FMT "\n", e->content->length);
474  if ((e->lines != 0) || (e->content->length == 0))
475  fprintf(fp_out, "Lines: %d\n", e->lines);
476  }
477 
478 #ifdef USE_NOTMUCH
479  if (chflags & CH_VIRTUAL)
480  {
481  /* Add some fake headers based on notmuch data */
482  char *folder = nm_email_get_folder(e);
483  if (folder && !(C_Weed && mutt_matches_ignore("folder")))
484  {
485  char buf[1024];
486  mutt_str_copy(buf, folder, sizeof(buf));
487  mutt_pretty_mailbox(buf, sizeof(buf));
488 
489  fputs("Folder: ", fp_out);
490  fputs(buf, fp_out);
491  fputc('\n', fp_out);
492  }
493  }
494 #endif
495  char *tags = driver_tags_get(&e->tags);
496  if (tags && !(C_Weed && mutt_matches_ignore("tags")))
497  {
498  fputs("Tags: ", fp_out);
499  fputs(tags, fp_out);
500  fputc('\n', fp_out);
501  }
502  FREE(&tags);
503 
504  if ((chflags & CH_UPDATE_LABEL) && e->env->x_label)
505  {
506  temp_hdr = e->env->x_label;
507  /* env->x_label isn't currently stored with direct references elsewhere.
508  * Context->label_hash strdups the keys. But to be safe, encode a copy */
509  if (!(chflags & CH_DECODE))
510  {
511  temp_hdr = mutt_str_dup(temp_hdr);
512  rfc2047_encode(&temp_hdr, NULL, sizeof("X-Label:"), C_SendCharset);
513  }
515  fp_out, "X-Label", temp_hdr, (chflags & CH_PREFIX) ? prefix : 0,
516  mutt_window_wrap_cols(wraplen, C_Wrap), chflags, NeoMutt->sub) == -1)
517  {
518  return -1;
519  }
520  if (!(chflags & CH_DECODE))
521  FREE(&temp_hdr);
522  }
523 
524  if ((chflags & CH_UPDATE_SUBJECT) && e->env->subject)
525  {
526  temp_hdr = e->env->subject;
527  /* env->subject is directly referenced in Context->subj_hash, so we
528  * have to be careful not to encode (and thus free) that memory. */
529  if (!(chflags & CH_DECODE))
530  {
531  temp_hdr = mutt_str_dup(temp_hdr);
532  rfc2047_encode(&temp_hdr, NULL, sizeof("Subject:"), C_SendCharset);
533  }
535  fp_out, "Subject", temp_hdr, (chflags & CH_PREFIX) ? prefix : 0,
536  mutt_window_wrap_cols(wraplen, C_Wrap), chflags, NeoMutt->sub) == -1)
537  {
538  return -1;
539  }
540  if (!(chflags & CH_DECODE))
541  FREE(&temp_hdr);
542  }
543 
544  if ((chflags & CH_NONEWLINE) == 0)
545  {
546  if (chflags & CH_PREFIX)
547  fputs(prefix, fp_out);
548  fputc('\n', fp_out); /* add header terminator */
549  }
550 
551  if (ferror(fp_out) || feof(fp_out))
552  return -1;
553 
554  return 0;
555 }
bool mutt_matches_ignore(const char *s)
Does the string match the ignore list.
Definition: parse.c:309
int lines
How many lines in the body of this message?
Definition: email.h:84
struct Body * content
List of MIME parts.
Definition: email.h:90
char * mutt_str_dup(const char *str)
Copy a string, safely.
Definition: string.c:375
LOFF_T offset
offset where the actual data begins
Definition: body.h:44
#define CH_NOSTATUS
Suppress the status and x-status fields.
Definition: copy.h:57
#define CH_UPDATE
Update the status and x-status fields?
Definition: copy.h:51
#define CH_UPDATE_REFS
Update References:
Definition: copy.h:68
void mutt_write_references(const struct ListHead *r, FILE *fp, size_t trim, struct ConfigSubset *sub)
Add the message references to a list.
Definition: header.c:514
Container for Accounts, Notifications.
Definition: neomutt.h:36
#define MUTT_ENV_CHANGED_SUBJECT
Protected header update.
Definition: envelope.h:35
unsigned char changed
Changed fields, e.g. MUTT_ENV_CHANGED_SUBJECT.
Definition: envelope.h:88
bool read
Email is read.
Definition: email.h:51
struct ListHead in_reply_to
in-reply-to header content
Definition: envelope.h:82
bool old
Email is seen, but unread.
Definition: email.h:50
struct Envelope * env
Envelope information.
Definition: email.h:89
void mutt_ch_canonical_charset(char *buf, size_t buflen, const char *name)
Canonicalise the charset of a string.
Definition: charset.c:352
#define CH_VIRTUAL
Write virtual header lines too.
Definition: copy.h:72
struct TagList tags
For drivers that support server tagging.
Definition: email.h:102
#define CH_TXTPLAIN
Generate text/plain MIME headers.
Definition: copy.h:62
#define CH_UPDATE_LABEL
Update X-Label: from email->env->x_label?
Definition: copy.h:70
#define MUTT_ENV_CHANGED_XLABEL
X-Label edited.
Definition: envelope.h:34
WHERE short C_Wrap
Config: Width to wrap text in the pager.
Definition: mutt_globals.h:119
#define CH_UPDATE_IRT
Update In-Reply-To:
Definition: copy.h:67
LOFF_T length
length (in bytes) of attachment
Definition: body.h:45
char * driver_tags_get(struct TagList *list)
Get tags.
Definition: tags.c:142
const char MimeSpecials[]
Characters that need special treatment in MIME.
Definition: mime.c:67
#define CH_DECODE
Do RFC2047 header decoding.
Definition: copy.h:53
char * nm_email_get_folder(struct Email *e)
Get the folder for a Email.
Definition: notmuch.c:1621
int mutt_window_wrap_cols(int width, short wrap)
Calculate the wrap column for a given screen width.
Definition: mutt_window.c:473
#define CH_UPDATE_LEN
Update Lines: and Content-Length:
Definition: copy.h:61
void mutt_pretty_mailbox(char *buf, size_t buflen)
Shorten a mailbox path using &#39;~&#39; or &#39;=&#39;.
Definition: muttlib.c:522
#define STAILQ_FOREACH(var, head, field)
Definition: queue.h:349
#define CH_NOLEN
Don&#39;t write Content-Length: and Lines:
Definition: copy.h:63
#define CH_UPDATE_SUBJECT
Update Subject: protected header update.
Definition: copy.h:71
void rfc2047_encode(char **pd, const char *specials, int col, const char *charsets)
RFC-2047-encode a string.
Definition: rfc2047.c:615
LOFF_T offset
Where in the stream does this message begin?
Definition: email.h:83
char * data
String.
Definition: list.h:36
char * subject
Email&#39;s subject.
Definition: envelope.h:66
bool flagged
Marked important?
Definition: email.h:43
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:721
bool replied
Email has been replied to.
Definition: email.h:54
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:77
#define FREE(x)
Definition: memory.h:40
bool C_Weed
Config: Filter headers when displaying/forwarding/printing/replying.
Definition: globals.c:40
#define STAILQ_EMPTY(head)
Definition: queue.h:345
char * C_Charset
Config: Default character set for displaying text on screen.
Definition: charset.c:53
char * C_SendCharset
Config: Character sets for outgoing mail.
Definition: globals.c:38
#define MUTT_ENV_CHANGED_REFS
References changed to break thread.
Definition: envelope.h:33
struct ConfigSubset * sub
Inherited config items.
Definition: neomutt.h:39
#define MUTT_ENV_CHANGED_IRT
In-Reply-To changed to link/break threads.
Definition: envelope.h:32
struct ListHead references
message references (in reverse order)
Definition: envelope.h:81
A List node for strings.
Definition: list.h:34
char * x_label
X-Label.
Definition: envelope.h:72
#define CH_PREFIX
Quote header using C_IndentString string?
Definition: copy.h:56
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
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:419
#define CH_NONEWLINE
Don&#39;t output terminating newline after the header.
Definition: copy.h:59
+ 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

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

Definition at line 567 of file copy.c.

568 {
569  int dellines = 0;
570 
571  if (b->deleted)
572  {
573  fseeko(fp, b->offset, SEEK_SET);
574  for (long l = b->length; l; l--)
575  {
576  const int ch = getc(fp);
577  if (ch == EOF)
578  break;
579  if (ch == '\n')
580  dellines++;
581  }
582  dellines -= 3;
583  *length -= b->length - (84 + datelen);
584  /* Count the number of digits exceeding the first one to write the size */
585  for (long l = 10; b->length >= l; l *= 10)
586  (*length)++;
587  }
588  else
589  {
590  for (b = b->parts; b; b = b->next)
591  dellines += count_delete_lines(fp, b, length, datelen);
592  }
593  return dellines;
594 }
LOFF_T offset
offset where the actual data begins
Definition: body.h:44
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:567
struct Body * next
next attachment in the list
Definition: body.h:53
LOFF_T length
length (in bytes) of attachment
Definition: body.h:45
struct Body * parts
parts of a multipart or message/rfc822
Definition: body.h:54
bool deleted
Attachment marked for deletion.
Definition: body.h:71
+ 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 607 of file copy.c.

609 {
610  struct Body *body = e->content;
611  char prefix[128];
612  LOFF_T new_offset = -1;
613  int rc = 0;
614 
615  if (cmflags & MUTT_CM_PREFIX)
616  {
617  if (C_TextFlowed)
618  mutt_str_copy(prefix, ">", sizeof(prefix));
619  else
620  {
621  mutt_make_string(prefix, sizeof(prefix), wraplen, NONULL(C_IndentString),
622  Context, Context->mailbox, e);
623  }
624  }
625 
626  if ((cmflags & MUTT_CM_NOHEADER) == 0)
627  {
628  if (cmflags & MUTT_CM_PREFIX)
629  chflags |= CH_PREFIX;
630  else if (e->attach_del && (chflags & CH_UPDATE_LEN))
631  {
632  int new_lines;
633  LOFF_T new_length = body->length;
634  char date[128];
635 
636  mutt_date_make_date(date, sizeof(date));
637  int dlen = mutt_str_len(date);
638  if (dlen == 0)
639  return -1;
640 
641  date[5] = '\"';
642  date[dlen - 1] = '\"';
643 
644  /* Count the number of lines and bytes to be deleted */
645  fseeko(fp_in, body->offset, SEEK_SET);
646  new_lines = e->lines - count_delete_lines(fp_in, body, &new_length, dlen);
647 
648  /* Copy the headers */
649  if (mutt_copy_header(fp_in, e, fp_out, chflags | CH_NOLEN | CH_NONEWLINE, NULL, wraplen))
650  return -1;
651  fprintf(fp_out, "Content-Length: " OFF_T_FMT "\n", new_length);
652  if (new_lines <= 0)
653  new_lines = 0;
654  else
655  fprintf(fp_out, "Lines: %d\n", new_lines);
656 
657  putc('\n', fp_out);
658  if (ferror(fp_out) || feof(fp_out))
659  return -1;
660  new_offset = ftello(fp_out);
661 
662  /* Copy the body */
663  if (fseeko(fp_in, body->offset, SEEK_SET) < 0)
664  return -1;
665  if (copy_delete_attach(body, fp_in, fp_out, date))
666  return -1;
667 
668  LOFF_T fail = ((ftello(fp_out) - new_offset) - new_length);
669  if (fail)
670  {
671  mutt_error(ngettext("The length calculation was wrong by %ld byte",
672  "The length calculation was wrong by %ld bytes", fail),
673  fail);
674  new_length += fail;
675  }
676 
677  /* Update original message if we are sync'ing a mailfolder */
678  if (cmflags & MUTT_CM_UPDATE)
679  {
680  e->attach_del = false;
681  e->lines = new_lines;
682  body->offset = new_offset;
683 
684  /* update the total size of the mailbox to reflect this deletion */
685  Context->mailbox->size -= body->length - new_length;
686  /* if the message is visible, update the visible size of the mailbox as well. */
687  if (Context->mailbox->v2r[e->msgno] != -1)
688  Context->vsize -= body->length - new_length;
689 
690  body->length = new_length;
691  mutt_body_free(&body->parts);
692  }
693 
694  return 0;
695  }
696 
697  if (mutt_copy_header(fp_in, e, fp_out, chflags,
698  (chflags & CH_PREFIX) ? prefix : NULL, wraplen) == -1)
699  {
700  return -1;
701  }
702 
703  new_offset = ftello(fp_out);
704  }
705 
706  if (cmflags & MUTT_CM_DECODE)
707  {
708  /* now make a text/plain version of the message */
709  struct State s = { 0 };
710  s.fp_in = fp_in;
711  s.fp_out = fp_out;
712  if (cmflags & MUTT_CM_PREFIX)
713  s.prefix = prefix;
714  if (cmflags & MUTT_CM_DISPLAY)
715  {
716  s.flags |= MUTT_DISPLAY;
717  s.wraplen = wraplen;
718  }
719  if (cmflags & MUTT_CM_PRINTING)
720  s.flags |= MUTT_PRINTING;
721  if (cmflags & MUTT_CM_WEED)
722  s.flags |= MUTT_WEED;
723  if (cmflags & MUTT_CM_CHARCONV)
724  s.flags |= MUTT_CHARCONV;
725  if (cmflags & MUTT_CM_REPLYING)
726  s.flags |= MUTT_REPLYING;
727 
728  if ((WithCrypto != 0) && cmflags & MUTT_CM_VERIFY)
729  s.flags |= MUTT_VERIFY;
730 
731  rc = mutt_body_handler(body, &s);
732  }
733  else if ((WithCrypto != 0) && (cmflags & MUTT_CM_DECODE_CRYPT) && (e->security & SEC_ENCRYPT))
734  {
735  struct Body *cur = NULL;
736  FILE *fp = NULL;
737 
738  if (((WithCrypto & APPLICATION_PGP) != 0) && (cmflags & MUTT_CM_DECODE_PGP) &&
739  (e->security & APPLICATION_PGP) && (e->content->type == TYPE_MULTIPART))
740  {
741  if (crypt_pgp_decrypt_mime(fp_in, &fp, e->content, &cur))
742  return -1;
743  fputs("MIME-Version: 1.0\n", fp_out);
744  }
745 
746  if (((WithCrypto & APPLICATION_SMIME) != 0) && (cmflags & MUTT_CM_DECODE_SMIME) &&
747  (e->security & APPLICATION_SMIME) && (e->content->type == TYPE_APPLICATION))
748  {
749  if (crypt_smime_decrypt_mime(fp_in, &fp, e->content, &cur))
750  return -1;
751  }
752 
753  if (!cur)
754  {
755  mutt_error(_("No decryption engine available for message"));
756  return -1;
757  }
758 
759  mutt_write_mime_header(cur, fp_out, NeoMutt->sub);
760  fputc('\n', fp_out);
761 
762  if (fseeko(fp, cur->offset, SEEK_SET) < 0)
763  return -1;
764  if (mutt_file_copy_bytes(fp, fp_out, cur->length) == -1)
765  {
766  mutt_file_fclose(&fp);
767  mutt_body_free(&cur);
768  return -1;
769  }
770  mutt_body_free(&cur);
771  mutt_file_fclose(&fp);
772  }
773  else
774  {
775  if (fseeko(fp_in, body->offset, SEEK_SET) < 0)
776  return -1;
777  if (cmflags & MUTT_CM_PREFIX)
778  {
779  int c;
780  size_t bytes = body->length;
781 
782  fputs(prefix, fp_out);
783 
784  while (((c = fgetc(fp_in)) != EOF) && bytes--)
785  {
786  fputc(c, fp_out);
787  if (c == '\n')
788  {
789  fputs(prefix, fp_out);
790  }
791  }
792  }
793  else if (mutt_file_copy_bytes(fp_in, fp_out, body->length) == -1)
794  return -1;
795  }
796 
797  if ((cmflags & MUTT_CM_UPDATE) && ((cmflags & MUTT_CM_NOHEADER) == 0) &&
798  (new_offset != -1))
799  {
800  body->offset = new_offset;
801  mutt_body_free(&body->parts);
802  }
803 
804  return rc;
805 }
#define MUTT_CM_DECODE_CRYPT
Definition: copy.h:47
The "current" mailbox.
Definition: context.h:37
#define MUTT_DISPLAY
Output is displayed to the user.
Definition: state.h:32
int lines
How many lines in the body of this message?
Definition: email.h:84
#define NONULL(x)
Definition: string2.h:37
off_t size
Size of the Mailbox.
Definition: mailbox.h:87
#define WithCrypto
Definition: lib.h:118
static int copy_delete_attach(struct Body *b, FILE *fp_in, FILE *fp_out, char *date)
Copy a message, deleting marked attachments.
Definition: copy.c:915
#define MUTT_CHARCONV
Do character set conversions.
Definition: state.h:36
#define MUTT_CM_UPDATE
Update structs on sync.
Definition: copy.h:39
#define SEC_ENCRYPT
Email is encrypted.
Definition: lib.h:80
#define mutt_make_string(BUF, BUFLEN, COLS, S, CTX, M, E)
Definition: hdrline.h:59
bool attach_del
Has an attachment marked for deletion.
Definition: email.h:49
struct Body * content
List of MIME parts.
Definition: email.h:90
#define MUTT_CM_WEED
Weed message/rfc822 attachment headers.
Definition: copy.h:40
char * prefix
String to add to the beginning of each output line.
Definition: state.h:48
LOFF_T offset
offset where the actual data begins
Definition: body.h:44
#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:567
FILE * fp_out
File to write to.
Definition: state.h:47
#define MUTT_PRINTING
Are we printing? - MUTT_DISPLAY "light".
Definition: state.h:37
#define MUTT_CM_PRINTING
Printing the message - display light.
Definition: copy.h:42
Container for Accounts, Notifications.
Definition: neomutt.h:36
FILE * fp_in
File to read from.
Definition: state.h:46
#define MUTT_CM_REPLYING
Replying the message.
Definition: copy.h:43
char * mutt_date_make_date(char *buf, size_t buflen)
Write a date in RFC822 format to a buffer.
Definition: date.c:375
The body of an email.
Definition: body.h:34
StateFlags flags
Flags, e.g. MUTT_DISPLAY.
Definition: state.h:49
struct Mailbox * mailbox
Definition: context.h:50
#define MUTT_CM_DISPLAY
Output is displayed to the user.
Definition: copy.h:38
int mutt_file_fclose(FILE **fp)
Close a FILE handle (and NULL the pointer)
Definition: file.c:153
int mutt_write_mime_header(struct Body *a, FILE *fp, struct ConfigSubset *sub)
Create a MIME header.
Definition: header.c:755
int wraplen
Width to wrap lines to (when flags & MUTT_DISPLAY)
Definition: state.h:50
off_t vsize
Definition: context.h:39
#define APPLICATION_SMIME
Use SMIME to encrypt/sign.
Definition: lib.h:93
#define MUTT_CM_PREFIX
Quote the header and body.
Definition: copy.h:36
#define APPLICATION_PGP
Use PGP to encrypt/sign.
Definition: lib.h:92
LOFF_T length
length (in bytes) of attachment
Definition: body.h:45
#define MUTT_CM_DECODE
Decode the message body into text/plain.
Definition: copy.h:37
#define MUTT_VERIFY
Perform signature verification.
Definition: state.h:33
#define MUTT_CM_CHARCONV
Perform character set conversions.
Definition: copy.h:41
struct Body * parts
parts of a multipart or message/rfc822
Definition: body.h:54
#define MUTT_WEED
Weed headers even when not in display mode.
Definition: state.h:35
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:431
#define CH_UPDATE_LEN
Update Lines: and Content-Length:
Definition: copy.h:61
void mutt_body_free(struct Body **ptr)
Free a Body.
Definition: body.c:57
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:241
#define MUTT_CM_VERIFY
Do signature verification.
Definition: copy.h:46
#define CH_NOLEN
Don&#39;t write Content-Length: and Lines:
Definition: copy.h:63
SecurityFlags security
bit 0-10: flags, bit 11,12: application, bit 13: traditional pgp See: ncrypt/lib.h pgplib...
Definition: email.h:39
unsigned int type
content-type primary type, ContentType
Definition: body.h:65
#define MUTT_CM_DECODE_SMIME
Used for decoding S/MIME messages.
Definition: copy.h:45
int * v2r
Mapping from virtual to real msgno.
Definition: mailbox.h:101
size_t mutt_str_len(const char *a)
Calculate the length of a string, safely.
Definition: string.c:636
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:207
Type: &#39;multipart/*&#39;.
Definition: mime.h:37
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:721
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:399
#define mutt_error(...)
Definition: logging.h:84
#define MUTT_CM_DECODE_PGP
Used for decoding PGP messages.
Definition: copy.h:44
#define MUTT_REPLYING
Are we replying?
Definition: state.h:38
Keep track when processing files.
Definition: state.h:44
int mutt_body_handler(struct Body *b, struct State *s)
Handler for the Body of an email.
Definition: handler.c:1585
struct ConfigSubset * sub
Inherited config items.
Definition: neomutt.h:39
#define MUTT_CM_NOHEADER
Don&#39;t copy the message header.
Definition: copy.h:35
#define CH_PREFIX
Quote header using C_IndentString string?
Definition: copy.h:56
Type: &#39;application/*&#39;.
Definition: mime.h:33
#define CH_NONEWLINE
Don&#39;t output terminating newline after the header.
Definition: copy.h:59
int msgno
Number displayed to the user.
Definition: email.h:86
WHERE char * C_IndentString
Config: String used to indent &#39;reply&#39; text.
Definition: mutt_globals.h:105
WHERE bool C_TextFlowed
Config: Generate &#39;format=flowed&#39; messages.
Definition: mutt_globals.h:168
+ 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 Mailbox m,
struct Email e,
CopyMessageFlags  cmflags,
CopyHeaderFlags  chflags,
int  wraplen 
)

Copy a message from a Mailbox.

Parameters
fp_outFILE pointer to write to
mSource mailbox
eEmail
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 821 of file copy.c.

823 {
824  struct Message *msg = mx_msg_open(m, e->msgno);
825  if (!msg)
826  return -1;
827  if (!e->content)
828  return -1;
829  int rc = mutt_copy_message_fp(fp_out, msg->fp, e, cmflags, chflags, wraplen);
830  if ((rc == 0) && (ferror(fp_out) || feof(fp_out)))
831  {
832  mutt_debug(LL_DEBUG1, "failed to detect EOF!\n");
833  rc = -1;
834  }
835  mx_msg_close(m, &msg);
836  return rc;
837 }
struct Body * content
List of MIME parts.
Definition: email.h:90
int mx_msg_close(struct Mailbox *m, struct Message **msg)
Close a message.
Definition: mx.c:1180
A local copy of an email.
Definition: mx.h:83
Log at debug level 1.
Definition: logging.h:40
FILE * fp
pointer to the message data
Definition: mx.h:85
#define mutt_debug(LEVEL,...)
Definition: logging.h:81
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:607
struct Message * mx_msg_open(struct Mailbox *m, int msgno)
return a stream pointer for a message
Definition: mx.c:1132
int msgno
Number displayed to the user.
Definition: email.h:86
+ 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 850 of file copy.c.

852 {
853  char buf[256];
854  struct Message *msg = NULL;
855  int rc;
856 
857  if (fseeko(fp_in, e->offset, SEEK_SET) < 0)
858  return -1;
859  if (!fgets(buf, sizeof(buf), fp_in))
860  return -1;
861 
862  msg = mx_msg_open_new(dest, e, is_from(buf, NULL, 0, NULL) ? MUTT_MSG_NO_FLAGS : MUTT_ADD_FROM);
863  if (!msg)
864  return -1;
865  if ((dest->type == MUTT_MBOX) || (dest->type == MUTT_MMDF))
866  chflags |= CH_FROM | CH_FORCE_FROM;
867  chflags |= ((dest->type == MUTT_MAILDIR) ? CH_NOSTATUS : CH_UPDATE);
868  rc = mutt_copy_message_fp(msg->fp, fp_in, e, cmflags, chflags, 0);
869  if (mx_msg_commit(dest, msg) != 0)
870  rc = -1;
871 
872 #ifdef USE_NOTMUCH
873  if (msg->committed_path && (dest->type == MUTT_MAILDIR) && (src->type == MUTT_NOTMUCH))
874  nm_update_filename(src, NULL, msg->committed_path, e);
875 #endif
876 
877  mx_msg_close(dest, &msg);
878  return rc;
879 }
#define MUTT_MSG_NO_FLAGS
No flags are set.
Definition: mx.h:65
enum MailboxType type
Mailbox type.
Definition: mailbox.h:105
#define CH_FROM
Retain the "From " message separator?
Definition: copy.h:55
#define CH_NOSTATUS
Suppress the status and x-status fields.
Definition: copy.h:57
#define CH_UPDATE
Update the status and x-status fields?
Definition: copy.h:51
int nm_update_filename(struct Mailbox *m, const char *old_file, const char *new_file, struct Email *e)
Change the filename.
Definition: notmuch.c:1882
int mx_msg_close(struct Mailbox *m, struct Message **msg)
Close a message.
Definition: mx.c:1180
struct Message * mx_msg_open_new(struct Mailbox *m, struct Email *e, MsgOpenFlags flags)
Open a new message.
Definition: mx.c:1046
&#39;Maildir&#39; Mailbox type
Definition: mailbox.h:51
#define CH_FORCE_FROM
Give CH_FROM precedence over CH_WEED?
Definition: copy.h:65
A local copy of an email.
Definition: mx.h:83
&#39;mmdf&#39; Mailbox type
Definition: mailbox.h:49
&#39;Notmuch&#39; (virtual) Mailbox type
Definition: mailbox.h:54
LOFF_T offset
Where in the stream does this message begin?
Definition: email.h:83
&#39;mbox&#39; Mailbox type
Definition: mailbox.h:48
char * committed_path
the final path generated by mx_msg_commit()
Definition: mx.h:87
int mx_msg_commit(struct Mailbox *m, struct Message *msg)
Commit a message to a folder - Wrapper for MxOps::msg_commit()
Definition: mx.c:1159
FILE * fp
pointer to the message data
Definition: mx.h:85
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:48
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:607
#define MUTT_ADD_FROM
add a From_ line
Definition: mx.h:66
+ 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 dest,
struct Mailbox src,
struct Email e,
CopyMessageFlags  cmflags,
CopyHeaderFlags  chflags 
)

Append a message.

Parameters
destDestination Mailbox
srcSource Mailbox
eEmail
cmflagsFlags, see CopyMessageFlags
chflagsFlags, see CopyHeaderFlags
Return values
0Success
-1Failure

Definition at line 891 of file copy.c.

893 {
894  struct Message *msg = mx_msg_open(src, e->msgno);
895  if (!msg)
896  return -1;
897  int rc = append_message(dest, msg->fp, src, e, cmflags, chflags);
898  mx_msg_close(src, &msg);
899  return rc;
900 }
int mx_msg_close(struct Mailbox *m, struct Message **msg)
Close a message.
Definition: mx.c:1180
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:850
A local copy of an email.
Definition: mx.h:83
FILE * fp
pointer to the message data
Definition: mx.h:85
struct Message * mx_msg_open(struct Mailbox *m, int msgno)
return a stream pointer for a message
Definition: mx.c:1132
int msgno
Number displayed to the user.
Definition: email.h:86
+ 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 971 of file copy.c.

972 {
973  char buf[8192];
974  char cbuf[256];
975  char c2buf[256];
976  char *p = NULL;
977  size_t linelen, buflen, plen;
978 
979  linelen = mutt_str_len(*h);
980  plen = linelen;
981  buflen = linelen + 3;
982 
983  mutt_mem_realloc(h, buflen);
984  struct Address *first = TAILQ_FIRST(al);
985  struct Address *a = NULL;
986  TAILQ_FOREACH(a, al, entries)
987  {
988  *buf = '\0';
989  *cbuf = '\0';
990  *c2buf = '\0';
991  const size_t l = mutt_addr_write(buf, sizeof(buf), a, false);
992 
993  if (a != first && (linelen + l > 74))
994  {
995  strcpy(cbuf, "\n\t");
996  linelen = l + 8;
997  }
998  else
999  {
1000  if (a->mailbox)
1001  {
1002  strcpy(cbuf, " ");
1003  linelen++;
1004  }
1005  linelen += l;
1006  }
1007  if (!a->group && TAILQ_NEXT(a, entries) && TAILQ_NEXT(a, entries)->mailbox)
1008  {
1009  linelen++;
1010  buflen++;
1011  strcpy(c2buf, ",");
1012  }
1013 
1014  const size_t cbuflen = mutt_str_len(cbuf);
1015  const size_t c2buflen = mutt_str_len(c2buf);
1016  buflen += l + cbuflen + c2buflen;
1017  mutt_mem_realloc(h, buflen);
1018  p = *h;
1019  strcat(p + plen, cbuf);
1020  plen += cbuflen;
1021  strcat(p + plen, buf);
1022  plen += l;
1023  strcat(p + plen, c2buf);
1024  plen += c2buflen;
1025  }
1026 
1027  /* Space for this was allocated in the beginning of this function. */
1028  strcat(p + plen, "\n");
1029 }
#define TAILQ_FIRST(head)
Definition: queue.h:716
#define TAILQ_FOREACH(var, head, field)
Definition: queue.h:718
static size_t plen
Length of cached packet.
Definition: pgppacket.c:39
An email address.
Definition: address.h:34
char * mailbox
Mailbox and host address.
Definition: address.h:37
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
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_len(const char *a)
Calculate the length of a string, safely.
Definition: string.c:636
bool group
Group mailbox?
Definition: address.h:38
#define TAILQ_NEXT(elm, field)
Definition: queue.h:825
+ Here is the call graph for this function:
+ Here is the caller graph for this function: