NeoMutt  2021-10-22-8-g9cb437
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 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 1121 of file copy.c.

1122 {
1123  char *s = *h;
1124  size_t l;
1125  bool rp = false;
1126 
1127  switch (tolower((unsigned char) *s))
1128  {
1129  case 'b':
1130  {
1131  if (!(l = mutt_istr_startswith(s, "bcc:")))
1132  return 0;
1133  break;
1134  }
1135  case 'c':
1136  {
1137  if (!(l = mutt_istr_startswith(s, "cc:")))
1138  return 0;
1139  break;
1140  }
1141  case 'f':
1142  {
1143  if (!(l = mutt_istr_startswith(s, "from:")))
1144  return 0;
1145  break;
1146  }
1147  case 'm':
1148  {
1149  if (!(l = mutt_istr_startswith(s, "mail-followup-to:")))
1150  return 0;
1151  break;
1152  }
1153  case 'r':
1154  {
1155  if ((l = mutt_istr_startswith(s, "return-path:")))
1156  {
1157  rp = true;
1158  break;
1159  }
1160  else if ((l = mutt_istr_startswith(s, "reply-to:")))
1161  {
1162  break;
1163  }
1164  return 0;
1165  }
1166  case 's':
1167  {
1168  if (!(l = mutt_istr_startswith(s, "sender:")))
1169  return 0;
1170  break;
1171  }
1172  case 't':
1173  {
1174  if (!(l = mutt_istr_startswith(s, "to:")))
1175  return 0;
1176  break;
1177  }
1178  default:
1179  return 0;
1180  }
1181 
1182  struct AddressList al = TAILQ_HEAD_INITIALIZER(al);
1183  mutt_addrlist_parse(&al, s + l);
1184  if (TAILQ_EMPTY(&al))
1185  return 0;
1186 
1189  struct Address *a = NULL;
1190  TAILQ_FOREACH(a, &al, entries)
1191  {
1192  if (a->personal)
1193  {
1195  }
1196  }
1197 
1198  /* angle brackets for return path are mandated by RFC5322,
1199  * so leave Return-Path as-is */
1200  if (rp)
1201  *h = mutt_str_dup(s);
1202  else
1203  {
1204  *h = mutt_mem_calloc(1, l + 2);
1205  mutt_str_copy(*h, s, l + 1);
1206  format_address_header(h, &al);
1207  }
1208 
1209  mutt_addrlist_clear(&al);
1210 
1211  FREE(&s);
1212  return 1;
1213 }
void mutt_addrlist_clear(struct AddressList *al)
Unlink and free all Address in an AddressList.
Definition: address.c:1470
int mutt_addrlist_to_local(struct AddressList *al)
Convert an Address list from Punycode.
Definition: address.c:1388
int mutt_addrlist_parse(struct AddressList *al, const char *s)
Parse a list of email addresses.
Definition: address.c:458
static void format_address_header(char **h, struct AddressList *al)
Write address headers to a buffer.
Definition: copy.c:1055
void * mutt_mem_calloc(size_t nmemb, size_t size)
Allocate zeroed memory on the heap.
Definition: memory.c:50
#define FREE(x)
Definition: memory.h:40
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
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
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 TAILQ_FOREACH(var, head, field)
Definition: queue.h:725
#define TAILQ_HEAD_INITIALIZER(head)
Definition: queue.h:637
#define TAILQ_EMPTY(head)
Definition: queue.h:721
void rfc2047_decode_addrlist(struct AddressList *al)
Decode any RFC2047 headers in an Address list.
Definition: rfc2047.c:767
An email address.
Definition: address.h:36
char * personal
Real name of address.
Definition: address.h:37
+ 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 987 of file copy.c.

988 {
989  struct Body *part = NULL;
990 
991  for (part = b->parts; part; part = part->next)
992  {
993  if (part->deleted || part->parts)
994  {
995  /* Copy till start of this part */
996  if (mutt_file_copy_bytes(fp_in, fp_out, part->hdr_offset - ftello(fp_in)))
997  {
998  return -1;
999  }
1000 
1001  if (part->deleted)
1002  {
1003  /* If this is modified, count_delete_lines() needs to be changed too */
1004  fprintf(
1005  fp_out,
1006  "Content-Type: message/external-body; access-type=x-mutt-deleted;\n"
1007  "\texpiration=%s; length=" OFF_T_FMT "\n"
1008  "\n",
1009  quoted_date, part->length);
1010  if (ferror(fp_out))
1011  {
1012  return -1;
1013  }
1014 
1015  /* Copy the original mime headers */
1016  if (mutt_file_copy_bytes(fp_in, fp_out, part->offset - ftello(fp_in)))
1017  {
1018  return -1;
1019  }
1020 
1021  /* Skip the deleted body */
1022  if (fseeko(fp_in, part->offset + part->length, SEEK_SET) != 0)
1023  {
1024  return -1;
1025  }
1026  }
1027  else
1028  {
1029  if (copy_delete_attach(part, fp_in, fp_out, quoted_date))
1030  {
1031  return -1;
1032  }
1033  }
1034  }
1035  }
1036 
1037  /* Copy the last parts */
1038  if (mutt_file_copy_bytes(fp_in, fp_out, b->offset + b->length - ftello(fp_in)))
1039  return -1;
1040 
1041  return 0;
1042 }
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:987
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
The body of an email.
Definition: body.h:35
struct Body * parts
parts of a multipart or message/rfc822
Definition: body.h:71
LOFF_T offset
offset where the actual data begins
Definition: body.h:51
bool deleted
Attachment marked for deletion.
Definition: body.h:87
LOFF_T length
length (in bytes) of attachment
Definition: body.h:52
struct Body * next
next attachment in the list
Definition: body.h:70
long hdr_offset
Offset in stream where the headers begin.
Definition: body.h:79
+ 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_SET(head, idx, elem)
Set an element in the array.
Definition: array.h:119
#define ARRAY_GET(head, idx)
Return the element at index.
Definition: array.h:105
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  int match = -1;
318  size_t match_len = 0, hdr_order_len;
319 
320  STAILQ_FOREACH(np, &HeaderOrderList, entries)
321  {
322  x++;
323  hdr_order_len = mutt_str_len(np->data);
324  if (mutt_strn_equal(buf, np->data, hdr_order_len))
325  {
326  if ((match == -1) || (hdr_order_len > match_len))
327  {
328  match = x;
329  match_len = hdr_order_len;
330  }
331  mutt_debug(LL_DEBUG2, "Reorder: %s matches %s", np->data, buf);
332  }
333  }
334  if (match != -1)
335  x = match;
336  }
337 
338  ignore = false;
339  } /* If beginning of header */
340 
341  if (!ignore)
342  {
343  mutt_debug(LL_DEBUG2, "Reorder: x = %d; hdr_count = %d\n", x, hdr_count);
344  if (this_one)
345  {
346  size_t blen = mutt_str_len(buf);
347 
348  mutt_mem_realloc(&this_one, this_one_len + blen + sizeof(char));
349  strcat(this_one + this_one_len, buf);
350  this_one_len += blen;
351  }
352  else
353  {
354  this_one = mutt_str_dup(buf);
355  this_one_len = mutt_str_len(this_one);
356  }
357  }
358  } /* while (ftello (fp_in) < off_end) */
359 
360  /* Do we have anything pending? -- XXX, same code as in above in the loop. */
361  if (this_one)
362  {
363  if (chflags & CH_DECODE)
364  {
365  if (address_header_decode(&this_one) == 0)
366  rfc2047_decode(&this_one);
367  this_one_len = mutt_str_len(this_one);
368  }
369 
370  add_one_header(&headers, x, this_one);
371  this_one = NULL;
372  }
373 
374  /* Now output the headers in order */
375  bool error = false;
376  char **hp = NULL;
377  ARRAY_FOREACH(hp, &headers)
378  {
379  if (!error && hp && *hp)
380  {
381  /* We couldn't do the prefixing when reading because RFC2047
382  * decoding may have concatenated lines. */
383  if (chflags & (CH_DECODE | CH_PREFIX))
384  {
385  const char *pre = (chflags & CH_PREFIX) ? prefix : NULL;
386  const short c_wrap = cs_subset_number(NeoMutt->sub, "wrap");
387  wraplen = mutt_window_wrap_cols(wraplen, c_wrap);
388 
389  if (mutt_write_one_header(fp_out, 0, *hp, pre, wraplen, chflags, NeoMutt->sub) == -1)
390  {
391  error = true;
392  }
393  }
394  else
395  {
396  if (fputs(*hp, fp_out) == EOF)
397  {
398  error = true;
399  }
400  }
401  }
402 
403  FREE(hp);
404  }
405  ARRAY_FREE(&headers);
406 
407  if (error)
408  return -1;
409  return 0;
410 }
#define ARRAY_RESERVE(head, num)
Reserve memory for the array.
Definition: array.h:185
#define ARRAY_FOREACH(elem, head)
Iterate over all elements of the array.
Definition: array.h:208
#define ARRAY_FREE(head)
Release all memory.
Definition: array.h:200
#define ARRAY_HEAD_INITIALIZER
Static initializer for arrays.
Definition: array.h:54
static int address_header_decode(char **h)
Parse an email's headers.
Definition: copy.c:1121
static void add_one_header(struct Headers *headers, size_t pos, char *value)
Add a header to a Headers array.
Definition: copy.c:74
#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
#define CH_PREFIX
Quote header using $indent_string string?
Definition: copy.h:57
#define CH_UPDATE
Update the status and x-status fields?
Definition: copy.h:52
#define CH_NOSTATUS
Suppress the status and x-status fields.
Definition: copy.h:58
#define CH_FROM
Retain the "From " message separator?
Definition: copy.h:56
#define CH_WEED_DELIVERED
Weed eventual Delivered-To headers.
Definition: copy.h:65
#define CH_UPDATE_LABEL
Update X-Label: from email->env->x_label?
Definition: copy.h:71
#define CH_WEED
Weed the headers?
Definition: copy.h:53
#define CH_REORDER
Re-order output of headers (specified by 'hdr_order')
Definition: copy.h:59
#define CH_MIME
Ignore MIME fields.
Definition: copy.h:61
#define CH_UPDATE_REFS
Update References:
Definition: copy.h:69
#define CH_NOQFROM
Ignore ">From " line.
Definition: copy.h:67
#define CH_UPDATE_LEN
Update Lines: and Content-Length:
Definition: copy.h:62
#define CH_UPDATE_IRT
Update In-Reply-To:
Definition: copy.h:68
#define CH_FORCE_FROM
Give CH_FROM precedence over CH_WEED?
Definition: copy.h:66
#define CH_UPDATE_SUBJECT
Update Subject: protected header update.
Definition: copy.h:72
#define CH_NOLEN
Don't write Content-Length: and Lines:
Definition: copy.h:64
#define mutt_debug(LEVEL,...)
Definition: logging.h:84
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
short cs_subset_number(const struct ConfigSubset *sub, const char *name)
Get a number config item by name.
Definition: helpers.c:169
@ LL_DEBUG3
Log at debug level 3.
Definition: logging.h:42
@ LL_DEBUG2
Log at debug level 2.
Definition: logging.h:41
@ LL_DEBUG1
Log at debug level 1.
Definition: logging.h:40
void mutt_mem_realloc(void *ptr, size_t size)
Resize a block of memory on the heap.
Definition: memory.c:114
bool mutt_strn_equal(const char *a, const char *b, size_t num)
Check for equality of two strings (to a maximum), safely.
Definition: string.c:593
size_t mutt_str_startswith(const char *str, const char *prefix)
Check whether a string starts with a prefix.
Definition: string.c:160
size_t mutt_str_len(const char *a)
Calculate the length of a string, safely.
Definition: string.c:664
struct ListHead HeaderOrderList
List of header fields in the order they should be displayed.
Definition: mutt_globals.h:66
int mutt_window_wrap_cols(int width, short wrap)
Calculate the wrap column for a given screen width.
Definition: mutt_window.c:364
bool mutt_matches_ignore(const char *s)
Does the string match the ignore list.
Definition: parse.c:314
static size_t plen
Length of cached packet.
Definition: pgppacket.c:39
#define STAILQ_FOREACH(var, head, field)
Definition: queue.h:352
void rfc2047_decode(char **pd)
Decode any RFC2047-encoded header fields.
Definition: rfc2047.c:644
A List node for strings.
Definition: list.h:35
char * data
String.
Definition: list.h:36
Container for Accounts, Notifications.
Definition: neomutt.h:37
struct ConfigSubset * sub
Inherited config items.
Definition: neomutt.h:39
+ 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 423 of file copy.c.

425 {
426  char *temp_hdr = NULL;
427 
428  if (e->env)
429  {
430  chflags |= ((e->env->changed & MUTT_ENV_CHANGED_IRT) ? CH_UPDATE_IRT : 0) |
434  }
435 
436  if (mutt_copy_hdr(fp_in, fp_out, e->offset, e->body->offset, chflags, prefix, wraplen) == -1)
437  return -1;
438 
439  if (chflags & CH_TXTPLAIN)
440  {
441  char chsbuf[128];
442  char buf[128];
443  fputs("MIME-Version: 1.0\n", fp_out);
444  fputs("Content-Transfer-Encoding: 8bit\n", fp_out);
445  fputs("Content-Type: text/plain; charset=", fp_out);
446  const char *const c_charset = cs_subset_string(NeoMutt->sub, "charset");
447  mutt_ch_canonical_charset(chsbuf, sizeof(chsbuf), c_charset ? c_charset : "us-ascii");
448  mutt_addr_cat(buf, sizeof(buf), chsbuf, MimeSpecials);
449  fputs(buf, fp_out);
450  fputc('\n', fp_out);
451  }
452 
453  if ((chflags & CH_UPDATE_IRT) && !STAILQ_EMPTY(&e->env->in_reply_to))
454  {
455  fputs("In-Reply-To:", fp_out);
456  struct ListNode *np = NULL;
457  STAILQ_FOREACH(np, &e->env->in_reply_to, entries)
458  {
459  fputc(' ', fp_out);
460  fputs(np->data, fp_out);
461  }
462  fputc('\n', fp_out);
463  }
464 
465  if ((chflags & CH_UPDATE_REFS) && !STAILQ_EMPTY(&e->env->references))
466  {
467  fputs("References:", fp_out);
468  mutt_write_references(&e->env->references, fp_out, 0);
469  fputc('\n', fp_out);
470  }
471 
472  if ((chflags & CH_UPDATE) && ((chflags & CH_NOSTATUS) == 0))
473  {
474  if (e->old || e->read)
475  {
476  fputs("Status: ", fp_out);
477  if (e->read)
478  fputs("RO", fp_out);
479  else if (e->old)
480  fputc('O', fp_out);
481  fputc('\n', fp_out);
482  }
483 
484  if (e->flagged || e->replied)
485  {
486  fputs("X-Status: ", fp_out);
487  if (e->replied)
488  fputc('A', fp_out);
489  if (e->flagged)
490  fputc('F', fp_out);
491  fputc('\n', fp_out);
492  }
493  }
494 
495  if (chflags & CH_UPDATE_LEN && ((chflags & CH_NOLEN) == 0))
496  {
497  fprintf(fp_out, "Content-Length: " OFF_T_FMT "\n", e->body->length);
498  if ((e->lines != 0) || (e->body->length == 0))
499  fprintf(fp_out, "Lines: %d\n", e->lines);
500  }
501 
502  const bool c_weed = cs_subset_bool(NeoMutt->sub, "weed");
503 #ifdef USE_NOTMUCH
504  if (chflags & CH_VIRTUAL)
505  {
506  /* Add some fake headers based on notmuch data */
507  char *folder = nm_email_get_folder(e);
508  if (folder && !(c_weed && mutt_matches_ignore("folder")))
509  {
510  char buf[1024];
511  mutt_str_copy(buf, folder, sizeof(buf));
512  mutt_pretty_mailbox(buf, sizeof(buf));
513 
514  fputs("Folder: ", fp_out);
515  fputs(buf, fp_out);
516  fputc('\n', fp_out);
517  }
518  }
519 #endif
520  char *tags = driver_tags_get(&e->tags);
521  if (tags && !(c_weed && mutt_matches_ignore("tags")))
522  {
523  fputs("Tags: ", fp_out);
524  fputs(tags, fp_out);
525  fputc('\n', fp_out);
526  }
527  FREE(&tags);
528 
529  const char *const c_send_charset =
530  cs_subset_string(NeoMutt->sub, "send_charset");
531  const short c_wrap = cs_subset_number(NeoMutt->sub, "wrap");
532  if ((chflags & CH_UPDATE_LABEL) && e->env->x_label)
533  {
534  temp_hdr = e->env->x_label;
535  /* env->x_label isn't currently stored with direct references elsewhere.
536  * Context->label_hash strdups the keys. But to be safe, encode a copy */
537  if (!(chflags & CH_DECODE))
538  {
539  temp_hdr = mutt_str_dup(temp_hdr);
540  rfc2047_encode(&temp_hdr, NULL, sizeof("X-Label:"), c_send_charset);
541  }
543  fp_out, "X-Label", temp_hdr, (chflags & CH_PREFIX) ? prefix : 0,
544  mutt_window_wrap_cols(wraplen, c_wrap), chflags, NeoMutt->sub) == -1)
545  {
546  return -1;
547  }
548  if (!(chflags & CH_DECODE))
549  FREE(&temp_hdr);
550  }
551 
552  if ((chflags & CH_UPDATE_SUBJECT) && e->env->subject)
553  {
554  temp_hdr = e->env->subject;
555  /* env->subject is directly referenced in Context->subj_hash, so we
556  * have to be careful not to encode (and thus free) that memory. */
557  if (!(chflags & CH_DECODE))
558  {
559  temp_hdr = mutt_str_dup(temp_hdr);
560  rfc2047_encode(&temp_hdr, NULL, sizeof("Subject:"), c_send_charset);
561  }
563  fp_out, "Subject", temp_hdr, (chflags & CH_PREFIX) ? prefix : 0,
564  mutt_window_wrap_cols(wraplen, c_wrap), chflags, NeoMutt->sub) == -1)
565  {
566  return -1;
567  }
568  if (!(chflags & CH_DECODE))
569  FREE(&temp_hdr);
570  }
571 
572  if ((chflags & CH_NONEWLINE) == 0)
573  {
574  if (chflags & CH_PREFIX)
575  fputs(prefix, fp_out);
576  fputc('\n', fp_out); /* add header terminator */
577  }
578 
579  if (ferror(fp_out) || feof(fp_out))
580  return -1;
581 
582  return 0;
583 }
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_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 CH_NONEWLINE
Don't output terminating newline after the header.
Definition: copy.h:60
#define CH_TXTPLAIN
Generate text/plain MIME headers.
Definition: copy.h:63
#define CH_VIRTUAL
Write virtual header lines too.
Definition: copy.h:73
void mutt_pretty_mailbox(char *buf, size_t buflen)
Shorten a mailbox path using '~' or '='.
Definition: muttlib.c:526
#define MUTT_ENV_CHANGED_SUBJECT
Protected header update.
Definition: envelope.h:35
#define MUTT_ENV_CHANGED_XLABEL
X-Label edited.
Definition: envelope.h:34
#define MUTT_ENV_CHANGED_IRT
In-Reply-To changed to link/break threads.
Definition: envelope.h:32
#define MUTT_ENV_CHANGED_REFS
References changed to break thread.
Definition: envelope.h:33
void mutt_write_references(const struct ListHead *r, FILE *fp, size_t trim)
Add the message references to a list.
Definition: header.c:514
const char * cs_subset_string(const struct ConfigSubset *sub, const char *name)
Get a string config item by name.
Definition: helpers.c:317
bool cs_subset_bool(const struct ConfigSubset *sub, const char *name)
Get a boolean config item by name.
Definition: helpers.c:73
const char MimeSpecials[]
Characters that need special treatment in MIME.
Definition: mime.c:67
void mutt_ch_canonical_charset(char *buf, size_t buflen, const char *name)
Canonicalise the charset of a string.
Definition: charset.c:355
char * nm_email_get_folder(struct Email *e)
Get the folder for a Email.
Definition: notmuch.c:1461
#define STAILQ_EMPTY(head)
Definition: queue.h:348
void rfc2047_encode(char **pd, const char *specials, int col, const char *charsets)
RFC-2047-encode a string.
Definition: rfc2047.c:619
bool read
Email is read.
Definition: email.h:48
struct Envelope * env
Envelope information.
Definition: email.h:66
int lines
How many lines in the body of this message?
Definition: email.h:60
struct Body * body
List of MIME parts.
Definition: email.h:67
bool old
Email is seen, but unread.
Definition: email.h:47
LOFF_T offset
Where in the stream does this message begin?
Definition: email.h:69
bool flagged
Marked important?
Definition: email.h:45
bool replied
Email has been replied to.
Definition: email.h:49
struct TagList tags
For drivers that support server tagging.
Definition: email.h:70
unsigned char changed
Changed fields, e.g. MUTT_ENV_CHANGED_SUBJECT.
Definition: envelope.h:90
struct ListHead references
message references (in reverse order)
Definition: envelope.h:83
struct ListHead in_reply_to
in-reply-to header content
Definition: envelope.h:84
char * subject
Email's subject.
Definition: envelope.h:68
char * x_label
X-Label.
Definition: envelope.h:74
char * driver_tags_get(struct TagList *list)
Get tags.
Definition: tags.c:145
+ 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
-1on error

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

Definition at line 596 of file copy.c.

597 {
598  int dellines = 0;
599 
600  if (b->deleted)
601  {
602  if (fseeko(fp, b->offset, SEEK_SET) != 0)
603  {
604  return -1;
605  }
606  for (long l = b->length; l; l--)
607  {
608  const int ch = getc(fp);
609  if (ch == EOF)
610  break;
611  if (ch == '\n')
612  dellines++;
613  }
614  /* 3 and 89 come from the added header of three lines in
615  * copy_delete_attach(). 89 is the size of the header(including
616  * the newlines, tabs, and a single digit length), not including
617  * the date length. */
618  dellines -= 3;
619  *length -= b->length - (89 + datelen);
620  /* Count the number of digits exceeding the first one to write the size */
621  for (long l = 10; b->length >= l; l *= 10)
622  (*length)++;
623  }
624  else
625  {
626  for (b = b->parts; b; b = b->next)
627  {
628  const int del = count_delete_lines(fp, b, length, datelen);
629  if (del == -1)
630  {
631  return -1;
632  }
633  dellines += del;
634  }
635  }
636  return dellines;
637 }
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:596
+ 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 650 of file copy.c.

652 {
653  struct Body *body = e->body;
654  char prefix[128];
655  LOFF_T new_offset = -1;
656  int rc = 0;
657 
658  if (cmflags & MUTT_CM_PREFIX)
659  {
660  const bool c_text_flowed = cs_subset_bool(NeoMutt->sub, "text_flowed");
661  if (c_text_flowed)
662  mutt_str_copy(prefix, ">", sizeof(prefix));
663  else
664  {
665  const char *const c_indent_string =
666  cs_subset_string(NeoMutt->sub, "indent_string");
667  mutt_make_string(prefix, sizeof(prefix), wraplen, NONULL(c_indent_string),
668  Context->mailbox, -1, e, MUTT_FORMAT_NO_FLAGS, NULL);
669  }
670  }
671 
672  if ((cmflags & MUTT_CM_NOHEADER) == 0)
673  {
674  if (cmflags & MUTT_CM_PREFIX)
675  chflags |= CH_PREFIX;
676  else if (e->attach_del && (chflags & CH_UPDATE_LEN))
677  {
678  int new_lines;
679  int rc_attach_del = -1;
680  LOFF_T new_length = body->length;
681  struct Buffer *quoted_date = NULL;
682 
683  quoted_date = mutt_buffer_pool_get();
684  mutt_buffer_addch(quoted_date, '"');
685  mutt_date_make_date(quoted_date,
686  cs_subset_bool(NeoMutt->sub, "local_date_header"));
687  mutt_buffer_addch(quoted_date, '"');
688 
689  /* Count the number of lines and bytes to be deleted */
690  if (fseeko(fp_in, body->offset, SEEK_SET) != 0)
691  {
692  goto attach_del_cleanup;
693  }
694  const int del =
695  count_delete_lines(fp_in, body, &new_length, mutt_buffer_len(quoted_date));
696  if (del == -1)
697  {
698  goto attach_del_cleanup;
699  }
700  new_lines = e->lines - del;
701 
702  /* Copy the headers */
703  if (mutt_copy_header(fp_in, e, fp_out, chflags | CH_NOLEN | CH_NONEWLINE, NULL, wraplen))
704  goto attach_del_cleanup;
705  fprintf(fp_out, "Content-Length: " OFF_T_FMT "\n", new_length);
706  if (new_lines <= 0)
707  new_lines = 0;
708  else
709  fprintf(fp_out, "Lines: %d\n", new_lines);
710 
711  putc('\n', fp_out);
712  if (ferror(fp_out) || feof(fp_out))
713  goto attach_del_cleanup;
714  new_offset = ftello(fp_out);
715 
716  /* Copy the body */
717  if (fseeko(fp_in, body->offset, SEEK_SET) < 0)
718  goto attach_del_cleanup;
719  if (copy_delete_attach(body, fp_in, fp_out, mutt_buffer_string(quoted_date)))
720  goto attach_del_cleanup;
721 
722  mutt_buffer_pool_release(&quoted_date);
723 
724  LOFF_T fail = ((ftello(fp_out) - new_offset) - new_length);
725  if (fail)
726  {
727  mutt_error(ngettext("The length calculation was wrong by %ld byte",
728  "The length calculation was wrong by %ld bytes", fail),
729  fail);
730  new_length += fail;
731  }
732 
733  /* Update original message if we are sync'ing a mailfolder */
734  if (cmflags & MUTT_CM_UPDATE)
735  {
736  e->attach_del = false;
737  e->lines = new_lines;
738  body->offset = new_offset;
739 
740  /* update the total size of the mailbox to reflect this deletion */
741  Context->mailbox->size -= body->length - new_length;
742  /* if the message is visible, update the visible size of the mailbox as well. */
743  if (Context->mailbox->v2r[e->msgno] != -1)
744  Context->vsize -= body->length - new_length;
745 
746  body->length = new_length;
747  mutt_body_free(&body->parts);
748  }
749 
750  rc_attach_del = 0;
751 
752  attach_del_cleanup:
753  mutt_buffer_pool_release(&quoted_date);
754  return rc_attach_del;
755  }
756 
757  if (mutt_copy_header(fp_in, e, fp_out, chflags,
758  (chflags & CH_PREFIX) ? prefix : NULL, wraplen) == -1)
759  {
760  return -1;
761  }
762 
763  new_offset = ftello(fp_out);
764  }
765 
766  if (cmflags & MUTT_CM_DECODE)
767  {
768  /* now make a text/plain version of the message */
769  struct State s = { 0 };
770  s.fp_in = fp_in;
771  s.fp_out = fp_out;
772  if (cmflags & MUTT_CM_PREFIX)
773  s.prefix = prefix;
774  if (cmflags & MUTT_CM_DISPLAY)
775  {
776  s.flags |= MUTT_DISPLAY;
777  s.wraplen = wraplen;
778  }
779  if (cmflags & MUTT_CM_PRINTING)
780  s.flags |= MUTT_PRINTING;
781  if (cmflags & MUTT_CM_WEED)
782  s.flags |= MUTT_WEED;
783  if (cmflags & MUTT_CM_CHARCONV)
784  s.flags |= MUTT_CHARCONV;
785  if (cmflags & MUTT_CM_REPLYING)
786  s.flags |= MUTT_REPLYING;
787 
788  if ((WithCrypto != 0) && cmflags & MUTT_CM_VERIFY)
789  s.flags |= MUTT_VERIFY;
790 
791  rc = mutt_body_handler(body, &s);
792  }
793  else if ((WithCrypto != 0) && (cmflags & MUTT_CM_DECODE_CRYPT) && (e->security & SEC_ENCRYPT))
794  {
795  struct Body *cur = NULL;
796  FILE *fp = NULL;
797 
798  if (((WithCrypto & APPLICATION_PGP) != 0) && (cmflags & MUTT_CM_DECODE_PGP) &&
799  (e->security & APPLICATION_PGP) && (e->body->type == TYPE_MULTIPART))
800  {
801  if (crypt_pgp_decrypt_mime(fp_in, &fp, e->body, &cur))
802  return -1;
803  fputs("MIME-Version: 1.0\n", fp_out);
804  }
805 
806  if (((WithCrypto & APPLICATION_SMIME) != 0) && (cmflags & MUTT_CM_DECODE_SMIME) &&
808  {
809  if (crypt_smime_decrypt_mime(fp_in, &fp, e->body, &cur))
810  return -1;
811  }
812 
813  if (!cur)
814  {
815  mutt_error(_("No decryption engine available for message"));
816  return -1;
817  }
818 
819  mutt_write_mime_header(cur, fp_out, NeoMutt->sub);
820  fputc('\n', fp_out);
821 
822  if (fseeko(fp, cur->offset, SEEK_SET) < 0)
823  return -1;
824  if (mutt_file_copy_bytes(fp, fp_out, cur->length) == -1)
825  {
826  mutt_file_fclose(&fp);
827  mutt_body_free(&cur);
828  return -1;
829  }
830  mutt_body_free(&cur);
831  mutt_file_fclose(&fp);
832  }
833  else
834  {
835  if (fseeko(fp_in, body->offset, SEEK_SET) < 0)
836  return -1;
837  if (cmflags & MUTT_CM_PREFIX)
838  {
839  int c;
840  size_t bytes = body->length;
841 
842  fputs(prefix, fp_out);
843 
844  while (((c = fgetc(fp_in)) != EOF) && bytes--)
845  {
846  fputc(c, fp_out);
847  if (c == '\n')
848  {
849  fputs(prefix, fp_out);
850  }
851  }
852  }
853  else if (mutt_file_copy_bytes(fp_in, fp_out, body->length) == -1)
854  return -1;
855  }
856 
857  if ((cmflags & MUTT_CM_UPDATE) && ((cmflags & MUTT_CM_NOHEADER) == 0) &&
858  (new_offset != -1))
859  {
860  body->offset = new_offset;
861  mutt_body_free(&body->parts);
862  }
863 
864  return rc;
865 }
size_t mutt_buffer_len(const struct Buffer *buf)
Calculate the length of a Buffer.
Definition: buffer.c:356
size_t mutt_buffer_addch(struct Buffer *buf, char c)
Add a single character to a Buffer.
Definition: buffer.c:240
static const char * mutt_buffer_string(const struct Buffer *buf)
Convert a buffer to a const char * "string".
Definition: buffer.h:77
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:423
#define MUTT_CM_WEED
Weed message/rfc822 attachment headers.
Definition: copy.h:41
#define MUTT_CM_REPLYING
Replying the message.
Definition: copy.h:44
#define MUTT_CM_PREFIX
Quote the header and body.
Definition: copy.h:37
#define MUTT_CM_UPDATE
Update structs on sync.
Definition: copy.h:40
#define MUTT_CM_VERIFY
Do signature verification.
Definition: copy.h:47
#define MUTT_CM_DECODE_PGP
Used for decoding PGP messages.
Definition: copy.h:45
#define MUTT_CM_DECODE
Decode the message body into text/plain.
Definition: copy.h:38
#define MUTT_CM_CHARCONV
Perform character set conversions.
Definition: copy.h:42
#define MUTT_CM_DECODE_SMIME
Used for decoding S/MIME messages.
Definition: copy.h:46
#define MUTT_CM_PRINTING
Printing the message - display light.
Definition: copy.h:43
#define MUTT_CM_DECODE_CRYPT
Definition: copy.h:48
#define MUTT_CM_NOHEADER
Don't copy the message header.
Definition: copy.h:36
#define MUTT_CM_DISPLAY
Output is displayed to the user.
Definition: copy.h:39
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:434
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
void mutt_date_make_date(struct Buffer *buf, bool local)
Write a date in RFC822 format to a buffer.
Definition: date.c:378
void mutt_body_free(struct Body **ptr)
Free a Body.
Definition: body.c:57
int mutt_file_fclose(FILE **fp)
Close a FILE handle (and NULL the pointer)
Definition: file.c:153
#define MUTT_FORMAT_NO_FLAGS
No flags are set.
Definition: format_flags.h:30
#define mutt_error(...)
Definition: logging.h:87
int mutt_body_handler(struct Body *b, struct State *s)
Handler for the Body of an email.
Definition: handler.c:1597
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:1410
int mutt_write_mime_header(struct Body *a, FILE *fp, struct ConfigSubset *sub)
Create a MIME header.
Definition: header.c:761
@ TYPE_MULTIPART
Type: 'multipart/*'.
Definition: mime.h:37
@ TYPE_APPLICATION
Type: 'application/*'.
Definition: mime.h:33
#define _(a)
Definition: message.h:28
#define APPLICATION_PGP
Use PGP to encrypt/sign.
Definition: lib.h:87
#define APPLICATION_SMIME
Use SMIME to encrypt/sign.
Definition: lib.h:88
#define SEC_ENCRYPT
Email is encrypted.
Definition: lib.h:75
#define WithCrypto
Definition: lib.h:113
void mutt_buffer_pool_release(struct Buffer **pbuf)
Free a Buffer from the pool.
Definition: pool.c:112
struct Buffer * mutt_buffer_pool_get(void)
Get a Buffer from the pool.
Definition: pool.c:101
#define MUTT_WEED
Weed headers even when not in display mode.
Definition: state.h:35
#define MUTT_VERIFY
Perform signature verification.
Definition: state.h:33
#define MUTT_CHARCONV
Do character set conversions.
Definition: state.h:36
#define MUTT_DISPLAY
Output is displayed to the user.
Definition: state.h:32
#define MUTT_REPLYING
Are we replying?
Definition: state.h:38
#define MUTT_PRINTING
Are we printing? - MUTT_DISPLAY "light".
Definition: state.h:37
#define NONULL(x)
Definition: string2.h:37
unsigned int type
content-type primary type, ContentType
Definition: body.h:39
String manipulation buffer.
Definition: buffer.h:34
The "current" mailbox.
Definition: context.h:38
struct Mailbox * mailbox
Current Mailbox.
Definition: context.h:49
off_t vsize
Size (in bytes) of the messages shown.
Definition: context.h:39
SecurityFlags security
bit 0-10: flags, bit 11,12: application, bit 13: traditional pgp See: ncrypt/lib.h pgplib....
Definition: email.h:41
bool attach_del
Has an attachment marked for deletion.
Definition: email.h:99
int msgno
Number displayed to the user.
Definition: email.h:111
int * v2r
Mapping from virtual to real msgno.
Definition: mailbox.h:101
off_t size
Size of the Mailbox.
Definition: mailbox.h:87
Keep track when processing files.
Definition: state.h:45
int wraplen
Width to wrap lines to (when flags & MUTT_DISPLAY)
Definition: state.h:50
StateFlags flags
Flags, e.g. MUTT_DISPLAY.
Definition: state.h:49
FILE * fp_out
File to write to.
Definition: state.h:47
char * prefix
String to add to the beginning of each output line.
Definition: state.h:48
FILE * fp_in
File to read from.
Definition: state.h:46
+ 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 Email e,
struct Message msg,
CopyMessageFlags  cmflags,
CopyHeaderFlags  chflags,
int  wraplen 
)

Copy a message from a Mailbox.

Parameters
fp_outFILE pointer to write to
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 881 of file copy.c.

883 {
884  if (!msg || !e->body)
885  {
886  return -1;
887  }
888  if (fp_out == msg->fp)
889  {
890  mutt_debug(LL_DEBUG1, "trying to read/write from/to the same FILE*!\n");
891  return -1;
892  }
893 
894  int rc = mutt_copy_message_fp(fp_out, msg->fp, e, cmflags, chflags, wraplen);
895  if ((rc == 0) && (ferror(fp_out) || feof(fp_out)))
896  {
897  mutt_debug(LL_DEBUG1, "failed to detect EOF!\n");
898  rc = -1;
899  }
900  return rc;
901 }
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:650
FILE * fp
pointer to the message data
Definition: mxapi.h:43
+ 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 914 of file copy.c.

916 {
917  char buf[256];
918  struct Message *msg = NULL;
919  int rc;
920 
921  if (fseeko(fp_in, e->offset, SEEK_SET) < 0)
922  return -1;
923  if (!fgets(buf, sizeof(buf), fp_in))
924  return -1;
925 
926  msg = mx_msg_open_new(dest, e, is_from(buf, NULL, 0, NULL) ? MUTT_MSG_NO_FLAGS : MUTT_ADD_FROM);
927  if (!msg)
928  return -1;
929  if ((dest->type == MUTT_MBOX) || (dest->type == MUTT_MMDF))
930  chflags |= CH_FROM | CH_FORCE_FROM;
931  chflags |= ((dest->type == MUTT_MAILDIR) ? CH_NOSTATUS : CH_UPDATE);
932  rc = mutt_copy_message_fp(msg->fp, fp_in, e, cmflags, chflags, 0);
933  if (mx_msg_commit(dest, msg) != 0)
934  rc = -1;
935 
936 #ifdef USE_NOTMUCH
937  if (msg->committed_path && (dest->type == MUTT_MAILDIR) && (src->type == MUTT_NOTMUCH))
938  nm_update_filename(src, NULL, msg->committed_path, e);
939 #endif
940 
941  mx_msg_close(dest, &msg);
942  return rc;
943 }
bool is_from(const char *s, char *path, size_t pathlen, time_t *tp)
Is a string a 'From' header line?
Definition: from.c:48
@ MUTT_NOTMUCH
'Notmuch' (virtual) Mailbox type
Definition: mailbox.h:54
@ MUTT_MMDF
'mmdf' Mailbox type
Definition: mailbox.h:49
@ MUTT_MBOX
'mbox' Mailbox type
Definition: mailbox.h:48
@ MUTT_MAILDIR
'Maildir' Mailbox type
Definition: mailbox.h:51
int mx_msg_close(struct Mailbox *m, struct Message **msg)
Close a message.
Definition: mx.c:1189
int mx_msg_commit(struct Mailbox *m, struct Message *msg)
Commit a message to a folder - Wrapper for MxOps::msg_commit()
Definition: mx.c:1168
struct Message * mx_msg_open_new(struct Mailbox *m, const struct Email *e, MsgOpenFlags flags)
Open a new message.
Definition: mx.c:1057
#define MUTT_ADD_FROM
add a From_ line
Definition: mx.h:42
#define MUTT_MSG_NO_FLAGS
No flags are set.
Definition: mx.h:41
int nm_update_filename(struct Mailbox *m, const char *old_file, const char *new_file, struct Email *e)
Change the filename.
Definition: notmuch.c:1750
enum MailboxType type
Mailbox type.
Definition: mailbox.h:105
A local copy of an email.
Definition: mxapi.h:42
char * committed_path
the final path generated by mx_msg_commit()
Definition: mxapi.h:45
+ 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 956 of file copy.c.

959 {
960  const bool own_msg = !msg;
961  if (own_msg && !(msg = mx_msg_open(m_src, e->msgno)))
962  {
963  return -1;
964  }
965 
966  int rc = append_message(m_dst, msg->fp, m_src, e, cmflags, chflags);
967  if (own_msg)
968  {
969  mx_msg_close(m_src, &msg);
970  }
971  return rc;
972 }
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:914
struct Message * mx_msg_open(struct Mailbox *m, int msgno)
Return a stream pointer for a message.
Definition: mx.c:1143
+ 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 1055 of file copy.c.

1056 {
1057  char buf[8192];
1058  char cbuf[256];
1059  char c2buf[256];
1060  char *p = NULL;
1061  size_t linelen, buflen, plen;
1062 
1063  linelen = mutt_str_len(*h);
1064  plen = linelen;
1065  buflen = linelen + 3;
1066 
1067  mutt_mem_realloc(h, buflen);
1068  struct Address *first = TAILQ_FIRST(al);
1069  struct Address *a = NULL;
1070  TAILQ_FOREACH(a, al, entries)
1071  {
1072  *buf = '\0';
1073  *cbuf = '\0';
1074  *c2buf = '\0';
1075  const size_t l = mutt_addr_write(buf, sizeof(buf), a, false);
1076 
1077  if (a != first && (linelen + l > 74))
1078  {
1079  strcpy(cbuf, "\n\t");
1080  linelen = l + 8;
1081  }
1082  else
1083  {
1084  if (a->mailbox)
1085  {
1086  strcpy(cbuf, " ");
1087  linelen++;
1088  }
1089  linelen += l;
1090  }
1091  if (!a->group && TAILQ_NEXT(a, entries) && TAILQ_NEXT(a, entries)->mailbox)
1092  {
1093  linelen++;
1094  buflen++;
1095  strcpy(c2buf, ",");
1096  }
1097 
1098  const size_t cbuflen = mutt_str_len(cbuf);
1099  const size_t c2buflen = mutt_str_len(c2buf);
1100  buflen += l + cbuflen + c2buflen;
1101  mutt_mem_realloc(h, buflen);
1102  p = *h;
1103  strcat(p + plen, cbuf);
1104  plen += cbuflen;
1105  strcat(p + plen, buf);
1106  plen += l;
1107  strcat(p + plen, c2buf);
1108  plen += c2buflen;
1109  }
1110 
1111  /* Space for this was allocated in the beginning of this function. */
1112  strcat(p + plen, "\n");
1113 }
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
#define TAILQ_FIRST(head)
Definition: queue.h:723
#define TAILQ_NEXT(elm, field)
Definition: queue.h:832
bool group
Group mailbox?
Definition: address.h:39
char * mailbox
Mailbox and host address.
Definition: address.h:38
+ Here is the call graph for this function:
+ Here is the caller graph for this function: