NeoMutt  2020-11-20
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 "ncrypt/lib.h"
#include "send/lib.h"
#include "context.h"
#include "handler.h"
#include "hdrline.h"
#include "mutt_globals.h"
#include "mx.h"
#include "state.h"
#include "notmuch/lib.h"
#include "muttlib.h"
#include <libintl.h>
+ Include dependency graph for copy.c:

Go to the source code of this file.

Functions

static int address_header_decode (char **h)
 Parse an email's headers. More...
 
static int copy_delete_attach (struct Body *b, FILE *fp_in, FILE *fp_out, const char *quoted_date)
 Copy a message, deleting marked attachments. More...
 
 ARRAY_HEAD (Headers, char *)
 
static void add_one_header (struct Headers *headers, size_t pos, char *value)
 Add a header to a Headers array. More...
 
int mutt_copy_hdr (FILE *fp_in, FILE *fp_out, LOFF_T off_start, LOFF_T off_end, CopyHeaderFlags chflags, const char *prefix, int wraplen)
 Copy header from one file to another. More...
 
int mutt_copy_header (FILE *fp_in, struct Email *e, FILE *fp_out, CopyHeaderFlags chflags, const char *prefix, int wraplen)
 Copy Email header. More...
 
static int count_delete_lines (FILE *fp, struct Body *b, LOFF_T *length, size_t datelen)
 Count lines to be deleted in this email body. More...
 
int mutt_copy_message_fp (FILE *fp_out, FILE *fp_in, struct Email *e, CopyMessageFlags cmflags, CopyHeaderFlags chflags, int wraplen)
 make a copy of a message from a FILE pointer More...
 
int mutt_copy_message (FILE *fp_out, struct 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 1052 of file copy.c.

1053 {
1054  char *s = *h;
1055  size_t l;
1056  bool rp = false;
1057 
1058  switch (tolower((unsigned char) *s))
1059  {
1060  case 'b':
1061  {
1062  if (!(l = mutt_istr_startswith(s, "bcc:")))
1063  return 0;
1064  break;
1065  }
1066  case 'c':
1067  {
1068  if (!(l = mutt_istr_startswith(s, "cc:")))
1069  return 0;
1070  break;
1071  }
1072  case 'f':
1073  {
1074  if (!(l = mutt_istr_startswith(s, "from:")))
1075  return 0;
1076  break;
1077  }
1078  case 'm':
1079  {
1080  if (!(l = mutt_istr_startswith(s, "mail-followup-to:")))
1081  return 0;
1082  break;
1083  }
1084  case 'r':
1085  {
1086  if ((l = mutt_istr_startswith(s, "return-path:")))
1087  {
1088  rp = true;
1089  break;
1090  }
1091  else if ((l = mutt_istr_startswith(s, "reply-to:")))
1092  {
1093  break;
1094  }
1095  return 0;
1096  }
1097  case 's':
1098  {
1099  if (!(l = mutt_istr_startswith(s, "sender:")))
1100  return 0;
1101  break;
1102  }
1103  case 't':
1104  {
1105  if (!(l = mutt_istr_startswith(s, "to:")))
1106  return 0;
1107  break;
1108  }
1109  default:
1110  return 0;
1111  }
1112 
1113  struct AddressList al = TAILQ_HEAD_INITIALIZER(al);
1114  mutt_addrlist_parse(&al, s + l);
1115  if (TAILQ_EMPTY(&al))
1116  return 0;
1117 
1120  struct Address *a = NULL;
1121  TAILQ_FOREACH(a, &al, entries)
1122  {
1123  if (a->personal)
1124  {
1126  }
1127  }
1128 
1129  /* angle brackets for return path are mandated by RFC5322,
1130  * so leave Return-Path as-is */
1131  if (rp)
1132  *h = mutt_str_dup(s);
1133  else
1134  {
1135  *h = mutt_mem_calloc(1, l + 2);
1136  mutt_str_copy(*h, s, l + 1);
1137  format_address_header(h, &al);
1138  }
1139 
1140  mutt_addrlist_clear(&al);
1141 
1142  FREE(&s);
1143  return 1;
1144 }
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:986
void rfc2047_decode_addrlist(struct AddressList *al)
Decode any RFC2047 headers in an Address list.
Definition: rfc2047.c:758
#define TAILQ_FOREACH(var, head, field)
Definition: queue.h:718
int mutt_addrlist_parse(struct AddressList *al, const char *s)
Parse a list of email addresses.
Definition: address.c:458
int mutt_addrlist_to_local(struct AddressList *al)
Convert an Address list from Punycode.
Definition: address.c:1386
void mutt_addrlist_clear(struct AddressList *al)
Unlink and free all Address in an AddressList.
Definition: address.c:1468
char * mutt_str_dup(const char *str)
Copy a string, safely.
Definition: string.c:370
An email address.
Definition: address.h:34
void mutt_str_dequote_comment(char *s)
Un-escape characters in an email address comment.
Definition: string.c:839
size_t mutt_istr_startswith(const char *str, const char *prefix)
Check whether a string starts with a prefix, ignoring case.
Definition: string.c:172
char * personal
Real name of address.
Definition: address.h:36
size_t mutt_str_copy(char *dest, const char *src, size_t dsize)
Copy a string into a buffer (guaranteeing NUL-termination)
Definition: string.c:716
#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,
const char *  quoted_date 
)
static

Copy a message, deleting marked attachments.

Parameters
bEmail Body
fp_inFILE pointer to read from
fp_outFILE pointer to write to
quoted_dateDate stamp
Return values
0Success
-1Failure

This function copies a message body, while deleting in_the_copy any attachments which are marked for deletion. Nothing is changed in the original message – this is left to the caller.

Definition at line 929 of file copy.c.

930 {
931  struct Body *part = NULL;
932 
933  for (part = b->parts; part; part = part->next)
934  {
935  if (part->deleted || part->parts)
936  {
937  /* Copy till start of this part */
938  if (mutt_file_copy_bytes(fp_in, fp_out, part->hdr_offset - ftello(fp_in)))
939  return -1;
940 
941  if (part->deleted)
942  {
943  /* If this is modified, count_delete_lines() needs to be changed too */
944  fprintf(
945  fp_out,
946  "Content-Type: message/external-body; access-type=x-mutt-deleted;\n"
947  "\texpiration=%s; length=" OFF_T_FMT "\n"
948  "\n",
949  quoted_date, part->length);
950  if (ferror(fp_out))
951  return -1;
952 
953  /* Copy the original mime headers */
954  if (mutt_file_copy_bytes(fp_in, fp_out, part->offset - ftello(fp_in)))
955  return -1;
956 
957  /* Skip the deleted body */
958  fseeko(fp_in, part->offset + part->length, SEEK_SET);
959  }
960  else
961  {
962  if (copy_delete_attach(part, fp_in, fp_out, quoted_date))
963  return -1;
964  }
965  }
966  }
967 
968  /* Copy the last parts */
969  if (mutt_file_copy_bytes(fp_in, fp_out, b->offset + b->length - ftello(fp_in)))
970  return -1;
971 
972  return 0;
973 }
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
static int copy_delete_attach(struct Body *b, FILE *fp_in, FILE *fp_out, const char *quoted_date)
Copy a message, deleting marked attachments.
Definition: copy.c:929
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:

◆ ARRAY_HEAD()

ARRAY_HEAD ( Headers  ,
char *   
)

◆ add_one_header()

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

Add a header to a Headers array.

Parameters
headersHeaders array
posPosition to insert new header
valueText to insert

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

Definition at line 73 of file copy.c.

74 {
75  char **old = ARRAY_GET(headers, pos);
76  if (old && *old)
77  {
78  char *new_value = NULL;
79  mutt_str_asprintf(&new_value, "%s%s", *old, value);
80  FREE(old);
81  FREE(&value);
82  value = new_value;
83  }
84  ARRAY_SET(headers, pos, value);
85 }
#define ARRAY_GET(head, idx)
Return the element at index.
Definition: array.h:105
#define ARRAY_SET(head, idx, elem)
Set an element in the array.
Definition: array.h:119
#define FREE(x)
Definition: memory.h:40
int mutt_str_asprintf(char **strp, const char *fmt,...)
Definition: string.c:1095
+ 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 103 of file copy.c.

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

◆ mutt_copy_header()

int mutt_copy_header ( FILE *  fp_in,
struct Email e,
FILE *  fp_out,
CopyHeaderFlags  chflags,
const char *  prefix,
int  wraplen 
)

Copy Email header.

Parameters
fp_inFILE pointer to read from
eEmail
fp_outFILE pointer to write to
chflagsSee CopyHeaderFlags
prefixPrefix for quoting headers (if CH_PREFIX is set)
wraplenWidth to wrap at (when chflags & CH_DISPLAY)
Return values
0Success
-1Failure

Definition at line 405 of file copy.c.

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

◆ count_delete_lines()

static int count_delete_lines ( FILE *  fp,
struct Body b,
LOFF_T *  length,
size_t  datelen 
)
static

Count lines to be deleted in this email body.

Parameters
fpFILE pointer to read from
bEmail Body
lengthNumber of bytes to be deleted
datelenLength of the date
Return values
numNumber of lines to be deleted

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

Definition at line 572 of file copy.c.

573 {
574  int dellines = 0;
575 
576  if (b->deleted)
577  {
578  fseeko(fp, b->offset, SEEK_SET);
579  for (long l = b->length; l; l--)
580  {
581  const int ch = getc(fp);
582  if (ch == EOF)
583  break;
584  if (ch == '\n')
585  dellines++;
586  }
587  /* 3 and 89 come from the added header of three lines in
588  * copy_delete_attach(). 89 is the size of the header(including
589  * the newlines, tabs, and a single digit length), not including
590  * the date length. */
591  dellines -= 3;
592  *length -= b->length - (89 + datelen);
593  /* Count the number of digits exceeding the first one to write the size */
594  for (long l = 10; b->length >= l; l *= 10)
595  (*length)++;
596  }
597  else
598  {
599  for (b = b->parts; b; b = b->next)
600  dellines += count_delete_lines(fp, b, length, datelen);
601  }
602  return dellines;
603 }
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:572
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 616 of file copy.c.

618 {
619  struct Body *body = e->body;
620  char prefix[128];
621  LOFF_T new_offset = -1;
622  int rc = 0;
623 
624  if (cmflags & MUTT_CM_PREFIX)
625  {
626  if (C_TextFlowed)
627  mutt_str_copy(prefix, ">", sizeof(prefix));
628  else
629  {
630  mutt_make_string(prefix, sizeof(prefix), wraplen, NONULL(C_IndentString),
632  }
633  }
634 
635  if ((cmflags & MUTT_CM_NOHEADER) == 0)
636  {
637  if (cmflags & MUTT_CM_PREFIX)
638  chflags |= CH_PREFIX;
639  else if (e->attach_del && (chflags & CH_UPDATE_LEN))
640  {
641  int new_lines;
642  int rc_attach_del = -1;
643  LOFF_T new_length = body->length;
644  struct Buffer *quoted_date = NULL;
645 
646  quoted_date = mutt_buffer_pool_get();
647  mutt_buffer_addch(quoted_date, '"');
648  mutt_date_make_date(quoted_date);
649  mutt_buffer_addch(quoted_date, '"');
650 
651  /* Count the number of lines and bytes to be deleted */
652  fseeko(fp_in, body->offset, SEEK_SET);
653  new_lines = e->lines - count_delete_lines(fp_in, body, &new_length,
654  mutt_buffer_len(quoted_date));
655 
656  /* Copy the headers */
657  if (mutt_copy_header(fp_in, e, fp_out, chflags | CH_NOLEN | CH_NONEWLINE, NULL, wraplen))
658  goto attach_del_cleanup;
659  fprintf(fp_out, "Content-Length: " OFF_T_FMT "\n", new_length);
660  if (new_lines <= 0)
661  new_lines = 0;
662  else
663  fprintf(fp_out, "Lines: %d\n", new_lines);
664 
665  putc('\n', fp_out);
666  if (ferror(fp_out) || feof(fp_out))
667  goto attach_del_cleanup;
668  new_offset = ftello(fp_out);
669 
670  /* Copy the body */
671  if (fseeko(fp_in, body->offset, SEEK_SET) < 0)
672  goto attach_del_cleanup;
673  if (copy_delete_attach(body, fp_in, fp_out, mutt_b2s(quoted_date)))
674  goto attach_del_cleanup;
675 
676  mutt_buffer_pool_release(&quoted_date);
677 
678  LOFF_T fail = ((ftello(fp_out) - new_offset) - new_length);
679  if (fail)
680  {
681  mutt_error(ngettext("The length calculation was wrong by %ld byte",
682  "The length calculation was wrong by %ld bytes", fail),
683  fail);
684  new_length += fail;
685  }
686 
687  /* Update original message if we are sync'ing a mailfolder */
688  if (cmflags & MUTT_CM_UPDATE)
689  {
690  e->attach_del = false;
691  e->lines = new_lines;
692  body->offset = new_offset;
693 
694  /* update the total size of the mailbox to reflect this deletion */
695  Context->mailbox->size -= body->length - new_length;
696  /* if the message is visible, update the visible size of the mailbox as well. */
697  if (Context->mailbox->v2r[e->msgno] != -1)
698  Context->vsize -= body->length - new_length;
699 
700  body->length = new_length;
701  mutt_body_free(&body->parts);
702  }
703 
704  rc_attach_del = 0;
705 
706  attach_del_cleanup:
707  mutt_buffer_pool_release(&quoted_date);
708  return rc_attach_del;
709  }
710 
711  if (mutt_copy_header(fp_in, e, fp_out, chflags,
712  (chflags & CH_PREFIX) ? prefix : NULL, wraplen) == -1)
713  {
714  return -1;
715  }
716 
717  new_offset = ftello(fp_out);
718  }
719 
720  if (cmflags & MUTT_CM_DECODE)
721  {
722  /* now make a text/plain version of the message */
723  struct State s = { 0 };
724  s.fp_in = fp_in;
725  s.fp_out = fp_out;
726  if (cmflags & MUTT_CM_PREFIX)
727  s.prefix = prefix;
728  if (cmflags & MUTT_CM_DISPLAY)
729  {
730  s.flags |= MUTT_DISPLAY;
731  s.wraplen = wraplen;
732  }
733  if (cmflags & MUTT_CM_PRINTING)
734  s.flags |= MUTT_PRINTING;
735  if (cmflags & MUTT_CM_WEED)
736  s.flags |= MUTT_WEED;
737  if (cmflags & MUTT_CM_CHARCONV)
738  s.flags |= MUTT_CHARCONV;
739  if (cmflags & MUTT_CM_REPLYING)
740  s.flags |= MUTT_REPLYING;
741 
742  if ((WithCrypto != 0) && cmflags & MUTT_CM_VERIFY)
743  s.flags |= MUTT_VERIFY;
744 
745  rc = mutt_body_handler(body, &s);
746  }
747  else if ((WithCrypto != 0) && (cmflags & MUTT_CM_DECODE_CRYPT) && (e->security & SEC_ENCRYPT))
748  {
749  struct Body *cur = NULL;
750  FILE *fp = NULL;
751 
752  if (((WithCrypto & APPLICATION_PGP) != 0) && (cmflags & MUTT_CM_DECODE_PGP) &&
753  (e->security & APPLICATION_PGP) && (e->body->type == TYPE_MULTIPART))
754  {
755  if (crypt_pgp_decrypt_mime(fp_in, &fp, e->body, &cur))
756  return -1;
757  fputs("MIME-Version: 1.0\n", fp_out);
758  }
759 
760  if (((WithCrypto & APPLICATION_SMIME) != 0) && (cmflags & MUTT_CM_DECODE_SMIME) &&
761  (e->security & APPLICATION_SMIME) && (e->body->type == TYPE_APPLICATION))
762  {
763  if (crypt_smime_decrypt_mime(fp_in, &fp, e->body, &cur))
764  return -1;
765  }
766 
767  if (!cur)
768  {
769  mutt_error(_("No decryption engine available for message"));
770  return -1;
771  }
772 
773  mutt_write_mime_header(cur, fp_out, NeoMutt->sub);
774  fputc('\n', fp_out);
775 
776  if (fseeko(fp, cur->offset, SEEK_SET) < 0)
777  return -1;
778  if (mutt_file_copy_bytes(fp, fp_out, cur->length) == -1)
779  {
780  mutt_file_fclose(&fp);
781  mutt_body_free(&cur);
782  return -1;
783  }
784  mutt_body_free(&cur);
785  mutt_file_fclose(&fp);
786  }
787  else
788  {
789  if (fseeko(fp_in, body->offset, SEEK_SET) < 0)
790  return -1;
791  if (cmflags & MUTT_CM_PREFIX)
792  {
793  int c;
794  size_t bytes = body->length;
795 
796  fputs(prefix, fp_out);
797 
798  while (((c = fgetc(fp_in)) != EOF) && bytes--)
799  {
800  fputc(c, fp_out);
801  if (c == '\n')
802  {
803  fputs(prefix, fp_out);
804  }
805  }
806  }
807  else if (mutt_file_copy_bytes(fp_in, fp_out, body->length) == -1)
808  return -1;
809  }
810 
811  if ((cmflags & MUTT_CM_UPDATE) && ((cmflags & MUTT_CM_NOHEADER) == 0) &&
812  (new_offset != -1))
813  {
814  body->offset = new_offset;
815  mutt_body_free(&body->parts);
816  }
817 
818  return rc;
819 }
#define MUTT_CM_DECODE_CRYPT
Definition: copy.h:47
The "current" mailbox.
Definition: context.h:38
#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:85
#define NONULL(x)
Definition: string2.h:37
off_t size
Size of the Mailbox.
Definition: mailbox.h:87
#define WithCrypto
Definition: lib.h:123
int msg_in_pager
Message currently shown in the pager.
Definition: context.h:44
void mutt_date_make_date(struct Buffer *buf)
Write a date in RFC822 format to a buffer.
Definition: date.c:377
struct Buffer * mutt_buffer_pool_get(void)
Get a Buffer from the pool.
Definition: pool.c:101
struct Body * body
List of MIME parts.
Definition: email.h:91
#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:85
bool attach_del
Has an attachment marked for deletion.
Definition: email.h:49
void mutt_buffer_pool_release(struct Buffer **pbuf)
Free a Buffer from the pool.
Definition: pool.c:112
#define MUTT_CM_WEED
Weed message/rfc822 attachment headers.
Definition: copy.h:40
String manipulation buffer.
Definition: buffer.h:33
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:572
FILE * fp_out
File to write to.
Definition: state.h:47
#define MUTT_PRINTING
Are we printing? - MUTT_DISPLAY "light".
Definition: state.h:37
#define MUTT_CM_PRINTING
Printing the message - display light.
Definition: copy.h:42
Container for Accounts, Notifications.
Definition: neomutt.h:36
FILE * fp_in
File to read from.
Definition: state.h:46
#define MUTT_CM_REPLYING
Replying the message.
Definition: copy.h:43
The body of an email.
Definition: body.h:34
StateFlags flags
Flags, e.g. MUTT_DISPLAY.
Definition: state.h:49
struct Mailbox * mailbox
Definition: context.h:50
#define MUTT_CM_DISPLAY
Output is displayed to the user.
Definition: copy.h:38
int mutt_file_fclose(FILE **fp)
Close a FILE handle (and NULL the pointer)
Definition: file.c:153
int mutt_write_mime_header(struct Body *a, FILE *fp, struct ConfigSubset *sub)
Create a MIME header.
Definition: header.c:761
int wraplen
Width to wrap lines to (when flags & MUTT_DISPLAY)
Definition: state.h:50
off_t vsize
Size (in bytes) of the messages shown.
Definition: context.h:40
#define mutt_b2s(buf)
Definition: buffer.h:41
#define APPLICATION_SMIME
Use SMIME to encrypt/sign.
Definition: lib.h:98
#define MUTT_CM_PREFIX
Quote the header and body.
Definition: copy.h:36
#define APPLICATION_PGP
Use PGP to encrypt/sign.
Definition: lib.h:97
LOFF_T length
length (in bytes) of attachment
Definition: body.h:45
size_t mutt_buffer_len(const struct Buffer *buf)
Calculate the length of a Buffer.
Definition: buffer.c:356
#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
static int copy_delete_attach(struct Body *b, FILE *fp_in, FILE *fp_out, const char *quoted_date)
Copy a message, deleting marked attachments.
Definition: copy.c:929
struct Body * parts
parts of a multipart or message/rfc822
Definition: body.h:54
#define MUTT_WEED
Weed headers even when not in display mode.
Definition: state.h:35
int crypt_smime_decrypt_mime(FILE *fp_in, FILE **fp_out, struct Body *b, struct Body **cur)
Wrapper for CryptModuleSpecs::decrypt_mime()
Definition: cryptglue.c:431
#define CH_UPDATE_LEN
Update Lines: and Content-Length:
Definition: copy.h:61
void mutt_body_free(struct Body **ptr)
Free a Body.
Definition: body.c:57
int mutt_file_copy_bytes(FILE *fp_in, FILE *fp_out, size_t size)
Copy some content from one file to another.
Definition: file.c:241
size_t mutt_buffer_addch(struct Buffer *buf, char c)
Add a single character to a Buffer.
Definition: buffer.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/lib.h pgplib...
Definition: email.h:39
unsigned int type
content-type primary type, ContentType
Definition: body.h:65
#define MUTT_CM_DECODE_SMIME
Used for decoding S/MIME messages.
Definition: copy.h:45
int * v2r
Mapping from virtual to real msgno.
Definition: mailbox.h:101
int crypt_pgp_decrypt_mime(FILE *fp_in, FILE **fp_out, struct Body *b, struct Body **cur)
Wrapper for CryptModuleSpecs::decrypt_mime()
Definition: cryptglue.c:207
Type: &#39;multipart/*&#39;.
Definition: mime.h:37
size_t mutt_str_copy(char *dest, const char *src, size_t dsize)
Copy a string into a buffer (guaranteeing NUL-termination)
Definition: string.c:716
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:405
#define mutt_error(...)
Definition: logging.h:84
#define MUTT_CM_DECODE_PGP
Used for decoding PGP messages.
Definition: copy.h:44
#define MUTT_REPLYING
Are we replying?
Definition: state.h:38
Keep track when processing files.
Definition: state.h:44
int mutt_body_handler(struct Body *b, struct State *s)
Handler for the Body of an email.
Definition: handler.c:1593
struct ConfigSubset * sub
Inherited config items.
Definition: neomutt.h:39
#define MUTT_CM_NOHEADER
Don&#39;t copy the message header.
Definition: copy.h:35
#define CH_PREFIX
Quote header using $indent_string 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
#define mutt_make_string(BUF, BUFLEN, COLS, S, M, INPGR, E)
Definition: hdrline.h:58
int msgno
Number displayed to the user.
Definition: email.h:87
WHERE char * C_IndentString
Config: String used to indent &#39;reply&#39; text.
Definition: mutt_globals.h:102
WHERE bool C_TextFlowed
Config: Generate &#39;format=flowed&#39; messages.
Definition: mutt_globals.h:166
+ 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 835 of file copy.c.

837 {
838  struct Message *msg = mx_msg_open(m, e->msgno);
839  if (!msg)
840  return -1;
841  if (!e->body)
842  return -1;
843  int rc = mutt_copy_message_fp(fp_out, msg->fp, e, cmflags, chflags, wraplen);
844  if ((rc == 0) && (ferror(fp_out) || feof(fp_out)))
845  {
846  mutt_debug(LL_DEBUG1, "failed to detect EOF!\n");
847  rc = -1;
848  }
849  mx_msg_close(m, &msg);
850  return rc;
851 }
struct Body * body
List of MIME parts.
Definition: email.h:91
int mx_msg_close(struct Mailbox *m, struct Message **msg)
Close a message.
Definition: mx.c:1204
A local copy of an email.
Definition: mx.h:82
Log at debug level 1.
Definition: logging.h:40
FILE * fp
pointer to the message data
Definition: mx.h:84
#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:616
struct Message * mx_msg_open(struct Mailbox *m, int msgno)
return a stream pointer for a message
Definition: mx.c:1158
int msgno
Number displayed to the user.
Definition: email.h:87
+ 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 864 of file copy.c.

866 {
867  char buf[256];
868  struct Message *msg = NULL;
869  int rc;
870 
871  if (fseeko(fp_in, e->offset, SEEK_SET) < 0)
872  return -1;
873  if (!fgets(buf, sizeof(buf), fp_in))
874  return -1;
875 
876  msg = mx_msg_open_new(dest, e, is_from(buf, NULL, 0, NULL) ? MUTT_MSG_NO_FLAGS : MUTT_ADD_FROM);
877  if (!msg)
878  return -1;
879  if ((dest->type == MUTT_MBOX) || (dest->type == MUTT_MMDF))
880  chflags |= CH_FROM | CH_FORCE_FROM;
881  chflags |= ((dest->type == MUTT_MAILDIR) ? CH_NOSTATUS : CH_UPDATE);
882  rc = mutt_copy_message_fp(msg->fp, fp_in, e, cmflags, chflags, 0);
883  if (mx_msg_commit(dest, msg) != 0)
884  rc = -1;
885 
886 #ifdef USE_NOTMUCH
887  if (msg->committed_path && (dest->type == MUTT_MAILDIR) && (src->type == MUTT_NOTMUCH))
888  nm_update_filename(src, NULL, msg->committed_path, e);
889 #endif
890 
891  mx_msg_close(dest, &msg);
892  return rc;
893 }
#define MUTT_MSG_NO_FLAGS
No flags are set.
Definition: mx.h:64
enum MailboxType type
Mailbox type.
Definition: mailbox.h:105
#define CH_FROM
Retain the "From " message separator?
Definition: copy.h:55
#define CH_NOSTATUS
Suppress the status and x-status fields.
Definition: copy.h:57
#define CH_UPDATE
Update the status and x-status fields?
Definition: copy.h:51
int nm_update_filename(struct Mailbox *m, const char *old_file, const char *new_file, struct Email *e)
Change the filename.
Definition: notmuch.c:1957
int mx_msg_close(struct Mailbox *m, struct Message **msg)
Close a message.
Definition: mx.c:1204
struct Message * mx_msg_open_new(struct Mailbox *m, const struct Email *e, MsgOpenFlags flags)
Open a new message.
Definition: mx.c:1072
&#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:82
&#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:84
&#39;mbox&#39; Mailbox type
Definition: mailbox.h:48
char * committed_path
the final path generated by mx_msg_commit()
Definition: mx.h:86
int mx_msg_commit(struct Mailbox *m, struct Message *msg)
Commit a message to a folder - Wrapper for MxOps::msg_commit()
Definition: mx.c:1183
FILE * fp
pointer to the message data
Definition: mx.h:84
bool is_from(const char *s, char *path, size_t pathlen, time_t *tp)
Is a string a &#39;From&#39; header line?
Definition: from.c:48
int mutt_copy_message_fp(FILE *fp_out, FILE *fp_in, struct Email *e, CopyMessageFlags cmflags, CopyHeaderFlags chflags, int wraplen)
make a copy of a message from a FILE pointer
Definition: copy.c:616
#define MUTT_ADD_FROM
add a From_ line
Definition: mx.h:65
+ 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 905 of file copy.c.

907 {
908  struct Message *msg = mx_msg_open(src, e->msgno);
909  if (!msg)
910  return -1;
911  int rc = append_message(dest, msg->fp, src, e, cmflags, chflags);
912  mx_msg_close(src, &msg);
913  return rc;
914 }
int mx_msg_close(struct Mailbox *m, struct Message **msg)
Close a message.
Definition: mx.c:1204
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:864
A local copy of an email.
Definition: mx.h:82
FILE * fp
pointer to the message data
Definition: mx.h:84
struct Message * mx_msg_open(struct Mailbox *m, int msgno)
return a stream pointer for a message
Definition: mx.c:1158
int msgno
Number displayed to the user.
Definition: email.h:87
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ format_address_header()

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

Write address headers to a buffer.

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

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

TODO fix that.

Definition at line 986 of file copy.c.

987 {
988  char buf[8192];
989  char cbuf[256];
990  char c2buf[256];
991  char *p = NULL;
992  size_t linelen, buflen, plen;
993 
994  linelen = mutt_str_len(*h);
995  plen = linelen;
996  buflen = linelen + 3;
997 
998  mutt_mem_realloc(h, buflen);
999  struct Address *first = TAILQ_FIRST(al);
1000  struct Address *a = NULL;
1001  TAILQ_FOREACH(a, al, entries)
1002  {
1003  *buf = '\0';
1004  *cbuf = '\0';
1005  *c2buf = '\0';
1006  const size_t l = mutt_addr_write(buf, sizeof(buf), a, false);
1007 
1008  if (a != first && (linelen + l > 74))
1009  {
1010  strcpy(cbuf, "\n\t");
1011  linelen = l + 8;
1012  }
1013  else
1014  {
1015  if (a->mailbox)
1016  {
1017  strcpy(cbuf, " ");
1018  linelen++;
1019  }
1020  linelen += l;
1021  }
1022  if (!a->group && TAILQ_NEXT(a, entries) && TAILQ_NEXT(a, entries)->mailbox)
1023  {
1024  linelen++;
1025  buflen++;
1026  strcpy(c2buf, ",");
1027  }
1028 
1029  const size_t cbuflen = mutt_str_len(cbuf);
1030  const size_t c2buflen = mutt_str_len(c2buf);
1031  buflen += l + cbuflen + c2buflen;
1032  mutt_mem_realloc(h, buflen);
1033  p = *h;
1034  strcat(p + plen, cbuf);
1035  plen += cbuflen;
1036  strcat(p + plen, buf);
1037  plen += l;
1038  strcat(p + plen, c2buf);
1039  plen += c2buflen;
1040  }
1041 
1042  /* Space for this was allocated in the beginning of this function. */
1043  strcat(p + plen, "\n");
1044 }
#define TAILQ_FIRST(head)
Definition: queue.h:716
#define TAILQ_FOREACH(var, head, field)
Definition: queue.h:718
static size_t plen
Length of cached packet.
Definition: pgppacket.c:39
An email address.
Definition: address.h:34
char * mailbox
Mailbox and host address.
Definition: address.h:37
size_t mutt_addr_write(char *buf, size_t buflen, struct Address *addr, bool display)
Write a single Address to a buffer.
Definition: address.c:1025
void mutt_mem_realloc(void *ptr, size_t size)
Resize a block of memory on the heap.
Definition: memory.c:114
size_t mutt_str_len(const char *a)
Calculate the length of a string, safely.
Definition: string.c:631
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: