NeoMutt  2020-08-21-74-g346364
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 1045 of file copy.c.

1046 {
1047  char *s = *h;
1048  size_t l;
1049  bool rp = false;
1050 
1051  switch (tolower((unsigned char) *s))
1052  {
1053  case 'b':
1054  {
1055  if (!(l = mutt_istr_startswith(s, "bcc:")))
1056  return 0;
1057  break;
1058  }
1059  case 'c':
1060  {
1061  if (!(l = mutt_istr_startswith(s, "cc:")))
1062  return 0;
1063  break;
1064  }
1065  case 'f':
1066  {
1067  if (!(l = mutt_istr_startswith(s, "from:")))
1068  return 0;
1069  break;
1070  }
1071  case 'm':
1072  {
1073  if (!(l = mutt_istr_startswith(s, "mail-followup-to:")))
1074  return 0;
1075  break;
1076  }
1077  case 'r':
1078  {
1079  if ((l = mutt_istr_startswith(s, "return-path:")))
1080  {
1081  rp = true;
1082  break;
1083  }
1084  else if ((l = mutt_istr_startswith(s, "reply-to:")))
1085  {
1086  break;
1087  }
1088  return 0;
1089  }
1090  case 's':
1091  {
1092  if (!(l = mutt_istr_startswith(s, "sender:")))
1093  return 0;
1094  break;
1095  }
1096  case 't':
1097  {
1098  if (!(l = mutt_istr_startswith(s, "to:")))
1099  return 0;
1100  break;
1101  }
1102  default:
1103  return 0;
1104  }
1105 
1106  struct AddressList al = TAILQ_HEAD_INITIALIZER(al);
1107  mutt_addrlist_parse(&al, s + l);
1108  if (TAILQ_EMPTY(&al))
1109  return 0;
1110 
1113  struct Address *a = NULL;
1114  TAILQ_FOREACH(a, &al, entries)
1115  {
1116  if (a->personal)
1117  {
1119  }
1120  }
1121 
1122  /* angle brackets for return path are mandated by RFC5322,
1123  * so leave Return-Path as-is */
1124  if (rp)
1125  *h = mutt_str_dup(s);
1126  else
1127  {
1128  *h = mutt_mem_calloc(1, l + 2);
1129  mutt_str_copy(*h, s, l + 1);
1130  format_address_header(h, &al);
1131  }
1132 
1133  mutt_addrlist_clear(&al);
1134 
1135  FREE(&s);
1136  return 1;
1137 }
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:979
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 922 of file copy.c.

923 {
924  struct Body *part = NULL;
925 
926  for (part = b->parts; part; part = part->next)
927  {
928  if (part->deleted || part->parts)
929  {
930  /* Copy till start of this part */
931  if (mutt_file_copy_bytes(fp_in, fp_out, part->hdr_offset - ftello(fp_in)))
932  return -1;
933 
934  if (part->deleted)
935  {
936  /* If this is modified, count_delete_lines() needs to be changed too */
937  fprintf(
938  fp_out,
939  "Content-Type: message/external-body; access-type=x-mutt-deleted;\n"
940  "\texpiration=%s; length=" OFF_T_FMT "\n"
941  "\n",
942  quoted_date, part->length);
943  if (ferror(fp_out))
944  return -1;
945 
946  /* Copy the original mime headers */
947  if (mutt_file_copy_bytes(fp_in, fp_out, part->offset - ftello(fp_in)))
948  return -1;
949 
950  /* Skip the deleted body */
951  fseeko(fp_in, part->offset + part->length, SEEK_SET);
952  }
953  else
954  {
955  if (copy_delete_attach(part, fp_in, fp_out, quoted_date))
956  return -1;
957  }
958  }
959  }
960 
961  /* Copy the last parts */
962  if (mutt_file_copy_bytes(fp_in, fp_out, b->offset + b->length - ftello(fp_in)))
963  return -1;
964 
965  return 0;
966 }
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:922
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(&value);
81  value = new_value;
82  }
83  ARRAY_SET(headers, pos, value);
84 }
#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 102 of file copy.c.

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

◆ mutt_copy_header()

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

Copy Email header.

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

Definition at line 398 of file copy.c.

400 {
401  char *temp_hdr = NULL;
402 
403  if (e->env)
404  {
405  chflags |= ((e->env->changed & MUTT_ENV_CHANGED_IRT) ? CH_UPDATE_IRT : 0) |
409  }
410 
411  if (mutt_copy_hdr(fp_in, fp_out, e->offset, e->body->offset, chflags, prefix, wraplen) == -1)
412  return -1;
413 
414  if (chflags & CH_TXTPLAIN)
415  {
416  char chsbuf[128];
417  char buf[128];
418  fputs("MIME-Version: 1.0\n", fp_out);
419  fputs("Content-Transfer-Encoding: 8bit\n", fp_out);
420  fputs("Content-Type: text/plain; charset=", fp_out);
421  mutt_ch_canonical_charset(chsbuf, sizeof(chsbuf), C_Charset ? C_Charset : "us-ascii");
422  mutt_addr_cat(buf, sizeof(buf), chsbuf, MimeSpecials);
423  fputs(buf, fp_out);
424  fputc('\n', fp_out);
425  }
426 
427  if ((chflags & CH_UPDATE_IRT) && !STAILQ_EMPTY(&e->env->in_reply_to))
428  {
429  fputs("In-Reply-To:", fp_out);
430  struct ListNode *np = NULL;
431  STAILQ_FOREACH(np, &e->env->in_reply_to, entries)
432  {
433  fputc(' ', fp_out);
434  fputs(np->data, fp_out);
435  }
436  fputc('\n', fp_out);
437  }
438 
439  if ((chflags & CH_UPDATE_REFS) && !STAILQ_EMPTY(&e->env->references))
440  {
441  fputs("References:", fp_out);
442  mutt_write_references(&e->env->references, fp_out, 0, NeoMutt->sub);
443  fputc('\n', fp_out);
444  }
445 
446  if ((chflags & CH_UPDATE) && ((chflags & CH_NOSTATUS) == 0))
447  {
448  if (e->old || e->read)
449  {
450  fputs("Status: ", fp_out);
451  if (e->read)
452  fputs("RO", fp_out);
453  else if (e->old)
454  fputc('O', fp_out);
455  fputc('\n', fp_out);
456  }
457 
458  if (e->flagged || e->replied)
459  {
460  fputs("X-Status: ", fp_out);
461  if (e->replied)
462  fputc('A', fp_out);
463  if (e->flagged)
464  fputc('F', fp_out);
465  fputc('\n', fp_out);
466  }
467  }
468 
469  if (chflags & CH_UPDATE_LEN && ((chflags & CH_NOLEN) == 0))
470  {
471  fprintf(fp_out, "Content-Length: " OFF_T_FMT "\n", e->body->length);
472  if ((e->lines != 0) || (e->body->length == 0))
473  fprintf(fp_out, "Lines: %d\n", e->lines);
474  }
475 
476 #ifdef USE_NOTMUCH
477  if (chflags & CH_VIRTUAL)
478  {
479  /* Add some fake headers based on notmuch data */
480  char *folder = nm_email_get_folder(e);
481  if (folder && !(C_Weed && mutt_matches_ignore("folder")))
482  {
483  char buf[1024];
484  mutt_str_copy(buf, folder, sizeof(buf));
485  mutt_pretty_mailbox(buf, sizeof(buf));
486 
487  fputs("Folder: ", fp_out);
488  fputs(buf, fp_out);
489  fputc('\n', fp_out);
490  }
491  }
492 #endif
493  char *tags = driver_tags_get(&e->tags);
494  if (tags && !(C_Weed && mutt_matches_ignore("tags")))
495  {
496  fputs("Tags: ", fp_out);
497  fputs(tags, fp_out);
498  fputc('\n', fp_out);
499  }
500  FREE(&tags);
501 
502  if ((chflags & CH_UPDATE_LABEL) && e->env->x_label)
503  {
504  temp_hdr = e->env->x_label;
505  /* env->x_label isn't currently stored with direct references elsewhere.
506  * Context->label_hash strdups the keys. But to be safe, encode a copy */
507  if (!(chflags & CH_DECODE))
508  {
509  temp_hdr = mutt_str_dup(temp_hdr);
510  rfc2047_encode(&temp_hdr, NULL, sizeof("X-Label:"), C_SendCharset);
511  }
513  fp_out, "X-Label", temp_hdr, (chflags & CH_PREFIX) ? prefix : 0,
514  mutt_window_wrap_cols(wraplen, C_Wrap), chflags, NeoMutt->sub) == -1)
515  {
516  return -1;
517  }
518  if (!(chflags & CH_DECODE))
519  FREE(&temp_hdr);
520  }
521 
522  if ((chflags & CH_UPDATE_SUBJECT) && e->env->subject)
523  {
524  temp_hdr = e->env->subject;
525  /* env->subject is directly referenced in Context->subj_hash, so we
526  * have to be careful not to encode (and thus free) that memory. */
527  if (!(chflags & CH_DECODE))
528  {
529  temp_hdr = mutt_str_dup(temp_hdr);
530  rfc2047_encode(&temp_hdr, NULL, sizeof("Subject:"), C_SendCharset);
531  }
533  fp_out, "Subject", temp_hdr, (chflags & CH_PREFIX) ? prefix : 0,
534  mutt_window_wrap_cols(wraplen, C_Wrap), chflags, NeoMutt->sub) == -1)
535  {
536  return -1;
537  }
538  if (!(chflags & CH_DECODE))
539  FREE(&temp_hdr);
540  }
541 
542  if ((chflags & CH_NONEWLINE) == 0)
543  {
544  if (chflags & CH_PREFIX)
545  fputs(prefix, fp_out);
546  fputc('\n', fp_out); /* add header terminator */
547  }
548 
549  if (ferror(fp_out) || feof(fp_out))
550  return -1;
551 
552  return 0;
553 }
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:1652
int mutt_window_wrap_cols(int width, short wrap)
Calculate the wrap column for a given screen width.
Definition: mutt_window.c:487
#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:102
#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 C_IndentString 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 565 of file copy.c.

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

611 {
612  struct Body *body = e->body;
613  char prefix[128];
614  LOFF_T new_offset = -1;
615  int rc = 0;
616 
617  if (cmflags & MUTT_CM_PREFIX)
618  {
619  if (C_TextFlowed)
620  mutt_str_copy(prefix, ">", sizeof(prefix));
621  else
622  {
623  mutt_make_string(prefix, sizeof(prefix), wraplen, NONULL(C_IndentString),
625  }
626  }
627 
628  if ((cmflags & MUTT_CM_NOHEADER) == 0)
629  {
630  if (cmflags & MUTT_CM_PREFIX)
631  chflags |= CH_PREFIX;
632  else if (e->attach_del && (chflags & CH_UPDATE_LEN))
633  {
634  int new_lines;
635  int rc_attach_del = -1;
636  LOFF_T new_length = body->length;
637  struct Buffer *quoted_date = NULL;
638 
639  quoted_date = mutt_buffer_pool_get();
640  mutt_buffer_addch(quoted_date, '"');
641  mutt_date_make_date(quoted_date);
642  mutt_buffer_addch(quoted_date, '"');
643 
644  /* Count the number of lines and bytes to be deleted */
645  fseeko(fp_in, body->offset, SEEK_SET);
646  new_lines = e->lines - count_delete_lines(fp_in, body, &new_length,
647  mutt_buffer_len(quoted_date));
648 
649  /* Copy the headers */
650  if (mutt_copy_header(fp_in, e, fp_out, chflags | CH_NOLEN | CH_NONEWLINE, NULL, wraplen))
651  goto attach_del_cleanup;
652  fprintf(fp_out, "Content-Length: " OFF_T_FMT "\n", new_length);
653  if (new_lines <= 0)
654  new_lines = 0;
655  else
656  fprintf(fp_out, "Lines: %d\n", new_lines);
657 
658  putc('\n', fp_out);
659  if (ferror(fp_out) || feof(fp_out))
660  goto attach_del_cleanup;
661  new_offset = ftello(fp_out);
662 
663  /* Copy the body */
664  if (fseeko(fp_in, body->offset, SEEK_SET) < 0)
665  goto attach_del_cleanup;
666  if (copy_delete_attach(body, fp_in, fp_out, mutt_b2s(quoted_date)))
667  goto attach_del_cleanup;
668 
669  mutt_buffer_pool_release(&quoted_date);
670 
671  LOFF_T fail = ((ftello(fp_out) - new_offset) - new_length);
672  if (fail)
673  {
674  mutt_error(ngettext("The length calculation was wrong by %ld byte",
675  "The length calculation was wrong by %ld bytes", fail),
676  fail);
677  new_length += fail;
678  }
679 
680  /* Update original message if we are sync'ing a mailfolder */
681  if (cmflags & MUTT_CM_UPDATE)
682  {
683  e->attach_del = false;
684  e->lines = new_lines;
685  body->offset = new_offset;
686 
687  /* update the total size of the mailbox to reflect this deletion */
688  Context->mailbox->size -= body->length - new_length;
689  /* if the message is visible, update the visible size of the mailbox as well. */
690  if (Context->mailbox->v2r[e->msgno] != -1)
691  Context->vsize -= body->length - new_length;
692 
693  body->length = new_length;
694  mutt_body_free(&body->parts);
695  }
696 
697  rc_attach_del = 0;
698 
699  attach_del_cleanup:
700  mutt_buffer_pool_release(&quoted_date);
701  return rc_attach_del;
702  }
703 
704  if (mutt_copy_header(fp_in, e, fp_out, chflags,
705  (chflags & CH_PREFIX) ? prefix : NULL, wraplen) == -1)
706  {
707  return -1;
708  }
709 
710  new_offset = ftello(fp_out);
711  }
712 
713  if (cmflags & MUTT_CM_DECODE)
714  {
715  /* now make a text/plain version of the message */
716  struct State s = { 0 };
717  s.fp_in = fp_in;
718  s.fp_out = fp_out;
719  if (cmflags & MUTT_CM_PREFIX)
720  s.prefix = prefix;
721  if (cmflags & MUTT_CM_DISPLAY)
722  {
723  s.flags |= MUTT_DISPLAY;
724  s.wraplen = wraplen;
725  }
726  if (cmflags & MUTT_CM_PRINTING)
727  s.flags |= MUTT_PRINTING;
728  if (cmflags & MUTT_CM_WEED)
729  s.flags |= MUTT_WEED;
730  if (cmflags & MUTT_CM_CHARCONV)
731  s.flags |= MUTT_CHARCONV;
732  if (cmflags & MUTT_CM_REPLYING)
733  s.flags |= MUTT_REPLYING;
734 
735  if ((WithCrypto != 0) && cmflags & MUTT_CM_VERIFY)
736  s.flags |= MUTT_VERIFY;
737 
738  rc = mutt_body_handler(body, &s);
739  }
740  else if ((WithCrypto != 0) && (cmflags & MUTT_CM_DECODE_CRYPT) && (e->security & SEC_ENCRYPT))
741  {
742  struct Body *cur = NULL;
743  FILE *fp = NULL;
744 
745  if (((WithCrypto & APPLICATION_PGP) != 0) && (cmflags & MUTT_CM_DECODE_PGP) &&
746  (e->security & APPLICATION_PGP) && (e->body->type == TYPE_MULTIPART))
747  {
748  if (crypt_pgp_decrypt_mime(fp_in, &fp, e->body, &cur))
749  return -1;
750  fputs("MIME-Version: 1.0\n", fp_out);
751  }
752 
753  if (((WithCrypto & APPLICATION_SMIME) != 0) && (cmflags & MUTT_CM_DECODE_SMIME) &&
754  (e->security & APPLICATION_SMIME) && (e->body->type == TYPE_APPLICATION))
755  {
756  if (crypt_smime_decrypt_mime(fp_in, &fp, e->body, &cur))
757  return -1;
758  }
759 
760  if (!cur)
761  {
762  mutt_error(_("No decryption engine available for message"));
763  return -1;
764  }
765 
766  mutt_write_mime_header(cur, fp_out, NeoMutt->sub);
767  fputc('\n', fp_out);
768 
769  if (fseeko(fp, cur->offset, SEEK_SET) < 0)
770  return -1;
771  if (mutt_file_copy_bytes(fp, fp_out, cur->length) == -1)
772  {
773  mutt_file_fclose(&fp);
774  mutt_body_free(&cur);
775  return -1;
776  }
777  mutt_body_free(&cur);
778  mutt_file_fclose(&fp);
779  }
780  else
781  {
782  if (fseeko(fp_in, body->offset, SEEK_SET) < 0)
783  return -1;
784  if (cmflags & MUTT_CM_PREFIX)
785  {
786  int c;
787  size_t bytes = body->length;
788 
789  fputs(prefix, fp_out);
790 
791  while (((c = fgetc(fp_in)) != EOF) && bytes--)
792  {
793  fputc(c, fp_out);
794  if (c == '\n')
795  {
796  fputs(prefix, fp_out);
797  }
798  }
799  }
800  else if (mutt_file_copy_bytes(fp_in, fp_out, body->length) == -1)
801  return -1;
802  }
803 
804  if ((cmflags & MUTT_CM_UPDATE) && ((cmflags & MUTT_CM_NOHEADER) == 0) &&
805  (new_offset != -1))
806  {
807  body->offset = new_offset;
808  mutt_body_free(&body->parts);
809  }
810 
811  return rc;
812 }
#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:565
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:760
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:922
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:398
#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 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
#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:165
+ 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 828 of file copy.c.

830 {
831  struct Message *msg = mx_msg_open(m, e->msgno);
832  if (!msg)
833  return -1;
834  if (!e->body)
835  return -1;
836  int rc = mutt_copy_message_fp(fp_out, msg->fp, e, cmflags, chflags, wraplen);
837  if ((rc == 0) && (ferror(fp_out) || feof(fp_out)))
838  {
839  mutt_debug(LL_DEBUG1, "failed to detect EOF!\n");
840  rc = -1;
841  }
842  mx_msg_close(m, &msg);
843  return rc;
844 }
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:1206
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:609
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 857 of file copy.c.

859 {
860  char buf[256];
861  struct Message *msg = NULL;
862  int rc;
863 
864  if (fseeko(fp_in, e->offset, SEEK_SET) < 0)
865  return -1;
866  if (!fgets(buf, sizeof(buf), fp_in))
867  return -1;
868 
869  msg = mx_msg_open_new(dest, e, is_from(buf, NULL, 0, NULL) ? MUTT_MSG_NO_FLAGS : MUTT_ADD_FROM);
870  if (!msg)
871  return -1;
872  if ((dest->type == MUTT_MBOX) || (dest->type == MUTT_MMDF))
873  chflags |= CH_FROM | CH_FORCE_FROM;
874  chflags |= ((dest->type == MUTT_MAILDIR) ? CH_NOSTATUS : CH_UPDATE);
875  rc = mutt_copy_message_fp(msg->fp, fp_in, e, cmflags, chflags, 0);
876  if (mx_msg_commit(dest, msg) != 0)
877  rc = -1;
878 
879 #ifdef USE_NOTMUCH
880  if (msg->committed_path && (dest->type == MUTT_MAILDIR) && (src->type == MUTT_NOTMUCH))
881  nm_update_filename(src, NULL, msg->committed_path, e);
882 #endif
883 
884  mx_msg_close(dest, &msg);
885  return rc;
886 }
#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:1917
int mx_msg_close(struct Mailbox *m, struct Message **msg)
Close a message.
Definition: mx.c:1206
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:1185
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:609
#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 898 of file copy.c.

900 {
901  struct Message *msg = mx_msg_open(src, e->msgno);
902  if (!msg)
903  return -1;
904  int rc = append_message(dest, msg->fp, src, e, cmflags, chflags);
905  mx_msg_close(src, &msg);
906  return rc;
907 }
int mx_msg_close(struct Mailbox *m, struct Message **msg)
Close a message.
Definition: mx.c:1206
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:857
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 979 of file copy.c.

980 {
981  char buf[8192];
982  char cbuf[256];
983  char c2buf[256];
984  char *p = NULL;
985  size_t linelen, buflen, plen;
986 
987  linelen = mutt_str_len(*h);
988  plen = linelen;
989  buflen = linelen + 3;
990 
991  mutt_mem_realloc(h, buflen);
992  struct Address *first = TAILQ_FIRST(al);
993  struct Address *a = NULL;
994  TAILQ_FOREACH(a, al, entries)
995  {
996  *buf = '\0';
997  *cbuf = '\0';
998  *c2buf = '\0';
999  const size_t l = mutt_addr_write(buf, sizeof(buf), a, false);
1000 
1001  if (a != first && (linelen + l > 74))
1002  {
1003  strcpy(cbuf, "\n\t");
1004  linelen = l + 8;
1005  }
1006  else
1007  {
1008  if (a->mailbox)
1009  {
1010  strcpy(cbuf, " ");
1011  linelen++;
1012  }
1013  linelen += l;
1014  }
1015  if (!a->group && TAILQ_NEXT(a, entries) && TAILQ_NEXT(a, entries)->mailbox)
1016  {
1017  linelen++;
1018  buflen++;
1019  strcpy(c2buf, ",");
1020  }
1021 
1022  const size_t cbuflen = mutt_str_len(cbuf);
1023  const size_t c2buflen = mutt_str_len(c2buf);
1024  buflen += l + cbuflen + c2buflen;
1025  mutt_mem_realloc(h, buflen);
1026  p = *h;
1027  strcat(p + plen, cbuf);
1028  plen += cbuflen;
1029  strcat(p + plen, buf);
1030  plen += l;
1031  strcat(p + plen, c2buf);
1032  plen += c2buflen;
1033  }
1034 
1035  /* Space for this was allocated in the beginning of this function. */
1036  strcat(p + plen, "\n");
1037 }
#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: