NeoMutt  2020-03-20-65-g141838
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 "globals.h"
#include "handler.h"
#include "hdrline.h"
#include "mx.h"
#include "sendlib.h"
#include "state.h"
#include "ncrypt/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 1028 of file copy.c.

1029 {
1030  char *s = *h;
1031  size_t l;
1032  bool rp = false;
1033 
1034  switch (tolower((unsigned char) *s))
1035  {
1036  case 'b':
1037  {
1038  if (!(l = mutt_str_startswith(s, "bcc:", CASE_IGNORE)))
1039  return 0;
1040  break;
1041  }
1042  case 'c':
1043  {
1044  if (!(l = mutt_str_startswith(s, "cc:", CASE_IGNORE)))
1045  return 0;
1046  break;
1047  }
1048  case 'f':
1049  {
1050  if (!(l = mutt_str_startswith(s, "from:", CASE_IGNORE)))
1051  return 0;
1052  break;
1053  }
1054  case 'm':
1055  {
1056  if (!(l = mutt_str_startswith(s, "mail-followup-to:", CASE_IGNORE)))
1057  return 0;
1058  break;
1059  }
1060  case 'r':
1061  {
1062  if ((l = mutt_str_startswith(s, "return-path:", CASE_IGNORE)))
1063  {
1064  rp = true;
1065  break;
1066  }
1067  else if ((l = mutt_str_startswith(s, "reply-to:", CASE_IGNORE)))
1068  {
1069  break;
1070  }
1071  return 0;
1072  }
1073  case 's':
1074  {
1075  if (!(l = mutt_str_startswith(s, "sender:", CASE_IGNORE)))
1076  return 0;
1077  break;
1078  }
1079  case 't':
1080  {
1081  if (!(l = mutt_str_startswith(s, "to:", CASE_IGNORE)))
1082  return 0;
1083  break;
1084  }
1085  default:
1086  return 0;
1087  }
1088 
1089  struct AddressList al = TAILQ_HEAD_INITIALIZER(al);
1090  mutt_addrlist_parse(&al, s + l);
1091  if (TAILQ_EMPTY(&al))
1092  return 0;
1093 
1096  struct Address *a = NULL;
1097  TAILQ_FOREACH(a, &al, entries)
1098  {
1099  if (a->personal)
1100  {
1102  }
1103  }
1104 
1105  /* angle brackets for return path are mandated by RFC5322,
1106  * so leave Return-Path as-is */
1107  if (rp)
1108  *h = mutt_str_strdup(s);
1109  else
1110  {
1111  *h = mutt_mem_calloc(1, l + 2);
1112  mutt_str_strfcpy(*h, s, l + 1);
1113  format_address_header(h, &al);
1114  }
1115 
1116  mutt_addrlist_clear(&al);
1117 
1118  FREE(&s);
1119  return 1;
1120 }
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:962
void rfc2047_decode_addrlist(struct AddressList *al)
Decode any RFC2047 headers in an Address list.
Definition: rfc2047.c:755
#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:1299
void mutt_addrlist_clear(struct AddressList *al)
Unlink and free all Address in an AddressList.
Definition: address.c:1382
An email address.
Definition: address.h:34
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:773
Ignore case when comparing strings.
Definition: string2.h:68
void mutt_str_dequote_comment(char *s)
Un-escape characters in an email address comment.
Definition: string.c:904
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:168
char * personal
Real name of address.
Definition: address.h:36
char * mutt_str_strdup(const char *str)
Copy a string, safely.
Definition: string.c:380
#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 906 of file copy.c.

907 {
908  struct Body *part = NULL;
909 
910  for (part = b->parts; part; part = part->next)
911  {
912  if (part->deleted || part->parts)
913  {
914  /* Copy till start of this part */
915  if (mutt_file_copy_bytes(fp_in, fp_out, part->hdr_offset - ftello(fp_in)))
916  return -1;
917 
918  if (part->deleted)
919  {
920  fprintf(
921  fp_out,
922  "Content-Type: message/external-body; access-type=x-mutt-deleted;\n"
923  "\texpiration=%s; length=" OFF_T_FMT "\n"
924  "\n",
925  date + 5, part->length);
926  if (ferror(fp_out))
927  return -1;
928 
929  /* Copy the original mime headers */
930  if (mutt_file_copy_bytes(fp_in, fp_out, part->offset - ftello(fp_in)))
931  return -1;
932 
933  /* Skip the deleted body */
934  fseeko(fp_in, part->offset + part->length, SEEK_SET);
935  }
936  else
937  {
938  if (copy_delete_attach(part, fp_in, fp_out, date))
939  return -1;
940  }
941  }
942  }
943 
944  /* Copy the last parts */
945  if (mutt_file_copy_bytes(fp_in, fp_out, b->offset + b->length - ftello(fp_in)))
946  return -1;
947 
948  return 0;
949 }
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:906
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 ", CASE_MATCH))
118  {
119  if ((chflags & CH_FROM) == 0)
120  continue;
121  from = true;
122  }
123  else if ((chflags & CH_NOQFROM) && mutt_str_startswith(buf, ">From ", CASE_IGNORE))
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_str_startswith(buf, "Status:", CASE_IGNORE) ||
130  mutt_str_startswith(buf, "X-Status:", CASE_IGNORE)))
131  {
132  continue;
133  }
134  if ((chflags & (CH_UPDATE_LEN | CH_XMIT | CH_NOLEN)) &&
135  (mutt_str_startswith(buf, "Content-Length:", CASE_IGNORE) ||
136  mutt_str_startswith(buf, "Lines:", CASE_IGNORE)))
137  {
138  continue;
139  }
140  if ((chflags & CH_UPDATE_REFS) && mutt_str_startswith(buf, "References:", CASE_IGNORE))
141  continue;
142  if ((chflags & CH_UPDATE_IRT) && mutt_str_startswith(buf, "In-Reply-To:", CASE_IGNORE))
143  continue;
144  if (chflags & CH_UPDATE_LABEL && mutt_str_startswith(buf, "X-Label:", CASE_IGNORE))
145  continue;
146  if ((chflags & CH_UPDATE_SUBJECT) && mutt_str_startswith(buf, "Subject:", CASE_IGNORE))
147  continue;
148 
149  ignore = false;
150  }
151 
152  if (!ignore && (fputs(buf, fp_out) == EOF))
153  return -1;
154  }
155  return 0;
156  }
157 
158  hdr_count = 1;
159  x = 0;
160  error = false;
161 
162  /* We are going to read and collect the headers in an array
163  * so we are able to do re-ordering.
164  * First count the number of entries in the array */
165  if (chflags & CH_REORDER)
166  {
167  struct ListNode *np = NULL;
168  STAILQ_FOREACH(np, &HeaderOrderList, entries)
169  {
170  mutt_debug(LL_DEBUG3, "Reorder list: %s\n", np->data);
171  hdr_count++;
172  }
173  }
174 
175  mutt_debug(LL_DEBUG1, "WEED is %sset\n", (chflags & CH_WEED) ? "" : "not ");
176 
177  headers = mutt_mem_calloc(hdr_count, sizeof(char *));
178 
179  /* Read all the headers into the array */
180  while (ftello(fp_in) < off_end)
181  {
182  nl = strchr(buf, '\n');
183 
184  /* Read a line */
185  if (!fgets(buf, sizeof(buf), fp_in))
186  break;
187 
188  /* Is it the beginning of a header? */
189  if (nl && (buf[0] != ' ') && (buf[0] != '\t'))
190  {
191  /* Do we have anything pending? */
192  if (this_one)
193  {
194  if (chflags & CH_DECODE)
195  {
196  if (address_header_decode(&this_one) == 0)
197  rfc2047_decode(&this_one);
198  this_one_len = mutt_str_strlen(this_one);
199 
200  /* Convert CRLF line endings to LF */
201  if ((this_one_len > 2) && (this_one[this_one_len - 2] == '\r') &&
202  (this_one[this_one_len - 1] == '\n'))
203  {
204  this_one[this_one_len - 2] = '\n';
205  this_one[this_one_len - 1] = '\0';
206  }
207  }
208 
209  if (!headers[x])
210  headers[x] = this_one;
211  else
212  {
213  int hlen = mutt_str_strlen(headers[x]);
214 
215  mutt_mem_realloc(&headers[x], hlen + this_one_len + sizeof(char));
216  strcat(headers[x] + hlen, this_one);
217  FREE(&this_one);
218  }
219 
220  this_one = NULL;
221  }
222 
223  ignore = true;
224  this_is_from = false;
225  if (!from && mutt_str_startswith(buf, "From ", CASE_MATCH))
226  {
227  if ((chflags & CH_FROM) == 0)
228  continue;
229  this_is_from = true;
230  from = true;
231  }
232  else if ((buf[0] == '\n') || ((buf[0] == '\r') && (buf[1] == '\n')))
233  break; /* end of header */
234 
235  /* note: CH_FROM takes precedence over header weeding. */
236  if (!((chflags & CH_FROM) && (chflags & CH_FORCE_FROM) && this_is_from) &&
237  (chflags & CH_WEED) && mutt_matches_ignore(buf))
238  {
239  continue;
240  }
241  if ((chflags & CH_WEED_DELIVERED) && mutt_str_startswith(buf, "Delivered-To:", CASE_IGNORE))
242  {
243  continue;
244  }
245  if ((chflags & (CH_UPDATE | CH_XMIT | CH_NOSTATUS)) &&
246  (mutt_str_startswith(buf, "Status:", CASE_IGNORE) ||
247  mutt_str_startswith(buf, "X-Status:", CASE_IGNORE)))
248  {
249  continue;
250  }
251  if ((chflags & (CH_UPDATE_LEN | CH_XMIT | CH_NOLEN)) &&
252  (mutt_str_startswith(buf, "Content-Length:", CASE_IGNORE) ||
253  mutt_str_startswith(buf, "Lines:", CASE_IGNORE)))
254  {
255  continue;
256  }
257  if ((chflags & CH_MIME))
258  {
259  if (mutt_str_startswith(buf, "mime-version:", CASE_IGNORE))
260  {
261  continue;
262  }
263  size_t plen = mutt_str_startswith(buf, "content-", CASE_IGNORE);
264  if ((plen != 0) && (mutt_str_startswith(buf + plen, "transfer-encoding:", CASE_IGNORE) ||
265  mutt_str_startswith(buf + plen, "type:", CASE_IGNORE)))
266  {
267  continue;
268  }
269  }
270  if ((chflags & CH_UPDATE_REFS) && mutt_str_startswith(buf, "References:", CASE_IGNORE))
271  continue;
272  if ((chflags & CH_UPDATE_IRT) && mutt_str_startswith(buf, "In-Reply-To:", CASE_IGNORE))
273  continue;
274  if ((chflags & CH_UPDATE_LABEL) && mutt_str_startswith(buf, "X-Label:", CASE_IGNORE))
275  continue;
276  if ((chflags & CH_UPDATE_SUBJECT) && mutt_str_startswith(buf, "Subject:", CASE_IGNORE))
277  continue;
278 
279  /* Find x -- the array entry where this header is to be saved */
280  if (chflags & CH_REORDER)
281  {
282  struct ListNode *np = NULL;
283  x = 0;
284  STAILQ_FOREACH(np, &HeaderOrderList, entries)
285  {
286  ++x;
287  if (mutt_str_startswith(buf, np->data, CASE_IGNORE))
288  {
289  mutt_debug(LL_DEBUG2, "Reorder: %s matches %s", np->data, buf);
290  break;
291  }
292  }
293  }
294 
295  ignore = false;
296  } /* If beginning of header */
297 
298  if (!ignore)
299  {
300  mutt_debug(LL_DEBUG2, "Reorder: x = %d; hdr_count = %d\n", x, hdr_count);
301  if (this_one)
302  {
303  size_t blen = mutt_str_strlen(buf);
304 
305  mutt_mem_realloc(&this_one, this_one_len + blen + sizeof(char));
306  strcat(this_one + this_one_len, buf);
307  this_one_len += blen;
308  }
309  else
310  {
311  this_one = mutt_str_strdup(buf);
312  this_one_len = mutt_str_strlen(this_one);
313  }
314  }
315  } /* while (ftello (fp_in) < off_end) */
316 
317  /* Do we have anything pending? -- XXX, same code as in above in the loop. */
318  if (this_one)
319  {
320  if (chflags & CH_DECODE)
321  {
322  if (address_header_decode(&this_one) == 0)
323  rfc2047_decode(&this_one);
324  this_one_len = mutt_str_strlen(this_one);
325  }
326 
327  if (!headers[x])
328  headers[x] = this_one;
329  else
330  {
331  int hlen = mutt_str_strlen(headers[x]);
332 
333  mutt_mem_realloc(&headers[x], hlen + this_one_len + sizeof(char));
334  strcat(headers[x] + hlen, this_one);
335  FREE(&this_one);
336  }
337 
338  this_one = NULL;
339  }
340 
341  /* Now output the headers in order */
342  for (x = 0; x < hdr_count; x++)
343  {
344  if (headers[x])
345  {
346  /* We couldn't do the prefixing when reading because RFC2047
347  * decoding may have concatenated lines. */
348  if (chflags & (CH_DECODE | CH_PREFIX))
349  {
350  const char *pre = (chflags & CH_PREFIX) ? prefix : NULL;
351  wraplen = mutt_window_wrap_cols(wraplen, C_Wrap);
352 
353  if (mutt_write_one_header(fp_out, 0, headers[x], pre, wraplen, chflags) == -1)
354  {
355  error = true;
356  break;
357  }
358  }
359  else
360  {
361  if (fputs(headers[x], fp_out) == EOF)
362  {
363  error = true;
364  break;
365  }
366  }
367  }
368  }
369 
370  /* Free in a separate loop to be sure that all headers are freed
371  * in case of error. */
372  for (x = 0; x < hdr_count; x++)
373  FREE(&headers[x]);
374  FREE(&headers);
375 
376  if (error)
377  return -1;
378  return 0;
379 }
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
#define CH_FROM
Retain the "From " message separator?
Definition: copy.h:55
WHERE short C_Wrap
Config: Width to wrap text in the pager.
Definition: globals.h:153
#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
Match case when comparing strings.
Definition: string2.h:67
size_t mutt_str_strlen(const char *a)
Calculate the length of a string, safely.
Definition: string.c:689
#define CH_UPDATE_REFS
Update References:
Definition: copy.h:68
#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:1028
void rfc2047_decode(char **pd)
Decode any RFC2047-encoded header fields.
Definition: rfc2047.c:636
#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
#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:385
Ignore case when comparing strings.
Definition: string2.h:68
#define CH_UPDATE_LEN
Update Lines: and Content-Length:
Definition: copy.h:61
#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
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:168
#define CH_NOQFROM
Ignore ">From " line.
Definition: copy.h:66
char * data
String.
Definition: list.h:35
Log at debug level 1.
Definition: logging.h:40
char * mutt_str_strdup(const char *str)
Copy a string, safely.
Definition: string.c:380
#define FREE(x)
Definition: memory.h:40
#define mutt_debug(LEVEL,...)
Definition: logging.h:81
A List node for strings.
Definition: list.h:33
#define CH_PREFIX
Quote header using C_IndentString string?
Definition: copy.h:56
int mutt_write_one_header(FILE *fp, const char *tag, const char *value, const char *pfx, int wraplen, CopyHeaderFlags chflags)
Write one header line to a file.
Definition: sendlib.c:2149
Log at debug level 3.
Definition: logging.h:42
+ 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 392 of file copy.c.

394 {
395  char *temp_hdr = NULL;
396 
397  if (e->env)
398  {
399  chflags |= ((e->env->changed & MUTT_ENV_CHANGED_IRT) ? CH_UPDATE_IRT : 0) |
403  }
404 
405  if (mutt_copy_hdr(fp_in, fp_out, e->offset, e->content->offset, chflags,
406  prefix, wraplen) == -1)
407  return -1;
408 
409  if (chflags & CH_TXTPLAIN)
410  {
411  char chsbuf[128];
412  char buf[128];
413  fputs("MIME-Version: 1.0\n", fp_out);
414  fputs("Content-Transfer-Encoding: 8bit\n", fp_out);
415  fputs("Content-Type: text/plain; charset=", fp_out);
416  mutt_ch_canonical_charset(chsbuf, sizeof(chsbuf), C_Charset ? C_Charset : "us-ascii");
417  mutt_addr_cat(buf, sizeof(buf), chsbuf, MimeSpecials);
418  fputs(buf, fp_out);
419  fputc('\n', fp_out);
420  }
421 
422  if ((chflags & CH_UPDATE_IRT) && !STAILQ_EMPTY(&e->env->in_reply_to))
423  {
424  fputs("In-Reply-To:", fp_out);
425  struct ListNode *np = NULL;
426  STAILQ_FOREACH(np, &e->env->in_reply_to, entries)
427  {
428  fputc(' ', fp_out);
429  fputs(np->data, fp_out);
430  }
431  fputc('\n', fp_out);
432  }
433 
434  if ((chflags & CH_UPDATE_REFS) && !STAILQ_EMPTY(&e->env->references))
435  {
436  fputs("References:", fp_out);
437  mutt_write_references(&e->env->references, fp_out, 0);
438  fputc('\n', fp_out);
439  }
440 
441  if ((chflags & CH_UPDATE) && ((chflags & CH_NOSTATUS) == 0))
442  {
443  if (e->old || e->read)
444  {
445  fputs("Status: ", fp_out);
446  if (e->read)
447  fputs("RO", fp_out);
448  else if (e->old)
449  fputc('O', fp_out);
450  fputc('\n', fp_out);
451  }
452 
453  if (e->flagged || e->replied)
454  {
455  fputs("X-Status: ", fp_out);
456  if (e->replied)
457  fputc('A', fp_out);
458  if (e->flagged)
459  fputc('F', fp_out);
460  fputc('\n', fp_out);
461  }
462  }
463 
464  if (chflags & CH_UPDATE_LEN && ((chflags & CH_NOLEN) == 0))
465  {
466  fprintf(fp_out, "Content-Length: " OFF_T_FMT "\n", e->content->length);
467  if ((e->lines != 0) || (e->content->length == 0))
468  fprintf(fp_out, "Lines: %d\n", e->lines);
469  }
470 
471 #ifdef USE_NOTMUCH
472  if (chflags & CH_VIRTUAL)
473  {
474  /* Add some fake headers based on notmuch data */
475  char *folder = nm_email_get_folder(e);
476  if (folder && !(C_Weed && mutt_matches_ignore("folder")))
477  {
478  char buf[1024];
479  mutt_str_strfcpy(buf, folder, sizeof(buf));
480  mutt_pretty_mailbox(buf, sizeof(buf));
481 
482  fputs("Folder: ", fp_out);
483  fputs(buf, fp_out);
484  fputc('\n', fp_out);
485  }
486  }
487 #endif
488  char *tags = driver_tags_get(&e->tags);
489  if (tags && !(C_Weed && mutt_matches_ignore("tags")))
490  {
491  fputs("Tags: ", fp_out);
492  fputs(tags, fp_out);
493  fputc('\n', fp_out);
494  }
495  FREE(&tags);
496 
497  if ((chflags & CH_UPDATE_LABEL) && e->env->x_label)
498  {
499  temp_hdr = e->env->x_label;
500  /* env->x_label isn't currently stored with direct references elsewhere.
501  * Context->label_hash strdups the keys. But to be safe, encode a copy */
502  if (!(chflags & CH_DECODE))
503  {
504  temp_hdr = mutt_str_strdup(temp_hdr);
505  rfc2047_encode(&temp_hdr, NULL, sizeof("X-Label:"), C_SendCharset);
506  }
507  if (mutt_write_one_header(fp_out, "X-Label", temp_hdr, (chflags & CH_PREFIX) ? prefix : 0,
508  mutt_window_wrap_cols(wraplen, C_Wrap), chflags) == -1)
509  {
510  return -1;
511  }
512  if (!(chflags & CH_DECODE))
513  FREE(&temp_hdr);
514  }
515 
516  if ((chflags & CH_UPDATE_SUBJECT) && e->env->subject)
517  {
518  temp_hdr = e->env->subject;
519  /* env->subject is directly referenced in Context->subj_hash, so we
520  * have to be careful not to encode (and thus free) that memory. */
521  if (!(chflags & CH_DECODE))
522  {
523  temp_hdr = mutt_str_strdup(temp_hdr);
524  rfc2047_encode(&temp_hdr, NULL, sizeof("Subject:"), C_SendCharset);
525  }
526  if (mutt_write_one_header(fp_out, "Subject", temp_hdr, (chflags & CH_PREFIX) ? prefix : 0,
527  mutt_window_wrap_cols(wraplen, C_Wrap), chflags) == -1)
528  {
529  return -1;
530  }
531  if (!(chflags & CH_DECODE))
532  FREE(&temp_hdr);
533  }
534 
535  if ((chflags & CH_NONEWLINE) == 0)
536  {
537  if (chflags & CH_PREFIX)
538  fputs(prefix, fp_out);
539  fputc('\n', fp_out); /* add header terminator */
540  }
541 
542  if (ferror(fp_out) || feof(fp_out))
543  return -1;
544 
545  return 0;
546 }
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
LOFF_T offset
offset where the actual data begins
Definition: body.h:44
WHERE short C_Wrap
Config: Width to wrap text in the pager.
Definition: globals.h:153
#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
#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
char * C_SendCharset
Config: Character sets for outgoing mail.
Definition: email_globals.c:38
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:345
#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
void mutt_write_references(const struct ListHead *r, FILE *fp, size_t trim)
Add the message references to a list.
Definition: sendlib.c:1837
#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
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:773
char * nm_email_get_folder(struct Email *e)
Get the folder for a Email.
int mutt_window_wrap_cols(int width, short wrap)
Calculate the wrap column for a given screen width.
Definition: mutt_window.c:385
#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:613
#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:612
LOFF_T offset
Where in the stream does this message begin?
Definition: email.h:83
char * data
String.
Definition: list.h:35
char * subject
Email&#39;s subject.
Definition: envelope.h:66
bool flagged
Marked important?
Definition: email.h:43
char * mutt_str_strdup(const char *str)
Copy a string, safely.
Definition: string.c:380
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
#define STAILQ_EMPTY(head)
Definition: queue.h:345
char * C_Charset
Config: Default character set for displaying text on screen.
Definition: charset.c:54
#define MUTT_ENV_CHANGED_REFS
References changed to break thread.
Definition: envelope.h:33
#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:33
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:672
int mutt_write_one_header(FILE *fp, const char *tag, const char *value, const char *pfx, int wraplen, CopyHeaderFlags chflags)
Write one header line to a file.
Definition: sendlib.c:2149
#define CH_NONEWLINE
Don&#39;t output terminating newline after the header.
Definition: copy.h:59
bool C_Weed
Config: Filter headers when displaying/forwarding/printing/replying.
Definition: email_globals.c:40
+ 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 558 of file copy.c.

559 {
560  int dellines = 0;
561 
562  if (b->deleted)
563  {
564  fseeko(fp, b->offset, SEEK_SET);
565  for (long l = b->length; l; l--)
566  {
567  const int ch = getc(fp);
568  if (ch == EOF)
569  break;
570  if (ch == '\n')
571  dellines++;
572  }
573  dellines -= 3;
574  *length -= b->length - (84 + datelen);
575  /* Count the number of digits exceeding the first one to write the size */
576  for (long l = 10; b->length >= l; l *= 10)
577  (*length)++;
578  }
579  else
580  {
581  for (b = b->parts; b; b = b->next)
582  dellines += count_delete_lines(fp, b, length, datelen);
583  }
584  return dellines;
585 }
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:558
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 598 of file copy.c.

600 {
601  struct Body *body = e->content;
602  char prefix[128];
603  LOFF_T new_offset = -1;
604  int rc = 0;
605 
606  if (cmflags & MUTT_CM_PREFIX)
607  {
608  if (C_TextFlowed)
609  mutt_str_strfcpy(prefix, ">", sizeof(prefix));
610  else
611  {
612  mutt_make_string(prefix, sizeof(prefix), wraplen, NONULL(C_IndentString),
613  Context, Context->mailbox, e);
614  }
615  }
616 
617  if ((cmflags & MUTT_CM_NOHEADER) == 0)
618  {
619  if (cmflags & MUTT_CM_PREFIX)
620  chflags |= CH_PREFIX;
621  else if (e->attach_del && (chflags & CH_UPDATE_LEN))
622  {
623  int new_lines;
624  LOFF_T new_length = body->length;
625  char date[128];
626 
627  mutt_date_make_date(date, sizeof(date));
628  int dlen = mutt_str_strlen(date);
629  if (dlen == 0)
630  return -1;
631 
632  date[5] = '\"';
633  date[dlen - 1] = '\"';
634 
635  /* Count the number of lines and bytes to be deleted */
636  fseeko(fp_in, body->offset, SEEK_SET);
637  new_lines = e->lines - count_delete_lines(fp_in, body, &new_length, dlen);
638 
639  /* Copy the headers */
640  if (mutt_copy_header(fp_in, e, fp_out, chflags | CH_NOLEN | CH_NONEWLINE, NULL, wraplen))
641  return -1;
642  fprintf(fp_out, "Content-Length: " OFF_T_FMT "\n", new_length);
643  if (new_lines <= 0)
644  new_lines = 0;
645  else
646  fprintf(fp_out, "Lines: %d\n", new_lines);
647 
648  putc('\n', fp_out);
649  if (ferror(fp_out) || feof(fp_out))
650  return -1;
651  new_offset = ftello(fp_out);
652 
653  /* Copy the body */
654  if (fseeko(fp_in, body->offset, SEEK_SET) < 0)
655  return -1;
656  if (copy_delete_attach(body, fp_in, fp_out, date))
657  return -1;
658 
659  LOFF_T fail = ((ftello(fp_out) - new_offset) - new_length);
660  if (fail)
661  {
662  mutt_error(ngettext("The length calculation was wrong by %ld byte",
663  "The length calculation was wrong by %ld bytes", fail),
664  fail);
665  new_length += fail;
666  }
667 
668  /* Update original message if we are sync'ing a mailfolder */
669  if (cmflags & MUTT_CM_UPDATE)
670  {
671  e->attach_del = false;
672  e->lines = new_lines;
673  body->offset = new_offset;
674 
675  /* update the total size of the mailbox to reflect this deletion */
676  Context->mailbox->size -= body->length - new_length;
677  /* if the message is visible, update the visible size of the mailbox as well. */
678  if (Context->mailbox->v2r[e->msgno] != -1)
679  Context->vsize -= body->length - new_length;
680 
681  body->length = new_length;
682  mutt_body_free(&body->parts);
683  }
684 
685  return 0;
686  }
687 
688  if (mutt_copy_header(fp_in, e, fp_out, chflags,
689  (chflags & CH_PREFIX) ? prefix : NULL, wraplen) == -1)
690  {
691  return -1;
692  }
693 
694  new_offset = ftello(fp_out);
695  }
696 
697  if (cmflags & MUTT_CM_DECODE)
698  {
699  /* now make a text/plain version of the message */
700  struct State s = { 0 };
701  s.fp_in = fp_in;
702  s.fp_out = fp_out;
703  if (cmflags & MUTT_CM_PREFIX)
704  s.prefix = prefix;
705  if (cmflags & MUTT_CM_DISPLAY)
706  {
707  s.flags |= MUTT_DISPLAY;
708  s.wraplen = wraplen;
709  }
710  if (cmflags & MUTT_CM_PRINTING)
711  s.flags |= MUTT_PRINTING;
712  if (cmflags & MUTT_CM_WEED)
713  s.flags |= MUTT_WEED;
714  if (cmflags & MUTT_CM_CHARCONV)
715  s.flags |= MUTT_CHARCONV;
716  if (cmflags & MUTT_CM_REPLYING)
717  s.flags |= MUTT_REPLYING;
718 
719  if ((WithCrypto != 0) && cmflags & MUTT_CM_VERIFY)
720  s.flags |= MUTT_VERIFY;
721 
722  rc = mutt_body_handler(body, &s);
723  }
724  else if ((WithCrypto != 0) && (cmflags & MUTT_CM_DECODE_CRYPT) && (e->security & SEC_ENCRYPT))
725  {
726  struct Body *cur = NULL;
727  FILE *fp = NULL;
728 
729  if (((WithCrypto & APPLICATION_PGP) != 0) && (cmflags & MUTT_CM_DECODE_PGP) &&
730  (e->security & APPLICATION_PGP) && (e->content->type == TYPE_MULTIPART))
731  {
732  if (crypt_pgp_decrypt_mime(fp_in, &fp, e->content, &cur))
733  return -1;
734  fputs("MIME-Version: 1.0\n", fp_out);
735  }
736 
737  if (((WithCrypto & APPLICATION_SMIME) != 0) && (cmflags & MUTT_CM_DECODE_SMIME) &&
738  (e->security & APPLICATION_SMIME) && (e->content->type == TYPE_APPLICATION))
739  {
740  if (crypt_smime_decrypt_mime(fp_in, &fp, e->content, &cur))
741  return -1;
742  }
743 
744  if (!cur)
745  {
746  mutt_error(_("No decryption engine available for message"));
747  return -1;
748  }
749 
750  mutt_write_mime_header(cur, fp_out);
751  fputc('\n', fp_out);
752 
753  if (fseeko(fp, cur->offset, SEEK_SET) < 0)
754  return -1;
755  if (mutt_file_copy_bytes(fp, fp_out, cur->length) == -1)
756  {
757  mutt_file_fclose(&fp);
758  mutt_body_free(&cur);
759  return -1;
760  }
761  mutt_body_free(&cur);
762  mutt_file_fclose(&fp);
763  }
764  else
765  {
766  if (fseeko(fp_in, body->offset, SEEK_SET) < 0)
767  return -1;
768  if (cmflags & MUTT_CM_PREFIX)
769  {
770  int c;
771  size_t bytes = body->length;
772 
773  fputs(prefix, fp_out);
774 
775  while (((c = fgetc(fp_in)) != EOF) && bytes--)
776  {
777  fputc(c, fp_out);
778  if (c == '\n')
779  {
780  fputs(prefix, fp_out);
781  }
782  }
783  }
784  else if (mutt_file_copy_bytes(fp_in, fp_out, body->length) == -1)
785  return -1;
786  }
787 
788  if ((cmflags & MUTT_CM_UPDATE) && ((cmflags & MUTT_CM_NOHEADER) == 0) &&
789  (new_offset != -1))
790  {
791  body->offset = new_offset;
792  mutt_body_free(&body->parts);
793  }
794 
795  return rc;
796 }
#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:163
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:906
WHERE char * C_IndentString
Config: String used to indent &#39;reply&#39; text.
Definition: globals.h:136
#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:125
#define mutt_make_string(BUF, BUFLEN, COLS, S, CTX, M, E)
Definition: hdrline.h:61
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:558
FILE * fp_out
File to write to.
Definition: state.h:47
size_t mutt_str_strlen(const char *a)
Calculate the length of a string, safely.
Definition: string.c:689
#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
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:372
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:51
#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 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:138
#define MUTT_CM_PREFIX
Quote the header and body.
Definition: copy.h:36
#define APPLICATION_PGP
Use PGP to encrypt/sign.
Definition: lib.h:137
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
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:773
#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:424
#define CH_UPDATE_LEN
Update Lines: and Content-Length:
Definition: copy.h:61
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
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
WHERE bool C_TextFlowed
Config: Generate &#39;format=flowed&#39; messages.
Definition: globals.h:254
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:200
Type: &#39;multipart/*&#39;.
Definition: mime.h:37
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:392
#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
int mutt_write_mime_header(struct Body *a, FILE *fp)
Create a MIME header.
Definition: sendlib.c:395
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:1550
void mutt_body_free(struct Body **ptr)
Free a Body.
Definition: body.c:57
#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
+ 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 812 of file copy.c.

814 {
815  struct Message *msg = mx_msg_open(m, e->msgno);
816  if (!msg)
817  return -1;
818  if (!e->content)
819  return -1;
820  int rc = mutt_copy_message_fp(fp_out, msg->fp, e, cmflags, chflags, wraplen);
821  if ((rc == 0) && (ferror(fp_out) || feof(fp_out)))
822  {
823  mutt_debug(LL_DEBUG1, "failed to detect EOF!\n");
824  rc = -1;
825  }
826  mx_msg_close(m, &msg);
827  return rc;
828 }
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:1171
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:598
struct Message * mx_msg_open(struct Mailbox *m, int msgno)
return a stream pointer for a message
Definition: mx.c:1123
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 841 of file copy.c.

843 {
844  char buf[256];
845  struct Message *msg = NULL;
846  int rc;
847 
848  if (fseeko(fp_in, e->offset, SEEK_SET) < 0)
849  return -1;
850  if (!fgets(buf, sizeof(buf), fp_in))
851  return -1;
852 
853  msg = mx_msg_open_new(dest, e, is_from(buf, NULL, 0, NULL) ? MUTT_MSG_NO_FLAGS : MUTT_ADD_FROM);
854  if (!msg)
855  return -1;
856  if ((dest->type == MUTT_MBOX) || (dest->type == MUTT_MMDF))
857  chflags |= CH_FROM | CH_FORCE_FROM;
858  chflags |= ((dest->type == MUTT_MAILDIR) ? CH_NOSTATUS : CH_UPDATE);
859  rc = mutt_copy_message_fp(msg->fp, fp_in, e, cmflags, chflags, 0);
860  if (mx_msg_commit(dest, msg) != 0)
861  rc = -1;
862 
863 #ifdef USE_NOTMUCH
864  if (msg->committed_path && (dest->type == MUTT_MAILDIR) && (src->type == MUTT_NOTMUCH))
865  nm_update_filename(src, NULL, msg->committed_path, e);
866 #endif
867 
868  mx_msg_close(dest, &msg);
869  return rc;
870 }
#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.
int mx_msg_close(struct Mailbox *m, struct Message **msg)
Close a message.
Definition: mx.c:1171
struct Message * mx_msg_open_new(struct Mailbox *m, struct Email *e, MsgOpenFlags flags)
Open a new message.
Definition: mx.c:1036
&#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:1150
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:50
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:598
#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 882 of file copy.c.

884 {
885  struct Message *msg = mx_msg_open(src, e->msgno);
886  if (!msg)
887  return -1;
888  int rc = append_message(dest, msg->fp, src, e, cmflags, chflags);
889  mx_msg_close(src, &msg);
890  return rc;
891 }
int mx_msg_close(struct Mailbox *m, struct Message **msg)
Close a message.
Definition: mx.c:1171
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:841
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:1123
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_write_addrlist(), but writes to a buffer instead of writing to a stream. mutt_write_addrlist could be re-used if we wouldn't store all the decoded headers in a huge array, first.

TODO fix that.

Definition at line 962 of file copy.c.

963 {
964  char buf[8192];
965  char cbuf[256];
966  char c2buf[256];
967  char *p = NULL;
968  size_t linelen, buflen, plen;
969 
970  linelen = mutt_str_strlen(*h);
971  plen = linelen;
972  buflen = linelen + 3;
973 
974  mutt_mem_realloc(h, buflen);
975  struct Address *first = TAILQ_FIRST(al);
976  struct Address *a = NULL;
977  TAILQ_FOREACH(a, al, entries)
978  {
979  *buf = '\0';
980  *cbuf = '\0';
981  *c2buf = '\0';
982  const size_t l = mutt_addr_write(buf, sizeof(buf), a, false);
983 
984  if (a != first && (linelen + l > 74))
985  {
986  strcpy(cbuf, "\n\t");
987  linelen = l + 8;
988  }
989  else
990  {
991  if (a->mailbox)
992  {
993  strcpy(cbuf, " ");
994  linelen++;
995  }
996  linelen += l;
997  }
998  if (!a->group && TAILQ_NEXT(a, entries) && TAILQ_NEXT(a, entries)->mailbox)
999  {
1000  linelen++;
1001  buflen++;
1002  strcpy(c2buf, ",");
1003  }
1004 
1005  const size_t cbuflen = mutt_str_strlen(cbuf);
1006  const size_t c2buflen = mutt_str_strlen(c2buf);
1007  buflen += l + cbuflen + c2buflen;
1008  mutt_mem_realloc(h, buflen);
1009  p = *h;
1010  strcat(p + plen, cbuf);
1011  plen += cbuflen;
1012  strcat(p + plen, buf);
1013  plen += l;
1014  strcat(p + plen, c2buf);
1015  plen += c2buflen;
1016  }
1017 
1018  /* Space for this was allocated in the beginning of this function. */
1019  strcat(p + plen, "\n");
1020 }
#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_str_strlen(const char *a)
Calculate the length of a string, safely.
Definition: string.c:689
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:1016
void mutt_mem_realloc(void *ptr, size_t size)
Resize a block of memory on the heap.
Definition: memory.c:114
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: