NeoMutt  2021-10-29-33-g41675a
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 Mailbox *m, 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 Mailbox m,
struct Email e,
struct AddressList *  to,
struct ConfigSubset sub 
)

Bounce an email message.

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

Definition at line 1390 of file sendlib.c.

1392 {
1393  if (!fp || !e || !to || TAILQ_EMPTY(to))
1394  return -1;
1395 
1396  const char *fqdn = mutt_fqdn(true, sub);
1397  char resent_from[256];
1398  char *err = NULL;
1399 
1400  resent_from[0] = '\0';
1401  struct Address *from = mutt_default_from(sub);
1402  struct AddressList from_list = TAILQ_HEAD_INITIALIZER(from_list);
1403  mutt_addrlist_append(&from_list, from);
1404 
1405  /* mutt_default_from() does not use $real_name if the real name is not set
1406  * in $from, so we add it here. The reason it is not added in
1407  * mutt_default_from() is that during normal sending, we execute
1408  * send-hooks and set the real_name last so that it can be changed based
1409  * upon message criteria. */
1410  if (!from->personal)
1411  {
1412  const char *const c_real_name = cs_subset_string(sub, "real_name");
1413  from->personal = mutt_str_dup(c_real_name);
1414  }
1415 
1416  mutt_addrlist_qualify(&from_list, fqdn);
1417 
1418  rfc2047_encode_addrlist(&from_list, "Resent-From");
1419  if (mutt_addrlist_to_intl(&from_list, &err))
1420  {
1421  mutt_error(_("Bad IDN %s while preparing resent-from"), err);
1422  FREE(&err);
1423  mutt_addrlist_clear(&from_list);
1424  return -1;
1425  }
1426  mutt_addrlist_write(&from_list, resent_from, sizeof(resent_from), false);
1427 
1428 #ifdef USE_NNTP
1429  OptNewsSend = false;
1430 #endif
1431 
1432  /* prepare recipient list. idna conversion appears to happen before this
1433  * function is called, since the user receives confirmation of the address
1434  * list being bounced to. */
1435  struct AddressList resent_to = TAILQ_HEAD_INITIALIZER(resent_to);
1436  mutt_addrlist_copy(&resent_to, to, false);
1437  rfc2047_encode_addrlist(&resent_to, "Resent-To");
1438  int rc = bounce_message(fp, m, e, &resent_to, resent_from, &from_list, sub);
1439  mutt_addrlist_clear(&resent_to);
1440  mutt_addrlist_clear(&from_list);
1441 
1442  return rc;
1443 }
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
void mutt_addrlist_qualify(struct AddressList *al, const char *host)
Expand local names in an Address list using a hostname.
Definition: address.c:650
void mutt_addrlist_clear(struct AddressList *al)
Unlink and free all Address in an AddressList.
Definition: address.c:1470
void mutt_addrlist_append(struct AddressList *al, struct Address *a)
Append an Address to an AddressList.
Definition: address.c:1490
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
int mutt_addrlist_to_intl(struct AddressList *al, char **err)
Convert an Address list to Punycode.
Definition: address.c:1305
#define mutt_error(...)
Definition: logging.h:87
const char * cs_subset_string(const struct ConfigSubset *sub, const char *name)
Get a string config item by name.
Definition: helpers.c:317
#define FREE(x)
Definition: memory.h:40
#define _(a)
Definition: message.h:28
char * mutt_str_dup(const char *str)
Copy a string, safely.
Definition: string.c:181
bool OptNewsSend
(pseudo) used to change behavior when posting
Definition: options.h:51
#define TAILQ_HEAD_INITIALIZER(head)
Definition: queue.h:637
#define TAILQ_EMPTY(head)
Definition: queue.h:721
void rfc2047_encode_addrlist(struct AddressList *al, const char *tag)
Encode any RFC2047 headers, where required, in an Address list.
Definition: rfc2047.c:745
struct Address * mutt_default_from(struct ConfigSubset *sub)
Get a default 'from' Address.
Definition: send.c:1448
const char * mutt_fqdn(bool may_hide_host, const struct ConfigSubset *sub)
Get the Fully-Qualified Domain Name.
Definition: sendlib.c:1194
static int bounce_message(FILE *fp, struct Mailbox *m, struct Email *e, struct AddressList *to, const char *resent_from, struct AddressList *env_from, struct ConfigSubset *sub)
Bounce an email message.
Definition: sendlib.c:1315
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:

◆ 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 1194 of file sendlib.c.

1195 {
1196  const char *const c_hostname = cs_subset_string(sub, "hostname");
1197  if (!c_hostname || (c_hostname[0] == '@'))
1198  return NULL;
1199 
1200  const char *p = c_hostname;
1201 
1202  const bool c_hidden_host = cs_subset_bool(sub, "hidden_host");
1203  if (may_hide_host && c_hidden_host)
1204  {
1205  p = strchr(c_hostname, '.');
1206  if (p)
1207  p++;
1208 
1209  // sanity check: don't hide the host if the fqdn is something like example.com
1210  if (!p || !strchr(p, '.'))
1211  p = c_hostname;
1212  }
1213 
1214  return p;
1215 }
bool cs_subset_bool(const struct ConfigSubset *sub, const char *name)
Get a boolean config item by name.
Definition: helpers.c:73
+ 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 465 of file sendlib.c.

467 {
468  struct Content *info = NULL;
469  struct ContentState state = { 0 };
470  FILE *fp = NULL;
471  char *fromcode = NULL;
472  char *tocode = NULL;
473  char buf[100];
474  size_t r;
475 
476  struct stat st = { 0 };
477 
478  if (b && !fname)
479  fname = b->filename;
480  if (!fname)
481  return NULL;
482 
483  if (stat(fname, &st) == -1)
484  {
485  mutt_error(_("Can't stat %s: %s"), fname, strerror(errno));
486  return NULL;
487  }
488 
489  if (!S_ISREG(st.st_mode))
490  {
491  mutt_error(_("%s isn't a regular file"), fname);
492  return NULL;
493  }
494 
495  fp = fopen(fname, "r");
496  if (!fp)
497  {
498  mutt_debug(LL_DEBUG1, "%s: %s (errno %d)\n", fname, strerror(errno), errno);
499  return NULL;
500  }
501 
502  info = mutt_mem_calloc(1, sizeof(struct Content));
503 
504  const char *const c_charset = cs_subset_string(sub, "charset");
505 
506  if (b && (b->type == TYPE_TEXT) && (!b->noconv && !b->force_charset))
507  {
508  const char *const c_attach_charset =
509  cs_subset_string(sub, "attach_charset");
510  const char *const 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 ? "us-ascii" :
544  c_charset && !mutt_ch_is_us_ascii(c_charset) ?
545  c_charset :
546  "unknown-8bit"));
547  }
548 
549  return info;
550 }
int mutt_file_fclose(FILE **fp)
Close a FILE handle (and NULL the pointer)
Definition: file.c:153
static char * chs
Definition: gnupgparse.c:73
#define mutt_debug(LEVEL,...)
Definition: logging.h:84
@ LL_DEBUG1
Log at debug level 1.
Definition: logging.h:40
void * mutt_mem_calloc(size_t nmemb, size_t size)
Allocate zeroed memory on the heap.
Definition: memory.c:50
@ TYPE_TEXT
Type: 'text/*'.
Definition: mime.h:38
void mutt_ch_canonical_charset(char *buf, size_t buflen, const char *name)
Canonicalise the charset of a string.
Definition: charset.c:355
#define mutt_ch_is_us_ascii(str)
Definition: charset.h:96
char * mutt_param_get(const struct ParameterList *pl, const char *s)
Find a matching Parameter.
Definition: parameter.c:84
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:379
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:79
bool noconv
Don't do character set conversion.
Definition: body.h:45
char * charset
Send mode: charset of attached file as stored on disk.
Definition: body.h:77
struct ParameterList parameter
Parameters of the content-type.
Definition: body.h:61
bool use_disp
Content-Disposition uses filename= ?
Definition: body.h:46
bool force_charset
Send mode: don't adjust the character set when in send-mode.
Definition: body.h:43
unsigned int type
content-type primary type, ContentType
Definition: body.h:39
char * filename
When sending a message, this is the file to which this structure refers.
Definition: body.h:57
Info about the body of an email.
Definition: sendlib.c:64
Info about an attachment.
Definition: content.h:34
long hibin
8-bit characters
Definition: content.h:35
+ 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 465 of file sendlib.c.

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

1093 {
1094  if (!path || (path[0] == '\0'))
1095  return NULL;
1096 
1097  struct Body *att = mutt_body_new();
1098  att->filename = mutt_str_dup(path);
1099 
1100  const char *const c_mime_type_query_command =
1101  cs_subset_string(sub, "mime_type_query_command");
1102  const bool c_mime_type_query_first =
1103  cs_subset_bool(sub, "mime_type_query_first");
1104 
1105  if (c_mime_type_query_command && c_mime_type_query_first)
1106  run_mime_type_query(att, sub);
1107 
1108  /* Attempt to determine the appropriate content-type based on the filename
1109  * suffix. */
1110  if (!att->subtype)
1111  mutt_lookup_mime_type(att, path);
1112 
1113  if (!att->subtype && c_mime_type_query_command && !c_mime_type_query_first)
1114  {
1115  run_mime_type_query(att, sub);
1116  }
1117 
1118  struct Content *info = mutt_get_content_info(path, att, sub);
1119  if (!info)
1120  {
1121  mutt_body_free(&att);
1122  return NULL;
1123  }
1124 
1125  if (!att->subtype)
1126  {
1127  if ((info->nulbin == 0) &&
1128  ((info->lobin == 0) || ((info->lobin + info->hibin + info->ascii) / info->lobin >= 10)))
1129  {
1130  /* Statistically speaking, there should be more than 10% "lobin"
1131  * chars if this is really a binary file... */
1132  att->type = TYPE_TEXT;
1133  att->subtype = mutt_str_dup("plain");
1134  }
1135  else
1136  {
1137  att->type = TYPE_APPLICATION;
1138  att->subtype = mutt_str_dup("octet-stream");
1139  }
1140  }
1141 
1142  FREE(&info);
1143  mutt_update_encoding(att, sub);
1144  return att;
1145 }
void mutt_body_free(struct Body **ptr)
Free a Body.
Definition: body.c:57
struct Body * mutt_body_new(void)
Create a new Body.
Definition: body.c:43
@ TYPE_APPLICATION
Type: 'application/*'.
Definition: mime.h:33
enum ContentType mutt_lookup_mime_type(struct Body *att, const char *path)
Find the MIME type for an attachment.
Definition: sendlib.c:564
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:465
void mutt_update_encoding(struct Body *a, struct ConfigSubset *sub)
Update the encoding type.
Definition: sendlib.c:907
static void run_mime_type_query(struct Body *att, struct ConfigSubset *sub)
Run an external command to determine the MIME type.
Definition: sendlib.c:1050
The body of an email.
Definition: body.h:35
long ascii
Number of ascii chars.
Definition: content.h:39
long nulbin
Null characters (0x0)
Definition: content.h:37
long lobin
Unprintable 7-bit chars (eg., control chars)
Definition: content.h:36
+ 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 939 of file sendlib.c.

941 {
942  struct Body *body = NULL;
943  FILE *fp = NULL;
944  CopyMessageFlags cmflags;
946 
947  const bool c_mime_forward_decode = cs_subset_bool(sub, "mime_forward_decode");
948  const bool c_forward_decrypt = cs_subset_bool(sub, "forward_decrypt");
949  if (WithCrypto)
950  {
951  if ((c_mime_forward_decode || c_forward_decrypt) && (e->security & SEC_ENCRYPT))
952  {
954  return NULL;
955  }
956  }
957 
958  struct Buffer *buf = mutt_buffer_pool_get();
959  mutt_buffer_mktemp(buf);
960  fp = mutt_file_fopen(mutt_buffer_string(buf), "w+");
961  if (!fp)
962  {
964  return NULL;
965  }
966 
967  body = mutt_body_new();
968  body->type = TYPE_MESSAGE;
969  body->subtype = mutt_str_dup("rfc822");
971  body->unlink = true;
972  body->use_disp = false;
973  body->disposition = DISP_INLINE;
974  body->noconv = true;
975 
977 
978  struct Message *msg = mx_msg_open(m, e->msgno);
979  if (!msg)
980  {
981  mutt_body_free(&body);
982  return NULL;
983  }
984  mutt_parse_mime_message(e, msg->fp);
985 
986  CopyHeaderFlags chflags = CH_XMIT;
987  cmflags = MUTT_CM_NO_FLAGS;
988 
989  /* If we are attaching a message, ignore `$mime_forward_decode` */
990  if (!attach_msg && c_mime_forward_decode)
991  {
992  chflags |= CH_MIME | CH_TXTPLAIN;
993  cmflags = MUTT_CM_DECODE | MUTT_CM_CHARCONV;
995  pgp &= ~PGP_ENCRYPT;
997  pgp &= ~SMIME_ENCRYPT;
998  }
999  else if ((WithCrypto != 0) && c_forward_decrypt && (e->security & SEC_ENCRYPT))
1000  {
1002  {
1003  chflags |= CH_MIME | CH_NONEWLINE;
1004  cmflags = MUTT_CM_DECODE_PGP;
1005  pgp &= ~PGP_ENCRYPT;
1006  }
1007  else if (((WithCrypto & APPLICATION_PGP) != 0) &&
1009  {
1010  chflags |= CH_MIME | CH_TXTPLAIN;
1011  cmflags = MUTT_CM_DECODE | MUTT_CM_CHARCONV;
1012  pgp &= ~PGP_ENCRYPT;
1013  }
1014  else if (((WithCrypto & APPLICATION_SMIME) != 0) &&
1016  {
1017  chflags |= CH_MIME | CH_TXTPLAIN;
1018  cmflags = MUTT_CM_DECODE | MUTT_CM_CHARCONV;
1019  pgp &= ~SMIME_ENCRYPT;
1020  }
1021  }
1022 
1023  mutt_copy_message(fp, e, msg, cmflags, chflags, 0);
1024  mx_msg_close(m, &msg);
1025 
1026  fflush(fp);
1027  rewind(fp);
1028 
1029  body->email = email_new();
1030  body->email->offset = 0;
1031  /* we don't need the user headers here */
1032  body->email->env = mutt_rfc822_read_header(fp, body->email, false, false);
1033  if (WithCrypto)
1034  body->email->security = pgp;
1035  mutt_update_encoding(body, sub);
1036  body->parts = body->email->body;
1037 
1038  mutt_file_fclose(&fp);
1039 
1040  return body;
1041 }
void mutt_parse_mime_message(struct Email *e, FILE *fp)
Parse a MIME email.
Definition: attachments.c:593
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_message(FILE *fp_out, struct Email *e, struct Message *msg, CopyMessageFlags cmflags, CopyHeaderFlags chflags, int wraplen)
Copy a message from a Mailbox.
Definition: copy.c:881
#define CH_XMIT
Transmitting this message? (Ignore Lines: and Content-Length:)
Definition: copy.h:55
#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 CH_NONEWLINE
Don't output terminating newline after the header.
Definition: copy.h:60
#define MUTT_CM_CHARCONV
Perform character set conversions.
Definition: copy.h:42
#define CH_MIME
Ignore MIME fields.
Definition: copy.h:61
uint32_t CopyHeaderFlags
Flags for mutt_copy_header(), e.g. CH_UPDATE.
Definition: copy.h:50
#define MUTT_CM_NO_FLAGS
No flags are set.
Definition: copy.h:35
#define CH_TXTPLAIN
Generate text/plain MIME headers.
Definition: copy.h:63
uint16_t CopyMessageFlags
Flags for mutt_copy_message(), e.g. MUTT_CM_NOHEADER.
Definition: copy.h:32
SecurityFlags mutt_is_application_pgp(struct Body *b)
Does the message use PGP?
Definition: crypt.c:559
SecurityFlags mutt_is_application_smime(struct Body *b)
Does the message use S/MIME?
Definition: crypt.c:617
bool crypt_valid_passphrase(SecurityFlags flags)
Check that we have a usable passphrase, ask if not.
Definition: crypt.c:135
SecurityFlags mutt_is_multipart_encrypted(struct Body *b)
Does the message have encrypted parts?
Definition: crypt.c:454
struct Email * email_new(void)
Create a new Email.
Definition: email.c:78
FILE * mutt_file_fopen(const char *path, const char *mode)
Call fopen() safely.
Definition: file.c:593
@ TYPE_MESSAGE
Type: 'message/*'.
Definition: mime.h:35
@ DISP_INLINE
Content is inline.
Definition: mime.h:62
#define mutt_buffer_mktemp(buf)
Definition: muttlib.h:74
int mx_msg_close(struct Mailbox *m, struct Message **msg)
Close a message.
Definition: mx.c:1191
struct Message * mx_msg_open(struct Mailbox *m, int msgno)
Return a stream pointer for a message.
Definition: mx.c:1145
uint16_t SecurityFlags
Flags, e.g. SEC_ENCRYPT.
Definition: lib.h:71
#define APPLICATION_PGP
Use PGP to encrypt/sign.
Definition: lib.h:87
#define PGP_ENCRYPT
Definition: lib.h:93
#define APPLICATION_SMIME
Use SMIME to encrypt/sign.
Definition: lib.h:88
#define SEC_NO_FLAGS
No flags are set.
Definition: lib.h:74
#define SEC_ENCRYPT
Email is encrypted.
Definition: lib.h:75
#define SMIME_ENCRYPT
Definition: lib.h:99
#define WithCrypto
Definition: lib.h:113
struct Envelope * mutt_rfc822_read_header(FILE *fp, struct Email *e, bool user_hdrs, bool weed)
Parses an RFC822 header.
Definition: parse.c:1164
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
struct Body * parts
parts of a multipart or message/rfc822
Definition: body.h:71
bool unlink
If true, filename should be unlink()ed before free()ing this structure.
Definition: body.h:66
struct Email * email
header information for message/rfc822
Definition: body.h:72
unsigned int disposition
content-disposition, ContentDisposition
Definition: body.h:41
String manipulation buffer.
Definition: buffer.h:34
struct Envelope * env
Envelope information.
Definition: email.h:66
SecurityFlags security
bit 0-10: flags, bit 11,12: application, bit 13: traditional pgp See: ncrypt/lib.h pgplib....
Definition: email.h:41
struct Body * body
List of MIME parts.
Definition: email.h:67
LOFF_T offset
Where in the stream does this message begin?
Definition: email.h:69
int msgno
Number displayed to the user.
Definition: email.h:111
A local copy of an email.
Definition: mxapi.h:42
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:

◆ 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 747 of file sendlib.c.

748 {
749  struct Buffer temp = mutt_buffer_make(0);
750  FILE *fp_in = NULL;
751  FILE *fp_out = NULL;
752  struct stat st = { 0 };
753 
754  if (!a->filename && fp)
755  fp_in = fp;
756  else if (!a->filename || !(fp_in = fopen(a->filename, "r")))
757  {
758  mutt_error(_("Could not open %s"), a->filename ? a->filename : "(null)");
759  return;
760  }
761  else
762  {
763  a->offset = 0;
764  if (stat(a->filename, &st) == -1)
765  {
766  mutt_perror("stat");
767  mutt_file_fclose(&fp_in);
768  goto cleanup;
769  }
770  a->length = st.st_size;
771  }
772 
773  /* Avoid buffer pool due to recursion */
774  mutt_buffer_mktemp(&temp);
775  fp_out = mutt_file_fopen(mutt_buffer_string(&temp), "w+");
776  if (!fp_out)
777  {
778  mutt_perror("fopen");
779  goto cleanup;
780  }
781 
782  if (!mutt_file_seek(fp_in, a->offset, SEEK_SET))
783  {
784  goto cleanup;
785  }
786  a->parts = mutt_rfc822_parse_message(fp_in, a);
787 
788  transform_to_7bit(a->parts, fp_in, sub);
789 
790  mutt_copy_hdr(fp_in, fp_out, a->offset, a->offset + a->length,
791  CH_MIME | CH_NONEWLINE | CH_XMIT, NULL, 0);
792 
793  fputs("MIME-Version: 1.0\n", fp_out);
794  mutt_write_mime_header(a->parts, fp_out, sub);
795  fputc('\n', fp_out);
796  mutt_write_mime_body(a->parts, fp_out, sub);
797 
798  if (fp_in != fp)
799  mutt_file_fclose(&fp_in);
800  mutt_file_fclose(&fp_out);
801 
802  a->encoding = ENC_7BIT;
803  FREE(&a->d_filename);
804  a->d_filename = a->filename;
805  if (a->filename && a->unlink)
806  unlink(a->filename);
807  a->filename = mutt_buffer_strdup(&temp);
808  a->unlink = true;
809  if (stat(a->filename, &st) == -1)
810  {
811  mutt_perror("stat");
812  goto cleanup;
813  }
814  a->length = st.st_size;
815  mutt_body_free(&a->parts);
816  a->email->body = NULL;
817 
818 cleanup:
819  if (fp_in && (fp_in != fp))
820  mutt_file_fclose(&fp_in);
821 
822  if (fp_out)
823  {
824  mutt_file_fclose(&fp_out);
826  }
827 
828  mutt_buffer_dealloc(&temp);
829 }
struct Buffer mutt_buffer_make(size_t size)
Make a new buffer on the stack.
Definition: buffer.c:61
void mutt_buffer_dealloc(struct Buffer *buf)
Release the memory allocated by a buffer.
Definition: buffer.c:294
char * mutt_buffer_strdup(const struct Buffer *buf)
Copy a Buffer's string.
Definition: buffer.c:432
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
bool mutt_file_seek(FILE *fp, LOFF_T offset, int whence)
Wrapper for fseeko with error handling.
Definition: file.c:665
void mutt_file_unlink(const char *s)
Delete a file, carefully.
Definition: file.c:195
#define mutt_perror(...)
Definition: logging.h:88
int mutt_write_mime_header(struct Body *a, FILE *fp, struct ConfigSubset *sub)
Create a MIME header.
Definition: header.c:761
@ ENC_7BIT
7-bit text
Definition: mime.h:49
struct Body * mutt_rfc822_parse_message(FILE *fp, struct Body *parent)
Parse a Message/RFC822 body.
Definition: parse.c:1736
int mutt_write_mime_body(struct Body *a, FILE *fp, struct ConfigSubset *sub)
Write a MIME part.
Definition: body.c:314
static void transform_to_7bit(struct Body *a, FILE *fp_in, struct ConfigSubset *sub)
Convert MIME parts to 7-bit.
Definition: sendlib.c:684
char * d_filename
filename to be used for the content-disposition header If NULL, filename is used instead.
Definition: body.h:55
LOFF_T offset
offset where the actual data begins
Definition: body.h:51
LOFF_T length
length (in bytes) of attachment
Definition: body.h:52
unsigned int encoding
content-transfer-encoding, ContentEncoding
Definition: body.h:40
+ 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 1250 of file sendlib.c.

1251 {
1252  if (final)
1253  {
1254  if (!TAILQ_EMPTY(&env->bcc) && TAILQ_EMPTY(&env->to) && TAILQ_EMPTY(&env->cc))
1255  {
1256  /* some MTA's will put an Apparently-To: header field showing the Bcc:
1257  * recipients if there is no To: or Cc: field, so attempt to suppress
1258  * it by using an empty To: field. */
1259  struct Address *to = mutt_addr_new();
1260  to->group = true;
1261  mutt_addrlist_append(&env->to, to);
1263 
1264  char buf[1024];
1265  buf[0] = '\0';
1266  mutt_addr_cat(buf, sizeof(buf), "undisclosed-recipients", AddressSpecials);
1267 
1268  to->mailbox = mutt_str_dup(buf);
1269  }
1270 
1271  mutt_set_followup_to(env, sub);
1272 
1273  if (!env->message_id)
1274  env->message_id = gen_msgid(sub);
1275  }
1276 
1277  /* Take care of 8-bit => 7-bit conversion. */
1279  encode_headers(&env->userhdrs, sub);
1280 }
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
const char AddressSpecials[]
Characters with special meaning for email addresses.
Definition: address.c:42
struct Address * mutt_addr_new(void)
Create a new Address.
Definition: address.c:385
void rfc2047_encode_envelope(struct Envelope *env)
Encode the fields of an Envelope.
Definition: rfc2047.c:810
void mutt_set_followup_to(struct Envelope *env, struct ConfigSubset *sub)
Set followup-to field.
Definition: send.c:1323
static char * gen_msgid(struct ConfigSubset *sub)
Generate a unique Message ID.
Definition: sendlib.c:1223
static void encode_headers(struct ListHead *h, struct ConfigSubset *sub)
RFC2047-encode a list of headers.
Definition: sendlib.c:1154
bool group
Group mailbox?
Definition: address.h:39
char * mailbox
Mailbox and host address.
Definition: address.h:38
struct ListHead userhdrs
user defined headers
Definition: envelope.h:85
struct AddressList to
Email's 'To' list.
Definition: envelope.h:58
char * message_id
Message ID.
Definition: envelope.h:71
struct AddressList cc
Email's 'Cc' list.
Definition: envelope.h:59
struct AddressList bcc
Email's 'Bcc' list.
Definition: envelope.h:60
+ 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 895 of file sendlib.c.

896 {
897  a->stamp = mutt_date_epoch();
898 }
time_t mutt_date_epoch(void)
Return the number of seconds since the Unix epoch.
Definition: date.c:427
time_t stamp
Time stamp of last encoding update.
Definition: body.h:75
+ 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 1289 of file sendlib.c.

1290 {
1291  struct ListNode *item = NULL;
1292  STAILQ_FOREACH(item, &env->userhdrs, entries)
1293  {
1294  rfc2047_decode(&item->data);
1295  }
1296 
1298 
1299  /* back conversions */
1301 }
#define STAILQ_FOREACH(var, head, field)
Definition: queue.h:352
void rfc2047_decode_envelope(struct Envelope *env)
Decode the fields of an Envelope.
Definition: rfc2047.c:790
void rfc2047_decode(char **pd)
Decode any RFC2047-encoded header fields.
Definition: rfc2047.c:644
struct AddressList mail_followup_to
Email's 'mail-followup-to'.
Definition: envelope.h:63
A List node for strings.
Definition: list.h:35
char * data
String.
Definition: list.h:36
+ 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 907 of file sendlib.c.

908 {
909  struct Content *info = NULL;
910  char chsbuf[256];
911 
912  /* override noconv when it's us-ascii */
913  if (mutt_ch_is_us_ascii(mutt_body_get_charset(a, chsbuf, sizeof(chsbuf))))
914  a->noconv = false;
915 
916  if (!a->force_charset && !a->noconv)
917  mutt_param_delete(&a->parameter, "charset");
918 
919  info = mutt_get_content_info(a->filename, a, sub);
920  if (!info)
921  return;
922 
923  set_encoding(a, info, sub);
925 
926  FREE(&a->content);
927  a->content = info;
928 }
char * mutt_body_get_charset(struct Body *b, char *buf, size_t buflen)
Get a body's character set.
Definition: body.c:131
void mutt_param_delete(struct ParameterList *pl, const char *attribute)
Delete a matching Parameter.
Definition: parameter.c:142
void mutt_stamp_attachment(struct Body *a)
Timestamp an Attachment.
Definition: sendlib.c:895
static void set_encoding(struct Body *b, struct Content *info, struct ConfigSubset *sub)
Determine which Content-Transfer-Encoding to use.
Definition: sendlib.c:837
struct Content * content
Detailed info about the content of the attachment.
Definition: body.h:68
+ 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 1526 of file sendlib.c.

1528 {
1529  struct Message *msg = NULL;
1530  struct Buffer *tempfile = NULL;
1531  FILE *fp_tmp = NULL;
1532  int rc = -1;
1533  bool need_mailbox_cleanup = false;
1534  struct stat st = { 0 };
1535  MsgOpenFlags onm_flags;
1536 
1537  if (post)
1538  set_noconv_flags(e->body, true);
1539 
1540 #ifdef RECORD_FOLDER_HOOK
1541  mutt_folder_hook(path, NULL);
1542 #endif
1543  struct Mailbox *m_fcc = mx_path_resolve(path);
1544  bool old_append = m_fcc->append;
1545  if (!mx_mbox_open(m_fcc, MUTT_APPEND | MUTT_QUIET))
1546  {
1547  mutt_debug(LL_DEBUG1, "unable to open mailbox %s in append-mode, aborting\n", path);
1548  goto done;
1549  }
1550 
1551  /* We need to add a Content-Length field to avoid problems where a line in
1552  * the message body begins with "From " */
1553  if ((m_fcc->type == MUTT_MMDF) || (m_fcc->type == MUTT_MBOX))
1554  {
1555  tempfile = mutt_buffer_pool_get();
1556  mutt_buffer_mktemp(tempfile);
1557  fp_tmp = mutt_file_fopen(mutt_buffer_string(tempfile), "w+");
1558  if (!fp_tmp)
1559  {
1560  mutt_perror(mutt_buffer_string(tempfile));
1561  mx_mbox_close(m_fcc);
1562  goto done;
1563  }
1564  /* remember new mail status before appending message */
1565  need_mailbox_cleanup = true;
1566  stat(path, &st);
1567  }
1568 
1569  e->read = !post; /* make sure to put it in the 'cur' directory (maildir) */
1570  onm_flags = MUTT_ADD_FROM;
1571  if (post)
1572  onm_flags |= MUTT_SET_DRAFT;
1573  msg = mx_msg_open_new(m_fcc, e, onm_flags);
1574  if (!msg)
1575  {
1576  mutt_file_fclose(&fp_tmp);
1577  mx_mbox_close(m_fcc);
1578  goto done;
1579  }
1580 
1581  const bool c_crypt_protected_headers_read =
1582  cs_subset_bool(sub, "crypt_protected_headers_read");
1583 
1584  /* post == 1 => postpone message.
1585  * post == 0 => Normal mode. */
1587  msg->fp, e->env, e->body,
1589  c_crypt_protected_headers_read && mutt_should_hide_protected_subject(e), sub);
1590 
1591  /* (postponement) if this was a reply of some sort, <msgid> contains the
1592  * Message-ID: of message replied to. Save it using a special X-Mutt-
1593  * header so it can be picked up if the message is recalled at a later
1594  * point in time. This will allow the message to be marked as replied if
1595  * the same mailbox is still open. */
1596  if (post && msgid)
1597  fprintf(msg->fp, "X-Mutt-References: %s\n", msgid);
1598 
1599  /* (postponement) save the Fcc: using a special X-Mutt- header so that
1600  * it can be picked up when the message is recalled */
1601  if (post && fcc)
1602  fprintf(msg->fp, "X-Mutt-Fcc: %s\n", fcc);
1603 
1604  if ((m_fcc->type == MUTT_MMDF) || (m_fcc->type == MUTT_MBOX))
1605  fprintf(msg->fp, "Status: RO\n");
1606 
1607  /* (postponement) if the mail is to be signed or encrypted, save this info */
1608  if (((WithCrypto & APPLICATION_PGP) != 0) && post && (e->security & APPLICATION_PGP))
1609  {
1610  fputs("X-Mutt-PGP: ", msg->fp);
1611  if (e->security & SEC_ENCRYPT)
1612  fputc('E', msg->fp);
1613  if (e->security & SEC_OPPENCRYPT)
1614  fputc('O', msg->fp);
1615  if (e->security & SEC_SIGN)
1616  {
1617  fputc('S', msg->fp);
1618 
1619  const char *const c_pgp_sign_as = cs_subset_string(sub, "pgp_sign_as");
1620  if (c_pgp_sign_as)
1621  fprintf(msg->fp, "<%s>", c_pgp_sign_as);
1622  }
1623  if (e->security & SEC_INLINE)
1624  fputc('I', msg->fp);
1625 #ifdef USE_AUTOCRYPT
1626  if (e->security & SEC_AUTOCRYPT)
1627  fputc('A', msg->fp);
1629  fputc('Z', msg->fp);
1630 #endif
1631  fputc('\n', msg->fp);
1632  }
1633 
1634  /* (postponement) if the mail is to be signed or encrypted, save this info */
1635  if (((WithCrypto & APPLICATION_SMIME) != 0) && post && (e->security & APPLICATION_SMIME))
1636  {
1637  fputs("X-Mutt-SMIME: ", msg->fp);
1638  if (e->security & SEC_ENCRYPT)
1639  {
1640  fputc('E', msg->fp);
1641 
1642  const char *const c_smime_encrypt_with =
1643  cs_subset_string(sub, "smime_encrypt_with");
1644  if (c_smime_encrypt_with)
1645  fprintf(msg->fp, "C<%s>", c_smime_encrypt_with);
1646  }
1647  if (e->security & SEC_OPPENCRYPT)
1648  fputc('O', msg->fp);
1649  if (e->security & SEC_SIGN)
1650  {
1651  fputc('S', msg->fp);
1652 
1653  const char *const c_smime_sign_as =
1654  cs_subset_string(sub, "smime_sign_as");
1655  if (c_smime_sign_as)
1656  fprintf(msg->fp, "<%s>", c_smime_sign_as);
1657  }
1658  if (e->security & SEC_INLINE)
1659  fputc('I', msg->fp);
1660  fputc('\n', msg->fp);
1661  }
1662 
1663 #ifdef MIXMASTER
1664  /* (postponement) if the mail is to be sent through a mixmaster
1665  * chain, save that information */
1666 
1667  if (post && !STAILQ_EMPTY(&e->chain))
1668  {
1669  fputs("X-Mutt-Mix:", msg->fp);
1670  struct ListNode *p = NULL;
1671  STAILQ_FOREACH(p, &e->chain, entries)
1672  {
1673  fprintf(msg->fp, " %s", (char *) p->data);
1674  }
1675 
1676  fputc('\n', msg->fp);
1677  }
1678 #endif
1679 
1680  if (fp_tmp)
1681  {
1682  mutt_write_mime_body(e->body, fp_tmp, sub);
1683 
1684  /* make sure the last line ends with a newline. Emacs doesn't ensure this
1685  * will happen, and it can cause problems parsing the mailbox later. */
1686  if (mutt_file_seek(fp_tmp, -1, SEEK_END) && (fgetc(fp_tmp) != '\n') &&
1687  mutt_file_seek(fp_tmp, 0, SEEK_END))
1688  {
1689  fputc('\n', fp_tmp);
1690  }
1691 
1692  fflush(fp_tmp);
1693  if (ferror(fp_tmp))
1694  {
1695  mutt_debug(LL_DEBUG1, "%s: write failed\n", mutt_buffer_string(tempfile));
1696  mutt_file_fclose(&fp_tmp);
1697  unlink(mutt_buffer_string(tempfile));
1698  mx_msg_commit(m_fcc, msg); /* XXX really? */
1699  mx_msg_close(m_fcc, &msg);
1700  mx_mbox_close(m_fcc);
1701  goto done;
1702  }
1703 
1704  /* count the number of lines */
1705  int lines = 0;
1706  char line_buf[1024];
1707  rewind(fp_tmp);
1708  while (fgets(line_buf, sizeof(line_buf), fp_tmp))
1709  lines++;
1710  fprintf(msg->fp, "Content-Length: " OFF_T_FMT "\n", (LOFF_T) ftello(fp_tmp));
1711  fprintf(msg->fp, "Lines: %d\n\n", lines);
1712 
1713  /* copy the body and clean up */
1714  rewind(fp_tmp);
1715  rc = mutt_file_copy_stream(fp_tmp, msg->fp);
1716  if (mutt_file_fclose(&fp_tmp) != 0)
1717  rc = -1;
1718  /* if there was an error, leave the temp version */
1719  if (rc >= 0)
1720  {
1721  unlink(mutt_buffer_string(tempfile));
1722  rc = 0;
1723  }
1724  }
1725  else
1726  {
1727  fputc('\n', msg->fp); /* finish off the header */
1728  rc = mutt_write_mime_body(e->body, msg->fp, sub);
1729  }
1730 
1731  if (mx_msg_commit(m_fcc, msg) != 0)
1732  rc = -1;
1733  else if (finalpath)
1734  *finalpath = mutt_str_dup(msg->committed_path);
1735  mx_msg_close(m_fcc, &msg);
1736  mx_mbox_close(m_fcc);
1737 
1738  if (!post && need_mailbox_cleanup)
1739  mutt_mailbox_cleanup(path, &st);
1740 
1741  if (post)
1742  set_noconv_flags(e->body, false);
1743 
1744 done:
1745  m_fcc->append = old_append;
1746  if (m_fcc->flags == MB_HIDDEN)
1747  mailbox_free(&m_fcc);
1748 
1749 #ifdef RECORD_FOLDER_HOOK
1750  /* We ran a folder hook for the destination mailbox,
1751  * now we run it for the user's current mailbox */
1752  const struct Mailbox *m = ctx_mailbox(Context);
1753  if (m)
1754  mutt_folder_hook(m->path, m->desc);
1755 #endif
1756 
1757  if (fp_tmp)
1758  {
1759  mutt_file_fclose(&fp_tmp);
1760  unlink(mutt_buffer_string(tempfile));
1761  }
1762  mutt_buffer_pool_release(&tempfile);
1763 
1764  return rc;
1765 }
struct Mailbox * ctx_mailbox(struct Context *ctx)
Wrapper to get the mailbox in a Context, or NULL.
Definition: context.c:444
bool mutt_should_hide_protected_subject(struct Email *e)
Should NeoMutt hide the protected subject?
Definition: crypt.c:1103
int mutt_file_copy_stream(FILE *fp_in, FILE *fp_out)
Copy the contents of one file into another.
Definition: file.c:271
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:572
@ MUTT_WRITE_HEADER_FCC
fcc mode, like normal mode but for Bcc header
Definition: header.h:41
@ MUTT_WRITE_HEADER_POSTPONE
A postponed Email, just the envelope info.
Definition: header.h:42
void mutt_folder_hook(const char *path, const char *desc)
Perform a folder hook.
Definition: hook.c:528
void mailbox_free(struct Mailbox **ptr)
Free a Mailbox.
Definition: mailbox.c:87
#define MB_HIDDEN
Definition: mailbox.h:38
@ MUTT_MMDF
'mmdf' Mailbox type
Definition: mailbox.h:49
@ MUTT_MBOX
'mbox' Mailbox type
Definition: mailbox.h:48
void mutt_mailbox_cleanup(const char *path, struct stat *st)
Restore the timestamp of a mailbox.
Definition: mutt_mailbox.c:430
bool mx_mbox_open(struct Mailbox *m, OpenMailboxFlags flags)
Open a mailbox and parse it.
Definition: mx.c:304
struct Mailbox * mx_path_resolve(const char *path)
Get a Mailbox for a path.
Definition: mx.c:1673
int mx_msg_commit(struct Mailbox *m, struct Message *msg)
Commit a message to a folder - Wrapper for MxOps::msg_commit()
Definition: mx.c:1170
struct Message * mx_msg_open_new(struct Mailbox *m, const struct Email *e, MsgOpenFlags flags)
Open a new message.
Definition: mx.c:1059
enum MxStatus mx_mbox_close(struct Mailbox *m)
Save changes and close mailbox.
Definition: mx.c:615
uint8_t MsgOpenFlags
Flags for mx_msg_open_new(), e.g. MUTT_ADD_FROM.
Definition: mx.h:40
#define MUTT_ADD_FROM
add a From_ line
Definition: mx.h:42
#define MUTT_SET_DRAFT
set the message draft flag
Definition: mx.h:43
#define MUTT_APPEND
Open mailbox for appending messages.
Definition: mxapi.h:62
#define MUTT_QUIET
Do not print any messages.
Definition: mxapi.h:64
#define SEC_INLINE
Email has an inline signature.
Definition: lib.h:82
#define SEC_AUTOCRYPT
(Autocrypt) Message will be, or was Autocrypt encrypt+signed
Definition: lib.h:84
#define SEC_OPPENCRYPT
Opportunistic encrypt mode.
Definition: lib.h:83
#define SEC_AUTOCRYPT_OVERRIDE
(Autocrypt) Indicates manual set/unset of encryption
Definition: lib.h:85
#define SEC_SIGN
Email is signed.
Definition: lib.h:76
#define STAILQ_EMPTY(head)
Definition: queue.h:348
static void set_noconv_flags(struct Body *b, bool flag)
Set/reset the "x-mutt-noconv" flag.
Definition: sendlib.c:1450
The "current" mailbox.
Definition: context.h:38
bool read
Email is read.
Definition: email.h:48
struct ListHead chain
Mixmaster chain.
Definition: email.h:90
A mailbox.
Definition: mailbox.h:82
bool append
Mailbox is opened in append mode.
Definition: mailbox.h:113
enum MailboxType type
Mailbox type.
Definition: mailbox.h:105
uint8_t flags
e.g. MB_NORMAL
Definition: mailbox.h:134
struct ConfigSubset * sub
Inherited config items.
Definition: mailbox.h:86
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_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 1478 of file sendlib.c.

1480 {
1481  char fcc_tok[PATH_MAX];
1482  char fcc_expanded[PATH_MAX];
1483 
1484  mutt_str_copy(fcc_tok, path, sizeof(fcc_tok));
1485 
1486  char *tok = strtok(fcc_tok, ",");
1487  if (!tok)
1488  return -1;
1489 
1490  mutt_debug(LL_DEBUG1, "Fcc: initial mailbox = '%s'\n", tok);
1491  /* mutt_expand_path already called above for the first token */
1492  int status = mutt_write_fcc(tok, e, msgid, post, fcc, finalpath, sub);
1493  if (status != 0)
1494  return status;
1495 
1496  while ((tok = strtok(NULL, ",")))
1497  {
1498  if (*tok == '\0')
1499  continue;
1500 
1501  /* Only call mutt_expand_path if tok has some data */
1502  mutt_debug(LL_DEBUG1, "Fcc: additional mailbox token = '%s'\n", tok);
1503  mutt_str_copy(fcc_expanded, tok, sizeof(fcc_expanded));
1504  mutt_expand_path(fcc_expanded, sizeof(fcc_expanded));
1505  mutt_debug(LL_DEBUG1, " Additional mailbox expanded = '%s'\n", fcc_expanded);
1506  status = mutt_write_fcc(fcc_expanded, e, msgid, post, fcc, finalpath, sub);
1507  if (status != 0)
1508  return status;
1509  }
1510 
1511  return 0;
1512 }
char * mutt_expand_path(char *buf, size_t buflen)
Create the canonical path.
Definition: muttlib.c:122
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:1526
+ Here is the call graph for this function:
+ Here is the caller graph for this function: