NeoMutt  2019-12-07-60-g0cfa53
Teaching an old dog new tricks
DOXYGEN
copy.c File Reference

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

#include "config.h"
#include <ctype.h>
#include <inttypes.h>
#include <stdbool.h>
#include <string.h>
#include "mutt/mutt.h"
#include "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 "ncrypt/ncrypt.h"
#include "sendlib.h"
#include "state.h"
#include "muttlib.h"
#include "notmuch/mutt_notmuch.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 1026 of file copy.c.

1027 {
1028  char *s = *h;
1029  size_t l;
1030  bool rp = false;
1031 
1032  switch (tolower((unsigned char) *s))
1033  {
1034  case 'b':
1035  {
1036  if (!(l = mutt_str_startswith(s, "bcc:", CASE_IGNORE)))
1037  return 0;
1038  break;
1039  }
1040  case 'c':
1041  {
1042  if (!(l = mutt_str_startswith(s, "cc:", CASE_IGNORE)))
1043  return 0;
1044  break;
1045  }
1046  case 'f':
1047  {
1048  if (!(l = mutt_str_startswith(s, "from:", CASE_IGNORE)))
1049  return 0;
1050  break;
1051  }
1052  case 'm':
1053  {
1054  if (!(l = mutt_str_startswith(s, "mail-followup-to:", CASE_IGNORE)))
1055  return 0;
1056  break;
1057  }
1058  case 'r':
1059  {
1060  if ((l = mutt_str_startswith(s, "return-path:", CASE_IGNORE)))
1061  {
1062  rp = true;
1063  break;
1064  }
1065  else if ((l = mutt_str_startswith(s, "reply-to:", CASE_IGNORE)))
1066  {
1067  break;
1068  }
1069  return 0;
1070  }
1071  case 's':
1072  {
1073  if (!(l = mutt_str_startswith(s, "sender:", CASE_IGNORE)))
1074  return 0;
1075  break;
1076  }
1077  case 't':
1078  {
1079  if (!(l = mutt_str_startswith(s, "to:", CASE_IGNORE)))
1080  return 0;
1081  break;
1082  }
1083  default:
1084  return 0;
1085  }
1086 
1087  struct AddressList al = TAILQ_HEAD_INITIALIZER(al);
1088  mutt_addrlist_parse(&al, s + l);
1089  if (TAILQ_EMPTY(&al))
1090  return 0;
1091 
1094  struct Address *a = NULL;
1095  TAILQ_FOREACH(a, &al, entries)
1096  {
1097  if (a->personal)
1098  {
1100  }
1101  }
1102 
1103  /* angle brackets for return path are mandated by RFC5322,
1104  * so leave Return-Path as-is */
1105  if (rp)
1106  *h = mutt_str_strdup(s);
1107  else
1108  {
1109  *h = mutt_mem_calloc(1, l + 2);
1110  mutt_str_strfcpy(*h, s, l + 1);
1111  format_address_header(h, &al);
1112  }
1113 
1114  mutt_addrlist_clear(&al);
1115 
1116  FREE(&s);
1117  return 1;
1118 }
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:960
void rfc2047_decode_addrlist(struct AddressList *al)
Decode any RFC2047 headers in an Address list.
Definition: rfc2047.c:770
#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:750
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:881
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 904 of file copy.c.

905 {
906  struct Body *part = NULL;
907 
908  for (part = b->parts; part; part = part->next)
909  {
910  if (part->deleted || part->parts)
911  {
912  /* Copy till start of this part */
913  if (mutt_file_copy_bytes(fp_in, fp_out, part->hdr_offset - ftello(fp_in)))
914  return -1;
915 
916  if (part->deleted)
917  {
918  fprintf(
919  fp_out,
920  "Content-Type: message/external-body; access-type=x-mutt-deleted;\n"
921  "\texpiration=%s; length=" OFF_T_FMT "\n"
922  "\n",
923  date + 5, part->length);
924  if (ferror(fp_out))
925  return -1;
926 
927  /* Copy the original mime headers */
928  if (mutt_file_copy_bytes(fp_in, fp_out, part->offset - ftello(fp_in)))
929  return -1;
930 
931  /* Skip the deleted body */
932  fseeko(fp_in, part->offset + part->length, SEEK_SET);
933  }
934  else
935  {
936  if (copy_delete_attach(part, fp_in, fp_out, date))
937  return -1;
938  }
939  }
940  }
941 
942  /* Copy the last parts */
943  if (mutt_file_copy_bytes(fp_in, fp_out, b->offset + b->length - ftello(fp_in)))
944  return -1;
945 
946  return 0;
947 }
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:904
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:240
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:152
#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:666
#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:1026
void rfc2047_decode(char **pd)
Decode any RFC2047-encoded header fields.
Definition: rfc2047.c:651
#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:383
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:2154
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:152
#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
char * nm_email_get_folder(struct Email *e)
Get the folder for a Email.
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:1842
#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:750
int mutt_window_wrap_cols(int width, short wrap)
Calculate the wrap column for a given screen width.
Definition: mutt_window.c:383
#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:627
#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:627
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:2154
#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  mutt_make_string(prefix, sizeof(prefix), wraplen, NONULL(C_IndentString),
612  Context, Context->mailbox, e);
613  }
614 
615  if ((cmflags & MUTT_CM_NOHEADER) == 0)
616  {
617  if (cmflags & MUTT_CM_PREFIX)
618  chflags |= CH_PREFIX;
619  else if (e->attach_del && (chflags & CH_UPDATE_LEN))
620  {
621  int new_lines;
622  LOFF_T new_length = body->length;
623  char date[128];
624 
625  mutt_date_make_date(date, sizeof(date));
626  int dlen = mutt_str_strlen(date);
627  if (dlen == 0)
628  return -1;
629 
630  date[5] = '\"';
631  date[dlen - 1] = '\"';
632 
633  /* Count the number of lines and bytes to be deleted */
634  fseeko(fp_in, body->offset, SEEK_SET);
635  new_lines = e->lines - count_delete_lines(fp_in, body, &new_length, dlen);
636 
637  /* Copy the headers */
638  if (mutt_copy_header(fp_in, e, fp_out, chflags | CH_NOLEN | CH_NONEWLINE, NULL, wraplen))
639  return -1;
640  fprintf(fp_out, "Content-Length: " OFF_T_FMT "\n", new_length);
641  if (new_lines <= 0)
642  new_lines = 0;
643  else
644  fprintf(fp_out, "Lines: %d\n", new_lines);
645 
646  putc('\n', fp_out);
647  if (ferror(fp_out) || feof(fp_out))
648  return -1;
649  new_offset = ftello(fp_out);
650 
651  /* Copy the body */
652  if (fseeko(fp_in, body->offset, SEEK_SET) < 0)
653  return -1;
654  if (copy_delete_attach(body, fp_in, fp_out, date))
655  return -1;
656 
657  LOFF_T fail = ((ftello(fp_out) - new_offset) - new_length);
658  if (fail)
659  {
660  mutt_error(ngettext("The length calculation was wrong by %ld byte",
661  "The length calculation was wrong by %ld bytes", fail),
662  fail);
663  new_length += fail;
664  }
665 
666  /* Update original message if we are sync'ing a mailfolder */
667  if (cmflags & MUTT_CM_UPDATE)
668  {
669  e->attach_del = false;
670  e->lines = new_lines;
671  body->offset = new_offset;
672 
673  /* update the total size of the mailbox to reflect this deletion */
674  Context->mailbox->size -= body->length - new_length;
675  /* if the message is visible, update the visible size of the mailbox as well. */
676  if (Context->mailbox->v2r[e->msgno] != -1)
677  Context->vsize -= body->length - new_length;
678 
679  body->length = new_length;
680  mutt_body_free(&body->parts);
681  }
682 
683  return 0;
684  }
685 
686  if (mutt_copy_header(fp_in, e, fp_out, chflags,
687  (chflags & CH_PREFIX) ? prefix : NULL, wraplen) == -1)
688  {
689  return -1;
690  }
691 
692  new_offset = ftello(fp_out);
693  }
694 
695  if (cmflags & MUTT_CM_DECODE)
696  {
697  /* now make a text/plain version of the message */
698  struct State s = { 0 };
699  s.fp_in = fp_in;
700  s.fp_out = fp_out;
701  if (cmflags & MUTT_CM_PREFIX)
702  s.prefix = prefix;
703  if (cmflags & MUTT_CM_DISPLAY)
704  {
705  s.flags |= MUTT_DISPLAY;
706  s.wraplen = wraplen;
707  }
708  if (cmflags & MUTT_CM_PRINTING)
709  s.flags |= MUTT_PRINTING;
710  if (cmflags & MUTT_CM_WEED)
711  s.flags |= MUTT_WEED;
712  if (cmflags & MUTT_CM_CHARCONV)
713  s.flags |= MUTT_CHARCONV;
714  if (cmflags & MUTT_CM_REPLYING)
715  s.flags |= MUTT_REPLYING;
716 
717  if ((WithCrypto != 0) && cmflags & MUTT_CM_VERIFY)
718  s.flags |= MUTT_VERIFY;
719 
720  rc = mutt_body_handler(body, &s);
721  }
722  else if ((WithCrypto != 0) && (cmflags & MUTT_CM_DECODE_CRYPT) && (e->security & SEC_ENCRYPT))
723  {
724  struct Body *cur = NULL;
725  FILE *fp = NULL;
726 
727  if (((WithCrypto & APPLICATION_PGP) != 0) && (cmflags & MUTT_CM_DECODE_PGP) &&
728  (e->security & APPLICATION_PGP) && (e->content->type == TYPE_MULTIPART))
729  {
730  if (crypt_pgp_decrypt_mime(fp_in, &fp, e->content, &cur))
731  return -1;
732  fputs("MIME-Version: 1.0\n", fp_out);
733  }
734 
735  if (((WithCrypto & APPLICATION_SMIME) != 0) && (cmflags & MUTT_CM_DECODE_SMIME) &&
736  (e->security & APPLICATION_SMIME) && (e->content->type == TYPE_APPLICATION))
737  {
738  if (crypt_smime_decrypt_mime(fp_in, &fp, e->content, &cur))
739  return -1;
740  }
741 
742  if (!cur)
743  {
744  mutt_error(_("No decryption engine available for message"));
745  return -1;
746  }
747 
748  mutt_write_mime_header(cur, fp_out);
749  fputc('\n', fp_out);
750 
751  if (fseeko(fp, cur->offset, SEEK_SET) < 0)
752  return -1;
753  if (mutt_file_copy_bytes(fp, fp_out, cur->length) == -1)
754  {
755  mutt_file_fclose(&fp);
756  mutt_body_free(&cur);
757  return -1;
758  }
759  mutt_body_free(&cur);
760  mutt_file_fclose(&fp);
761  }
762  else
763  {
764  if (fseeko(fp_in, body->offset, SEEK_SET) < 0)
765  return -1;
766  if (cmflags & MUTT_CM_PREFIX)
767  {
768  int c;
769  size_t bytes = body->length;
770 
771  fputs(prefix, fp_out);
772 
773  while (((c = fgetc(fp_in)) != EOF) && bytes--)
774  {
775  fputc(c, fp_out);
776  if (c == '\n')
777  {
778  fputs(prefix, fp_out);
779  }
780  }
781  }
782  else if (mutt_file_copy_bytes(fp_in, fp_out, body->length) == -1)
783  return -1;
784  }
785 
786  if ((cmflags & MUTT_CM_UPDATE) && ((cmflags & MUTT_CM_NOHEADER) == 0) &&
787  (new_offset != -1))
788  {
789  body->offset = new_offset;
790  mutt_body_free(&body->parts);
791  }
792 
793  return rc;
794 }
#define MUTT_CM_DECODE_CRYPT
Definition: copy.h:47
The "current" mailbox.
Definition: context.h:36
#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:86
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:904
WHERE char * C_IndentString
Config: String used to indent &#39;reply&#39; text.
Definition: globals.h:135
#define MUTT_CHARCONV
Do character set conversions.
Definition: state.h:36
#define MUTT_CM_UPDATE
Update structs on sync.
Definition: copy.h:39
#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:666
#define MUTT_PRINTING
Are we printing? - MUTT_DISPLAY "light".
Definition: state.h:37
#define SEC_ENCRYPT
Email is encrypted.
Definition: ncrypt.h:122
#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: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:152
int wraplen
Width to wrap lines to (when flags & MUTT_DISPLAY)
Definition: state.h:50
off_t vsize
Definition: context.h:38
#define MUTT_CM_PREFIX
Quote the header and body.
Definition: copy.h:36
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:750
#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:427
#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:240
#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/ncrypt.h pgplib.h, smime.h
Definition: email.h:39
unsigned int type
content-type primary type
Definition: body.h:65
#define APPLICATION_PGP
Use PGP to encrypt/sign.
Definition: ncrypt.h:134
#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:100
WHERE bool C_TextFlowed
Config: Generate &#39;format=flowed&#39; messages.
Definition: globals.h:257
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:203
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:396
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:1551
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 WithCrypto
Definition: ncrypt.h:160
#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
#define APPLICATION_SMIME
Use SMIME to encrypt/sign.
Definition: ncrypt.h:135
+ 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 810 of file copy.c.

812 {
813  struct Message *msg = mx_msg_open(m, e->msgno);
814  if (!msg)
815  return -1;
816  if (!e->content)
817  return -1;
818  int rc = mutt_copy_message_fp(fp_out, msg->fp, e, cmflags, chflags, wraplen);
819  if ((rc == 0) && (ferror(fp_out) || feof(fp_out)))
820  {
821  mutt_debug(LL_DEBUG1, "failed to detect EOF!\n");
822  rc = -1;
823  }
824  mx_msg_close(m, &msg);
825  return rc;
826 }
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:1140
A local copy of an email.
Definition: mx.h:81
Log at debug level 1.
Definition: logging.h:40
FILE * fp
pointer to the message data
Definition: mx.h:83
#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:1092
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 839 of file copy.c.

841 {
842  char buf[256];
843  struct Message *msg = NULL;
844  int rc;
845 
846  if (fseeko(fp_in, e->offset, SEEK_SET) < 0)
847  return -1;
848  if (!fgets(buf, sizeof(buf), fp_in))
849  return -1;
850 
851  msg = mx_msg_open_new(dest, e, is_from(buf, NULL, 0, NULL) ? MUTT_MSG_NO_FLAGS : MUTT_ADD_FROM);
852  if (!msg)
853  return -1;
854  if ((dest->magic == MUTT_MBOX) || (dest->magic == MUTT_MMDF))
855  chflags |= CH_FROM | CH_FORCE_FROM;
856  chflags |= ((dest->magic == MUTT_MAILDIR) ? CH_NOSTATUS : CH_UPDATE);
857  rc = mutt_copy_message_fp(msg->fp, fp_in, e, cmflags, chflags, 0);
858  if (mx_msg_commit(dest, msg) != 0)
859  rc = -1;
860 
861 #ifdef USE_NOTMUCH
862  if (msg->committed_path && (dest->magic == MUTT_MAILDIR) && (src->magic == MUTT_NOTMUCH))
863  nm_update_filename(src, NULL, msg->committed_path, e);
864 #endif
865 
866  mx_msg_close(dest, &msg);
867  return rc;
868 }
#define MUTT_MSG_NO_FLAGS
No flags are set.
Definition: mx.h:63
#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 mx_msg_close(struct Mailbox *m, struct Message **msg)
Close a message.
Definition: mx.c:1140
enum MailboxType magic
Mailbox type.
Definition: mailbox.h:104
struct Message * mx_msg_open_new(struct Mailbox *m, struct Email *e, MsgOpenFlags flags)
Open a new message.
Definition: mx.c:1009
&#39;Maildir&#39; Mailbox type
Definition: mailbox.h:50
#define CH_FORCE_FROM
Give CH_FROM precedence over CH_WEED?
Definition: copy.h:65
A local copy of an email.
Definition: mx.h:81
&#39;mmdf&#39; Mailbox type
Definition: mailbox.h:48
&#39;Notmuch&#39; (virtual) Mailbox type
Definition: mailbox.h:53
LOFF_T offset
Where in the stream does this message begin?
Definition: email.h:83
&#39;mbox&#39; Mailbox type
Definition: mailbox.h:47
char * committed_path
the final path generated by mx_msg_commit()
Definition: mx.h:85
int mx_msg_commit(struct Mailbox *m, struct Message *msg)
Commit a message to a folder - Wrapper for MxOps::msg_commit()
Definition: mx.c:1119
FILE * fp
pointer to the message data
Definition: mx.h:83
bool is_from(const char *s, char *path, size_t pathlen, time_t *tp)
Is a string a &#39;From&#39; header line?
Definition: from.c: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:64
int nm_update_filename(struct Mailbox *m, const char *old_file, const char *new_file, struct Email *e)
Change the filename.
+ 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 880 of file copy.c.

882 {
883  struct Message *msg = mx_msg_open(src, e->msgno);
884  if (!msg)
885  return -1;
886  int rc = append_message(dest, msg->fp, src, e, cmflags, chflags);
887  mx_msg_close(src, &msg);
888  return rc;
889 }
int mx_msg_close(struct Mailbox *m, struct Message **msg)
Close a message.
Definition: mx.c:1140
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:839
A local copy of an email.
Definition: mx.h:81
FILE * fp
pointer to the message data
Definition: mx.h:83
struct Message * mx_msg_open(struct Mailbox *m, int msgno)
return a stream pointer for a message
Definition: mx.c:1092
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 960 of file copy.c.

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