NeoMutt  2020-11-20
Teaching an old dog new tricks
DOXYGEN
sendlib.h File Reference

Miscellaneous functions for sending an email. More...

#include <stdbool.h>
#include <stdio.h>
#include "email/lib.h"
+ Include dependency graph for sendlib.h:
+ This graph shows which files directly or indirectly include this file:

Go to the source code of this file.

Macros

#define MUTT_RANDTAG_LEN   16
 

Functions

int mutt_bounce_message (FILE *fp, struct Email *e, struct AddressList *to, struct ConfigSubset *sub)
 Bounce an email message. More...
 
const char * mutt_fqdn (bool may_hide_host, const struct ConfigSubset *sub)
 Get the Fully-Qualified Domain Name. More...
 
struct Contentmutt_get_content_info (const char *fname, struct Body *b, struct ConfigSubset *sub)
 Analyze file to determine MIME encoding to use. More...
 
enum ContentType mutt_lookup_mime_type (struct Body *att, const char *path)
 Find the MIME type for an attachment. More...
 
struct Bodymutt_make_file_attach (const char *path, struct ConfigSubset *sub)
 Create a file attachment. More...
 
struct Bodymutt_make_message_attach (struct Mailbox *m, struct Email *e, bool attach_msg, struct ConfigSubset *sub)
 Create a message attachment. More...
 
void mutt_message_to_7bit (struct Body *a, FILE *fp, struct ConfigSubset *sub)
 Convert an email's MIME parts to 7-bit. More...
 
void mutt_prepare_envelope (struct Envelope *env, bool final, struct ConfigSubset *sub)
 Prepare an email header. More...
 
void mutt_stamp_attachment (struct Body *a)
 Timestamp an Attachment. More...
 
void mutt_unprepare_envelope (struct Envelope *env)
 Undo the encodings of mutt_prepare_envelope() More...
 
void mutt_update_encoding (struct Body *a, struct ConfigSubset *sub)
 Update the encoding type. More...
 
int mutt_write_fcc (const char *path, struct Email *e, const char *msgid, bool post, const char *fcc, char **finalpath, struct ConfigSubset *sub)
 Write email to FCC mailbox. More...
 
int mutt_write_multiple_fcc (const char *path, struct Email *e, const char *msgid, bool post, char *fcc, char **finalpath, struct ConfigSubset *sub)
 Handle FCC with multiple, comma separated entries. More...
 

Detailed Description

Miscellaneous functions for sending an email.

Authors
  • Richard Russon
  • 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 sendlib.h.

Macro Definition Documentation

◆ MUTT_RANDTAG_LEN

#define MUTT_RANDTAG_LEN   16

Definition at line 35 of file sendlib.h.

Function Documentation

◆ mutt_bounce_message()

int mutt_bounce_message ( FILE *  fp,
struct Email e,
struct AddressList *  to,
struct ConfigSubset sub 
)

Bounce an email message.

Parameters
fpHandle of message
eEmail
toAddressList to bounce to
subConfig Subset
Return values
0Success
-1Failure

Definition at line 1371 of file sendlib.c.

1373 {
1374  if (!fp || !e || !to || TAILQ_EMPTY(to))
1375  return -1;
1376 
1377  const char *fqdn = mutt_fqdn(true, sub);
1378  char resent_from[256];
1379  char *err = NULL;
1380 
1381  resent_from[0] = '\0';
1382  struct Address *from = mutt_default_from(sub);
1383  struct AddressList from_list = TAILQ_HEAD_INITIALIZER(from_list);
1384  mutt_addrlist_append(&from_list, from);
1385 
1386  /* mutt_default_from() does not use $realname if the real name is not set
1387  * in $from, so we add it here. The reason it is not added in
1388  * mutt_default_from() is that during normal sending, we execute
1389  * send-hooks and set the realname last so that it can be changed based
1390  * upon message criteria. */
1391  if (!from->personal)
1392  {
1393  const char *c_realname = cs_subset_string(sub, "realname");
1394  from->personal = mutt_str_dup(c_realname);
1395  }
1396 
1397  mutt_addrlist_qualify(&from_list, fqdn);
1398 
1399  rfc2047_encode_addrlist(&from_list, "Resent-From");
1400  if (mutt_addrlist_to_intl(&from_list, &err))
1401  {
1402  mutt_error(_("Bad IDN %s while preparing resent-from"), err);
1403  FREE(&err);
1404  mutt_addrlist_clear(&from_list);
1405  return -1;
1406  }
1407  mutt_addrlist_write(&from_list, resent_from, sizeof(resent_from), false);
1408 
1409 #ifdef USE_NNTP
1410  OptNewsSend = false;
1411 #endif
1412 
1413  /* prepare recipient list. idna conversion appears to happen before this
1414  * function is called, since the user receives confirmation of the address
1415  * list being bounced to. */
1416  struct AddressList resent_to = TAILQ_HEAD_INITIALIZER(resent_to);
1417  mutt_addrlist_copy(&resent_to, to, false);
1418  rfc2047_encode_addrlist(&resent_to, "Resent-To");
1419  int rc = bounce_message(fp, e, &resent_to, resent_from, &from_list, sub);
1420  mutt_addrlist_clear(&resent_to);
1421  mutt_addrlist_clear(&from_list);
1422 
1423  return rc;
1424 }
void mutt_addrlist_clear(struct AddressList *al)
Unlink and free all Address in an AddressList.
Definition: address.c:1468
void mutt_addrlist_copy(struct AddressList *dst, const struct AddressList *src, bool prune)
Copy a list of addresses into another list.
Definition: address.c:737
char * mutt_str_dup(const char *str)
Copy a string, safely.
Definition: string.c:370
#define _(a)
Definition: message.h:28
An email address.
Definition: address.h:34
void rfc2047_encode_addrlist(struct AddressList *al, const char *tag)
Encode any RFC2047 headers, where required, in an Address list.
Definition: rfc2047.c:738
struct Address * mutt_default_from(struct ConfigSubset *sub)
Get a default &#39;from&#39; Address.
Definition: send.c:1328
const char * cs_subset_string(const struct ConfigSubset *sub, const char *name)
Get a string config item by name.
Definition: helpers.c:241
char * personal
Real name of address.
Definition: address.h:36
void mutt_addrlist_qualify(struct AddressList *al, const char *host)
Expand local names in an Address list using a hostname.
Definition: address.c:650
const char * mutt_fqdn(bool may_hide_host, const struct ConfigSubset *sub)
Get the Fully-Qualified Domain Name.
Definition: sendlib.c:1181
int mutt_addrlist_to_intl(struct AddressList *al, char **err)
Convert an Address list to Punycode.
Definition: address.c:1304
#define mutt_error(...)
Definition: logging.h:84
static int bounce_message(FILE *fp, struct Email *e, struct AddressList *to, const char *resent_from, struct AddressList *env_from, struct ConfigSubset *sub)
Bounce an email message.
Definition: sendlib.c:1301
#define FREE(x)
Definition: memory.h:40
#define TAILQ_EMPTY(head)
Definition: queue.h:714
WHERE bool OptNewsSend
(pseudo) used to change behavior when posting
Definition: options.h:46
#define TAILQ_HEAD_INITIALIZER(head)
Definition: queue.h:630
size_t mutt_addrlist_write(const struct AddressList *al, char *buf, size_t buflen, bool display)
Write an Address to a buffer.
Definition: address.c:1150
void mutt_addrlist_append(struct AddressList *al, struct Address *a)
Append an Address to an AddressList.
Definition: address.c:1488
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_fqdn()

const char* mutt_fqdn ( bool  may_hide_host,
const struct ConfigSubset sub 
)

Get the Fully-Qualified Domain Name.

Parameters
may_hide_hostIf true, hide the hostname (leaving just the domain)
subConfig Subset
Return values
ptrstring pointer into Hostname
NULLError, e.g no Hostname
Warning
Do not free the returned pointer

Definition at line 1181 of file sendlib.c.

1182 {
1183  const char *c_hostname = cs_subset_string(sub, "hostname");
1184  if (!c_hostname || (c_hostname[0] == '@'))
1185  return NULL;
1186 
1187  const char *p = c_hostname;
1188 
1189  const bool c_hidden_host = cs_subset_bool(sub, "hidden_host");
1190  if (may_hide_host && c_hidden_host)
1191  {
1192  p = strchr(c_hostname, '.');
1193  if (p)
1194  p++;
1195 
1196  // sanity check: don't hide the host if the fqdn is something like example.com
1197  if (!p || !strchr(p, '.'))
1198  p = c_hostname;
1199  }
1200 
1201  return p;
1202 }
bool cs_subset_bool(const struct ConfigSubset *sub, const char *name)
Get a boolean config item by name.
Definition: helpers.c:69
const char * cs_subset_string(const struct ConfigSubset *sub, const char *name)
Get a string config item by name.
Definition: helpers.c:241
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_get_content_info()

struct Content* mutt_get_content_info ( const char *  fname,
struct Body b,
struct ConfigSubset sub 
)

Analyze file to determine MIME encoding to use.

Parameters
fnameFile to examine
bBody to update
subConfig Subset
Return values
ptrNewly allocated Content

Also set the body charset, sometimes, or not.

Definition at line 466 of file sendlib.c.

468 {
469  struct Content *info = NULL;
470  struct ContentState state = { 0 };
471  FILE *fp = NULL;
472  char *fromcode = NULL;
473  char *tocode = NULL;
474  char buf[100];
475  size_t r;
476 
477  struct stat sb;
478 
479  if (b && !fname)
480  fname = b->filename;
481  if (!fname)
482  return NULL;
483 
484  if (stat(fname, &sb) == -1)
485  {
486  mutt_error(_("Can't stat %s: %s"), fname, strerror(errno));
487  return NULL;
488  }
489 
490  if (!S_ISREG(sb.st_mode))
491  {
492  mutt_error(_("%s isn't a regular file"), fname);
493  return NULL;
494  }
495 
496  fp = fopen(fname, "r");
497  if (!fp)
498  {
499  mutt_debug(LL_DEBUG1, "%s: %s (errno %d)\n", fname, strerror(errno), errno);
500  return NULL;
501  }
502 
503  info = mutt_mem_calloc(1, sizeof(struct Content));
504 
505  const char *c_charset = cs_subset_string(sub, "charset");
506 
507  if (b && (b->type == TYPE_TEXT) && (!b->noconv && !b->force_charset))
508  {
509  const char *c_attach_charset = cs_subset_string(sub, "attach_charset");
510  const char *c_send_charset = cs_subset_string(sub, "send_charset");
511 
512  char *chs = mutt_param_get(&b->parameter, "charset");
513  const char *fchs =
514  b->use_disp ? (c_attach_charset ? c_attach_charset : c_charset) : c_charset;
515  if (c_charset && (chs || c_send_charset) &&
516  (convert_file_from_to(fp, fchs, chs ? chs : c_send_charset, &fromcode,
517  &tocode, info) != (size_t)(-1)))
518  {
519  if (!chs)
520  {
521  char chsbuf[256];
522  mutt_ch_canonical_charset(chsbuf, sizeof(chsbuf), tocode);
523  mutt_param_set(&b->parameter, "charset", chsbuf);
524  }
525  FREE(&b->charset);
526  b->charset = fromcode;
527  FREE(&tocode);
528  mutt_file_fclose(&fp);
529  return info;
530  }
531  }
532 
533  rewind(fp);
534  while ((r = fread(buf, 1, sizeof(buf), fp)))
535  update_content_info(info, &state, buf, r);
536  update_content_info(info, &state, 0, 0);
537 
538  mutt_file_fclose(&fp);
539 
540  if (b && (b->type == TYPE_TEXT) && (!b->noconv && !b->force_charset))
541  {
542  mutt_param_set(&b->parameter, "charset",
543  (!info->hibin ?
544  "us-ascii" :
545  c_charset && !mutt_ch_is_us_ascii(c_charset) ? c_charset : "unknown-8bit"));
546  }
547 
548  return info;
549 }
Info about the body of an email.
Definition: sendlib.c:64
static void update_content_info(struct Content *info, struct ContentState *s, char *buf, size_t buflen)
Cache some info about an email.
Definition: sendlib.c:80
char * filename
when sending a message, this is the file to which this structure refers
Definition: body.h:46
void * mutt_mem_calloc(size_t nmemb, size_t size)
Allocate zeroed memory on the heap.
Definition: memory.c:50
bool noconv
Don&#39;t do character set conversion.
Definition: body.h:73
#define _(a)
Definition: message.h:28
long hibin
8-bit characters
Definition: content.h:35
int mutt_file_fclose(FILE **fp)
Close a FILE handle (and NULL the pointer)
Definition: file.c:153
bool force_charset
Send mode: don&#39;t adjust the character set when in send-mode.
Definition: body.h:74
static char * chs
Definition: gnupgparse.c:73
Info about an attachment.
Definition: content.h:33
Type: &#39;text/*&#39;.
Definition: mime.h:38
char * charset
Send mode: charset of attached file as stored on disk.
Definition: body.h:49
const char * cs_subset_string(const struct ConfigSubset *sub, const char *name)
Get a string config item by name.
Definition: helpers.c:241
unsigned int type
content-type primary type, ContentType
Definition: body.h:65
#define mutt_ch_is_us_ascii(str)
Definition: charset.h:96
Log at debug level 1.
Definition: logging.h:40
bool use_disp
Content-Disposition uses filename= ?
Definition: body.h:68
#define mutt_error(...)
Definition: logging.h:84
#define FREE(x)
Definition: memory.h:40
char * mutt_param_get(const struct ParameterList *pl, const char *s)
Find a matching Parameter.
Definition: parameter.c:84
#define mutt_debug(LEVEL,...)
Definition: logging.h:81
struct ParameterList parameter
parameters of the content-type
Definition: body.h:39
void mutt_ch_canonical_charset(char *buf, size_t buflen, const char *name)
Canonicalise the charset of a string.
Definition: charset.c:352
void mutt_param_set(struct ParameterList *pl, const char *attribute, const char *value)
Set a Parameter.
Definition: parameter.c:110
static size_t convert_file_from_to(FILE *fp, const char *fromcodes, const char *tocodes, char **fromcode, char **tocode, struct Content *info)
Convert a file between encodings.
Definition: sendlib.c:380
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_lookup_mime_type()

enum ContentType mutt_lookup_mime_type ( struct Body att,
const char *  path 
)

Find the MIME type for an attachment.

Parameters
attEmail with attachment
pathPath to attachment
Return values
numMIME type, e.g. TYPE_IMAGE

Given a file at 'path', see if there is a registered MIME type. Returns the major MIME type, and copies the subtype to "d". First look in a system mime.types if we can find one, then look for ~/.mime.types. The longest match is used so that we can match 'ps.gz' when 'gz' also exists.

Definition at line 563 of file sendlib.c.

564 {
565  FILE *fp = NULL;
566  char *p = NULL, *q = NULL, *ct = NULL;
567  char buf[PATH_MAX];
568  char subtype[256] = { 0 };
569  char xtype[256] = { 0 };
570  int sze, cur_sze = 0;
571  bool found_mimetypes = false;
572  enum ContentType type = TYPE_OTHER;
573 
574  int szf = mutt_str_len(path);
575 
576  for (int count = 0; count < 4; count++)
577  {
578  /* can't use strtok() because we use it in an inner loop below, so use
579  * a switch statement here instead. */
580  switch (count)
581  {
582  /* last file with last entry to match wins type/xtype */
583  case 0:
584  /* check default unix mimetypes location first */
585  mutt_str_copy(buf, "/etc/mime.types", sizeof(buf));
586  break;
587  case 1:
588  mutt_str_copy(buf, SYSCONFDIR "/mime.types", sizeof(buf));
589  break;
590  case 2:
591  mutt_str_copy(buf, PKGDATADIR "/mime.types", sizeof(buf));
592  break;
593  case 3:
594  snprintf(buf, sizeof(buf), "%s/.mime.types", NONULL(HomeDir));
595  break;
596  default:
597  mutt_debug(LL_DEBUG1, "Internal error, count = %d\n", count);
598  goto bye; /* shouldn't happen */
599  }
600 
601  fp = fopen(buf, "r");
602  if (fp)
603  {
604  found_mimetypes = true;
605 
606  while (fgets(buf, sizeof(buf) - 1, fp))
607  {
608  /* weed out any comments */
609  p = strchr(buf, '#');
610  if (p)
611  *p = '\0';
612 
613  /* remove any leading space. */
614  ct = buf;
615  SKIPWS(ct);
616 
617  /* position on the next field in this line */
618  p = strpbrk(ct, " \t");
619  if (!p)
620  continue;
621  *p++ = 0;
622  SKIPWS(p);
623 
624  /* cycle through the file extensions */
625  while ((p = strtok(p, " \t\n")))
626  {
627  sze = mutt_str_len(p);
628  if ((sze > cur_sze) && (szf >= sze) && mutt_istr_equal(path + szf - sze, p) &&
629  ((szf == sze) || (path[szf - sze - 1] == '.')))
630  {
631  /* get the content-type */
632 
633  p = strchr(ct, '/');
634  if (!p)
635  {
636  /* malformed line, just skip it. */
637  break;
638  }
639  *p++ = 0;
640 
641  for (q = p; *q && !IS_SPACE(*q); q++)
642  ; // do nothing
643 
644  mutt_strn_copy(subtype, p, q - p, sizeof(subtype));
645 
646  type = mutt_check_mime_type(ct);
647  if (type == TYPE_OTHER)
648  mutt_str_copy(xtype, ct, sizeof(xtype));
649 
650  cur_sze = sze;
651  }
652  p = NULL;
653  }
654  }
655  mutt_file_fclose(&fp);
656  }
657  }
658 
659 bye:
660 
661  /* no mime.types file found */
662  if (!found_mimetypes)
663  {
664  mutt_error(_("Could not find any mime.types file."));
665  }
666 
667  if ((type != TYPE_OTHER) || (*xtype != '\0'))
668  {
669  att->type = type;
670  mutt_str_replace(&att->subtype, subtype);
671  mutt_str_replace(&att->xtype, xtype);
672  }
673 
674  return type;
675 }
Unknown Content-Type.
Definition: mime.h:31
#define NONULL(x)
Definition: string2.h:37
#define _(a)
Definition: message.h:28
char * HomeDir
User&#39;s home directory.
Definition: mutt_globals.h:49
enum ContentType mutt_check_mime_type(const char *s)
Check a MIME type string.
Definition: parse.c:324
int mutt_file_fclose(FILE **fp)
Close a FILE handle (and NULL the pointer)
Definition: file.c:153
#define SKIPWS(ch)
Definition: string2.h:46
char * mutt_strn_copy(char *dest, const char *src, size_t len, size_t dsize)
Copy a sub-string into a buffer.
Definition: string.c:528
bool mutt_istr_equal(const char *a, const char *b)
Compare two strings, ignoring case.
Definition: string.c:883
char * subtype
content-type subtype
Definition: body.h:37
#define PATH_MAX
Definition: mutt.h:44
char * xtype
content-type if x-unknown
Definition: body.h:36
unsigned int type
content-type primary type, ContentType
Definition: body.h:65
#define IS_SPACE(ch)
Definition: string2.h:38
size_t mutt_str_len(const char *a)
Calculate the length of a string, safely.
Definition: string.c:631
Log at debug level 1.
Definition: logging.h:40
size_t mutt_str_copy(char *dest, const char *src, size_t dsize)
Copy a string into a buffer (guaranteeing NUL-termination)
Definition: string.c:716
char * mutt_str_replace(char **p, const char *s)
Replace one string with another.
Definition: string.c:446
#define mutt_error(...)
Definition: logging.h:84
#define mutt_debug(LEVEL,...)
Definition: logging.h:81
ContentType
Content-Type.
Definition: mime.h:29
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_make_file_attach()

struct Body* mutt_make_file_attach ( const char *  path,
struct ConfigSubset sub 
)

Create a file attachment.

Parameters
pathFile to attach
subConfig Subset
Return values
ptrNewly allocated Body
NULLError

Definition at line 1082 of file sendlib.c.

1083 {
1084  struct Body *att = mutt_body_new();
1085  att->filename = mutt_str_dup(path);
1086 
1087  const char *c_mime_type_query_command =
1088  cs_subset_string(sub, "mime_type_query_command");
1089  const bool c_mime_type_query_first =
1090  cs_subset_bool(sub, "mime_type_query_first");
1091 
1092  if (c_mime_type_query_command && c_mime_type_query_first)
1093  run_mime_type_query(att, sub);
1094 
1095  /* Attempt to determine the appropriate content-type based on the filename
1096  * suffix. */
1097  if (!att->subtype)
1098  mutt_lookup_mime_type(att, path);
1099 
1100  if (!att->subtype && c_mime_type_query_command && !c_mime_type_query_first)
1101  {
1102  run_mime_type_query(att, sub);
1103  }
1104 
1105  struct Content *info = mutt_get_content_info(path, att, sub);
1106  if (!info)
1107  {
1108  mutt_body_free(&att);
1109  return NULL;
1110  }
1111 
1112  if (!att->subtype)
1113  {
1114  if ((info->nulbin == 0) &&
1115  ((info->lobin == 0) || ((info->lobin + info->hibin + info->ascii) / info->lobin >= 10)))
1116  {
1117  /* Statistically speaking, there should be more than 10% "lobin"
1118  * chars if this is really a binary file... */
1119  att->type = TYPE_TEXT;
1120  att->subtype = mutt_str_dup("plain");
1121  }
1122  else
1123  {
1124  att->type = TYPE_APPLICATION;
1125  att->subtype = mutt_str_dup("octet-stream");
1126  }
1127  }
1128 
1129  FREE(&info);
1130  mutt_update_encoding(att, sub);
1131  return att;
1132 }
struct Content * mutt_get_content_info(const char *fname, struct Body *b, struct ConfigSubset *sub)
Analyze file to determine MIME encoding to use.
Definition: sendlib.c:466
char * filename
when sending a message, this is the file to which this structure refers
Definition: body.h:46
bool cs_subset_bool(const struct ConfigSubset *sub, const char *name)
Get a boolean config item by name.
Definition: helpers.c:69
void mutt_update_encoding(struct Body *a, struct ConfigSubset *sub)
Update the encoding type.
Definition: sendlib.c:903
char * mutt_str_dup(const char *str)
Copy a string, safely.
Definition: string.c:370
long hibin
8-bit characters
Definition: content.h:35
The body of an email.
Definition: body.h:34
struct Body * mutt_body_new(void)
Create a new Body.
Definition: body.c:43
char * subtype
content-type subtype
Definition: body.h:37
Info about an attachment.
Definition: content.h:33
long ascii
Number of ascii chars.
Definition: content.h:39
Type: &#39;text/*&#39;.
Definition: mime.h:38
const char * cs_subset_string(const struct ConfigSubset *sub, const char *name)
Get a string config item by name.
Definition: helpers.c:241
void mutt_body_free(struct Body **ptr)
Free a Body.
Definition: body.c:57
unsigned int type
content-type primary type, ContentType
Definition: body.h:65
long lobin
Unprintable 7-bit chars (eg., control chars)
Definition: content.h:36
enum ContentType mutt_lookup_mime_type(struct Body *att, const char *path)
Find the MIME type for an attachment.
Definition: sendlib.c:563
#define FREE(x)
Definition: memory.h:40
long nulbin
Null characters (0x0)
Definition: content.h:37
Type: &#39;application/*&#39;.
Definition: mime.h:33
static void run_mime_type_query(struct Body *att, struct ConfigSubset *sub)
Run an external command to determine the MIME type.
Definition: sendlib.c:1040
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_make_message_attach()

struct Body* mutt_make_message_attach ( struct Mailbox m,
struct Email e,
bool  attach_msg,
struct ConfigSubset sub 
)

Create a message attachment.

Parameters
mMailbox
eEmail
attach_msgtrue if attaching a message
subConfig Subset
Return values
ptrNewly allocated Body
NULLError

Definition at line 935 of file sendlib.c.

937 {
938  struct Body *body = NULL;
939  FILE *fp = NULL;
940  CopyMessageFlags cmflags;
942 
943  const bool c_mime_forward_decode = cs_subset_bool(sub, "mime_forward_decode");
944  const bool c_forward_decrypt = cs_subset_bool(sub, "forward_decrypt");
945  if (WithCrypto)
946  {
947  if ((c_mime_forward_decode || c_forward_decrypt) && (e->security & SEC_ENCRYPT))
948  {
950  return NULL;
951  }
952  }
953 
954  struct Buffer *buf = mutt_buffer_pool_get();
955  mutt_buffer_mktemp(buf);
956  fp = mutt_file_fopen(mutt_b2s(buf), "w+");
957  if (!fp)
958  {
960  return NULL;
961  }
962 
963  body = mutt_body_new();
964  body->type = TYPE_MESSAGE;
965  body->subtype = mutt_str_dup("rfc822");
966  body->filename = mutt_str_dup(mutt_b2s(buf));
967  body->unlink = true;
968  body->use_disp = false;
969  body->disposition = DISP_INLINE;
970  body->noconv = true;
971 
973 
975 
976  CopyHeaderFlags chflags = CH_XMIT;
977  cmflags = MUTT_CM_NO_FLAGS;
978 
979  const bool c_forward_decode = cs_subset_bool(sub, "forward_decode");
980  /* If we are attaching a message, ignore `$mime_forward_decode` */
981  if (!attach_msg && c_forward_decode)
982  {
983  chflags |= CH_MIME | CH_TXTPLAIN;
984  cmflags = MUTT_CM_DECODE | MUTT_CM_CHARCONV;
986  pgp &= ~PGP_ENCRYPT;
988  pgp &= ~SMIME_ENCRYPT;
989  }
990  else if ((WithCrypto != 0) && c_forward_decrypt && (e->security & SEC_ENCRYPT))
991  {
992  if (((WithCrypto & APPLICATION_PGP) != 0) && mutt_is_multipart_encrypted(e->body))
993  {
994  chflags |= CH_MIME | CH_NONEWLINE;
995  cmflags = MUTT_CM_DECODE_PGP;
996  pgp &= ~PGP_ENCRYPT;
997  }
998  else if (((WithCrypto & APPLICATION_PGP) != 0) &&
1000  {
1001  chflags |= CH_MIME | CH_TXTPLAIN;
1002  cmflags = MUTT_CM_DECODE | MUTT_CM_CHARCONV;
1003  pgp &= ~PGP_ENCRYPT;
1004  }
1005  else if (((WithCrypto & APPLICATION_SMIME) != 0) &&
1007  {
1008  chflags |= CH_MIME | CH_TXTPLAIN;
1009  cmflags = MUTT_CM_DECODE | MUTT_CM_CHARCONV;
1010  pgp &= ~SMIME_ENCRYPT;
1011  }
1012  }
1013 
1014  mutt_copy_message(fp, m, e, cmflags, chflags, 0);
1015 
1016  fflush(fp);
1017  rewind(fp);
1018 
1019  body->email = email_new();
1020  body->email->offset = 0;
1021  /* we don't need the user headers here */
1022  body->email->env = mutt_rfc822_read_header(fp, body->email, false, false);
1023  if (WithCrypto)
1024  body->email->security = pgp;
1025  mutt_update_encoding(body, sub);
1026  body->parts = body->email->body;
1027 
1028  mutt_file_fclose(&fp);
1029 
1030  return body;
1031 }
#define mutt_buffer_mktemp(buf)
Definition: muttlib.h:77
#define CH_MIME
Ignore MIME fields.
Definition: copy.h:60
char * filename
when sending a message, this is the file to which this structure refers
Definition: body.h:46
bool cs_subset_bool(const struct ConfigSubset *sub, const char *name)
Get a boolean config item by name.
Definition: helpers.c:69
#define WithCrypto
Definition: lib.h:123
struct Buffer * mutt_buffer_pool_get(void)
Get a Buffer from the pool.
Definition: pool.c:101
void mutt_update_encoding(struct Body *a, struct ConfigSubset *sub)
Update the encoding type.
Definition: sendlib.c:903
struct Body * body
List of MIME parts.
Definition: email.h:91
#define SEC_NO_FLAGS
No flags are set.
Definition: lib.h:84
#define SMIME_ENCRYPT
Definition: lib.h:109
#define SEC_ENCRYPT
Email is encrypted.
Definition: lib.h:85
void mutt_buffer_pool_release(struct Buffer **pbuf)
Free a Buffer from the pool.
Definition: pool.c:112
bool noconv
Don&#39;t do character set conversion.
Definition: body.h:73
#define PGP_ENCRYPT
Definition: lib.h:103
String manipulation buffer.
Definition: buffer.h:33
void mutt_parse_mime_message(struct Mailbox *m, struct Email *e)
Parse a MIME email.
Definition: mutt_parse.c:49
char * mutt_str_dup(const char *str)
Copy a string, safely.
Definition: string.c:370
int mutt_copy_message(FILE *fp_out, struct Mailbox *m, struct Email *e, CopyMessageFlags cmflags, CopyHeaderFlags chflags, int wraplen)
Copy a message from a Mailbox.
Definition: copy.c:835
uint16_t SecurityFlags
Flags, e.g. SEC_ENCRYPT.
Definition: lib.h:83
uint16_t CopyMessageFlags
Flags for mutt_copy_message(), e.g. MUTT_CM_NOHEADER.
Definition: copy.h:31
#define MUTT_CM_NO_FLAGS
No flags are set.
Definition: copy.h:34
The body of an email.
Definition: body.h:34
unsigned int disposition
content-disposition, ContentDisposition
Definition: body.h:67
struct Body * mutt_body_new(void)
Create a new Body.
Definition: body.c:43
bool crypt_valid_passphrase(SecurityFlags flags)
Check that we have a usable passphrase, ask if not.
Definition: crypt.c:134
SecurityFlags mutt_is_multipart_encrypted(struct Body *b)
Does the message have encrypted parts?
Definition: crypt.c:447
int mutt_file_fclose(FILE **fp)
Close a FILE handle (and NULL the pointer)
Definition: file.c:153
struct Envelope * env
Envelope information.
Definition: email.h:90
char * subtype
content-type subtype
Definition: body.h:37
#define CH_TXTPLAIN
Generate text/plain MIME headers.
Definition: copy.h:62
#define mutt_b2s(buf)
Definition: buffer.h:41
#define APPLICATION_SMIME
Use SMIME to encrypt/sign.
Definition: lib.h:98
SecurityFlags mutt_is_application_pgp(struct Body *m)
Does the message use PGP?
Definition: crypt.c:552
#define APPLICATION_PGP
Use PGP to encrypt/sign.
Definition: lib.h:97
#define MUTT_CM_DECODE
Decode the message body into text/plain.
Definition: copy.h:37
#define MUTT_CM_CHARCONV
Perform character set conversions.
Definition: copy.h:41
#define CH_XMIT
Transmitting this message? (Ignore Lines: and Content-Length:)
Definition: copy.h:54
struct Body * parts
parts of a multipart or message/rfc822
Definition: body.h:54
SecurityFlags mutt_is_application_smime(struct Body *m)
Does the message use S/MIME?
Definition: crypt.c:610
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
LOFF_T offset
Where in the stream does this message begin?
Definition: email.h:84
Type: &#39;message/*&#39;.
Definition: mime.h:35
bool use_disp
Content-Disposition uses filename= ?
Definition: body.h:68
uint32_t CopyHeaderFlags
Flags for mutt_copy_header(), e.g. CH_UPDATE.
Definition: copy.h:49
bool unlink
If true, filename should be unlink()ed before free()ing this structure.
Definition: body.h:69
#define MUTT_CM_DECODE_PGP
Used for decoding PGP messages.
Definition: copy.h:44
struct Email * email_new(void)
Create a new Email.
Definition: email.c:72
FILE * mutt_file_fopen(const char *path, const char *mode)
Call fopen() safely.
Definition: file.c:588
Content is inline.
Definition: mime.h:62
struct Envelope * mutt_rfc822_read_header(FILE *fp, struct Email *e, bool user_hdrs, bool weed)
parses an RFC822 header
Definition: parse.c:1111
struct Email * email
header information for message/rfc822
Definition: body.h:55
#define CH_NONEWLINE
Don&#39;t output terminating newline after the header.
Definition: copy.h:59
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_message_to_7bit()

void mutt_message_to_7bit ( struct Body a,
FILE *  fp,
struct ConfigSubset sub 
)

Convert an email's MIME parts to 7-bit.

Parameters
aBody of the email
fpFile to read (OPTIONAL)
subConfig Subset

Definition at line 746 of file sendlib.c.

747 {
748  struct Buffer temp = mutt_buffer_make(0);
749  FILE *fp_in = NULL;
750  FILE *fp_out = NULL;
751  struct stat sb;
752 
753  if (!a->filename && fp)
754  fp_in = fp;
755  else if (!a->filename || !(fp_in = fopen(a->filename, "r")))
756  {
757  mutt_error(_("Could not open %s"), a->filename ? a->filename : "(null)");
758  return;
759  }
760  else
761  {
762  a->offset = 0;
763  if (stat(a->filename, &sb) == -1)
764  {
765  mutt_perror("stat");
766  mutt_file_fclose(&fp_in);
767  goto cleanup;
768  }
769  a->length = sb.st_size;
770  }
771 
772  /* Avoid buffer pool due to recursion */
773  mutt_buffer_mktemp(&temp);
774  fp_out = mutt_file_fopen(mutt_b2s(&temp), "w+");
775  if (!fp_out)
776  {
777  mutt_perror("fopen");
778  goto cleanup;
779  }
780 
781  fseeko(fp_in, a->offset, SEEK_SET);
782  a->parts = mutt_rfc822_parse_message(fp_in, a);
783 
784  transform_to_7bit(a->parts, fp_in, sub);
785 
786  mutt_copy_hdr(fp_in, fp_out, a->offset, a->offset + a->length,
787  CH_MIME | CH_NONEWLINE | CH_XMIT, NULL, 0);
788 
789  fputs("MIME-Version: 1.0\n", fp_out);
790  mutt_write_mime_header(a->parts, fp_out, sub);
791  fputc('\n', fp_out);
792  mutt_write_mime_body(a->parts, fp_out, sub);
793 
794  if (fp_in != fp)
795  mutt_file_fclose(&fp_in);
796  mutt_file_fclose(&fp_out);
797 
798  a->encoding = ENC_7BIT;
799  FREE(&a->d_filename);
800  a->d_filename = a->filename;
801  if (a->filename && a->unlink)
802  unlink(a->filename);
803  a->filename = mutt_buffer_strdup(&temp);
804  a->unlink = true;
805  if (stat(a->filename, &sb) == -1)
806  {
807  mutt_perror("stat");
808  goto cleanup;
809  }
810  a->length = sb.st_size;
811  mutt_body_free(&a->parts);
812  a->email->body = NULL;
813 
814 cleanup:
815  if (fp_in && (fp_in != fp))
816  mutt_file_fclose(&fp_in);
817 
818  if (fp_out)
819  {
820  mutt_file_fclose(&fp_out);
821  mutt_file_unlink(mutt_b2s(&temp));
822  }
823 
824  mutt_buffer_dealloc(&temp);
825 }
#define mutt_buffer_mktemp(buf)
Definition: muttlib.h:77
#define CH_MIME
Ignore MIME fields.
Definition: copy.h:60
char * filename
when sending a message, this is the file to which this structure refers
Definition: body.h:46
#define mutt_perror(...)
Definition: logging.h:85
struct Body * body
List of MIME parts.
Definition: email.h:91
char * mutt_buffer_strdup(const struct Buffer *buf)
Copy a Buffer&#39;s string.
Definition: buffer.c:432
7-bit text
Definition: mime.h:49
int mutt_write_mime_body(struct Body *a, FILE *fp, struct ConfigSubset *sub)
Write a MIME part.
Definition: body.c:314
void mutt_file_unlink(const char *s)
Delete a file, carefully.
Definition: file.c:195
struct Buffer mutt_buffer_make(size_t size)
Make a new buffer on the stack.
Definition: buffer.c:61
String manipulation buffer.
Definition: buffer.h:33
LOFF_T offset
offset where the actual data begins
Definition: body.h:44
#define _(a)
Definition: message.h:28
struct Body * mutt_rfc822_parse_message(FILE *fp, struct Body *parent)
parse a Message/RFC822 body
Definition: parse.c:1672
int mutt_file_fclose(FILE **fp)
Close a FILE handle (and NULL the pointer)
Definition: file.c:153
void mutt_buffer_dealloc(struct Buffer *buf)
Release the memory allocated by a buffer.
Definition: buffer.c:294
int mutt_write_mime_header(struct Body *a, FILE *fp, struct ConfigSubset *sub)
Create a MIME header.
Definition: header.c:761
unsigned int encoding
content-transfer-encoding, ContentEncoding
Definition: body.h:66
#define mutt_b2s(buf)
Definition: buffer.h:41
LOFF_T length
length (in bytes) of attachment
Definition: body.h:45
#define CH_XMIT
Transmitting this message? (Ignore Lines: and Content-Length:)
Definition: copy.h:54
struct Body * parts
parts of a multipart or message/rfc822
Definition: body.h:54
void mutt_body_free(struct Body **ptr)
Free a Body.
Definition: body.c:57
static void transform_to_7bit(struct Body *a, FILE *fp_in, struct ConfigSubset *sub)
Convert MIME parts to 7-bit.
Definition: sendlib.c:683
#define mutt_error(...)
Definition: logging.h:84
bool unlink
If true, filename should be unlink()ed before free()ing this structure.
Definition: body.h:69
int mutt_copy_hdr(FILE *fp_in, FILE *fp_out, LOFF_T off_start, LOFF_T off_end, CopyHeaderFlags chflags, const char *prefix, int wraplen)
Copy header from one file to another.
Definition: copy.c:103
#define FREE(x)
Definition: memory.h:40
char * d_filename
filename to be used for the content-disposition header.
Definition: body.h:47
FILE * mutt_file_fopen(const char *path, const char *mode)
Call fopen() safely.
Definition: file.c:588
struct Email * email
header information for message/rfc822
Definition: body.h:55
#define CH_NONEWLINE
Don&#39;t output terminating newline after the header.
Definition: copy.h:59
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_prepare_envelope()

void mutt_prepare_envelope ( struct Envelope env,
bool  final,
struct ConfigSubset sub 
)

Prepare an email header.

Parameters
envEnvelope to prepare
finaltrue if this email is going to be sent (not postponed)
subConfig Subset

Encode all the headers prior to sending the email.

For postponing (!final) do the necessary encodings only

Definition at line 1237 of file sendlib.c.

1238 {
1239  if (final)
1240  {
1241  if (!TAILQ_EMPTY(&env->bcc) && TAILQ_EMPTY(&env->to) && TAILQ_EMPTY(&env->cc))
1242  {
1243  /* some MTA's will put an Apparently-To: header field showing the Bcc:
1244  * recipients if there is no To: or Cc: field, so attempt to suppress
1245  * it by using an empty To: field. */
1246  struct Address *to = mutt_addr_new();
1247  to->group = true;
1248  mutt_addrlist_append(&env->to, to);
1250 
1251  char buf[1024];
1252  buf[0] = '\0';
1253  mutt_addr_cat(buf, sizeof(buf), "undisclosed-recipients", AddressSpecials);
1254 
1255  to->mailbox = mutt_str_dup(buf);
1256  }
1257 
1258  mutt_set_followup_to(env, sub);
1259 
1260  if (!env->message_id)
1261  env->message_id = gen_msgid(sub);
1262  }
1263 
1264  /* Take care of 8-bit => 7-bit conversion. */
1266  encode_headers(&env->userhdrs, sub);
1267 }
void rfc2047_encode_envelope(struct Envelope *env)
Encode the fields of an Envelope.
Definition: rfc2047.c:799
const char AddressSpecials[]
Characters with special meaning for email addresses.
Definition: address.c:42
struct AddressList bcc
Email&#39;s &#39;Bcc&#39; list.
Definition: envelope.h:60
static void encode_headers(struct ListHead *h, struct ConfigSubset *sub)
RFC2047-encode a list of headers.
Definition: sendlib.c:1141
char * mutt_str_dup(const char *str)
Copy a string, safely.
Definition: string.c:370
struct ListHead userhdrs
user defined headers
Definition: envelope.h:83
struct Address * mutt_addr_new(void)
Create a new Address.
Definition: address.c:385
An email address.
Definition: address.h:34
char * mailbox
Mailbox and host address.
Definition: address.h:37
char * message_id
Message ID.
Definition: envelope.h:69
static char * gen_msgid(struct ConfigSubset *sub)
Generate a unique Message ID.
Definition: sendlib.c:1210
struct AddressList cc
Email&#39;s &#39;Cc&#39; list.
Definition: envelope.h:59
void mutt_set_followup_to(struct Envelope *env, struct ConfigSubset *sub)
Set followup-to field.
Definition: send.c:1203
bool group
Group mailbox?
Definition: address.h:38
struct AddressList to
Email&#39;s &#39;To&#39; list.
Definition: envelope.h:58
#define TAILQ_EMPTY(head)
Definition: queue.h:714
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
void mutt_addrlist_append(struct AddressList *al, struct Address *a)
Append an Address to an AddressList.
Definition: address.c:1488
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_stamp_attachment()

void mutt_stamp_attachment ( struct Body a)

Timestamp an Attachment.

Parameters
aAttachment

Definition at line 891 of file sendlib.c.

892 {
893  a->stamp = mutt_date_epoch();
894 }
time_t mutt_date_epoch(void)
Return the number of seconds since the Unix epoch.
Definition: date.c:416
time_t stamp
Time stamp of last encoding update.
Definition: body.h:61
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_unprepare_envelope()

void mutt_unprepare_envelope ( struct Envelope env)

Undo the encodings of mutt_prepare_envelope()

Parameters
envEnvelope to unprepare

Decode all the headers of an email, e.g. when the sending failed or was aborted.

Definition at line 1276 of file sendlib.c.

1277 {
1278  struct ListNode *item = NULL;
1279  STAILQ_FOREACH(item, &env->userhdrs, entries)
1280  {
1281  rfc2047_decode(&item->data);
1282  }
1283 
1285 
1286  /* back conversions */
1288 }
struct AddressList mail_followup_to
Email&#39;s &#39;mail-followup-to&#39;.
Definition: envelope.h:63
void mutt_addrlist_clear(struct AddressList *al)
Unlink and free all Address in an AddressList.
Definition: address.c:1468
struct ListHead userhdrs
user defined headers
Definition: envelope.h:83
void rfc2047_decode_envelope(struct Envelope *env)
Decode the fields of an Envelope.
Definition: rfc2047.c:779
void rfc2047_decode(char **pd)
Decode any RFC2047-encoded header fields.
Definition: rfc2047.c:639
#define STAILQ_FOREACH(var, head, field)
Definition: queue.h:349
char * data
String.
Definition: list.h:36
A List node for strings.
Definition: list.h:34
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_update_encoding()

void mutt_update_encoding ( struct Body a,
struct ConfigSubset sub 
)

Update the encoding type.

Parameters
aBody to update
subConfig Subset

Assumes called from send mode where Body->filename points to actual file

Definition at line 903 of file sendlib.c.

904 {
905  struct Content *info = NULL;
906  char chsbuf[256];
907 
908  /* override noconv when it's us-ascii */
909  if (mutt_ch_is_us_ascii(mutt_body_get_charset(a, chsbuf, sizeof(chsbuf))))
910  a->noconv = false;
911 
912  if (!a->force_charset && !a->noconv)
913  mutt_param_delete(&a->parameter, "charset");
914 
915  info = mutt_get_content_info(a->filename, a, sub);
916  if (!info)
917  return;
918 
919  set_encoding(a, info, sub);
921 
922  FREE(&a->content);
923  a->content = info;
924 }
struct Content * mutt_get_content_info(const char *fname, struct Body *b, struct ConfigSubset *sub)
Analyze file to determine MIME encoding to use.
Definition: sendlib.c:466
void mutt_stamp_attachment(struct Body *a)
Timestamp an Attachment.
Definition: sendlib.c:891
char * filename
when sending a message, this is the file to which this structure refers
Definition: body.h:46
struct Content * content
Detailed info about the content of the attachment.
Definition: body.h:51
bool noconv
Don&#39;t do character set conversion.
Definition: body.h:73
bool force_charset
Send mode: don&#39;t adjust the character set when in send-mode.
Definition: body.h:74
char * mutt_body_get_charset(struct Body *b, char *buf, size_t buflen)
Get a body&#39;s character set.
Definition: body.c:131
Info about an attachment.
Definition: content.h:33
void mutt_param_delete(struct ParameterList *pl, const char *attribute)
Delete a matching Parameter.
Definition: parameter.c:142
#define mutt_ch_is_us_ascii(str)
Definition: charset.h:96
#define FREE(x)
Definition: memory.h:40
struct ParameterList parameter
parameters of the content-type
Definition: body.h:39
static void set_encoding(struct Body *b, struct Content *info, struct ConfigSubset *sub)
determine which Content-Transfer-Encoding to use
Definition: sendlib.c:833
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_write_fcc()

int mutt_write_fcc ( const char *  path,
struct Email e,
const char *  msgid,
bool  post,
const char *  fcc,
char **  finalpath,
struct ConfigSubset sub 
)

Write email to FCC mailbox.

Parameters
[in]pathPath to mailbox
[in]eEmail
[in]msgidMessage id
[in]postIf true, postpone message, else fcc mode
[in]fccfcc setting to save (postpone only)
[out]finalpathFinal path of email
[in]subConfig Subset
Return values
0Success
-1Failure

Definition at line 1507 of file sendlib.c.

1509 {
1510  struct Message *msg = NULL;
1511  struct Buffer *tempfile = NULL;
1512  FILE *fp_tmp = NULL;
1513  int rc = -1;
1514  bool need_mailbox_cleanup = false;
1515  struct stat st;
1516  MsgOpenFlags onm_flags;
1517 
1518  if (post)
1519  set_noconv_flags(e->body, true);
1520 
1521 #ifdef RECORD_FOLDER_HOOK
1522  mutt_folder_hook(path, NULL);
1523 #endif
1524  struct Mailbox *m_fcc = mx_path_resolve(path);
1525  bool old_append = m_fcc->append;
1526  struct Context *ctx_fcc = mx_mbox_open(m_fcc, MUTT_APPEND | MUTT_QUIET);
1527  if (!ctx_fcc)
1528  {
1529  mutt_debug(LL_DEBUG1, "unable to open mailbox %s in append-mode, aborting\n", path);
1530  mailbox_free(&m_fcc);
1531  goto done;
1532  }
1533 
1534  /* We need to add a Content-Length field to avoid problems where a line in
1535  * the message body begins with "From " */
1536  if ((ctx_fcc->mailbox->type == MUTT_MMDF) || (ctx_fcc->mailbox->type == MUTT_MBOX))
1537  {
1538  tempfile = mutt_buffer_pool_get();
1539  mutt_buffer_mktemp(tempfile);
1540  fp_tmp = mutt_file_fopen(mutt_b2s(tempfile), "w+");
1541  if (!fp_tmp)
1542  {
1543  mutt_perror(mutt_b2s(tempfile));
1544  mx_mbox_close(&ctx_fcc);
1545  goto done;
1546  }
1547  /* remember new mail status before appending message */
1548  need_mailbox_cleanup = true;
1549  stat(path, &st);
1550  }
1551 
1552  e->read = !post; /* make sure to put it in the 'cur' directory (maildir) */
1553  onm_flags = MUTT_ADD_FROM;
1554  if (post)
1555  onm_flags |= MUTT_SET_DRAFT;
1556  msg = mx_msg_open_new(ctx_fcc->mailbox, e, onm_flags);
1557  if (!msg)
1558  {
1559  mutt_file_fclose(&fp_tmp);
1560  mx_mbox_close(&ctx_fcc);
1561  goto done;
1562  }
1563 
1564  const bool c_crypt_protected_headers_read =
1565  cs_subset_bool(sub, "crypt_protected_headers_read");
1566 
1567  /* post == 1 => postpone message.
1568  * post == 0 => Normal mode. */
1570  msg->fp, e->env, e->body,
1572  c_crypt_protected_headers_read && mutt_should_hide_protected_subject(e), sub);
1573 
1574  /* (postponement) if this was a reply of some sort, <msgid> contains the
1575  * Message-ID: of message replied to. Save it using a special X-Mutt-
1576  * header so it can be picked up if the message is recalled at a later
1577  * point in time. This will allow the message to be marked as replied if
1578  * the same mailbox is still open. */
1579  if (post && msgid)
1580  fprintf(msg->fp, "X-Mutt-References: %s\n", msgid);
1581 
1582  /* (postponement) save the Fcc: using a special X-Mutt- header so that
1583  * it can be picked up when the message is recalled */
1584  if (post && fcc)
1585  fprintf(msg->fp, "X-Mutt-Fcc: %s\n", fcc);
1586 
1587  if ((ctx_fcc->mailbox->type == MUTT_MMDF) || (ctx_fcc->mailbox->type == MUTT_MBOX))
1588  fprintf(msg->fp, "Status: RO\n");
1589 
1590  /* (postponement) if the mail is to be signed or encrypted, save this info */
1591  if (((WithCrypto & APPLICATION_PGP) != 0) && post && (e->security & APPLICATION_PGP))
1592  {
1593  fputs("X-Mutt-PGP: ", msg->fp);
1594  if (e->security & SEC_ENCRYPT)
1595  fputc('E', msg->fp);
1596  if (e->security & SEC_OPPENCRYPT)
1597  fputc('O', msg->fp);
1598  if (e->security & SEC_SIGN)
1599  {
1600  fputc('S', msg->fp);
1601 
1602  const char *c_pgp_sign_as = cs_subset_string(sub, "pgp_sign_as");
1603  if (c_pgp_sign_as)
1604  fprintf(msg->fp, "<%s>", c_pgp_sign_as);
1605  }
1606  if (e->security & SEC_INLINE)
1607  fputc('I', msg->fp);
1608 #ifdef USE_AUTOCRYPT
1609  if (e->security & SEC_AUTOCRYPT)
1610  fputc('A', msg->fp);
1612  fputc('Z', msg->fp);
1613 #endif
1614  fputc('\n', msg->fp);
1615  }
1616 
1617  /* (postponement) if the mail is to be signed or encrypted, save this info */
1618  if (((WithCrypto & APPLICATION_SMIME) != 0) && post && (e->security & APPLICATION_SMIME))
1619  {
1620  fputs("X-Mutt-SMIME: ", msg->fp);
1621  if (e->security & SEC_ENCRYPT)
1622  {
1623  fputc('E', msg->fp);
1624 
1625  const char *c_smime_encrypt_with =
1626  cs_subset_string(sub, "smime_encrypt_with");
1627  if (c_smime_encrypt_with)
1628  fprintf(msg->fp, "C<%s>", c_smime_encrypt_with);
1629  }
1630  if (e->security & SEC_OPPENCRYPT)
1631  fputc('O', msg->fp);
1632  if (e->security & SEC_SIGN)
1633  {
1634  fputc('S', msg->fp);
1635 
1636  const char *c_smime_sign_as = cs_subset_string(sub, "smime_sign_as");
1637  if (c_smime_sign_as)
1638  fprintf(msg->fp, "<%s>", c_smime_sign_as);
1639  }
1640  if (e->security & SEC_INLINE)
1641  fputc('I', msg->fp);
1642  fputc('\n', msg->fp);
1643  }
1644 
1645 #ifdef MIXMASTER
1646  /* (postponement) if the mail is to be sent through a mixmaster
1647  * chain, save that information */
1648 
1649  if (post && !STAILQ_EMPTY(&e->chain))
1650  {
1651  fputs("X-Mutt-Mix:", msg->fp);
1652  struct ListNode *p = NULL;
1653  STAILQ_FOREACH(p, &e->chain, entries)
1654  {
1655  fprintf(msg->fp, " %s", (char *) p->data);
1656  }
1657 
1658  fputc('\n', msg->fp);
1659  }
1660 #endif
1661 
1662  if (fp_tmp)
1663  {
1664  mutt_write_mime_body(e->body, fp_tmp, sub);
1665 
1666  /* make sure the last line ends with a newline. Emacs doesn't ensure this
1667  * will happen, and it can cause problems parsing the mailbox later. */
1668  fseek(fp_tmp, -1, SEEK_END);
1669  if (fgetc(fp_tmp) != '\n')
1670  {
1671  fseek(fp_tmp, 0, SEEK_END);
1672  fputc('\n', fp_tmp);
1673  }
1674 
1675  fflush(fp_tmp);
1676  if (ferror(fp_tmp))
1677  {
1678  mutt_debug(LL_DEBUG1, "%s: write failed\n", mutt_b2s(tempfile));
1679  mutt_file_fclose(&fp_tmp);
1680  unlink(mutt_b2s(tempfile));
1681  mx_msg_commit(ctx_fcc->mailbox, msg); /* XXX really? */
1682  mx_msg_close(ctx_fcc->mailbox, &msg);
1683  mx_mbox_close(&ctx_fcc);
1684  goto done;
1685  }
1686 
1687  /* count the number of lines */
1688  int lines = 0;
1689  char line_buf[1024];
1690  rewind(fp_tmp);
1691  while (fgets(line_buf, sizeof(line_buf), fp_tmp))
1692  lines++;
1693  fprintf(msg->fp, "Content-Length: " OFF_T_FMT "\n", (LOFF_T) ftello(fp_tmp));
1694  fprintf(msg->fp, "Lines: %d\n\n", lines);
1695 
1696  /* copy the body and clean up */
1697  rewind(fp_tmp);
1698  rc = mutt_file_copy_stream(fp_tmp, msg->fp);
1699  if (mutt_file_fclose(&fp_tmp) != 0)
1700  rc = -1;
1701  /* if there was an error, leave the temp version */
1702  if (rc >= 0)
1703  {
1704  unlink(mutt_b2s(tempfile));
1705  rc = 0;
1706  }
1707  }
1708  else
1709  {
1710  fputc('\n', msg->fp); /* finish off the header */
1711  rc = mutt_write_mime_body(e->body, msg->fp, sub);
1712  }
1713 
1714  if (mx_msg_commit(ctx_fcc->mailbox, msg) != 0)
1715  rc = -1;
1716  else if (finalpath)
1717  *finalpath = mutt_str_dup(msg->committed_path);
1718  mx_msg_close(ctx_fcc->mailbox, &msg);
1719  mx_mbox_close(&ctx_fcc);
1720 
1721  if (!post && need_mailbox_cleanup)
1722  mutt_mailbox_cleanup(path, &st);
1723 
1724  if (post)
1725  set_noconv_flags(e->body, false);
1726 
1727 done:
1728  if (m_fcc)
1729  m_fcc->append = old_append;
1730 #ifdef RECORD_FOLDER_HOOK
1731  /* We ran a folder hook for the destination mailbox,
1732  * now we run it for the user's current mailbox */
1733  if (Context && Context->mailbox->path)
1735 #endif
1736 
1737  if (fp_tmp)
1738  {
1739  mutt_file_fclose(&fp_tmp);
1740  unlink(mutt_b2s(tempfile));
1741  }
1742  mutt_buffer_pool_release(&tempfile);
1743 
1744  return rc;
1745 }
#define MUTT_APPEND
Open mailbox for appending messages.
Definition: mx.h:53
The "current" mailbox.
Definition: context.h:38
#define mutt_buffer_mktemp(buf)
Definition: muttlib.h:77
enum MailboxType type
Mailbox type.
Definition: mailbox.h:105
bool cs_subset_bool(const struct ConfigSubset *sub, const char *name)
Get a boolean config item by name.
Definition: helpers.c:69
#define WithCrypto
Definition: lib.h:123
struct Buffer * mutt_buffer_pool_get(void)
Get a Buffer from the pool.
Definition: pool.c:101
#define mutt_perror(...)
Definition: logging.h:85
A postponed Email, just the envelope info.
Definition: header.h:42
struct Body * body
List of MIME parts.
Definition: email.h:91
int mx_mbox_close(struct Context **ptr)
Save changes and close mailbox.
Definition: mx.c:630
void mutt_mailbox_cleanup(const char *path, struct stat *st)
Restore the timestamp of a mailbox.
Definition: mutt_mailbox.c:354
int mutt_write_mime_body(struct Body *a, FILE *fp, struct ConfigSubset *sub)
Write a MIME part.
Definition: body.c:314
#define SEC_ENCRYPT
Email is encrypted.
Definition: lib.h:85
bool mutt_should_hide_protected_subject(struct Email *e)
Should NeoMutt hide the protected subject?
Definition: crypt.c:1073
void mutt_buffer_pool_release(struct Buffer **pbuf)
Free a Buffer from the pool.
Definition: pool.c:112
String manipulation buffer.
Definition: buffer.h:33
char * mutt_str_dup(const char *str)
Copy a string, safely.
Definition: string.c:370
struct Context * mx_mbox_open(struct Mailbox *m, OpenMailboxFlags flags)
Open a mailbox and parse it.
Definition: mx.c:303
#define SEC_AUTOCRYPT
(Autocrypt) Message will be, or was Autocrypt encrypt+signed
Definition: lib.h:94
#define MUTT_SET_DRAFT
set the message draft flag
Definition: mx.h:66
#define SEC_INLINE
Email has an inline signature.
Definition: lib.h:92
int mx_msg_close(struct Mailbox *m, struct Message **msg)
Close a message.
Definition: mx.c:1204
void mutt_folder_hook(const char *path, const char *desc)
Perform a folder hook.
Definition: hook.c:504
fcc mode, like normal mode but for Bcc header
Definition: header.h:41
bool read
Email is read.
Definition: email.h:51
struct Message * mx_msg_open_new(struct Mailbox *m, const struct Email *e, MsgOpenFlags flags)
Open a new message.
Definition: mx.c:1072
struct Mailbox * mailbox
Definition: context.h:50
void mailbox_free(struct Mailbox **ptr)
Free a Mailbox.
Definition: mailbox.c:63
int mutt_file_fclose(FILE **fp)
Close a FILE handle (and NULL the pointer)
Definition: file.c:153
struct Envelope * env
Envelope information.
Definition: email.h:90
#define mutt_b2s(buf)
Definition: buffer.h:41
#define APPLICATION_SMIME
Use SMIME to encrypt/sign.
Definition: lib.h:98
struct ListHead chain
Mixmaster chain.
Definition: email.h:102
#define APPLICATION_PGP
Use PGP to encrypt/sign.
Definition: lib.h:97
A local copy of an email.
Definition: mx.h:82
A mailbox.
Definition: mailbox.h:81
#define SEC_AUTOCRYPT_OVERRIDE
(Autocrypt) Indicates manual set/unset of encryption
Definition: lib.h:95
&#39;mmdf&#39; Mailbox type
Definition: mailbox.h:49
const char * cs_subset_string(const struct ConfigSubset *sub, const char *name)
Get a string config item by name.
Definition: helpers.c:241
bool append
Mailbox is opened in append mode.
Definition: mailbox.h:113
#define MUTT_QUIET
Do not print any messages.
Definition: mx.h:55
#define STAILQ_FOREACH(var, head, field)
Definition: queue.h:349
SecurityFlags security
bit 0-10: flags, bit 11,12: application, bit 13: traditional pgp See: ncrypt/lib.h pgplib...
Definition: email.h:39
uint8_t MsgOpenFlags
Flags for mx_msg_open_new(), e.g. MUTT_ADD_FROM.
Definition: mx.h:63
#define SEC_OPPENCRYPT
Opportunistic encrypt mode.
Definition: lib.h:93
&#39;mbox&#39; Mailbox type
Definition: mailbox.h:48
#define SEC_SIGN
Email is signed.
Definition: lib.h:86
char * committed_path
the final path generated by mx_msg_commit()
Definition: mx.h:86
char * data
String.
Definition: list.h:36
Log at debug level 1.
Definition: logging.h:40
int mutt_file_copy_stream(FILE *fp_in, FILE *fp_out)
Copy the contents of one file into another.
Definition: file.c:271
int mx_msg_commit(struct Mailbox *m, struct Message *msg)
Commit a message to a folder - Wrapper for MxOps::msg_commit()
Definition: mx.c:1183
FILE * fp
pointer to the message data
Definition: mx.h:84
struct Mailbox * mx_path_resolve(const char *path)
Get a Mailbox for a path.
Definition: mx.c:1681
static void set_noconv_flags(struct Body *b, bool flag)
Set/reset the "x-mutt-noconv" flag.
Definition: sendlib.c:1431
#define STAILQ_EMPTY(head)
Definition: queue.h:345
#define mutt_debug(LEVEL,...)
Definition: logging.h:81
FILE * mutt_file_fopen(const char *path, const char *mode)
Call fopen() safely.
Definition: file.c:588
A List node for strings.
Definition: list.h:34
#define MUTT_ADD_FROM
add a From_ line
Definition: mx.h:65
int mutt_rfc822_write_header(FILE *fp, struct Envelope *env, struct Body *attach, enum MuttWriteHeaderMode mode, bool privacy, bool hide_protected_subject, struct ConfigSubset *sub)
Write out one RFC822 header line.
Definition: header.c:573
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_write_multiple_fcc()

int mutt_write_multiple_fcc ( const char *  path,
struct Email e,
const char *  msgid,
bool  post,
char *  fcc,
char **  finalpath,
struct ConfigSubset sub 
)

Handle FCC with multiple, comma separated entries.

Parameters
[in]pathPath to mailboxes (comma separated)
[in]eEmail
[in]msgidMessage id
[in]postIf true, postpone message
[in]fccfcc setting to save (postpone only)
[out]finalpathFinal path of email
[in]subConfig Subset
Return values
0Success
-1Failure

Definition at line 1459 of file sendlib.c.

1461 {
1462  char fcc_tok[PATH_MAX];
1463  char fcc_expanded[PATH_MAX];
1464 
1465  mutt_str_copy(fcc_tok, path, sizeof(fcc_tok));
1466 
1467  char *tok = strtok(fcc_tok, ",");
1468  if (!tok)
1469  return -1;
1470 
1471  mutt_debug(LL_DEBUG1, "Fcc: initial mailbox = '%s'\n", tok);
1472  /* mutt_expand_path already called above for the first token */
1473  int status = mutt_write_fcc(tok, e, msgid, post, fcc, finalpath, sub);
1474  if (status != 0)
1475  return status;
1476 
1477  while ((tok = strtok(NULL, ",")))
1478  {
1479  if (*tok == '\0')
1480  continue;
1481 
1482  /* Only call mutt_expand_path if tok has some data */
1483  mutt_debug(LL_DEBUG1, "Fcc: additional mailbox token = '%s'\n", tok);
1484  mutt_str_copy(fcc_expanded, tok, sizeof(fcc_expanded));
1485  mutt_expand_path(fcc_expanded, sizeof(fcc_expanded));
1486  mutt_debug(LL_DEBUG1, " Additional mailbox expanded = '%s'\n", fcc_expanded);
1487  status = mutt_write_fcc(fcc_expanded, e, msgid, post, fcc, finalpath, sub);
1488  if (status != 0)
1489  return status;
1490  }
1491 
1492  return 0;
1493 }
int mutt_write_fcc(const char *path, struct Email *e, const char *msgid, bool post, const char *fcc, char **finalpath, struct ConfigSubset *sub)
Write email to FCC mailbox.
Definition: sendlib.c:1507
char * mutt_expand_path(char *buf, size_t buflen)
Create the canonical path.
Definition: muttlib.c:128
#define PATH_MAX
Definition: mutt.h:44
Log at debug level 1.
Definition: logging.h:40
size_t mutt_str_copy(char *dest, const char *src, size_t dsize)
Copy a string into a buffer (guaranteeing NUL-termination)
Definition: string.c:716
#define mutt_debug(LEVEL,...)
Definition: logging.h:81
+ Here is the call graph for this function:
+ Here is the caller graph for this function: