NeoMutt  2021-02-05-666-ge300cd
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 "config/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 "format_flags.h"
#include "handler.h"
#include "hdrline.h"
#include "mutt_globals.h"
#include "mx.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, struct Message *msg, 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 *m_dst, struct Mailbox *m_src, struct Email *e, struct Message *msg, 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 1077 of file copy.c.

1078 {
1079  char *s = *h;
1080  size_t l;
1081  bool rp = false;
1082 
1083  switch (tolower((unsigned char) *s))
1084  {
1085  case 'b':
1086  {
1087  if (!(l = mutt_istr_startswith(s, "bcc:")))
1088  return 0;
1089  break;
1090  }
1091  case 'c':
1092  {
1093  if (!(l = mutt_istr_startswith(s, "cc:")))
1094  return 0;
1095  break;
1096  }
1097  case 'f':
1098  {
1099  if (!(l = mutt_istr_startswith(s, "from:")))
1100  return 0;
1101  break;
1102  }
1103  case 'm':
1104  {
1105  if (!(l = mutt_istr_startswith(s, "mail-followup-to:")))
1106  return 0;
1107  break;
1108  }
1109  case 'r':
1110  {
1111  if ((l = mutt_istr_startswith(s, "return-path:")))
1112  {
1113  rp = true;
1114  break;
1115  }
1116  else if ((l = mutt_istr_startswith(s, "reply-to:")))
1117  {
1118  break;
1119  }
1120  return 0;
1121  }
1122  case 's':
1123  {
1124  if (!(l = mutt_istr_startswith(s, "sender:")))
1125  return 0;
1126  break;
1127  }
1128  case 't':
1129  {
1130  if (!(l = mutt_istr_startswith(s, "to:")))
1131  return 0;
1132  break;
1133  }
1134  default:
1135  return 0;
1136  }
1137 
1138  struct AddressList al = TAILQ_HEAD_INITIALIZER(al);
1139  mutt_addrlist_parse(&al, s + l);
1140  if (TAILQ_EMPTY(&al))
1141  return 0;
1142 
1145  struct Address *a = NULL;
1146  TAILQ_FOREACH(a, &al, entries)
1147  {
1148  if (a->personal)
1149  {
1151  }
1152  }
1153 
1154  /* angle brackets for return path are mandated by RFC5322,
1155  * so leave Return-Path as-is */
1156  if (rp)
1157  *h = mutt_str_dup(s);
1158  else
1159  {
1160  *h = mutt_mem_calloc(1, l + 2);
1161  mutt_str_copy(*h, s, l + 1);
1162  format_address_header(h, &al);
1163  }
1164 
1165  mutt_addrlist_clear(&al);
1166 
1167  FREE(&s);
1168  return 1;
1169 }
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:1011
void rfc2047_decode_addrlist(struct AddressList *al)
Decode any RFC2047 headers in an Address list.
Definition: rfc2047.c:764
#define TAILQ_FOREACH(var, head, field)
Definition: queue.h:725
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:1388
void mutt_addrlist_clear(struct AddressList *al)
Unlink and free all Address in an AddressList.
Definition: address.c:1470
void mutt_str_dequote_comment(char *str)
Un-escape characters in an email address comment.
Definition: string.c:872
char * mutt_str_dup(const char *str)
Copy a string, safely.
Definition: string.c:370
An email address.
Definition: address.h:35
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: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:749
#define FREE(x)
Definition: memory.h:40
#define TAILQ_EMPTY(head)
Definition: queue.h:721
#define TAILQ_HEAD_INITIALIZER(head)
Definition: queue.h:637
+ 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 954 of file copy.c.

955 {
956  struct Body *part = NULL;
957 
958  for (part = b->parts; part; part = part->next)
959  {
960  if (part->deleted || part->parts)
961  {
962  /* Copy till start of this part */
963  if (mutt_file_copy_bytes(fp_in, fp_out, part->hdr_offset - ftello(fp_in)))
964  return -1;
965 
966  if (part->deleted)
967  {
968  /* If this is modified, count_delete_lines() needs to be changed too */
969  fprintf(
970  fp_out,
971  "Content-Type: message/external-body; access-type=x-mutt-deleted;\n"
972  "\texpiration=%s; length=" OFF_T_FMT "\n"
973  "\n",
974  quoted_date, part->length);
975  if (ferror(fp_out))
976  return -1;
977 
978  /* Copy the original mime headers */
979  if (mutt_file_copy_bytes(fp_in, fp_out, part->offset - ftello(fp_in)))
980  return -1;
981 
982  /* Skip the deleted body */
983  fseeko(fp_in, part->offset + part->length, SEEK_SET);
984  }
985  else
986  {
987  if (copy_delete_attach(part, fp_in, fp_out, quoted_date))
988  return -1;
989  }
990  }
991  }
992 
993  /* Copy the last parts */
994  if (mutt_file_copy_bytes(fp_in, fp_out, b->offset + b->length - ftello(fp_in)))
995  return -1;
996 
997  return 0;
998 }
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:954
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 74 of file copy.c.

75 {
76  char **old = ARRAY_GET(headers, pos);
77  if (old && *old)
78  {
79  char *new_value = NULL;
80  mutt_str_asprintf(&new_value, "%s%s", *old, value);
81  FREE(old);
82  FREE(&value);
83  value = new_value;
84  }
85  ARRAY_SET(headers, pos, value);
86 }
#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:1128
+ 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 104 of file copy.c.

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

415 {
416  char *temp_hdr = NULL;
417 
418  if (e->env)
419  {
420  chflags |= ((e->env->changed & MUTT_ENV_CHANGED_IRT) ? CH_UPDATE_IRT : 0) |
424  }
425 
426  if (mutt_copy_hdr(fp_in, fp_out, e->offset, e->body->offset, chflags, prefix, wraplen) == -1)
427  return -1;
428 
429  if (chflags & CH_TXTPLAIN)
430  {
431  char chsbuf[128];
432  char buf[128];
433  fputs("MIME-Version: 1.0\n", fp_out);
434  fputs("Content-Transfer-Encoding: 8bit\n", fp_out);
435  fputs("Content-Type: text/plain; charset=", fp_out);
436  const char *const c_charset = cs_subset_string(NeoMutt->sub, "charset");
437  mutt_ch_canonical_charset(chsbuf, sizeof(chsbuf), c_charset ? c_charset : "us-ascii");
438  mutt_addr_cat(buf, sizeof(buf), chsbuf, MimeSpecials);
439  fputs(buf, fp_out);
440  fputc('\n', fp_out);
441  }
442 
443  if ((chflags & CH_UPDATE_IRT) && !STAILQ_EMPTY(&e->env->in_reply_to))
444  {
445  fputs("In-Reply-To:", fp_out);
446  struct ListNode *np = NULL;
447  STAILQ_FOREACH(np, &e->env->in_reply_to, entries)
448  {
449  fputc(' ', fp_out);
450  fputs(np->data, fp_out);
451  }
452  fputc('\n', fp_out);
453  }
454 
455  if ((chflags & CH_UPDATE_REFS) && !STAILQ_EMPTY(&e->env->references))
456  {
457  fputs("References:", fp_out);
458  mutt_write_references(&e->env->references, fp_out, 0, NeoMutt->sub);
459  fputc('\n', fp_out);
460  }
461 
462  if ((chflags & CH_UPDATE) && ((chflags & CH_NOSTATUS) == 0))
463  {
464  if (e->old || e->read)
465  {
466  fputs("Status: ", fp_out);
467  if (e->read)
468  fputs("RO", fp_out);
469  else if (e->old)
470  fputc('O', fp_out);
471  fputc('\n', fp_out);
472  }
473 
474  if (e->flagged || e->replied)
475  {
476  fputs("X-Status: ", fp_out);
477  if (e->replied)
478  fputc('A', fp_out);
479  if (e->flagged)
480  fputc('F', fp_out);
481  fputc('\n', fp_out);
482  }
483  }
484 
485  if (chflags & CH_UPDATE_LEN && ((chflags & CH_NOLEN) == 0))
486  {
487  fprintf(fp_out, "Content-Length: " OFF_T_FMT "\n", e->body->length);
488  if ((e->lines != 0) || (e->body->length == 0))
489  fprintf(fp_out, "Lines: %d\n", e->lines);
490  }
491 
492  const bool c_weed = cs_subset_bool(NeoMutt->sub, "weed");
493 #ifdef USE_NOTMUCH
494  if (chflags & CH_VIRTUAL)
495  {
496  /* Add some fake headers based on notmuch data */
497  char *folder = nm_email_get_folder(e);
498  if (folder && !(c_weed && mutt_matches_ignore("folder")))
499  {
500  char buf[1024];
501  mutt_str_copy(buf, folder, sizeof(buf));
502  mutt_pretty_mailbox(buf, sizeof(buf));
503 
504  fputs("Folder: ", fp_out);
505  fputs(buf, fp_out);
506  fputc('\n', fp_out);
507  }
508  }
509 #endif
510  char *tags = driver_tags_get(&e->tags);
511  if (tags && !(c_weed && mutt_matches_ignore("tags")))
512  {
513  fputs("Tags: ", fp_out);
514  fputs(tags, fp_out);
515  fputc('\n', fp_out);
516  }
517  FREE(&tags);
518 
519  const char *const c_send_charset =
520  cs_subset_string(NeoMutt->sub, "send_charset");
521  const short c_wrap = cs_subset_number(NeoMutt->sub, "wrap");
522  if ((chflags & CH_UPDATE_LABEL) && e->env->x_label)
523  {
524  temp_hdr = e->env->x_label;
525  /* env->x_label isn't currently stored with direct references elsewhere.
526  * Context->label_hash strdups the keys. But to be safe, encode a copy */
527  if (!(chflags & CH_DECODE))
528  {
529  temp_hdr = mutt_str_dup(temp_hdr);
530  rfc2047_encode(&temp_hdr, NULL, sizeof("X-Label:"), c_send_charset);
531  }
533  fp_out, "X-Label", 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_UPDATE_SUBJECT) && e->env->subject)
543  {
544  temp_hdr = e->env->subject;
545  /* env->subject is directly referenced in Context->subj_hash, so we
546  * have to be careful not to encode (and thus free) that memory. */
547  if (!(chflags & CH_DECODE))
548  {
549  temp_hdr = mutt_str_dup(temp_hdr);
550  rfc2047_encode(&temp_hdr, NULL, sizeof("Subject:"), c_send_charset);
551  }
553  fp_out, "Subject", temp_hdr, (chflags & CH_PREFIX) ? prefix : 0,
554  mutt_window_wrap_cols(wraplen, c_wrap), chflags, NeoMutt->sub) == -1)
555  {
556  return -1;
557  }
558  if (!(chflags & CH_DECODE))
559  FREE(&temp_hdr);
560  }
561 
562  if ((chflags & CH_NONEWLINE) == 0)
563  {
564  if (chflags & CH_PREFIX)
565  fputs(prefix, fp_out);
566  fputc('\n', fp_out); /* add header terminator */
567  }
568 
569  if (ferror(fp_out) || feof(fp_out))
570  return -1;
571 
572  return 0;
573 }
bool mutt_matches_ignore(const char *s)
Does the string match the ignore list.
Definition: parse.c:316
void mutt_pretty_mailbox(char *buf, size_t buflen)
Shorten a mailbox path using &#39;~&#39; or &#39;=&#39;.
Definition: muttlib.c:526
int lines
How many lines in the body of this message?
Definition: email.h:85
bool cs_subset_bool(const struct ConfigSubset *sub, const char *name)
Get a boolean config item by name.
Definition: helpers.c:73
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:58
#define CH_UPDATE
Update the status and x-status fields?
Definition: copy.h:52
#define CH_UPDATE_REFS
Update References:
Definition: copy.h:69
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:515
short cs_subset_number(const struct ConfigSubset *sub, const char *name)
Get a number config item by name.
Definition: helpers.c:169
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:73
struct TagList tags
For drivers that support server tagging.
Definition: email.h:109
#define CH_TXTPLAIN
Generate text/plain MIME headers.
Definition: copy.h:63
#define CH_UPDATE_LABEL
Update X-Label: from email->env->x_label?
Definition: copy.h:71
#define MUTT_ENV_CHANGED_XLABEL
X-Label edited.
Definition: envelope.h:34
#define CH_UPDATE_IRT
Update In-Reply-To:
Definition: copy.h:68
LOFF_T length
length (in bytes) of attachment
Definition: body.h:45
char * driver_tags_get(struct TagList *list)
Get tags.
Definition: tags.c:145
const char MimeSpecials[]
Characters that need special treatment in MIME.
Definition: mime.c:67
#define CH_DECODE
Do RFC2047 header decoding.
Definition: copy.h:54
char * nm_email_get_folder(struct Email *e)
Get the folder for a Email.
Definition: notmuch.c:1458
const char * cs_subset_string(const struct ConfigSubset *sub, const char *name)
Get a string config item by name.
Definition: helpers.c:317
int mutt_window_wrap_cols(int width, short wrap)
Calculate the wrap column for a given screen width.
Definition: mutt_window.c:386
#define CH_UPDATE_LEN
Update Lines: and Content-Length:
Definition: copy.h:62
#define STAILQ_FOREACH(var, head, field)
Definition: queue.h:352
#define CH_NOLEN
Don&#39;t write Content-Length: and Lines:
Definition: copy.h:64
#define CH_UPDATE_SUBJECT
Update Subject: protected header update.
Definition: copy.h:72
void rfc2047_encode(char **pd, const char *specials, int col, const char *charsets)
RFC-2047-encode a string.
Definition: rfc2047.c:616
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:749
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:104
#define FREE(x)
Definition: memory.h:40
#define STAILQ_EMPTY(head)
Definition: queue.h:348
#define MUTT_ENV_CHANGED_REFS
References changed to break thread.
Definition: envelope.h:33
struct ConfigSubset * sub
Inherited config items.
Definition: neomutt.h:39
#define MUTT_ENV_CHANGED_IRT
In-Reply-To changed to link/break threads.
Definition: envelope.h:32
struct ListHead references
message references (in reverse order)
Definition: envelope.h:81
A List node for strings.
Definition: list.h:34
char * x_label
X-Label.
Definition: envelope.h:72
#define CH_PREFIX
Quote header using $indent_string string?
Definition: copy.h:57
void mutt_ch_canonical_charset(char *buf, size_t buflen, const char *name)
Canonicalise the charset of a string.
Definition: charset.c:354
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:420
#define CH_NONEWLINE
Don&#39;t output terminating newline after the header.
Definition: copy.h:60
+ 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 585 of file copy.c.

586 {
587  int dellines = 0;
588 
589  if (b->deleted)
590  {
591  fseeko(fp, b->offset, SEEK_SET);
592  for (long l = b->length; l; l--)
593  {
594  const int ch = getc(fp);
595  if (ch == EOF)
596  break;
597  if (ch == '\n')
598  dellines++;
599  }
600  /* 3 and 89 come from the added header of three lines in
601  * copy_delete_attach(). 89 is the size of the header(including
602  * the newlines, tabs, and a single digit length), not including
603  * the date length. */
604  dellines -= 3;
605  *length -= b->length - (89 + datelen);
606  /* Count the number of digits exceeding the first one to write the size */
607  for (long l = 10; b->length >= l; l *= 10)
608  (*length)++;
609  }
610  else
611  {
612  for (b = b->parts; b; b = b->next)
613  dellines += count_delete_lines(fp, b, length, datelen);
614  }
615  return dellines;
616 }
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:585
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 629 of file copy.c.

631 {
632  struct Body *body = e->body;
633  char prefix[128];
634  LOFF_T new_offset = -1;
635  int rc = 0;
636 
637  if (cmflags & MUTT_CM_PREFIX)
638  {
639  const bool c_text_flowed = cs_subset_bool(NeoMutt->sub, "text_flowed");
640  if (c_text_flowed)
641  mutt_str_copy(prefix, ">", sizeof(prefix));
642  else
643  {
644  const char *const c_indent_string =
645  cs_subset_string(NeoMutt->sub, "indent_string");
646  mutt_make_string(prefix, sizeof(prefix), wraplen, NONULL(c_indent_string),
647  Context->mailbox, -1, e, MUTT_FORMAT_NO_FLAGS, NULL);
648  }
649  }
650 
651  if ((cmflags & MUTT_CM_NOHEADER) == 0)
652  {
653  if (cmflags & MUTT_CM_PREFIX)
654  chflags |= CH_PREFIX;
655  else if (e->attach_del && (chflags & CH_UPDATE_LEN))
656  {
657  int new_lines;
658  int rc_attach_del = -1;
659  LOFF_T new_length = body->length;
660  struct Buffer *quoted_date = NULL;
661 
662  quoted_date = mutt_buffer_pool_get();
663  mutt_buffer_addch(quoted_date, '"');
664  mutt_date_make_date(quoted_date,
665  cs_subset_bool(NeoMutt->sub, "local_date_header"));
666  mutt_buffer_addch(quoted_date, '"');
667 
668  /* Count the number of lines and bytes to be deleted */
669  fseeko(fp_in, body->offset, SEEK_SET);
670  new_lines = e->lines - count_delete_lines(fp_in, body, &new_length,
671  mutt_buffer_len(quoted_date));
672 
673  /* Copy the headers */
674  if (mutt_copy_header(fp_in, e, fp_out, chflags | CH_NOLEN | CH_NONEWLINE, NULL, wraplen))
675  goto attach_del_cleanup;
676  fprintf(fp_out, "Content-Length: " OFF_T_FMT "\n", new_length);
677  if (new_lines <= 0)
678  new_lines = 0;
679  else
680  fprintf(fp_out, "Lines: %d\n", new_lines);
681 
682  putc('\n', fp_out);
683  if (ferror(fp_out) || feof(fp_out))
684  goto attach_del_cleanup;
685  new_offset = ftello(fp_out);
686 
687  /* Copy the body */
688  if (fseeko(fp_in, body->offset, SEEK_SET) < 0)
689  goto attach_del_cleanup;
690  if (copy_delete_attach(body, fp_in, fp_out, mutt_buffer_string(quoted_date)))
691  goto attach_del_cleanup;
692 
693  mutt_buffer_pool_release(&quoted_date);
694 
695  LOFF_T fail = ((ftello(fp_out) - new_offset) - new_length);
696  if (fail)
697  {
698  mutt_error(ngettext("The length calculation was wrong by %ld byte",
699  "The length calculation was wrong by %ld bytes", fail),
700  fail);
701  new_length += fail;
702  }
703 
704  /* Update original message if we are sync'ing a mailfolder */
705  if (cmflags & MUTT_CM_UPDATE)
706  {
707  e->attach_del = false;
708  e->lines = new_lines;
709  body->offset = new_offset;
710 
711  /* update the total size of the mailbox to reflect this deletion */
712  Context->mailbox->size -= body->length - new_length;
713  /* if the message is visible, update the visible size of the mailbox as well. */
714  if (Context->mailbox->v2r[e->msgno] != -1)
715  Context->vsize -= body->length - new_length;
716 
717  body->length = new_length;
718  mutt_body_free(&body->parts);
719  }
720 
721  rc_attach_del = 0;
722 
723  attach_del_cleanup:
724  mutt_buffer_pool_release(&quoted_date);
725  return rc_attach_del;
726  }
727 
728  if (mutt_copy_header(fp_in, e, fp_out, chflags,
729  (chflags & CH_PREFIX) ? prefix : NULL, wraplen) == -1)
730  {
731  return -1;
732  }
733 
734  new_offset = ftello(fp_out);
735  }
736 
737  if (cmflags & MUTT_CM_DECODE)
738  {
739  /* now make a text/plain version of the message */
740  struct State s = { 0 };
741  s.fp_in = fp_in;
742  s.fp_out = fp_out;
743  if (cmflags & MUTT_CM_PREFIX)
744  s.prefix = prefix;
745  if (cmflags & MUTT_CM_DISPLAY)
746  {
747  s.flags |= MUTT_DISPLAY;
748  s.wraplen = wraplen;
749  }
750  if (cmflags & MUTT_CM_PRINTING)
751  s.flags |= MUTT_PRINTING;
752  if (cmflags & MUTT_CM_WEED)
753  s.flags |= MUTT_WEED;
754  if (cmflags & MUTT_CM_CHARCONV)
755  s.flags |= MUTT_CHARCONV;
756  if (cmflags & MUTT_CM_REPLYING)
757  s.flags |= MUTT_REPLYING;
758 
759  if ((WithCrypto != 0) && cmflags & MUTT_CM_VERIFY)
760  s.flags |= MUTT_VERIFY;
761 
762  rc = mutt_body_handler(body, &s);
763  }
764  else if ((WithCrypto != 0) && (cmflags & MUTT_CM_DECODE_CRYPT) && (e->security & SEC_ENCRYPT))
765  {
766  struct Body *cur = NULL;
767  FILE *fp = NULL;
768 
769  if (((WithCrypto & APPLICATION_PGP) != 0) && (cmflags & MUTT_CM_DECODE_PGP) &&
770  (e->security & APPLICATION_PGP) && (e->body->type == TYPE_MULTIPART))
771  {
772  if (crypt_pgp_decrypt_mime(fp_in, &fp, e->body, &cur))
773  return -1;
774  fputs("MIME-Version: 1.0\n", fp_out);
775  }
776 
777  if (((WithCrypto & APPLICATION_SMIME) != 0) && (cmflags & MUTT_CM_DECODE_SMIME) &&
778  (e->security & APPLICATION_SMIME) && (e->body->type == TYPE_APPLICATION))
779  {
780  if (crypt_smime_decrypt_mime(fp_in, &fp, e->body, &cur))
781  return -1;
782  }
783 
784  if (!cur)
785  {
786  mutt_error(_("No decryption engine available for message"));
787  return -1;
788  }
789 
790  mutt_write_mime_header(cur, fp_out, NeoMutt->sub);
791  fputc('\n', fp_out);
792 
793  if (fseeko(fp, cur->offset, SEEK_SET) < 0)
794  return -1;
795  if (mutt_file_copy_bytes(fp, fp_out, cur->length) == -1)
796  {
797  mutt_file_fclose(&fp);
798  mutt_body_free(&cur);
799  return -1;
800  }
801  mutt_body_free(&cur);
802  mutt_file_fclose(&fp);
803  }
804  else
805  {
806  if (fseeko(fp_in, body->offset, SEEK_SET) < 0)
807  return -1;
808  if (cmflags & MUTT_CM_PREFIX)
809  {
810  int c;
811  size_t bytes = body->length;
812 
813  fputs(prefix, fp_out);
814 
815  while (((c = fgetc(fp_in)) != EOF) && bytes--)
816  {
817  fputc(c, fp_out);
818  if (c == '\n')
819  {
820  fputs(prefix, fp_out);
821  }
822  }
823  }
824  else if (mutt_file_copy_bytes(fp_in, fp_out, body->length) == -1)
825  return -1;
826  }
827 
828  if ((cmflags & MUTT_CM_UPDATE) && ((cmflags & MUTT_CM_NOHEADER) == 0) &&
829  (new_offset != -1))
830  {
831  body->offset = new_offset;
832  mutt_body_free(&body->parts);
833  }
834 
835  return rc;
836 }
#define MUTT_CM_DECODE_CRYPT
Definition: copy.h:48
The "current" mailbox.
Definition: context.h:37
#define MUTT_DISPLAY
Output is displayed to the user.
Definition: state.h:32
int lines
How many lines in the body of this message?
Definition: email.h:85
#define NONULL(x)
Definition: string2.h:37
off_t size
Size of the Mailbox.
Definition: mailbox.h:87
bool cs_subset_bool(const struct ConfigSubset *sub, const char *name)
Get a boolean config item by name.
Definition: helpers.c:73
#define WithCrypto
Definition: lib.h:113
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_error(...)
Definition: logging.h:88
#define MUTT_CM_UPDATE
Update structs on sync.
Definition: copy.h:40
#define SEC_ENCRYPT
Email is encrypted.
Definition: lib.h:75
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:41
String manipulation buffer.
Definition: buffer.h:33
void mutt_date_make_date(struct Buffer *buf, bool local)
Write a date in RFC822 format to a buffer.
Definition: date.c:378
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:585
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:43
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:44
#define MUTT_FORMAT_NO_FLAGS
No flags are set.
Definition: format_flags.h:30
The body of an email.
Definition: body.h:34
static const char * mutt_buffer_string(const struct Buffer *buf)
Convert a buffer to a const char * "string".
Definition: buffer.h:77
StateFlags flags
Flags, e.g. MUTT_DISPLAY.
Definition: state.h:49
struct Mailbox * mailbox
Definition: context.h:49
#define MUTT_CM_DISPLAY
Output is displayed to the user.
Definition: copy.h:39
int mutt_file_fclose(FILE **fp)
Close a FILE handle (and NULL the pointer)
Definition: file.c:153
void mutt_make_string(char *buf, size_t buflen, int cols, const char *s, struct Mailbox *m, int inpgr, struct Email *e, MuttFormatFlags flags, const char *progress)
Create formatted strings using mailbox expandos.
Definition: hdrline.c:1409
int mutt_write_mime_header(struct Body *a, FILE *fp, struct ConfigSubset *sub)
Create a MIME header.
Definition: header.c:764
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:39
#define APPLICATION_SMIME
Use SMIME to encrypt/sign.
Definition: lib.h:88
#define MUTT_CM_PREFIX
Quote the header and body.
Definition: copy.h:37
#define APPLICATION_PGP
Use PGP to encrypt/sign.
Definition: lib.h:87
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:38
#define MUTT_VERIFY
Perform signature verification.
Definition: state.h:33
#define MUTT_CM_CHARCONV
Perform character set conversions.
Definition: copy.h:42
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:954
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
const char * cs_subset_string(const struct ConfigSubset *sub, const char *name)
Get a string config item by name.
Definition: helpers.c:317
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:439
#define CH_UPDATE_LEN
Update Lines: and Content-Length:
Definition: copy.h:62
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:47
#define CH_NOLEN
Don&#39;t write Content-Length: and Lines:
Definition: copy.h:64
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:46
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:212
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:749
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:413
#define MUTT_CM_DECODE_PGP
Used for decoding PGP messages.
Definition: copy.h:45
#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:1604
struct ConfigSubset * sub
Inherited config items.
Definition: neomutt.h:39
#define MUTT_CM_NOHEADER
Don&#39;t copy the message header.
Definition: copy.h:36
#define CH_PREFIX
Quote header using $indent_string string?
Definition: copy.h:57
Type: &#39;application/*&#39;.
Definition: mime.h:33
#define CH_NONEWLINE
Don&#39;t output terminating newline after the header.
Definition: copy.h:60
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:

◆ mutt_copy_message()

int mutt_copy_message ( FILE *  fp_out,
struct Mailbox m,
struct Email e,
struct Message msg,
CopyMessageFlags  cmflags,
CopyHeaderFlags  chflags,
int  wraplen 
)

Copy a message from a Mailbox.

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

856 {
857  if (!msg || !e->body)
858  {
859  return -1;
860  }
861  int rc = mutt_copy_message_fp(fp_out, msg->fp, e, cmflags, chflags, wraplen);
862  if ((rc == 0) && (ferror(fp_out) || feof(fp_out)))
863  {
864  mutt_debug(LL_DEBUG1, "failed to detect EOF!\n");
865  rc = -1;
866  }
867  return rc;
868 }
struct Body * body
List of MIME parts.
Definition: email.h:91
#define mutt_debug(LEVEL,...)
Definition: logging.h:85
Log at debug level 1.
Definition: logging.h:40
FILE * fp
pointer to the message data
Definition: mxapi.h:43
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:629
+ 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 881 of file copy.c.

883 {
884  char buf[256];
885  struct Message *msg = NULL;
886  int rc;
887 
888  if (fseeko(fp_in, e->offset, SEEK_SET) < 0)
889  return -1;
890  if (!fgets(buf, sizeof(buf), fp_in))
891  return -1;
892 
893  msg = mx_msg_open_new(dest, e, is_from(buf, NULL, 0, NULL) ? MUTT_MSG_NO_FLAGS : MUTT_ADD_FROM);
894  if (!msg)
895  return -1;
896  if ((dest->type == MUTT_MBOX) || (dest->type == MUTT_MMDF))
897  chflags |= CH_FROM | CH_FORCE_FROM;
898  chflags |= ((dest->type == MUTT_MAILDIR) ? CH_NOSTATUS : CH_UPDATE);
899  rc = mutt_copy_message_fp(msg->fp, fp_in, e, cmflags, chflags, 0);
900  if (mx_msg_commit(dest, msg) != 0)
901  rc = -1;
902 
903 #ifdef USE_NOTMUCH
904  if (msg->committed_path && (dest->type == MUTT_MAILDIR) && (src->type == MUTT_NOTMUCH))
905  nm_update_filename(src, NULL, msg->committed_path, e);
906 #endif
907 
908  mx_msg_close(dest, &msg);
909  return rc;
910 }
#define MUTT_MSG_NO_FLAGS
No flags are set.
Definition: mx.h:41
enum MailboxType type
Mailbox type.
Definition: mailbox.h:105
#define CH_FROM
Retain the "From " message separator?
Definition: copy.h:56
#define CH_NOSTATUS
Suppress the status and x-status fields.
Definition: copy.h:58
#define CH_UPDATE
Update the status and x-status fields?
Definition: copy.h:52
int nm_update_filename(struct Mailbox *m, const char *old_file, const char *new_file, struct Email *e)
Change the filename.
Definition: notmuch.c:1747
int mx_msg_close(struct Mailbox *m, struct Message **msg)
Close a message.
Definition: mx.c:1186
struct Message * mx_msg_open_new(struct Mailbox *m, const struct Email *e, MsgOpenFlags flags)
Open a new message.
Definition: mx.c:1054
&#39;Maildir&#39; Mailbox type
Definition: mailbox.h:51
#define CH_FORCE_FROM
Give CH_FROM precedence over CH_WEED?
Definition: copy.h:66
A local copy of an email.
Definition: mxapi.h:41
&#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: mxapi.h:45
int mx_msg_commit(struct Mailbox *m, struct Message *msg)
Commit a message to a folder - Wrapper for MxOps::msg_commit()
Definition: mx.c:1165
FILE * fp
pointer to the message data
Definition: mxapi.h:43
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:629
#define MUTT_ADD_FROM
add a From_ line
Definition: mx.h:42
+ 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 m_dst,
struct Mailbox m_src,
struct Email e,
struct Message msg,
CopyMessageFlags  cmflags,
CopyHeaderFlags  chflags 
)

Append a message.

Parameters
m_dstDestination Mailbox
m_srcSource Mailbox
eEmail
msgMessage
cmflagsFlags, see CopyMessageFlags
chflagsFlags, see CopyHeaderFlags
Return values
0Success
-1Failure

Definition at line 923 of file copy.c.

926 {
927  const bool own_msg = !msg;
928  if (own_msg && !(msg = mx_msg_open(m_src, e->msgno)))
929  {
930  return -1;
931  }
932 
933  int rc = append_message(m_dst, msg->fp, m_src, e, cmflags, chflags);
934  if (own_msg)
935  {
936  mx_msg_close(m_src, &msg);
937  }
938  return rc;
939 }
int mx_msg_close(struct Mailbox *m, struct Message **msg)
Close a message.
Definition: mx.c:1186
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:881
FILE * fp
pointer to the message data
Definition: mxapi.h:43
struct Message * mx_msg_open(struct Mailbox *m, int msgno)
return a stream pointer for a message
Definition: mx.c:1140
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 1011 of file copy.c.

1012 {
1013  char buf[8192];
1014  char cbuf[256];
1015  char c2buf[256];
1016  char *p = NULL;
1017  size_t linelen, buflen, plen;
1018 
1019  linelen = mutt_str_len(*h);
1020  plen = linelen;
1021  buflen = linelen + 3;
1022 
1023  mutt_mem_realloc(h, buflen);
1024  struct Address *first = TAILQ_FIRST(al);
1025  struct Address *a = NULL;
1026  TAILQ_FOREACH(a, al, entries)
1027  {
1028  *buf = '\0';
1029  *cbuf = '\0';
1030  *c2buf = '\0';
1031  const size_t l = mutt_addr_write(buf, sizeof(buf), a, false);
1032 
1033  if (a != first && (linelen + l > 74))
1034  {
1035  strcpy(cbuf, "\n\t");
1036  linelen = l + 8;
1037  }
1038  else
1039  {
1040  if (a->mailbox)
1041  {
1042  strcpy(cbuf, " ");
1043  linelen++;
1044  }
1045  linelen += l;
1046  }
1047  if (!a->group && TAILQ_NEXT(a, entries) && TAILQ_NEXT(a, entries)->mailbox)
1048  {
1049  linelen++;
1050  buflen++;
1051  strcpy(c2buf, ",");
1052  }
1053 
1054  const size_t cbuflen = mutt_str_len(cbuf);
1055  const size_t c2buflen = mutt_str_len(c2buf);
1056  buflen += l + cbuflen + c2buflen;
1057  mutt_mem_realloc(h, buflen);
1058  p = *h;
1059  strcat(p + plen, cbuf);
1060  plen += cbuflen;
1061  strcat(p + plen, buf);
1062  plen += l;
1063  strcat(p + plen, c2buf);
1064  plen += c2buflen;
1065  }
1066 
1067  /* Space for this was allocated in the beginning of this function. */
1068  strcat(p + plen, "\n");
1069 }
#define TAILQ_FIRST(head)
Definition: queue.h:723
#define TAILQ_FOREACH(var, head, field)
Definition: queue.h:725
static size_t plen
Length of cached packet.
Definition: pgppacket.c:39
An email address.
Definition: address.h:35
char * mailbox
Mailbox and host address.
Definition: address.h:38
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:664
bool group
Group mailbox?
Definition: address.h:39
#define TAILQ_NEXT(elm, field)
Definition: queue.h:832
+ Here is the call graph for this function:
+ Here is the caller graph for this function: