NeoMutt  2018-07-16 +2225-8687db
Teaching an old dog new tricks
DOXYGEN
sendlib.c File Reference

Miscellaneous functions for sending an email. More...

#include "config.h"
#include <errno.h>
#include <fcntl.h>
#include <iconv.h>
#include <inttypes.h>
#include <limits.h>
#include <signal.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include <time.h>
#include <unistd.h>
#include "mutt/mutt.h"
#include "address/lib.h"
#include "config/lib.h"
#include "email/lib.h"
#include "mutt.h"
#include "sendlib.h"
#include "context.h"
#include "copy.h"
#include "core/lib.h"
#include "curs_lib.h"
#include "filter.h"
#include "globals.h"
#include "handler.h"
#include "hook.h"
#include "mutt_mailbox.h"
#include "mutt_parse.h"
#include "mutt_window.h"
#include "muttlib.h"
#include "mx.h"
#include "ncrypt/ncrypt.h"
#include "options.h"
#include "send.h"
#include "smtp.h"
#include "state.h"
#include "nntp/nntp.h"

Go to the source code of this file.

Data Structures

struct  B64Context
 Cursor for the Base64 conversion. More...
 
struct  ContentState
 Info about the body of an email. More...
 

Macros

#define EX_OK   0
 

Functions

static void encode_quoted (struct FgetConv *fc, FILE *fp_out, bool istext)
 Encode text as quoted printable. More...
 
static int b64_init (struct B64Context *bctx)
 Set up the base64 conversion. More...
 
static void b64_flush (struct B64Context *bctx, FILE *fp_out)
 Save the bytes to the file. More...
 
static void b64_putc (struct B64Context *bctx, char c, FILE *fp_out)
 Base64-encode one character. More...
 
static void encode_base64 (struct FgetConv *fc, FILE *fp_out, int istext)
 Base64-encode some data. More...
 
static void encode_8bit (struct FgetConv *fc, FILE *fp_out)
 Write the data as raw 8-bit data. More...
 
int mutt_write_mime_header (struct Body *a, FILE *fp)
 Create a MIME header. More...
 
static bool write_as_text_part (struct Body *b)
 Should the Body be written as a text MIME part. More...
 
int mutt_write_mime_body (struct Body *a, FILE *fp)
 Write a MIME part. More...
 
void mutt_generate_boundary (struct ParameterList *parm)
 Create a unique boundary id for a MIME part. More...
 
static void update_content_info (struct Content *info, struct ContentState *s, char *buf, size_t buflen)
 Cache some info about an email. More...
 
static size_t convert_file_to (FILE *fp, const char *fromcode, int ncodes, char const *const *tocodes, int *tocode, struct Content *info)
 Change the encoding of a file. More...
 
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. More...
 
struct Contentmutt_get_content_info (const char *fname, struct Body *b)
 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...
 
static void transform_to_7bit (struct Body *a, FILE *fp_in)
 Convert MIME parts to 7-bit. More...
 
void mutt_message_to_7bit (struct Body *a, FILE *fp)
 Convert an email's MIME parts to 7-bit. More...
 
static void set_encoding (struct Body *b, struct Content *info)
 determine which Content-Transfer-Encoding to use More...
 
void mutt_stamp_attachment (struct Body *a)
 Timestamp an Attachment. More...
 
char * mutt_body_get_charset (struct Body *b, char *buf, size_t buflen)
 Get a body's character set. More...
 
void mutt_update_encoding (struct Body *a)
 Update the encoding type. More...
 
struct Bodymutt_make_message_attach (struct Mailbox *m, struct Email *e, bool attach_msg)
 Create a message attachment. More...
 
static void run_mime_type_query (struct Body *att)
 Run an external command to determine the MIME type. More...
 
struct Bodymutt_make_file_attach (const char *path)
 Create a file attachment. More...
 
static int get_toplevel_encoding (struct Body *a)
 Find the most restrictive encoding type. More...
 
static bool check_boundary (const char *boundary, struct Body *b)
 check for duplicate boundary More...
 
struct Bodymutt_make_multipart (struct Body *b)
 Create a multipart email. More...
 
struct Bodymutt_remove_multipart (struct Body *b)
 Extract the multipart body if it exists. More...
 
void mutt_write_addrlist (struct AddressList *al, FILE *fp, int linelen, bool display)
 wrapper around mutt_write_address() More...
 
void mutt_write_references (const struct ListHead *r, FILE *fp, size_t trim)
 Add the message references to a list. More...
 
static int print_val (FILE *fp, const char *pfx, const char *value, CopyHeaderFlags chflags, size_t col)
 Add pieces to an email header, wrapping where necessary. More...
 
static int fold_one_header (FILE *fp, const char *tag, const char *value, const char *pfx, int wraplen, CopyHeaderFlags chflags)
 Fold one header line. More...
 
static char * unfold_header (char *s)
 Unfold a wrapped email header. More...
 
static int write_one_header (FILE *fp, int pfxw, int max, int wraplen, const char *pfx, const char *start, const char *end, CopyHeaderFlags chflags)
 Write out one header line. More...
 
int mutt_write_one_header (FILE *fp, const char *tag, const char *value, const char *pfx, int wraplen, CopyHeaderFlags chflags)
 Write one header line to a file. More...
 
int mutt_rfc822_write_header (FILE *fp, struct Envelope *env, struct Body *attach, enum MuttWriteHeaderMode mode, bool privacy, bool hide_protected_subject)
 Write out one RFC822 header line. More...
 
static void encode_headers (struct ListHead *h)
 RFC2047-encode a list of headers. More...
 
const char * mutt_fqdn (bool may_hide_host)
 Get the Fully-Qualified Domain Name. More...
 
static char * gen_msgid (void)
 Generate a unique Message ID. More...
 
static void alarm_handler (int sig)
 Async notification of an alarm signal. More...
 
static int send_msg (const char *path, char **args, const char *msg, char **tempfile)
 invoke sendmail in a subshell More...
 
static char ** add_args_one (char **args, size_t *argslen, size_t *argsmax, struct Address *addr)
 Add an Address to a dynamic array. More...
 
static char ** add_args (char **args, size_t *argslen, size_t *argsmax, struct AddressList *al)
 Add a list of Addresses to a dynamic array. More...
 
static char ** add_option (char **args, size_t *argslen, size_t *argsmax, char *s)
 Add a string to a dynamic array. More...
 
int mutt_invoke_sendmail (struct AddressList *from, struct AddressList *to, struct AddressList *cc, struct AddressList *bcc, const char *msg, int eightbit)
 Run sendmail. More...
 
void mutt_prepare_envelope (struct Envelope *env, bool final)
 Prepare an email header. More...
 
void mutt_unprepare_envelope (struct Envelope *env)
 Undo the encodings of mutt_prepare_envelope() More...
 
static int bounce_message (FILE *fp, struct Email *e, struct AddressList *to, const char *resent_from, struct AddressList *env_from)
 Bounce an email message. More...
 
int mutt_bounce_message (FILE *fp, struct Email *e, struct AddressList *to)
 Bounce an email message. More...
 
static void set_noconv_flags (struct Body *b, bool flag)
 Set/reset the "x-mutt-noconv" flag. More...
 
int mutt_write_multiple_fcc (const char *path, struct Email *e, const char *msgid, bool post, char *fcc, char **finalpath)
 Handle FCC with multiple, comma separated entries. More...
 
int mutt_write_fcc (const char *path, struct Email *e, const char *msgid, bool post, char *fcc, char **finalpath)
 Write email to FCC mailbox. More...
 

Variables

bool C_Allow8bit
 Config: Allow 8-bit messages, don't use quoted-printable or base64. More...
 
char * C_AttachCharset
 Config: When attaching files, use one of these character sets. More...
 
bool C_BounceDelivered
 Config: Add 'Delivered-To' to bounced messages. More...
 
bool C_EncodeFrom
 Config: Encode 'From ' as 'quote-printable' at the beginning of lines. More...
 
bool C_ForwardDecrypt
 Config: Decrypt the message when forwarding it. More...
 
bool C_HiddenHost
 Config: Don't use the hostname, just the domain, when generating the message id. More...
 
char * C_Inews
 Config: (nntp) External command to post news articles. More...
 
bool C_MimeForwardDecode
 Config: Decode the forwarded message before attaching it. More...
 
bool C_MimeSubject
 Config: (nntp) Encode the article subject in base64. More...
 
char * C_MimeTypeQueryCommand
 Config: External command to determine the MIME type of an attachment. More...
 
bool C_MimeTypeQueryFirst
 Config: Run the C_MimeTypeQueryCommand before the mime.types lookup. More...
 
char * C_Sendmail
 Config: External command to send email. More...
 
short C_SendmailWait
 Config: Time to wait for sendmail to finish. More...
 
bool C_Use8bitmime
 Config: Use 8-bit messages and ESMTP to send messages. More...
 
bool C_UseEnvelopeFrom
 Config: Set the envelope sender of the message. More...
 
bool C_UserAgent
 Config: Add a 'User-Agent' head to outgoing mail. More...
 
short C_WrapHeaders
 Config: Width to wrap headers in outgoing messages. More...
 

Detailed Description

Miscellaneous functions for sending an email.

Authors
  • Michael R. Elkins
  • Pietro Cerutti

This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.

You should have received a copy of the GNU General Public License along with this program. If not, see http://www.gnu.org/licenses/.

Definition in file sendlib.c.

Macro Definition Documentation

#define EX_OK   0

Definition at line 75 of file sendlib.c.

Function Documentation

static void encode_quoted ( struct FgetConv fc,
FILE *  fp_out,
bool  istext 
)
static

Encode text as quoted printable.

Parameters
fcCursor for converting a file's encoding
fp_outFile to store the result
istextIs the input text?

Definition at line 103 of file sendlib.c.

104 {
105  int c, linelen = 0;
106  char line[77], savechar;
107 
108  while ((c = mutt_ch_fgetconv(fc)) != EOF)
109  {
110  /* Wrap the line if needed. */
111  if ((linelen == 76) && ((istext && (c != '\n')) || !istext))
112  {
113  /* If the last character is "quoted", then be sure to move all three
114  * characters to the next line. Otherwise, just move the last
115  * character... */
116  if (line[linelen - 3] == '=')
117  {
118  line[linelen - 3] = 0;
119  fputs(line, fp_out);
120  fputs("=\n", fp_out);
121  line[linelen] = 0;
122  line[0] = '=';
123  line[1] = line[linelen - 2];
124  line[2] = line[linelen - 1];
125  linelen = 3;
126  }
127  else
128  {
129  savechar = line[linelen - 1];
130  line[linelen - 1] = '=';
131  line[linelen] = 0;
132  fputs(line, fp_out);
133  fputc('\n', fp_out);
134  line[0] = savechar;
135  linelen = 1;
136  }
137  }
138 
139  /* Escape lines that begin with/only contain "the message separator". */
140  if ((linelen == 4) && mutt_str_startswith(line, "From", CASE_MATCH))
141  {
142  mutt_str_strfcpy(line, "=46rom", sizeof(line));
143  linelen = 6;
144  }
145  else if ((linelen == 4) && mutt_str_startswith(line, "from", CASE_MATCH))
146  {
147  mutt_str_strfcpy(line, "=66rom", sizeof(line));
148  linelen = 6;
149  }
150  else if ((linelen == 1) && (line[0] == '.'))
151  {
152  mutt_str_strfcpy(line, "=2E", sizeof(line));
153  linelen = 3;
154  }
155 
156  if ((c == '\n') && istext)
157  {
158  /* Check to make sure there is no trailing space on this line. */
159  if ((linelen > 0) && ((line[linelen - 1] == ' ') || (line[linelen - 1] == '\t')))
160  {
161  if (linelen < 74)
162  {
163  sprintf(line + linelen - 1, "=%2.2X", (unsigned char) line[linelen - 1]);
164  fputs(line, fp_out);
165  }
166  else
167  {
168  int savechar2 = line[linelen - 1];
169 
170  line[linelen - 1] = '=';
171  line[linelen] = 0;
172  fputs(line, fp_out);
173  fprintf(fp_out, "\n=%2.2X", (unsigned char) savechar2);
174  }
175  }
176  else
177  {
178  line[linelen] = 0;
179  fputs(line, fp_out);
180  }
181  fputc('\n', fp_out);
182  linelen = 0;
183  }
184  else if ((c != 9) && ((c < 32) || (c > 126) || (c == '=')))
185  {
186  /* Check to make sure there is enough room for the quoted character.
187  * If not, wrap to the next line. */
188  if (linelen > 73)
189  {
190  line[linelen++] = '=';
191  line[linelen] = 0;
192  fputs(line, fp_out);
193  fputc('\n', fp_out);
194  linelen = 0;
195  }
196  sprintf(line + linelen, "=%2.2X", (unsigned char) c);
197  linelen += 3;
198  }
199  else
200  {
201  /* Don't worry about wrapping the line here. That will happen during
202  * the next iteration when I'll also know what the next character is. */
203  line[linelen++] = c;
204  }
205  }
206 
207  /* Take care of anything left in the buffer */
208  if (linelen > 0)
209  {
210  if ((line[linelen - 1] == ' ') || (line[linelen - 1] == '\t'))
211  {
212  /* take care of trailing whitespace */
213  if (linelen < 74)
214  sprintf(line + linelen - 1, "=%2.2X", (unsigned char) line[linelen - 1]);
215  else
216  {
217  savechar = line[linelen - 1];
218  line[linelen - 1] = '=';
219  line[linelen] = 0;
220  fputs(line, fp_out);
221  fputc('\n', fp_out);
222  sprintf(line, "=%2.2X", (unsigned char) savechar);
223  }
224  }
225  else
226  line[linelen] = 0;
227  fputs(line, fp_out);
228  }
229 }
int mutt_ch_fgetconv(struct FgetConv *fc)
Convert a file&#39;s character set.
Definition: charset.c:878
Match case when comparing strings.
Definition: string2.h:67
const char * line
Definition: common.c:36
size_t mutt_str_strfcpy(char *dest, const char *src, size_t dsize)
Copy a string into a buffer (guaranteeing NUL-termination)
Definition: string.c:750
size_t mutt_str_startswith(const char *str, const char *prefix, enum CaseSensitivity cs)
Check whether a string starts with a prefix.
Definition: string.c:168
static int b64_init ( struct B64Context bctx)
static

Set up the base64 conversion.

Parameters
bctxCursor for the base64 conversion
Return values
0Always

Definition at line 246 of file sendlib.c.

247 {
248  memset(bctx->buffer, '\0', sizeof(bctx->buffer));
249  bctx->size = 0;
250  bctx->linelen = 0;
251 
252  return 0;
253 }
char buffer[3]
Definition: sendlib.c:236
short size
Definition: sendlib.c:237
short linelen
Definition: sendlib.c:238
static void b64_flush ( struct B64Context bctx,
FILE *  fp_out 
)
static

Save the bytes to the file.

Parameters
bctxCursor for the base64 conversion
fp_outFile to save the output

Definition at line 260 of file sendlib.c.

261 {
262  /* for some reasons, mutt_b64_encode expects the
263  * output buffer to be larger than 10B */
264  char encoded[11];
265  size_t ret;
266 
267  if (bctx->size == 0)
268  return;
269 
270  if (bctx->linelen >= 72)
271  {
272  fputc('\n', fp_out);
273  bctx->linelen = 0;
274  }
275 
276  /* ret should always be equal to 4 here, because bctx->size
277  * is a value between 1 and 3 (included), but let's not hardcode it
278  * and prefer the return value of the function */
279  ret = mutt_b64_encode(bctx->buffer, bctx->size, encoded, sizeof(encoded));
280  for (size_t i = 0; i < ret; i++)
281  {
282  fputc(encoded[i], fp_out);
283  bctx->linelen++;
284  }
285 
286  bctx->size = 0;
287 }
size_t mutt_b64_encode(const char *in, size_t inlen, char *out, size_t outlen)
Convert raw bytes to null-terminated base64 string.
Definition: base64.c:88
char buffer[3]
Definition: sendlib.c:236
static const char encoded[]
short size
Definition: sendlib.c:237
short linelen
Definition: sendlib.c:238
static void b64_putc ( struct B64Context bctx,
char  c,
FILE *  fp_out 
)
static

Base64-encode one character.

Parameters
bctxCursor for the base64 conversion
cCharacter to encode
fp_outFile to save the output

Definition at line 295 of file sendlib.c.

296 {
297  if (bctx->size == 3)
298  b64_flush(bctx, fp_out);
299 
300  bctx->buffer[bctx->size++] = c;
301 }
char buffer[3]
Definition: sendlib.c:236
short size
Definition: sendlib.c:237
static void b64_flush(struct B64Context *bctx, FILE *fp_out)
Save the bytes to the file.
Definition: sendlib.c:260
static void encode_base64 ( struct FgetConv fc,
FILE *  fp_out,
int  istext 
)
static

Base64-encode some data.

Parameters
fcCursor for converting a file's encoding
fp_outFile to store the result
istextIs the input text?

Definition at line 309 of file sendlib.c.

310 {
311  struct B64Context bctx;
312  int ch, ch1 = EOF;
313 
314  b64_init(&bctx);
315 
316  while ((ch = mutt_ch_fgetconv(fc)) != EOF)
317  {
318  if (SigInt == 1)
319  {
320  SigInt = 0;
321  return;
322  }
323  if (istext && (ch == '\n') && (ch1 != '\r'))
324  b64_putc(&bctx, '\r', fp_out);
325  b64_putc(&bctx, ch, fp_out);
326  ch1 = ch;
327  }
328  b64_flush(&bctx, fp_out);
329  fputc('\n', fp_out);
330 }
static void b64_putc(struct B64Context *bctx, char c, FILE *fp_out)
Base64-encode one character.
Definition: sendlib.c:295
int mutt_ch_fgetconv(struct FgetConv *fc)
Convert a file&#39;s character set.
Definition: charset.c:878
WHERE SIG_ATOMIC_VOLATILE_T SigInt
true after SIGINT is received
Definition: globals.h:83
static int b64_init(struct B64Context *bctx)
Set up the base64 conversion.
Definition: sendlib.c:246
static void b64_flush(struct B64Context *bctx, FILE *fp_out)
Save the bytes to the file.
Definition: sendlib.c:260
Cursor for the Base64 conversion.
Definition: sendlib.c:234
static void encode_8bit ( struct FgetConv fc,
FILE *  fp_out 
)
static

Write the data as raw 8-bit data.

Parameters
fcCursor for converting a file's encoding
fp_outFile to store the result

Definition at line 337 of file sendlib.c.

338 {
339  int ch;
340 
341  while ((ch = mutt_ch_fgetconv(fc)) != EOF)
342  {
343  if (SigInt == 1)
344  {
345  SigInt = 0;
346  return;
347  }
348  fputc(ch, fp_out);
349  }
350 }
int mutt_ch_fgetconv(struct FgetConv *fc)
Convert a file&#39;s character set.
Definition: charset.c:878
WHERE SIG_ATOMIC_VOLATILE_T SigInt
true after SIGINT is received
Definition: globals.h:83
int mutt_write_mime_header ( struct Body a,
FILE *  fp 
)

Create a MIME header.

Parameters
aBody part
fpFile to write to
Return values
0Success
-1Failure

Definition at line 359 of file sendlib.c.

360 {
361  if (!a || !fp)
362  return -1;
363 
364  int len;
365  int tmplen;
366  char buf[256] = { 0 };
367 
368  fprintf(fp, "Content-Type: %s/%s", TYPE(a), a->subtype);
369 
370  if (!TAILQ_EMPTY(&a->parameter))
371  {
372  len = 25 + mutt_str_strlen(a->subtype); /* approximate len. of content-type */
373 
374  struct Parameter *np = NULL;
375  TAILQ_FOREACH(np, &a->parameter, entries)
376  {
377  if (!np->attribute || !np->value)
378  continue;
379 
380  struct ParameterList param_conts = rfc2231_encode_string(np->attribute, np->value);
381  struct Parameter *cont = NULL;
382  TAILQ_FOREACH(cont, &param_conts, entries)
383  {
384  fputc(';', fp);
385 
386  buf[0] = 0;
387  mutt_addr_cat(buf, sizeof(buf), cont->value, MimeSpecials);
388 
389  /* Dirty hack to make messages readable by Outlook Express
390  * for the Mac: force quotes around the boundary parameter
391  * even when they aren't needed.
392  */
393  if (!mutt_str_strcasecmp(cont->attribute, "boundary") &&
394  !mutt_str_strcmp(buf, cont->value))
395  snprintf(buf, sizeof(buf), "\"%s\"", cont->value);
396 
397  tmplen = mutt_str_strlen(buf) + mutt_str_strlen(cont->attribute) + 1;
398  if (len + tmplen + 2 > 76)
399  {
400  fputs("\n\t", fp);
401  len = tmplen + 1;
402  }
403  else
404  {
405  fputc(' ', fp);
406  len += tmplen + 1;
407  }
408 
409  fprintf(fp, "%s=%s", cont->attribute, buf);
410  }
411 
412  mutt_param_free(&param_conts);
413  }
414  }
415 
416  fputc('\n', fp);
417 
418  if (a->language)
419  fprintf(fp, "Content-Language: %s\n", a->language);
420 
421  if (a->description)
422  fprintf(fp, "Content-Description: %s\n", a->description);
423 
424  if (a->disposition != DISP_NONE)
425  {
426  const char *dispstr[] = { "inline", "attachment", "form-data" };
427 
428  if (a->disposition < sizeof(dispstr) / sizeof(char *))
429  {
430  fprintf(fp, "Content-Disposition: %s", dispstr[a->disposition]);
431  len = 21 + mutt_str_strlen(dispstr[a->disposition]);
432 
433  if (a->use_disp && (a->disposition != DISP_INLINE))
434  {
435  char *fn = a->d_filename;
436  if (!fn)
437  fn = a->filename;
438 
439  if (fn)
440  {
441  /* Strip off the leading path... */
442  char *t = strrchr(fn, '/');
443  if (t)
444  t++;
445  else
446  t = fn;
447 
448  struct ParameterList param_conts = rfc2231_encode_string("filename", t);
449  struct Parameter *cont = NULL;
450  TAILQ_FOREACH(cont, &param_conts, entries)
451  {
452  fputc(';', fp);
453  buf[0] = 0;
454  mutt_addr_cat(buf, sizeof(buf), cont->value, MimeSpecials);
455 
456  tmplen = mutt_str_strlen(buf) + mutt_str_strlen(cont->attribute) + 1;
457  if (len + tmplen + 2 > 76)
458  {
459  fputs("\n\t", fp);
460  len = tmplen + 1;
461  }
462  else
463  {
464  fputc(' ', fp);
465  len += tmplen + 1;
466  }
467 
468  fprintf(fp, "%s=%s", cont->attribute, buf);
469  }
470 
471  mutt_param_free(&param_conts);
472  }
473  }
474 
475  fputc('\n', fp);
476  }
477  else
478  {
479  mutt_debug(LL_DEBUG1, "ERROR: invalid content-disposition %d\n", a->disposition);
480  }
481  }
482 
483  if (a->encoding != ENC_7BIT)
484  fprintf(fp, "Content-Transfer-Encoding: %s\n", ENCODING(a->encoding));
485 
487  mutt_rfc822_write_header(fp, a->mime_headers, NULL, MUTT_WRITE_HEADER_MIME, false, false);
488 
489  /* Do NOT add the terminator here!!! */
490  return ferror(fp) ? -1 : 0;
491 }
char * attribute
Parameter name.
Definition: parameter.h:34
char * filename
when sending a message, this is the file to which this structure refers
Definition: body.h:46
struct Envelope * mime_headers
Memory hole protected headers.
Definition: body.h:63
#define TAILQ_FOREACH(var, head, field)
Definition: queue.h:719
7-bit text
Definition: mime.h:49
WHERE bool C_CryptProtectedHeadersWrite
Config: Generate protected header (Memory Hole) for signed and encrypted emails.
Definition: globals.h:270
size_t mutt_str_strlen(const char *a)
Calculate the length of a string, safely.
Definition: string.c:666
unsigned int disposition
content-disposition
Definition: body.h:67
int mutt_rfc822_write_header(FILE *fp, struct Envelope *env, struct Body *attach, enum MuttWriteHeaderMode mode, bool privacy, bool hide_protected_subject)
Write out one RFC822 header line.
Definition: sendlib.c:2229
#define ENCODING(x)
Definition: mime.h:85
unsigned int encoding
content-transfer-encoding
Definition: body.h:66
char * subtype
content-type subtype
Definition: body.h:37
void mutt_param_free(struct ParameterList *p)
Free a ParameterList.
Definition: parameter.c:61
const char MimeSpecials[]
Characters that need special treatment in MIME.
Definition: mime.c:67
char * description
content-description
Definition: body.h:40
#define TYPE(body)
Definition: mime.h:83
char * value
Parameter value.
Definition: parameter.h:35
Log at debug level 1.
Definition: logging.h:56
No preferred disposition.
Definition: mime.h:65
bool use_disp
Content-Disposition uses filename= ?
Definition: body.h:68
struct ParameterList rfc2231_encode_string(const char *attribute, char *value)
Encode a string to be suitable for an RFC2231 header.
Definition: rfc2231.c:329
int mutt_str_strcasecmp(const char *a, const char *b)
Compare two strings ignoring case, safely.
Definition: string.c:628
Attribute associated with a MIME part.
Definition: parameter.h:32
char * language
content-language (RFC8255)
Definition: body.h:38
char * d_filename
filename to be used for the content-disposition header.
Definition: body.h:47
#define mutt_debug(LEVEL,...)
Definition: logging.h:81
Write protected headers.
Definition: sendlib.h:67
#define TAILQ_EMPTY(head)
Definition: queue.h:715
Content is inline.
Definition: mime.h:62
struct ParameterList parameter
parameters of the content-type
Definition: body.h:39
int mutt_str_strcmp(const char *a, const char *b)
Compare two strings, safely.
Definition: string.c:615
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:668
static bool write_as_text_part ( struct Body b)
static

Should the Body be written as a text MIME part.

Parameters
bEmail to examine
Return values
trueIf the Body should be written as text

Definition at line 498 of file sendlib.c.

499 {
500  return mutt_is_text_part(b) ||
502 }
SecurityFlags mutt_is_application_pgp(struct Body *m)
Does the message use PGP?
Definition: crypt.c:527
bool mutt_is_text_part(struct Body *b)
Is this part of an email in plain text?
Definition: muttlib.c:436
#define APPLICATION_PGP
Use PGP to encrypt/sign.
Definition: ncrypt.h:130
#define WithCrypto
Definition: ncrypt.h:156
int mutt_write_mime_body ( struct Body a,
FILE *  fp 
)

Write a MIME part.

Parameters
aBody to use
fpFile to write to
Return values
0Success
-1Failure

Definition at line 511 of file sendlib.c.

512 {
513  FILE *fp_in = NULL;
514  struct FgetConv *fc = NULL;
515 
516  if (a->type == TYPE_MULTIPART)
517  {
518  /* First, find the boundary to use */
519  const char *p = mutt_param_get(&a->parameter, "boundary");
520  if (!p)
521  {
522  mutt_debug(LL_DEBUG1, "no boundary parameter found\n");
523  mutt_error(_("No boundary parameter found [report this error]"));
524  return -1;
525  }
526  char boundary[128];
527  mutt_str_strfcpy(boundary, p, sizeof(boundary));
528 
529  for (struct Body *t = a->parts; t; t = t->next)
530  {
531  fprintf(fp, "\n--%s\n", boundary);
532  if (mutt_write_mime_header(t, fp) == -1)
533  return -1;
534  fputc('\n', fp);
535  if (mutt_write_mime_body(t, fp) == -1)
536  return -1;
537  }
538  fprintf(fp, "\n--%s--\n", boundary);
539  return ferror(fp) ? -1 : 0;
540  }
541 
542  /* This is pretty gross, but it's the best solution for now... */
543  if (((WithCrypto & APPLICATION_PGP) != 0) && (a->type == TYPE_APPLICATION) &&
544  (mutt_str_strcmp(a->subtype, "pgp-encrypted") == 0))
545  {
546  fputs("Version: 1\n", fp);
547  return 0;
548  }
549 
550  fp_in = fopen(a->filename, "r");
551  if (!fp_in)
552  {
553  mutt_debug(LL_DEBUG1, "%s no longer exists\n", a->filename);
554  mutt_error(_("%s no longer exists"), a->filename);
555  return -1;
556  }
557 
558  if ((a->type == TYPE_TEXT) && (!a->noconv))
559  {
560  char send_charset[128];
562  fp_in, a->charset,
563  mutt_body_get_charset(a, send_charset, sizeof(send_charset)), 0);
564  }
565  else
566  fc = mutt_ch_fgetconv_open(fp_in, 0, 0, 0);
567 
569  if (a->encoding == ENC_QUOTED_PRINTABLE)
571  else if (a->encoding == ENC_BASE64)
573  else if ((a->type == TYPE_TEXT) && (!a->noconv))
574  encode_8bit(fc, fp);
575  else
576  mutt_file_copy_stream(fp_in, fp);
578 
580  mutt_file_fclose(&fp_in);
581 
582  if (SigInt == 1)
583  {
584  SigInt = 0;
585  return -1;
586  }
587  return ferror(fp) ? -1 : 0;
588 }
char * filename
when sending a message, this is the file to which this structure refers
Definition: body.h:46
WHERE SIG_ATOMIC_VOLATILE_T SigInt
true after SIGINT is received
Definition: globals.h:83
static void encode_base64(struct FgetConv *fc, FILE *fp_out, int istext)
Base64-encode some data.
Definition: sendlib.c:309
bool noconv
Don&#39;t do character set conversion.
Definition: body.h:73
#define _(a)
Definition: message.h:28
struct Body * next
next attachment in the list
Definition: body.h:53
static bool write_as_text_part(struct Body *b)
Should the Body be written as a text MIME part.
Definition: sendlib.c:498
void mutt_sig_allow_interrupt(bool allow)
Allow/disallow Ctrl-C (SIGINT)
Definition: signal.c:238
The body of an email.
Definition: body.h:34
int mutt_file_fclose(FILE **fp)
Close a FILE handle (and NULL the pointer)
Definition: file.c:149
unsigned int encoding
content-transfer-encoding
Definition: body.h:66
Base-64 encoded text.
Definition: mime.h:52
static void encode_quoted(struct FgetConv *fc, FILE *fp_out, bool istext)
Encode text as quoted printable.
Definition: sendlib.c:103
char * subtype
content-type subtype
Definition: body.h:37
FILE * fp
Definition: charset.h:43
Type: &#39;text/*&#39;.
Definition: mime.h:38
int mutt_write_mime_body(struct Body *a, FILE *fp)
Write a MIME part.
Definition: sendlib.c:511
struct Body * parts
parts of a multipart or message/rfc822
Definition: body.h:54
size_t mutt_str_strfcpy(char *dest, const char *src, size_t dsize)
Copy a string into a buffer (guaranteeing NUL-termination)
Definition: string.c:750
char * charset
Send mode: charset of attached file as stored on disk.
Definition: body.h:49
char * mutt_body_get_charset(struct Body *b, char *buf, size_t buflen)
Get a body&#39;s character set.
Definition: sendlib.c:1422
char * p
Definition: charset.h:47
static void encode_8bit(struct FgetConv *fc, FILE *fp_out)
Write the data as raw 8-bit data.
Definition: sendlib.c:337
unsigned int type
content-type primary type
Definition: body.h:65
#define APPLICATION_PGP
Use PGP to encrypt/sign.
Definition: ncrypt.h:130
void mutt_ch_fgetconv_close(struct FgetConv **fc)
Close an fgetconv handle.
Definition: charset.c:858
char * mutt_param_get(const struct ParameterList *p, const char *s)
Find a matching Parameter.
Definition: parameter.c:84
Type: &#39;multipart/*&#39;.
Definition: mime.h:37
Log at debug level 1.
Definition: logging.h:56
int mutt_file_copy_stream(FILE *fp_in, FILE *fp_out)
Copy the contents of one file into another.
Definition: file.c:267
#define mutt_error(...)
Definition: logging.h:84
Quoted-printable text.
Definition: mime.h:51
int mutt_write_mime_header(struct Body *a, FILE *fp)
Create a MIME header.
Definition: sendlib.c:359
#define mutt_debug(LEVEL,...)
Definition: logging.h:81
struct FgetConv * mutt_ch_fgetconv_open(FILE *fp, const char *from, const char *to, int flags)
Prepare a file for charset conversion.
Definition: charset.c:828
struct ParameterList parameter
parameters of the content-type
Definition: body.h:39
#define WithCrypto
Definition: ncrypt.h:156
Cursor for converting a file&#39;s encoding.
Definition: charset.h:41
int mutt_str_strcmp(const char *a, const char *b)
Compare two strings, safely.
Definition: string.c:615
Type: &#39;application/*&#39;.
Definition: mime.h:33
void mutt_generate_boundary ( struct ParameterList *  parm)

Create a unique boundary id for a MIME part.

Parameters
parmMIME part

Definition at line 594 of file sendlib.c.

595 {
596  char rs[MUTT_RANDTAG_LEN + 1];
597 
598  mutt_rand_base32(rs, sizeof(rs) - 1);
599  rs[MUTT_RANDTAG_LEN] = 0;
600  mutt_param_set(parm, "boundary", rs);
601 }
#define MUTT_RANDTAG_LEN
Definition: muttlib.h:44
void mutt_param_set(struct ParameterList *p, const char *attribute, const char *value)
Set a Parameter.
Definition: parameter.c:110
void mutt_rand_base32(void *buf, size_t buflen)
Fill a buffer with a base32-encoded random string.
Definition: muttlib.c:516
static void update_content_info ( struct Content info,
struct ContentState s,
char *  buf,
size_t  buflen 
)
static

Cache some info about an email.

Parameters
infoInfo about an Attachment
sInfo about the Body of an email
bufBuffer for the result
buflenLength of the buffer

Definition at line 622 of file sendlib.c.

624 {
625  bool from = s->from;
626  int whitespace = s->whitespace;
627  bool dot = s->dot;
628  int linelen = s->linelen;
629  bool was_cr = s->was_cr;
630 
631  if (!buf) /* This signals EOF */
632  {
633  if (was_cr)
634  info->binary = true;
635  if (linelen > info->linemax)
636  info->linemax = linelen;
637 
638  return;
639  }
640 
641  for (; buflen; buf++, buflen--)
642  {
643  char ch = *buf;
644 
645  if (was_cr)
646  {
647  was_cr = false;
648  if (ch != '\n')
649  {
650  info->binary = true;
651  }
652  else
653  {
654  if (whitespace)
655  info->space = true;
656  if (dot)
657  info->dot = true;
658  if (linelen > info->linemax)
659  info->linemax = linelen;
660  whitespace = 0;
661  dot = false;
662  linelen = 0;
663  continue;
664  }
665  }
666 
667  linelen++;
668  if (ch == '\n')
669  {
670  info->crlf++;
671  if (whitespace)
672  info->space = true;
673  if (dot)
674  info->dot = true;
675  if (linelen > info->linemax)
676  info->linemax = linelen;
677  whitespace = 0;
678  linelen = 0;
679  dot = false;
680  }
681  else if (ch == '\r')
682  {
683  info->crlf++;
684  info->cr = true;
685  was_cr = true;
686  continue;
687  }
688  else if (ch & 0x80)
689  info->hibin++;
690  else if ((ch == '\t') || (ch == '\f'))
691  {
692  info->ascii++;
693  whitespace++;
694  }
695  else if (ch == 0)
696  {
697  info->nulbin++;
698  info->lobin++;
699  }
700  else if ((ch < 32) || (ch == 127))
701  info->lobin++;
702  else
703  {
704  if (linelen == 1)
705  {
706  if ((ch == 'F') || (ch == 'f'))
707  from = true;
708  else
709  from = false;
710  if (ch == '.')
711  dot = true;
712  else
713  dot = false;
714  }
715  else if (from)
716  {
717  if ((linelen == 2) && (ch != 'r'))
718  from = false;
719  else if ((linelen == 3) && (ch != 'o'))
720  from = false;
721  else if (linelen == 4)
722  {
723  if (ch == 'm')
724  info->from = true;
725  from = false;
726  }
727  }
728  if (ch == ' ')
729  whitespace++;
730  info->ascii++;
731  }
732 
733  if (linelen > 1)
734  dot = false;
735  if ((ch != ' ') && (ch != '\t'))
736  whitespace = 0;
737  }
738 
739  s->from = from;
740  s->whitespace = whitespace;
741  s->dot = dot;
742  s->linelen = linelen;
743  s->was_cr = was_cr;
744 }
int whitespace
Definition: sendlib.c:609
bool dot
Has a line consisting of a single dot?
Definition: content.h:44
long linemax
Length of the longest line in the file.
Definition: content.h:40
bool dot
Definition: sendlib.c:610
long hibin
8-bit characters
Definition: content.h:35
bool was_cr
Definition: sendlib.c:612
bool from
Definition: sendlib.c:608
bool binary
Long lines, or CR not in CRLF pair.
Definition: content.h:42
long ascii
Number of ascii chars.
Definition: content.h:39
int linelen
Definition: sendlib.c:611
bool from
Has a line beginning with "From "?
Definition: content.h:43
long lobin
Unprintable 7-bit chars (eg., control chars)
Definition: content.h:36
long crlf
\r and \n characters
Definition: content.h:38
bool space
Whitespace at the end of lines?
Definition: content.h:41
long nulbin
Null characters (0x0)
Definition: content.h:37
bool cr
Has CR, even when in a CRLF pair.
Definition: content.h:45
static size_t convert_file_to ( FILE *  fp,
const char *  fromcode,
int  ncodes,
char const *const *  tocodes,
int *  tocode,
struct Content info 
)
static

Change the encoding of a file.

Parameters
[in]fpFile to convert
[in]fromcodeOriginal encoding
[in]ncodesNumber of target encodings
[in]tocodesList of target encodings
[out]tocodeChosen encoding
[in]infoEncoding information
Return values
-1Error, no conversion was possible
>0Success, number of bytes converted

Find the best charset conversion of the file from fromcode into one of the tocodes. If successful, set *tocode and Content *info and return the number of characters converted inexactly.

We convert via UTF-8 in order to avoid the condition -1(EINVAL), which would otherwise prevent us from knowing the number of inexact conversions. Where the candidate target charset is UTF-8 we avoid doing the second conversion because iconv_open("UTF-8", "UTF-8") fails with some libraries.

We assume that the output from iconv is never more than 4 times as long as the input for any pair of charsets we might be interested in.

Definition at line 771 of file sendlib.c.

773 {
774  char bufi[256], bufu[512], bufo[4 * sizeof(bufi)];
775  size_t ret;
776 
777  const iconv_t cd1 = mutt_ch_iconv_open("utf-8", fromcode, 0);
778  if (cd1 == (iconv_t)(-1))
779  return -1;
780 
781  iconv_t *cd = mutt_mem_calloc(ncodes, sizeof(iconv_t));
782  size_t *score = mutt_mem_calloc(ncodes, sizeof(size_t));
783  struct ContentState *states = mutt_mem_calloc(ncodes, sizeof(struct ContentState));
784  struct Content *infos = mutt_mem_calloc(ncodes, sizeof(struct Content));
785 
786  for (int i = 0; i < ncodes; i++)
787  {
788  if (mutt_str_strcasecmp(tocodes[i], "utf-8") != 0)
789  cd[i] = mutt_ch_iconv_open(tocodes[i], "utf-8", 0);
790  else
791  {
792  /* Special case for conversion to UTF-8 */
793  cd[i] = (iconv_t)(-1);
794  score[i] = (size_t)(-1);
795  }
796  }
797 
798  rewind(fp);
799  size_t ibl = 0;
800  while (true)
801  {
802  /* Try to fill input buffer */
803  size_t n = fread(bufi + ibl, 1, sizeof(bufi) - ibl, fp);
804  ibl += n;
805 
806  /* Convert to UTF-8 */
807  const char *ib = bufi;
808  char *ob = bufu;
809  size_t obl = sizeof(bufu);
810  n = iconv(cd1, (ICONV_CONST char **) ((ibl != 0) ? &ib : 0), &ibl, &ob, &obl);
811  /* assert(n == (size_t)(-1) || !n); */
812  if ((n == (size_t)(-1)) && (((errno != EINVAL) && (errno != E2BIG)) || (ib == bufi)))
813  {
814  /* assert(errno == EILSEQ || (errno == EINVAL && ib == bufi && ibl < sizeof(bufi))); */
815  ret = (size_t)(-1);
816  break;
817  }
818  const size_t ubl1 = ob - bufu;
819 
820  /* Convert from UTF-8 */
821  for (int i = 0; i < ncodes; i++)
822  {
823  if ((cd[i] != (iconv_t)(-1)) && (score[i] != (size_t)(-1)))
824  {
825  const char *ub = bufu;
826  size_t ubl = ubl1;
827  ob = bufo;
828  obl = sizeof(bufo);
829  n = iconv(cd[i], (ICONV_CONST char **) ((ibl || ubl) ? &ub : 0), &ubl, &ob, &obl);
830  if (n == (size_t)(-1))
831  {
832  /* assert(errno == E2BIG || (BUGGY_ICONV && (errno == EILSEQ || errno == ENOENT))); */
833  score[i] = (size_t)(-1);
834  }
835  else
836  {
837  score[i] += n;
838  update_content_info(&infos[i], &states[i], bufo, ob - bufo);
839  }
840  }
841  else if ((cd[i] == (iconv_t)(-1)) && (score[i] == (size_t)(-1)))
842  {
843  /* Special case for conversion to UTF-8 */
844  update_content_info(&infos[i], &states[i], bufu, ubl1);
845  }
846  }
847 
848  if (ibl)
849  {
850  /* Save unused input */
851  memmove(bufi, ib, ibl);
852  }
853  else if (!ubl1 && (ib < bufi + sizeof(bufi)))
854  {
855  ret = 0;
856  break;
857  }
858  }
859 
860  if (ret == 0)
861  {
862  /* Find best score */
863  ret = (size_t)(-1);
864  for (int i = 0; i < ncodes; i++)
865  {
866  if ((cd[i] == (iconv_t)(-1)) && (score[i] == (size_t)(-1)))
867  {
868  /* Special case for conversion to UTF-8 */
869  *tocode = i;
870  ret = 0;
871  break;
872  }
873  else if ((cd[i] == (iconv_t)(-1)) || (score[i] == (size_t)(-1)))
874  continue;
875  else if ((ret == (size_t)(-1)) || (score[i] < ret))
876  {
877  *tocode = i;
878  ret = score[i];
879  if (ret == 0)
880  break;
881  }
882  }
883  if (ret != (size_t)(-1))
884  {
885  memcpy(info, &infos[*tocode], sizeof(struct Content));
886  update_content_info(info, &states[*tocode], 0, 0); /* EOF */
887  }
888  }
889 
890  for (int i = 0; i < ncodes; i++)
891  if (cd[i] != (iconv_t)(-1))
892  iconv_close(cd[i]);
893 
894  iconv_close(cd1);
895  FREE(&cd);
896  FREE(&infos);
897  FREE(&score);
898  FREE(&states);
899 
900  return ret;
901 }
Info about the body of an email.
Definition: sendlib.c:606
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:622
void * mutt_mem_calloc(size_t nmemb, size_t size)
Allocate zeroed memory on the heap.
Definition: memory.c:50
char bufi[512]
Definition: charset.h:45
Info about an attachment.
Definition: content.h:33
iconv_t cd
Definition: charset.h:44
iconv_t mutt_ch_iconv_open(const char *tocode, const char *fromcode, int flags)
Set up iconv for conversions.
Definition: charset.c:535
char bufo[512]
Definition: charset.h:46
int mutt_str_strcasecmp(const char *a, const char *b)
Compare two strings ignoring case, safely.
Definition: string.c:628
#define FREE(x)
Definition: memory.h:40
static size_t convert_file_from_to ( FILE *  fp,
const char *  fromcodes,
const char *  tocodes,
char **  fromcode,
char **  tocode,
struct Content info 
)
static

Convert a file between encodings.

Parameters
[in]fpFile to read from
[in]fromcodesCharsets to try converting FROM
[in]tocodesCharsets to try converting TO
[out]fromcodeFrom charset selected
[out]tocodeTo charset selected
[out]infoInfo about the file
Return values
numCharacters converted
-1Error (as a size_t)

Find the first of the fromcodes that gives a valid conversion and the best charset conversion of the file into one of the tocodes. If successful, set *fromcode and *tocode to dynamically allocated strings, set Content *info, and return the number of characters converted inexactly. If no conversion was possible, return -1.

Both fromcodes and tocodes may be colon-separated lists of charsets. However, if fromcode is zero then fromcodes is assumed to be the name of a single charset even if it contains a colon.

Definition at line 924 of file sendlib.c.

926 {
927  char *fcode = NULL;
928  char **tcode = NULL;
929  const char *c = NULL, *c1 = NULL;
930  size_t ret;
931  int ncodes, i, cn;
932 
933  /* Count the tocodes */
934  ncodes = 0;
935  for (c = tocodes; c; c = c1 ? c1 + 1 : 0)
936  {
937  c1 = strchr(c, ':');
938  if (c1 == c)
939  continue;
940  ncodes++;
941  }
942 
943  /* Copy them */
944  tcode = mutt_mem_malloc(ncodes * sizeof(char *));
945  for (c = tocodes, i = 0; c; c = c1 ? c1 + 1 : 0, i++)
946  {
947  c1 = strchr(c, ':');
948  if (c1 == c)
949  continue;
950  tcode[i] = mutt_str_substr_dup(c, c1);
951  }
952 
953  ret = (size_t)(-1);
954  if (fromcode)
955  {
956  /* Try each fromcode in turn */
957  for (c = fromcodes; c; c = c1 ? c1 + 1 : 0)
958  {
959  c1 = strchr(c, ':');
960  if (c1 == c)
961  continue;
962  fcode = mutt_str_substr_dup(c, c1);
963 
964  ret = convert_file_to(fp, fcode, ncodes, (char const *const *) tcode, &cn, info);
965  if (ret != (size_t)(-1))
966  {
967  *fromcode = fcode;
968  *tocode = tcode[cn];
969  tcode[cn] = 0;
970  break;
971  }
972  FREE(&fcode);
973  }
974  }
975  else
976  {
977  /* There is only one fromcode */
978  ret = convert_file_to(fp, fromcodes, ncodes, (char const *const *) tcode, &cn, info);
979  if (ret != (size_t)(-1))
980  {
981  *tocode = tcode[cn];
982  tcode[cn] = 0;
983  }
984  }
985 
986  /* Free memory */
987  for (i = 0; i < ncodes; i++)
988  FREE(&tcode[i]);
989 
990  FREE(&tcode);
991 
992  return ret;
993 }
void * mutt_mem_malloc(size_t size)
Allocate memory on the heap.
Definition: memory.c:90
#define FREE(x)
Definition: memory.h:40
static size_t convert_file_to(FILE *fp, const char *fromcode, int ncodes, char const *const *tocodes, int *tocode, struct Content *info)
Change the encoding of a file.
Definition: sendlib.c:771
char * mutt_str_substr_dup(const char *begin, const char *end)
Duplicate a sub-string.
Definition: string.c:579
struct Content* mutt_get_content_info ( const char *  fname,
struct Body b 
)

Analyze file to determine MIME encoding to use.

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

Also set the body charset, sometimes, or not.

Definition at line 1003 of file sendlib.c.

1004 {
1005  struct Content *info = NULL;
1006  struct ContentState state = { 0 };
1007  FILE *fp = NULL;
1008  char *fromcode = NULL;
1009  char *tocode = NULL;
1010  char buf[100];
1011  size_t r;
1012 
1013  struct stat sb;
1014 
1015  if (b && !fname)
1016  fname = b->filename;
1017 
1018  if (stat(fname, &sb) == -1)
1019  {
1020  mutt_error(_("Can't stat %s: %s"), fname, strerror(errno));
1021  return NULL;
1022  }
1023 
1024  if (!S_ISREG(sb.st_mode))
1025  {
1026  mutt_error(_("%s isn't a regular file"), fname);
1027  return NULL;
1028  }
1029 
1030  fp = fopen(fname, "r");
1031  if (!fp)
1032  {
1033  mutt_debug(LL_DEBUG1, "%s: %s (errno %d)\n", fname, strerror(errno), errno);
1034  return NULL;
1035  }
1036 
1037  info = mutt_mem_calloc(1, sizeof(struct Content));
1038 
1039  if (b && (b->type == TYPE_TEXT) && (!b->noconv && !b->force_charset))
1040  {
1041  char *chs = mutt_param_get(&b->parameter, "charset");
1042  char *fchs = b->use_disp ? (C_AttachCharset ? C_AttachCharset : C_Charset) : C_Charset;
1043  if (C_Charset && (chs || C_SendCharset) &&
1044  (convert_file_from_to(fp, fchs, chs ? chs : C_SendCharset, &fromcode,
1045  &tocode, info) != (size_t)(-1)))
1046  {
1047  if (!chs)
1048  {
1049  char chsbuf[256];
1050  mutt_ch_canonical_charset(chsbuf, sizeof(chsbuf), tocode);
1051  mutt_param_set(&b->parameter, "charset", chsbuf);
1052  }
1053  FREE(&b->charset);
1054  b->charset = fromcode;
1055  FREE(&tocode);
1056  mutt_file_fclose(&fp);
1057  return info;
1058  }
1059  }
1060 
1061  rewind(fp);
1062  while ((r = fread(buf, 1, sizeof(buf), fp)))
1063  update_content_info(info, &state, buf, r);
1064  update_content_info(info, &state, 0, 0);
1065 
1066  mutt_file_fclose(&fp);
1067 
1068  if (b && (b->type == TYPE_TEXT) && (!b->noconv && !b->force_charset))
1069  {
1070  mutt_param_set(&b->parameter, "charset",
1071  (!info->hibin ?
1072  "us-ascii" :
1073  C_Charset && !mutt_ch_is_us_ascii(C_Charset) ? C_Charset : "unknown-8bit"));
1074  }
1075 
1076  return info;
1077 }
Info about the body of an email.
Definition: sendlib.c:606
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:622
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
char * C_SendCharset
Config: Character sets for outgoing mail.
Definition: email_globals.c:38
int mutt_file_fclose(FILE **fp)
Close a FILE handle (and NULL the pointer)
Definition: file.c:149
bool force_charset
Send mode: don&#39;t adjust the character set when in send-mode.
Definition: body.h:74
void mutt_ch_canonical_charset(char *buf, size_t buflen, const char *name)
Canonicalise the charset of a string.
Definition: charset.c:314
#define mutt_ch_is_us_ascii(str)
Definition: charset.h:107
static char * chs
Definition: gnupgparse.c:72
Info about an attachment.
Definition: content.h:33
Type: &#39;text/*&#39;.
Definition: mime.h:38
char * C_AttachCharset
Config: When attaching files, use one of these character sets.
Definition: sendlib.c:80
void mutt_param_set(struct ParameterList *p, const char *attribute, const char *value)
Set a Parameter.
Definition: parameter.c:110
char * charset
Send mode: charset of attached file as stored on disk.
Definition: body.h:49
unsigned int type
content-type primary type
Definition: body.h:65
char * mutt_param_get(const struct ParameterList *p, const char *s)
Find a matching Parameter.
Definition: parameter.c:84
Log at debug level 1.
Definition: logging.h:56
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 * C_Charset
Config: Default character set for displaying text on screen.
Definition: charset.c:54
#define mutt_debug(LEVEL,...)
Definition: logging.h:81
struct ParameterList parameter
parameters of the content-type
Definition: body.h:39
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:924
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 1091 of file sendlib.c.

1092 {
1093  FILE *fp = NULL;
1094  char *p = NULL, *q = NULL, *ct = NULL;
1095  char buf[PATH_MAX];
1096  char subtype[256] = { 0 };
1097  char xtype[256] = { 0 };
1098  int sze, cur_sze = 0;
1099  bool found_mimetypes = false;
1100  enum ContentType type = TYPE_OTHER;
1101 
1102  int szf = mutt_str_strlen(path);
1103 
1104  for (int count = 0; count < 4; count++)
1105  {
1106  /* can't use strtok() because we use it in an inner loop below, so use
1107  * a switch statement here instead. */
1108  switch (count)
1109  {
1110  /* last file with last entry to match wins type/xtype */
1111  case 0:
1112  /* check default unix mimetypes location first */
1113  mutt_str_strfcpy(buf, "/etc/mime.types", sizeof(buf));
1114  break;
1115  case 1:
1116  mutt_str_strfcpy(buf, SYSCONFDIR "/mime.types", sizeof(buf));
1117  break;
1118  case 2:
1119  mutt_str_strfcpy(buf, PKGDATADIR "/mime.types", sizeof(buf));
1120  break;
1121  case 3:
1122  snprintf(buf, sizeof(buf), "%s/.mime.types", NONULL(HomeDir));
1123  break;
1124  default:
1125  mutt_debug(LL_DEBUG1, "Internal error, count = %d\n", count);
1126  goto bye; /* shouldn't happen */
1127  }
1128 
1129  fp = fopen(buf, "r");
1130  if (fp)
1131  {
1132  found_mimetypes = true;
1133 
1134  while (fgets(buf, sizeof(buf) - 1, fp))
1135  {
1136  /* weed out any comments */
1137  p = strchr(buf, '#');
1138  if (p)
1139  *p = '\0';
1140 
1141  /* remove any leading space. */
1142  ct = buf;
1143  SKIPWS(ct);
1144 
1145  /* position on the next field in this line */
1146  p = strpbrk(ct, " \t");
1147  if (!p)
1148  continue;
1149  *p++ = 0;
1150  SKIPWS(p);
1151 
1152  /* cycle through the file extensions */
1153  while ((p = strtok(p, " \t\n")))
1154  {
1155  sze = mutt_str_strlen(p);
1156  if ((sze > cur_sze) && (szf >= sze) &&
1157  ((mutt_str_strcasecmp(path + szf - sze, p) == 0) ||
1158  (mutt_str_strcasecmp(path + szf - sze, p) == 0)) &&
1159  ((szf == sze) || (path[szf - sze - 1] == '.')))
1160  {
1161  /* get the content-type */
1162 
1163  p = strchr(ct, '/');
1164  if (!p)
1165  {
1166  /* malformed line, just skip it. */
1167  break;
1168  }
1169  *p++ = 0;
1170 
1171  for (q = p; *q && !IS_SPACE(*q); q++)
1172  ;
1173 
1174  mutt_str_substr_copy(p, q, subtype, sizeof(subtype));
1175 
1176  type = mutt_check_mime_type(ct);
1177  if (type == TYPE_OTHER)
1178  mutt_str_strfcpy(xtype, ct, sizeof(xtype));
1179 
1180  cur_sze = sze;
1181  }
1182  p = NULL;
1183  }
1184  }
1185  mutt_file_fclose(&fp);
1186  }
1187  }
1188 
1189 bye:
1190 
1191  /* no mime.types file found */
1192  if (!found_mimetypes)
1193  {
1194  mutt_error(_("Could not find any mime.types file."));
1195  }
1196 
1197  if ((type != TYPE_OTHER) || (*xtype != '\0'))
1198  {
1199  att->type = type;
1200  mutt_str_replace(&att->subtype, subtype);
1201  mutt_str_replace(&att->xtype, xtype);
1202  }
1203 
1204  return type;
1205 }
Unknown Content-Type.
Definition: mime.h:31
#define NONULL(x)
Definition: string2.h:37
#define _(a)
Definition: message.h:28
size_t mutt_str_strlen(const char *a)
Calculate the length of a string, safely.
Definition: string.c:666
enum ContentType mutt_check_mime_type(const char *s)
Check a MIME type string.
Definition: parse.c:296
int mutt_file_fclose(FILE **fp)
Close a FILE handle (and NULL the pointer)
Definition: file.c:149
WHERE char * HomeDir
User&#39;s home directory.
Definition: globals.h:48
#define SKIPWS(ch)
Definition: string2.h:47
char * subtype
content-type subtype
Definition: body.h:37
#define PATH_MAX
Definition: mutt.h:50
char * xtype
content-type if x-unknown
Definition: body.h:36
size_t mutt_str_strfcpy(char *dest, const char *src, size_t dsize)
Copy a string into a buffer (guaranteeing NUL-termination)
Definition: string.c:750
void mutt_str_replace(char **p, const char *s)
Replace one string with another.
Definition: string.c:453
unsigned int type
content-type primary type
Definition: body.h:65
#define IS_SPACE(ch)
Definition: string2.h:38
Log at debug level 1.
Definition: logging.h:56
#define mutt_error(...)
Definition: logging.h:84
int mutt_str_strcasecmp(const char *a, const char *b)
Compare two strings ignoring case, safely.
Definition: string.c:628
#define mutt_debug(LEVEL,...)
Definition: logging.h:81
ContentType
Content-Type.
Definition: mime.h:29
char * mutt_str_substr_copy(const char *begin, const char *end, char *buf, size_t buflen)
Copy a sub-string into a buffer.
Definition: string.c:556
static void transform_to_7bit ( struct Body a,
FILE *  fp_in 
)
static

Convert MIME parts to 7-bit.

Parameters
aBody of the email
fp_inFile to read

Definition at line 1212 of file sendlib.c.

1213 {
1214  char buf[PATH_MAX];
1215  struct State s = { 0 };
1216  struct stat sb;
1217 
1218  for (; a; a = a->next)
1219  {
1220  if (a->type == TYPE_MULTIPART)
1221  {
1222  if (a->encoding != ENC_7BIT)
1223  a->encoding = ENC_7BIT;
1224 
1225  transform_to_7bit(a->parts, fp_in);
1226  }
1227  else if (mutt_is_message_type(a->type, a->subtype))
1228  {
1229  mutt_message_to_7bit(a, fp_in);
1230  }
1231  else
1232  {
1233  a->noconv = true;
1234  a->force_charset = true;
1235 
1236  mutt_mktemp(buf, sizeof(buf));
1237  s.fp_out = mutt_file_fopen(buf, "w");
1238  if (!s.fp_out)
1239  {
1240  mutt_perror("fopen");
1241  return;
1242  }
1243  s.fp_in = fp_in;
1244  mutt_decode_attachment(a, &s);
1246  FREE(&a->d_filename);
1247  a->d_filename = a->filename;
1248  a->filename = mutt_str_strdup(buf);
1249  a->unlink = true;
1250  if (stat(a->filename, &sb) == -1)
1251  {
1252  mutt_perror("stat");
1253  return;
1254  }
1255  a->length = sb.st_size;
1256 
1258  if (a->encoding == ENC_8BIT)
1260  else if (a->encoding == ENC_BINARY)
1261  a->encoding = ENC_BASE64;
1262  }
1263  }
1264 }
void mutt_decode_attachment(struct Body *b, struct State *s)
Decode an email&#39;s attachment.
Definition: handler.c:1789
void mutt_message_to_7bit(struct Body *a, FILE *fp)
Convert an email&#39;s MIME parts to 7-bit.
Definition: sendlib.c:1271
char * filename
when sending a message, this is the file to which this structure refers
Definition: body.h:46
bool mutt_is_message_type(int type, const char *subtype)
Determine if a mime type matches a message or not.
Definition: parse.c:1270
#define mutt_perror(...)
Definition: logging.h:85
7-bit text
Definition: mime.h:49
bool noconv
Don&#39;t do character set conversion.
Definition: body.h:73
struct Body * next
next attachment in the list
Definition: body.h:53
8-bit text
Definition: mime.h:50
FILE * fp_out
File to write to.
Definition: state.h:47
static void transform_to_7bit(struct Body *a, FILE *fp_in)
Convert MIME parts to 7-bit.
Definition: sendlib.c:1212
FILE * fp_in
File to read from.
Definition: state.h:46
void mutt_update_encoding(struct Body *a)
Update the encoding type.
Definition: sendlib.c:1446
int mutt_file_fclose(FILE **fp)
Close a FILE handle (and NULL the pointer)
Definition: file.c:149
bool force_charset
Send mode: don&#39;t adjust the character set when in send-mode.
Definition: body.h:74
unsigned int encoding
content-transfer-encoding
Definition: body.h:66
Base-64 encoded text.
Definition: mime.h:52
char * subtype
content-type subtype
Definition: body.h:37
#define mutt_mktemp(buf, buflen)
Definition: muttlib.h:76
LOFF_T length
length (in bytes) of attachment
Definition: body.h:45
#define PATH_MAX
Definition: mutt.h:50
struct Body * parts
parts of a multipart or message/rfc822
Definition: body.h:54
unsigned int type
content-type primary type
Definition: body.h:65
Type: &#39;multipart/*&#39;.
Definition: mime.h:37
char * mutt_str_strdup(const char *str)
Copy a string, safely.
Definition: string.c:380
bool unlink
If true, filename should be unlink()ed before free()ing this structure.
Definition: body.h:69
Binary.
Definition: mime.h:53
Quoted-printable text.
Definition: mime.h:51
#define FREE(x)
Definition: memory.h:40
Keep track when processing files.
Definition: state.h:44
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:584
void mutt_message_to_7bit ( struct Body a,
FILE *  fp 
)

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

Parameters
aBody of the email
fpFile to read (OPTIONAL)

Definition at line 1271 of file sendlib.c.

1272 {
1273  char temp[PATH_MAX];
1274  char *line = NULL;
1275  FILE *fp_in = NULL;
1276  FILE *fp_out = NULL;
1277  struct stat sb;
1278 
1279  if (!a->filename && fp)
1280  fp_in = fp;
1281  else if (!a->filename || !(fp_in = fopen(a->filename, "r")))
1282  {
1283  mutt_error(_("Could not open %s"), a->filename ? a->filename : "(null)");
1284  return;
1285  }
1286  else
1287  {
1288  a->offset = 0;
1289  if (stat(a->filename, &sb) == -1)
1290  {
1291  mutt_perror("stat");
1292  mutt_file_fclose(&fp_in);
1293  }
1294  a->length = sb.st_size;
1295  }
1296 
1297  mutt_mktemp(temp, sizeof(temp));
1298  fp_out = mutt_file_fopen(temp, "w+");
1299  if (!fp_out)
1300  {
1301  mutt_perror("fopen");
1302  goto cleanup;
1303  }
1304 
1305  if (!fp_in)
1306  goto cleanup;
1307 
1308  fseeko(fp_in, a->offset, SEEK_SET);
1309  a->parts = mutt_rfc822_parse_message(fp_in, a);
1310 
1311  transform_to_7bit(a->parts, fp_in);
1312 
1313  mutt_copy_hdr(fp_in, fp_out, a->offset, a->offset + a->length,
1314  CH_MIME | CH_NONEWLINE | CH_XMIT, NULL);
1315 
1316  fputs("MIME-Version: 1.0\n", fp_out);
1317  mutt_write_mime_header(a->parts, fp_out);
1318  fputc('\n', fp_out);
1319  mutt_write_mime_body(a->parts, fp_out);
1320 
1321 cleanup:
1322  FREE(&line);
1323 
1324  if (fp_in && (fp_in != fp))
1325  mutt_file_fclose(&fp_in);
1326  if (fp_out)
1327  mutt_file_fclose(&fp_out);
1328  else
1329  return;
1330 
1331  a->encoding = ENC_7BIT;
1332  FREE(&a->d_filename);
1333  a->d_filename = a->filename;
1334  if (a->filename && a->unlink)
1335  unlink(a->filename);
1336  a->filename = mutt_str_strdup(temp);
1337  a->unlink = true;
1338  if (stat(a->filename, &sb) == -1)
1339  {
1340  mutt_perror("stat");
1341  return;
1342  }
1343  a->length = sb.st_size;
1344  mutt_body_free(&a->parts);
1345  a->email->content = NULL;
1346 }
#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
7-bit text
Definition: mime.h:49
struct Body * content
List of MIME parts.
Definition: email.h:90
LOFF_T offset
offset where the actual data begins
Definition: body.h:44
#define _(a)
Definition: message.h:28
static void transform_to_7bit(struct Body *a, FILE *fp_in)
Convert MIME parts to 7-bit.
Definition: sendlib.c:1212
struct Body * mutt_rfc822_parse_message(FILE *fp, struct Body *parent)
parse a Message/RFC822 body
Definition: parse.c:1443
int mutt_file_fclose(FILE **fp)
Close a FILE handle (and NULL the pointer)
Definition: file.c:149
unsigned int encoding
content-transfer-encoding
Definition: body.h:66
const char * line
Definition: common.c:36
#define mutt_mktemp(buf, buflen)
Definition: muttlib.h:76
LOFF_T length
length (in bytes) of attachment
Definition: body.h:45
#define PATH_MAX
Definition: mutt.h:50
int mutt_write_mime_body(struct Body *a, FILE *fp)
Write a MIME part.
Definition: sendlib.c:511
#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 **p)
Free a Body.
Definition: body.c:57
char * mutt_str_strdup(const char *str)
Copy a string, safely.
Definition: string.c:380
#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
#define FREE(x)
Definition: memory.h:40
int mutt_write_mime_header(struct Body *a, FILE *fp)
Create a MIME header.
Definition: sendlib.c:359
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:584
struct Email * email
header information for message/rfc822
Definition: body.h:55
int mutt_copy_hdr(FILE *fp_in, FILE *fp_out, LOFF_T off_start, LOFF_T off_end, CopyHeaderFlags chflags, const char *prefix)
Copy header from one file to another.
Definition: copy.c:74
#define CH_NONEWLINE
Don&#39;t output terminating newline after the header.
Definition: copy.h:59
static void set_encoding ( struct Body b,
struct Content info 
)
static

determine which Content-Transfer-Encoding to use

Parameters
[in]bBody of email
[out]infoInfo about the email

Definition at line 1353 of file sendlib.c.

1354 {
1355  if (b->type == TYPE_TEXT)
1356  {
1357  char send_charset[128];
1358  char *chsname = mutt_body_get_charset(b, send_charset, sizeof(send_charset));
1359  if ((info->lobin && !mutt_str_startswith(chsname, "iso-2022", CASE_IGNORE)) ||
1360  (info->linemax > 990) || (info->from && C_EncodeFrom))
1361  {
1363  }
1364  else if (info->hibin)
1365  {
1367  }
1368  else
1369  {
1370  b->encoding = ENC_7BIT;
1371  }
1372  }
1373  else if ((b->type == TYPE_MESSAGE) || (b->type == TYPE_MULTIPART))
1374  {
1375  if (info->lobin || info->hibin)
1376  {
1377  if (C_Allow8bit && !info->lobin)
1378  b->encoding = ENC_8BIT;
1379  else
1380  mutt_message_to_7bit(b, NULL);
1381  }
1382  else
1383  b->encoding = ENC_7BIT;
1384  }
1385  else if ((b->type == TYPE_APPLICATION) &&
1386  (mutt_str_strcasecmp(b->subtype, "pgp-keys") == 0))
1387  {
1388  b->encoding = ENC_7BIT;
1389  }
1390  else
1391  {
1392  /* Determine which encoding is smaller */
1393  if (1.33 * (float) (info->lobin + info->hibin + info->ascii) <
1394  3.0 * (float) (info->lobin + info->hibin) + (float) info->ascii)
1395  {
1396  b->encoding = ENC_BASE64;
1397  }
1398  else
1399  {
1401  }
1402  }
1403 }
void mutt_message_to_7bit(struct Body *a, FILE *fp)
Convert an email&#39;s MIME parts to 7-bit.
Definition: sendlib.c:1271
long linemax
Length of the longest line in the file.
Definition: content.h:40
bool C_EncodeFrom
Config: Encode &#39;From &#39; as &#39;quote-printable&#39; at the beginning of lines.
Definition: sendlib.c:82
7-bit text
Definition: mime.h:49
8-bit text
Definition: mime.h:50
long hibin
8-bit characters
Definition: content.h:35
unsigned int encoding
content-transfer-encoding
Definition: body.h:66
Base-64 encoded text.
Definition: mime.h:52
char * subtype
content-type subtype
Definition: body.h:37
long ascii
Number of ascii chars.
Definition: content.h:39
Type: &#39;text/*&#39;.
Definition: mime.h:38
Ignore case when comparing strings.
Definition: string2.h:68
char * mutt_body_get_charset(struct Body *b, char *buf, size_t buflen)
Get a body&#39;s character set.
Definition: sendlib.c:1422
unsigned int type
content-type primary type
Definition: body.h:65
bool from
Has a line beginning with "From "?
Definition: content.h:43
size_t mutt_str_startswith(const char *str, const char *prefix, enum CaseSensitivity cs)
Check whether a string starts with a prefix.
Definition: string.c:168
Type: &#39;message/*&#39;.
Definition: mime.h:35
long lobin
Unprintable 7-bit chars (eg., control chars)
Definition: content.h:36
Type: &#39;multipart/*&#39;.
Definition: mime.h:37
int mutt_str_strcasecmp(const char *a, const char *b)
Compare two strings ignoring case, safely.
Definition: string.c:628
Quoted-printable text.
Definition: mime.h:51
bool C_Allow8bit
Config: Allow 8-bit messages, don&#39;t use quoted-printable or base64.
Definition: sendlib.c:79
Type: &#39;application/*&#39;.
Definition: mime.h:33
void mutt_stamp_attachment ( struct Body a)

Timestamp an Attachment.

Parameters
aAttachment

Definition at line 1409 of file sendlib.c.

1410 {
1411  a->stamp = time(NULL);
1412 }
time_t stamp
Time stamp of last encoding update.
Definition: body.h:61
char* mutt_body_get_charset ( struct Body b,
char *  buf,
size_t  buflen 
)

Get a body's character set.

Parameters
bBody to examine
bufBuffer for the result
buflenLength of the buffer
Return values
ptrBuffer containing character set
NULLOn error, or if not a text type

Definition at line 1422 of file sendlib.c.

1423 {
1424  char *p = NULL;
1425 
1426  if (b && (b->type != TYPE_TEXT))
1427  return NULL;
1428 
1429  if (b)
1430  p = mutt_param_get(&b->parameter, "charset");
1431 
1432  if (p)
1433  mutt_ch_canonical_charset(buf, buflen, p);
1434  else
1435  mutt_str_strfcpy(buf, "us-ascii", buflen);
1436 
1437  return buf;
1438 }
void mutt_ch_canonical_charset(char *buf, size_t buflen, const char *name)
Canonicalise the charset of a string.
Definition: charset.c:314
Type: &#39;text/*&#39;.
Definition: mime.h:38
size_t mutt_str_strfcpy(char *dest, const char *src, size_t dsize)
Copy a string into a buffer (guaranteeing NUL-termination)
Definition: string.c:750
unsigned int type
content-type primary type
Definition: body.h:65
char * mutt_param_get(const struct ParameterList *p, const char *s)
Find a matching Parameter.
Definition: parameter.c:84
struct ParameterList parameter
parameters of the content-type
Definition: body.h:39
void mutt_update_encoding ( struct Body a)

Update the encoding type.

Parameters
aBody to update

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

Definition at line 1446 of file sendlib.c.

1447 {
1448  struct Content *info = NULL;
1449  char chsbuf[256];
1450 
1451  /* override noconv when it's us-ascii */
1452  if (mutt_ch_is_us_ascii(mutt_body_get_charset(a, chsbuf, sizeof(chsbuf))))
1453  a->noconv = false;
1454 
1455  if (!a->force_charset && !a->noconv)
1456  mutt_param_delete(&a->parameter, "charset");
1457 
1458  info = mutt_get_content_info(a->filename, a);
1459  if (!info)
1460  return;
1461 
1462  set_encoding(a, info);
1464 
1465  FREE(&a->content);
1466  a->content = info;
1467 }
void mutt_stamp_attachment(struct Body *a)
Timestamp an Attachment.
Definition: sendlib.c:1409
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
struct Content * mutt_get_content_info(const char *fname, struct Body *b)
Analyze file to determine MIME encoding to use.
Definition: sendlib.c:1003
bool force_charset
Send mode: don&#39;t adjust the character set when in send-mode.
Definition: body.h:74
#define mutt_ch_is_us_ascii(str)
Definition: charset.h:107
Info about an attachment.
Definition: content.h:33
static void set_encoding(struct Body *b, struct Content *info)
determine which Content-Transfer-Encoding to use
Definition: sendlib.c:1353
char * mutt_body_get_charset(struct Body *b, char *buf, size_t buflen)
Get a body&#39;s character set.
Definition: sendlib.c:1422
#define FREE(x)
Definition: memory.h:40
void mutt_param_delete(struct ParameterList *p, const char *attribute)
Delete a matching Parameter.
Definition: parameter.c:142
struct ParameterList parameter
parameters of the content-type
Definition: body.h:39
struct Body* mutt_make_message_attach ( struct Mailbox m,
struct Email e,
bool  attach_msg 
)

Create a message attachment.

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

Definition at line 1477 of file sendlib.c.

1478 {
1479  char buf[1024];
1480  struct Body *body = NULL;
1481  FILE *fp = NULL;
1482  CopyMessageFlags cmflags;
1484 
1485  if (WithCrypto)
1486  {
1488  {
1490  return NULL;
1491  }
1492  }
1493 
1494  mutt_mktemp(buf, sizeof(buf));
1495  fp = mutt_file_fopen(buf, "w+");
1496  if (!fp)
1497  return NULL;
1498 
1499  body = mutt_body_new();
1500  body->type = TYPE_MESSAGE;
1501  body->subtype = mutt_str_strdup("rfc822");
1502  body->filename = mutt_str_strdup(buf);
1503  body->unlink = true;
1504  body->use_disp = false;
1505  body->disposition = DISP_INLINE;
1506  body->noconv = true;
1507 
1509 
1510  CopyHeaderFlags chflags = CH_XMIT;
1511  cmflags = MUTT_CM_NO_FLAGS;
1512 
1513  /* If we are attaching a message, ignore C_MimeForwardDecode */
1514  if (!attach_msg && C_MimeForwardDecode)
1515  {
1516  chflags |= CH_MIME | CH_TXTPLAIN;
1517  cmflags = MUTT_CM_DECODE | MUTT_CM_CHARCONV;
1519  pgp &= ~PGP_ENCRYPT;
1521  pgp &= ~SMIME_ENCRYPT;
1522  }
1523  else if ((WithCrypto != 0) && C_ForwardDecrypt && (e->security & SEC_ENCRYPT))
1524  {
1525  if (((WithCrypto & APPLICATION_PGP) != 0) && mutt_is_multipart_encrypted(e->content))
1526  {
1527  chflags |= CH_MIME | CH_NONEWLINE;
1528  cmflags = MUTT_CM_DECODE_PGP;
1529  pgp &= ~PGP_ENCRYPT;
1530  }
1531  else if (((WithCrypto & APPLICATION_PGP) != 0) &&
1533  {
1534  chflags |= CH_MIME | CH_TXTPLAIN;
1535  cmflags = MUTT_CM_DECODE | MUTT_CM_CHARCONV;
1536  pgp &= ~PGP_ENCRYPT;
1537  }
1538  else if (((WithCrypto & APPLICATION_SMIME) != 0) &&
1540  {
1541  chflags |= CH_MIME | CH_TXTPLAIN;
1542  cmflags = MUTT_CM_DECODE | MUTT_CM_CHARCONV;
1543  pgp &= ~SMIME_ENCRYPT;
1544  }
1545  }
1546 
1547  mutt_copy_message(fp, m, e, cmflags, chflags);
1548 
1549  fflush(fp);
1550  rewind(fp);
1551 
1552  body->email = mutt_email_new();
1553  body->email->offset = 0;
1554  /* we don't need the user headers here */
1555  body->email->env = mutt_rfc822_read_header(fp, body->email, false, false);
1556  if (WithCrypto)
1557  body->email->security = pgp;
1558  mutt_update_encoding(body);
1559  body->parts = body->email->content;
1560 
1561  mutt_file_fclose(&fp);
1562 
1563  return body;
1564 }
#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 C_MimeForwardDecode
Config: Decode the forwarded message before attaching it.
Definition: sendlib.c:86
#define SEC_NO_FLAGS
No flags are set.
Definition: ncrypt.h:120
struct Body * content
List of MIME parts.
Definition: email.h:90
bool noconv
Don&#39;t do character set conversion.
Definition: body.h:73
void mutt_parse_mime_message(struct Mailbox *m, struct Email *e)
Parse a MIME email.
Definition: mutt_parse.c:50
int mutt_copy_message(FILE *fp_out, struct Mailbox *m, struct Email *e, CopyMessageFlags cmflags, CopyHeaderFlags chflags)
Copy a message from a Mailbox.
Definition: copy.c:802
struct Email * mutt_email_new(void)
Create a new Email.
Definition: email.c:63
uint16_t CopyMessageFlags
Flags for mutt_copy_message(), e.g. MUTT_CM_NOHEADER.
Definition: copy.h:31
#define SEC_ENCRYPT
Email is encrypted.
Definition: ncrypt.h:121
#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
Definition: body.h:67
bool crypt_valid_passphrase(SecurityFlags flags)
Check that we have a usable passphrase, ask if not.
Definition: crypt.c:143
struct Body * mutt_body_new(void)
Create a new Body.
Definition: body.c:43
SecurityFlags mutt_is_multipart_encrypted(struct Body *b)
Does the message have encrypted parts?
Definition: crypt.c:420
void mutt_update_encoding(struct Body *a)
Update the encoding type.
Definition: sendlib.c:1446
int mutt_file_fclose(FILE **fp)
Close a FILE handle (and NULL the pointer)
Definition: file.c:149
struct Envelope * env
Envelope information.
Definition: email.h:89
char * subtype
content-type subtype
Definition: body.h:37
#define CH_TXTPLAIN
Generate text/plain MIME headers.
Definition: copy.h:62
SecurityFlags mutt_is_application_pgp(struct Body *m)
Does the message use PGP?
Definition: crypt.c:527
#define mutt_mktemp(buf, buflen)
Definition: muttlib.h:76
#define MUTT_CM_DECODE
Decode the message body into text/plain.
Definition: copy.h:37
bool C_ForwardDecrypt
Config: Decrypt the message when forwarding it.
Definition: sendlib.c:83
#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:586
SecurityFlags security
bit 0-8: flags, bit 9,10: application.
Definition: email.h:39
unsigned int type
content-type primary type
Definition: body.h:65
LOFF_T offset
Where in the stream does this message begin?
Definition: email.h:83
#define APPLICATION_PGP
Use PGP to encrypt/sign.
Definition: ncrypt.h:130
Type: &#39;message/*&#39;.
Definition: mime.h:35
bool use_disp
Content-Disposition uses filename= ?
Definition: body.h:68
char * mutt_str_strdup(const char *str)
Copy a string, safely.
Definition: string.c:380
uint32_t CopyHeaderFlags
Flags for mutt_copy_header(), e.g. CH_UPDATE.
Definition: copy.h:49
#define SMIME_ENCRYPT
Definition: ncrypt.h:142
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
uint16_t SecurityFlags
Flags, e.g. SEC_ENCRYPT.
Definition: ncrypt.h:119
FILE * mutt_file_fopen(const char *path, const char *mode)
Call fopen() safely.
Definition: file.c:584
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:1023
struct Email * email
header information for message/rfc822
Definition: body.h:55
#define WithCrypto
Definition: ncrypt.h:156
#define PGP_ENCRYPT
Definition: ncrypt.h:136
#define CH_NONEWLINE
Don&#39;t output terminating newline after the header.
Definition: copy.h:59
#define APPLICATION_SMIME
Use SMIME to encrypt/sign.
Definition: ncrypt.h:131
static void run_mime_type_query ( struct Body att)
static

Run an external command to determine the MIME type.

Parameters
attAttachment

The command in $mime_type_query_command is run.

Definition at line 1572 of file sendlib.c.

1573 {
1574  FILE *fp = NULL, *fp_err = NULL;
1575  char *buf = NULL;
1576  size_t buflen;
1577  int dummy = 0;
1578  pid_t pid;
1579  struct Buffer *cmd = mutt_buffer_pool_get();
1580 
1582 
1583  pid = mutt_create_filter(mutt_b2s(cmd), NULL, &fp, &fp_err);
1584  if (pid < 0)
1585  {
1586  mutt_error(_("Error running \"%s\""), mutt_b2s(cmd));
1588  return;
1589  }
1591 
1592  buf = mutt_file_read_line(buf, &buflen, fp, &dummy, 0);
1593  if (buf)
1594  {
1595  if (strchr(buf, '/'))
1596  mutt_parse_content_type(buf, att);
1597  FREE(&buf);
1598  }
1599 
1600  mutt_file_fclose(&fp);
1601  mutt_file_fclose(&fp_err);
1602  mutt_wait_filter(pid);
1603 }
pid_t mutt_create_filter(const char *s, FILE **fp_in, FILE **fp_out, FILE **fp_err)
Set up filter program.
Definition: filter.c:216
char * filename
when sending a message, this is the file to which this structure refers
Definition: body.h:46
struct Buffer * mutt_buffer_pool_get(void)
Get a Buffer from the pool.
Definition: pool.c:75
void mutt_buffer_pool_release(struct Buffer **pbuf)
Free a Buffer from the pool.
Definition: pool.c:86
String manipulation buffer.
Definition: buffer.h:33
#define _(a)
Definition: message.h:28
char * mutt_file_read_line(char *line, size_t *size, FILE *fp, int *line_num, int flags)
Read a line from a file.
Definition: file.c:663
int mutt_file_fclose(FILE **fp)
Close a FILE handle (and NULL the pointer)
Definition: file.c:149
#define mutt_b2s(buf)
Definition: buffer.h:42
void mutt_parse_content_type(const char *s, struct Body *ct)
Parse a content type.
Definition: parse.c:434
char * C_MimeTypeQueryCommand
Config: External command to determine the MIME type of an attachment.
Definition: sendlib.c:88
#define mutt_error(...)
Definition: logging.h:84
void mutt_buffer_file_expand_fmt_quote(struct Buffer *dest, const char *fmt, const char *src)
Replace s in a string with a filename.
Definition: file.c:1418
#define FREE(x)
Definition: memory.h:40
int mutt_wait_filter(pid_t pid)
Wait for the exit of a process and return its status.
Definition: filter.c:227
struct Body* mutt_make_file_attach ( const char *  path)

Create a file attachment.

Parameters
pathFile to attach
Return values
ptrNewly allocated Body
NULLError

Definition at line 1611 of file sendlib.c.

1612 {
1613  struct Body *att = mutt_body_new();
1614  att->filename = mutt_str_strdup(path);
1615 
1617  run_mime_type_query(att);
1618 
1619  /* Attempt to determine the appropriate content-type based on the filename
1620  * suffix. */
1621  if (!att->subtype)
1622  mutt_lookup_mime_type(att, path);
1623 
1625  {
1626  run_mime_type_query(att);
1627  }
1628 
1629  struct Content *info = mutt_get_content_info(path, att);
1630  if (!info)
1631  {
1632  mutt_body_free(&att);
1633  return NULL;
1634  }
1635 
1636  if (!att->subtype)
1637  {
1638  if ((info->nulbin == 0) &&
1639  ((info->lobin == 0) || ((info->lobin + info->hibin + info->ascii) / info->lobin >= 10)))
1640  {
1641  /* Statistically speaking, there should be more than 10% "lobin"
1642  * chars if this is really a binary file... */
1643  att->type = TYPE_TEXT;
1644  att->subtype = mutt_str_strdup("plain");
1645  }
1646  else
1647  {
1648  att->type = TYPE_APPLICATION;
1649  att->subtype = mutt_str_strdup("octet-stream");
1650  }
1651  }
1652 
1653  FREE(&info);
1654  mutt_update_encoding(att);
1655  return att;
1656 }
char * filename
when sending a message, this is the file to which this structure refers
Definition: body.h:46
static void run_mime_type_query(struct Body *att)
Run an external command to determine the MIME type.
Definition: sendlib.c:1572
long hibin
8-bit characters
Definition: content.h:35
The body of an email.
Definition: body.h:34
struct Content * mutt_get_content_info(const char *fname, struct Body *b)
Analyze file to determine MIME encoding to use.
Definition: sendlib.c:1003
struct Body * mutt_body_new(void)
Create a new Body.
Definition: body.c:43
void mutt_update_encoding(struct Body *a)
Update the encoding type.
Definition: sendlib.c:1446
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
unsigned int type
content-type primary type
Definition: body.h:65
long lobin
Unprintable 7-bit chars (eg., control chars)
Definition: content.h:36
void mutt_body_free(struct Body **p)
Free a Body.
Definition: body.c:57
enum ContentType mutt_lookup_mime_type(struct Body *att, const char *path)
Find the MIME type for an attachment.
Definition: sendlib.c:1091
char * mutt_str_strdup(const char *str)
Copy a string, safely.
Definition: string.c:380
char * C_MimeTypeQueryCommand
Config: External command to determine the MIME type of an attachment.
Definition: sendlib.c:88
#define FREE(x)
Definition: memory.h:40
long nulbin
Null characters (0x0)
Definition: content.h:37
Type: &#39;application/*&#39;.
Definition: mime.h:33
bool C_MimeTypeQueryFirst
Config: Run the C_MimeTypeQueryCommand before the mime.types lookup.
Definition: sendlib.c:89
static int get_toplevel_encoding ( struct Body a)
static

Find the most restrictive encoding type.

Parameters
aBody to examine
Return values
numEncoding type, e.g. ENC_7BIT

Definition at line 1663 of file sendlib.c.

1664 {
1665  int e = ENC_7BIT;
1666 
1667  for (; a; a = a->next)
1668  {
1669  if (a->encoding == ENC_BINARY)
1670  return ENC_BINARY;
1671  else if (a->encoding == ENC_8BIT)
1672  e = ENC_8BIT;
1673  }
1674 
1675  return e;
1676 }
7-bit text
Definition: mime.h:49
struct Body * next
next attachment in the list
Definition: body.h:53
8-bit text
Definition: mime.h:50
unsigned int encoding
content-transfer-encoding
Definition: body.h:66
Binary.
Definition: mime.h:53
static bool check_boundary ( const char *  boundary,
struct Body b 
)
static

check for duplicate boundary

Parameters
boundaryBoundary to look for
bBody parts to check
Return values
trueif duplicate found

Definition at line 1684 of file sendlib.c.

1685 {
1686  char *p = NULL;
1687 
1688  if (b->parts && check_boundary(boundary, b->parts))
1689  return true;
1690 
1691  if (b->next && check_boundary(boundary, b->next))
1692  return true;
1693 
1694  p = mutt_param_get(&b->parameter, "boundary");
1695  if (p && (mutt_str_strcmp(p, boundary) == 0))
1696  {
1697  return true;
1698  }
1699  return false;
1700 }
struct Body * next
next attachment in the list
Definition: body.h:53
static bool check_boundary(const char *boundary, struct Body *b)
check for duplicate boundary
Definition: sendlib.c:1684
struct Body * parts
parts of a multipart or message/rfc822
Definition: body.h:54
char * mutt_param_get(const struct ParameterList *p, const char *s)
Find a matching Parameter.
Definition: parameter.c:84
struct ParameterList parameter
parameters of the content-type
Definition: body.h:39
int mutt_str_strcmp(const char *a, const char *b)
Compare two strings, safely.
Definition: string.c:615
struct Body* mutt_make_multipart ( struct Body b)

Create a multipart email.

Parameters
bBody of email to start
Return values
ptrNewly allocated Body

Definition at line 1707 of file sendlib.c.

1708 {
1709  struct Body *new_body = mutt_body_new();
1710  new_body->type = TYPE_MULTIPART;
1711  new_body->subtype = mutt_str_strdup("mixed");
1712  new_body->encoding = get_toplevel_encoding(b);
1713  do
1714  {
1715  mutt_generate_boundary(&new_body->parameter);
1716  if (check_boundary(mutt_param_get(&new_body->parameter, "boundary"), b))
1717  mutt_param_delete(&new_body->parameter, "boundary");
1718  } while (!mutt_param_get(&new_body->parameter, "boundary"));
1719  new_body->use_disp = false;
1720  new_body->disposition = DISP_INLINE;
1721  new_body->parts = b;
1722 
1723  return new_body;
1724 }
static int get_toplevel_encoding(struct Body *a)
Find the most restrictive encoding type.
Definition: sendlib.c:1663
The body of an email.
Definition: body.h:34
unsigned int disposition
content-disposition
Definition: body.h:67
void mutt_generate_boundary(struct ParameterList *parm)
Create a unique boundary id for a MIME part.
Definition: sendlib.c:594
struct Body * mutt_body_new(void)
Create a new Body.
Definition: body.c:43
static bool check_boundary(const char *boundary, struct Body *b)
check for duplicate boundary
Definition: sendlib.c:1684
unsigned int encoding
content-transfer-encoding
Definition: body.h:66
char * subtype
content-type subtype
Definition: body.h:37
struct Body * parts
parts of a multipart or message/rfc822
Definition: body.h:54
unsigned int type
content-type primary type
Definition: body.h:65
char * mutt_param_get(const struct ParameterList *p, const char *s)
Find a matching Parameter.
Definition: parameter.c:84
Type: &#39;multipart/*&#39;.
Definition: mime.h:37
bool use_disp
Content-Disposition uses filename= ?
Definition: body.h:68
char * mutt_str_strdup(const char *str)
Copy a string, safely.
Definition: string.c:380
void mutt_param_delete(struct ParameterList *p, const char *attribute)
Delete a matching Parameter.
Definition: parameter.c:142
Content is inline.
Definition: mime.h:62
struct ParameterList parameter
parameters of the content-type
Definition: body.h:39
struct Body* mutt_remove_multipart ( struct Body b)

Extract the multipart body if it exists.

Parameters
bBody to alter
Return values
ptrThe parts of the Body
Note
The original Body is freed

Definition at line 1733 of file sendlib.c.

1734 {
1735  struct Body *t = NULL;
1736 
1737  if (b->parts)
1738  {
1739  t = b;
1740  b = b->parts;
1741  t->parts = NULL;
1742  mutt_body_free(&t);
1743  }
1744  return b;
1745 }
The body of an email.
Definition: body.h:34
struct Body * parts
parts of a multipart or message/rfc822
Definition: body.h:54
void mutt_body_free(struct Body **p)
Free a Body.
Definition: body.c:57
void mutt_write_addrlist ( struct AddressList *  al,
FILE *  fp,
int  linelen,
bool  display 
)

wrapper around mutt_write_address()

Parameters
alAddress list
fpFile to write to
linelenLine length to use
displayTrue if these addresses will be displayed to the user

So we can handle very large recipient lists without needing a huge temporary buffer in memory

Definition at line 1757 of file sendlib.c.

1758 {
1759  char buf[1024];
1760  int count = 0;
1761 
1762  struct Address *a = NULL;
1763  TAILQ_FOREACH(a, al, entries)
1764  {
1765  buf[0] = '\0';
1766  mutt_addr_write(buf, sizeof(buf), a, display);
1767  size_t len = mutt_str_strlen(buf);
1768  if (count && (linelen + len > 74))
1769  {
1770  fputs("\n\t", fp);
1771  linelen = len + 8; /* tab is usually about 8 spaces... */
1772  }
1773  else
1774  {
1775  if (count && a->mailbox)
1776  {
1777  fputc(' ', fp);
1778  linelen++;
1779  }
1780  linelen += len;
1781  }
1782  fputs(buf, fp);
1783  struct Address *next = TAILQ_NEXT(a, entries);
1784  if (!a->group && next && next->mailbox)
1785  {
1786  linelen++;
1787  fputc(',', fp);
1788  }
1789  count++;
1790  }
1791  fputc('\n', fp);
1792 }
#define TAILQ_FOREACH(var, head, field)
Definition: queue.h:719
An email address.
Definition: address.h:34
char * mailbox
Mailbox and host address.
Definition: address.h:37
size_t mutt_str_strlen(const char *a)
Calculate the length of a string, safely.
Definition: string.c:666
size_t mutt_addr_write(char *buf, size_t buflen, struct Address *addr, bool display)
Write a single Address to a buffer.
Definition: address.c:1012
bool group
Group mailbox?
Definition: address.h:38
#define TAILQ_NEXT(elm, field)
Definition: queue.h:816
void mutt_write_references ( const struct ListHead *  r,
FILE *  fp,
size_t  trim 
)

Add the message references to a list.

Parameters
rString List of references
fpFile to write to
trimTrim the list to at most this many items

Write the list in reverse because they are stored in reverse order when parsed to speed up threading.

Definition at line 1803 of file sendlib.c.

1804 {
1805  struct ListNode *np = NULL;
1806  size_t length = 0;
1807 
1808  STAILQ_FOREACH(np, r, entries)
1809  {
1810  if (++length == trim)
1811  break;
1812  }
1813 
1814  struct ListNode **ref = mutt_mem_calloc(length, sizeof(struct ListNode *));
1815 
1816  // store in reverse order
1817  size_t tmp = length;
1818  STAILQ_FOREACH(np, r, entries)
1819  {
1820  ref[--tmp] = np;
1821  if (tmp == 0)
1822  break;
1823  }
1824 
1825  for (size_t i = 0; i < length; i++)
1826  {
1827  fputc(' ', fp);
1828  fputs(ref[i]->data, fp);
1829  if (i != length - 1)
1830  fputc('\n', fp);
1831  }
1832 
1833  FREE(&ref);
1834 }
void * mutt_mem_calloc(size_t nmemb, size_t size)
Allocate zeroed memory on the heap.
Definition: memory.c:50
#define STAILQ_FOREACH(var, head, field)
Definition: queue.h:350
char * data
Definition: list.h:35
#define FREE(x)
Definition: memory.h:40
A List node for strings.
Definition: list.h:33
static int print_val ( FILE *  fp,
const char *  pfx,
const char *  value,
CopyHeaderFlags  chflags,
size_t  col 
)
static

Add pieces to an email header, wrapping where necessary.

Parameters
fpFile to write to
pfxPrefix for headers
valueText to be added
chflagsFlags, see CopyHeaderFlags
colColumn that this text starts at
Return values
0Success
-1Failure

Definition at line 1846 of file sendlib.c.

1848 {
1849  while (value && (value[0] != '\0'))
1850  {
1851  if (fputc(*value, fp) == EOF)
1852  return -1;
1853  /* corner-case: break words longer than 998 chars by force,
1854  * mandated by RFC5322 */
1855  if (!(chflags & CH_DISPLAY) && (++col >= 998))
1856  {
1857  if (fputs("\n ", fp) < 0)
1858  return -1;
1859  col = 1;
1860  }
1861  if (*value == '\n')
1862  {
1863  if ((value[1] != '\0') && pfx && (pfx[0] != '\0') && (fputs(pfx, fp) == EOF))
1864  return -1;
1865  /* for display, turn folding spaces into folding tabs */
1866  if ((chflags & CH_DISPLAY) && ((value[1] == ' ') || (value[1] == '\t')))
1867  {
1868  value++;
1869  while ((value[0] != '\0') && ((value[0] == ' ') || (value[0] == '\t')))
1870  value++;
1871  if (fputc('\t', fp) == EOF)
1872  return -1;
1873  continue;
1874  }
1875  }
1876  value++;
1877  }
1878  return 0;
1879 }
#define CH_DISPLAY
Display result to user.
Definition: copy.h:69
static int fold_one_header ( FILE *  fp,
const char *  tag,
const char *  value,
const char *  pfx,
int  wraplen,
CopyHeaderFlags  chflags 
)
static

Fold one header line.

Parameters
fpFile to write to
tagHeader key, e.g. "From"
valueHeader value
pfxPrefix for header
wraplenColumn to wrap at
chflagsFlags, see CopyHeaderFlags
Return values
0Success
-1Failure

Definition at line 1892 of file sendlib.c.

1894 {
1895  const char *p = value;
1896  char buf[8192] = { 0 };
1897  int first = 1, col = 0, l = 0;
1898  const bool display = (chflags & CH_DISPLAY);
1899 
1900  mutt_debug(LL_DEBUG5, "pfx=[%s], tag=[%s], flags=%d value=[%s]\n", pfx, tag,
1901  chflags, NONULL(value));
1902 
1903  if (tag && *tag && (fprintf(fp, "%s%s: ", NONULL(pfx), tag) < 0))
1904  return -1;
1905  col = mutt_str_strlen(tag) + ((tag && (tag[0] != '\0')) ? 2 : 0) + mutt_str_strlen(pfx);
1906 
1907  while (p && (p[0] != '\0'))
1908  {
1909  int fold = 0;
1910 
1911  /* find the next word and place it in 'buf'. it may start with
1912  * whitespace we can fold before */
1913  const char *next = mutt_str_find_word(p);
1914  l = MIN(sizeof(buf) - 1, next - p);
1915  memcpy(buf, p, l);
1916  buf[l] = '\0';
1917 
1918  /* determine width: character cells for display, bytes for sending
1919  * (we get pure ascii only) */
1920  const int w = mutt_mb_width(buf, col, display);
1921  const int enc = mutt_str_startswith(buf, "=?", CASE_MATCH);
1922 
1923  mutt_debug(LL_DEBUG5, "word=[%s], col=%d, w=%d, next=[0x0%x]\n", buf, col, w, *next);
1924 
1925  /* insert a folding \n before the current word's lwsp except for
1926  * header name, first word on a line (word longer than wrap width)
1927  * and encoded words */
1928  if (!first && !enc && col && ((col + w) >= wraplen))
1929  {
1930  col = mutt_str_strlen(pfx);
1931  fold = 1;
1932  if (fprintf(fp, "\n%s", NONULL(pfx)) <= 0)
1933  return -1;
1934  }
1935 
1936  /* print the actual word; for display, ignore leading ws for word
1937  * and fold with tab for readability */
1938  if (display && fold)
1939  {
1940  char *pc = buf;
1941  while ((pc[0] != '\0') && ((pc[0] == ' ') || (pc[0] == '\t')))
1942  {
1943  pc++;
1944  col--;
1945  }
1946  if (fputc('\t', fp) == EOF)
1947  return -1;
1948  if (print_val(fp, pfx, pc, chflags, col) < 0)
1949  return -1;
1950  col += 8;
1951  }
1952  else if (print_val(fp, pfx, buf, chflags, col) < 0)
1953  return -1;
1954  col += w;
1955 
1956  /* if the current word ends in \n, ignore all its trailing spaces
1957  * and reset column; this prevents us from putting only spaces (or
1958  * even none) on a line if the trailing spaces are located at our
1959  * current line width
1960  * XXX this covers ASCII space only, for display we probably
1961  * want something like iswspace() here */
1962  const char *sp = next;
1963  while ((sp[0] != '\0') && ((sp[0] == ' ') || (sp[0] == '\t')))
1964  sp++;
1965  if (sp[0] == '\n')
1966  {
1967  next = sp;
1968  col = 0;
1969  }
1970 
1971  p = next;
1972  first = 0;
1973  }
1974 
1975  /* if we have printed something but didn't \n-terminate it, do it
1976  * except the last word we printed ended in \n already */
1977  if (col && ((l == 0) || (buf[l - 1] != '\n')))
1978  if (putc('\n', fp) == EOF)
1979  return -1;
1980 
1981  return 0;
1982 }
#define NONULL(x)
Definition: string2.h:37
#define MIN(a, b)
Definition: memory.h:31
Match case when comparing strings.
Definition: string2.h:67
size_t mutt_str_strlen(const char *a)
Calculate the length of a string, safely.
Definition: string.c:666
int mutt_mb_width(const char *str, int col, bool display)
Measure a string&#39;s display width (in screen columns)
Definition: mbyte.c:139
#define CH_DISPLAY
Display result to user.
Definition: copy.h:69
size_t mutt_str_startswith(const char *str, const char *prefix, enum CaseSensitivity cs)
Check whether a string starts with a prefix.
Definition: string.c:168
#define mutt_debug(LEVEL,...)
Definition: logging.h:81
Log at debug level 5.
Definition: logging.h:60
static int print_val(FILE *fp, const char *pfx, const char *value, CopyHeaderFlags chflags, size_t col)
Add pieces to an email header, wrapping where necessary.
Definition: sendlib.c:1846
const char * mutt_str_find_word(const char *src)
Find the end of a word (non-space)
Definition: string.c:1029
static char* unfold_header ( char *  s)
static

Unfold a wrapped email header.

Parameters
sString to process
Return values
ptrUnfolded string
Note
The string is altered in-place

Definition at line 1991 of file sendlib.c.

1992 {
1993  char *p = s;
1994  char *q = s;
1995 
1996  while (p && (p[0] != '\0'))
1997  {
1998  /* remove CRLF prior to FWSP, turn \t into ' ' */
1999  if ((p[0] == '\r') && (p[1] == '\n') && ((p[2] == ' ') || (p[2] == '\t')))
2000  {
2001  *q++ = ' ';
2002  p += 3;
2003  continue;
2004  }
2005  /* remove LF prior to FWSP, turn \t into ' ' */
2006  else if ((p[0] == '\n') && ((p[1] == ' ') || (p[1] == '\t')))
2007  {
2008  *q++ = ' ';
2009  p += 2;
2010  continue;
2011  }
2012  *q++ = *p++;
2013  }
2014  if (q)
2015  q[0] = '\0';
2016 
2017  return s;
2018 }
static int write_one_header ( FILE *  fp,
int  pfxw,
int  max,
int  wraplen,
const char *  pfx,
const char *  start,
const char *  end,
CopyHeaderFlags  chflags 
)
static

Write out one header line.

Parameters
fpFile to write to
pfxwWidth of prefix string
maxMax width
wraplenColumn to wrap at
pfxPrefix for header
startStart of header line
endEnd of header line
chflagsFlags, see CopyHeaderFlags
Return values
0Success
-1Failure

Definition at line 2033 of file sendlib.c.

2035 {
2036  char *tagbuf = NULL, *valbuf = NULL, *t = NULL;
2037  bool is_from = ((end - start) > 5) && mutt_str_startswith(start, "from ", CASE_IGNORE);
2038 
2039  /* only pass through folding machinery if necessary for sending,
2040  * never wrap From_ headers on sending */
2041  if (!(chflags & CH_DISPLAY) && ((pfxw + max <= wraplen) || is_from))
2042  {
2043  valbuf = mutt_str_substr_dup(start, end);
2044  mutt_debug(LL_DEBUG5, "buf[%s%s] short enough, max width = %d <= %d\n",
2045  NONULL(pfx), valbuf, max, wraplen);
2046  if (pfx && *pfx)
2047  {
2048  if (fputs(pfx, fp) == EOF)
2049  {
2050  FREE(&valbuf);
2051  return -1;
2052  }
2053  }
2054 
2055  t = strchr(valbuf, ':');
2056  if (!t)
2057  {
2058  mutt_debug(LL_DEBUG1, "#1 warning: header not in 'key: value' format!\n");
2059  FREE(&valbuf);
2060  return 0;
2061  }
2062  if (print_val(fp, pfx, valbuf, chflags, mutt_str_strlen(pfx)) < 0)
2063  {
2064  FREE(&valbuf);
2065  return -1;
2066  }
2067  FREE(&valbuf);
2068  }
2069  else
2070  {
2071  t = strchr(start, ':');
2072  if (!t || (t > end))
2073  {
2074  mutt_debug(LL_DEBUG1, "#2 warning: header not in 'key: value' format!\n");
2075  return 0;
2076  }
2077  if (is_from)
2078  {
2079  tagbuf = NULL;
2080  valbuf = mutt_str_substr_dup(start, end);
2081  }
2082  else
2083  {
2084  tagbuf = mutt_str_substr_dup(start, t);
2085  /* skip over the colon separating the header field name and value */
2086  t++;
2087 
2088  /* skip over any leading whitespace (WSP, as defined in RFC5322)
2089  * NOTE: mutt_str_skip_email_wsp() does the wrong thing here.
2090  * See tickets 3609 and 3716. */
2091  while ((*t == ' ') || (*t == '\t'))
2092  t++;
2093 
2094  valbuf = mutt_str_substr_dup(t, end);
2095  }
2096  mutt_debug(LL_DEBUG2, "buf[%s%s] too long, max width = %d > %d\n",
2097  NONULL(pfx), NONULL(valbuf), max, wraplen);
2098  if (fold_one_header(fp, tagbuf, valbuf, pfx, wraplen, chflags) < 0)
2099  {
2100  FREE(&valbuf);
2101  FREE(&tagbuf);
2102  return -1;
2103  }
2104  FREE(&tagbuf);
2105  FREE(&valbuf);
2106  }
2107  return 0;
2108 }
#define NONULL(x)
Definition: string2.h:37
size_t mutt_str_strlen(const char *a)
Calculate the length of a string, safely.
Definition: string.c:666
Log at debug level 2.
Definition: logging.h:57
#define CH_DISPLAY
Display result to user.
Definition: copy.h:69
Ignore case when comparing strings.
Definition: string2.h:68
size_t mutt_str_startswith(const char *str, const char *prefix, enum CaseSensitivity cs)
Check whether a string starts with a prefix.
Definition: string.c:168
Log at debug level 1.
Definition: logging.h:56
static int fold_one_header(FILE *fp, const char *tag, const char *value, const char *pfx, int wraplen, CopyHeaderFlags chflags)
Fold one header line.
Definition: sendlib.c:1892
#define FREE(x)
Definition: memory.h:40
bool is_from(const char *s, char *path, size_t pathlen, time_t *tp)
Is a string a &#39;From&#39; header line?
Definition: from.c:49
#define mutt_debug(LEVEL,...)
Definition: logging.h:81
Log at debug level 5.
Definition: logging.h:60
static int print_val(FILE *fp, const char *pfx, const char *value, CopyHeaderFlags chflags, size_t col)
Add pieces to an email header, wrapping where necessary.
Definition: sendlib.c:1846
char * mutt_str_substr_dup(const char *begin, const char *end)
Duplicate a sub-string.
Definition: string.c:579
int mutt_write_one_header ( FILE *  fp,
const char *  tag,
const char *  value,
const char *  pfx,
int  wraplen,
CopyHeaderFlags  chflags 
)

Write one header line to a file.

Parameters
fpFile to write to
tagHeader key, e.g. "From"
valueHeader value
pfxPrefix for header
wraplenColumn to wrap at
chflagsFlags, see CopyHeaderFlags
Return values
0Success
-1Failure

split several headers into individual ones and call write_one_header for each one

Definition at line 2124 of file sendlib.c.

2126 {
2127  char *last = NULL, *line = NULL;
2128  int max = 0, w, rc = -1;
2129  int pfxw = mutt_strwidth(pfx);
2130  char *v = mutt_str_strdup(value);
2131  bool display = (chflags & CH_DISPLAY);
2132 
2133  if (!display || C_Weed)
2134  v = unfold_header(v);
2135 
2136  /* when not displaying, use sane wrap value */
2137  if (!display)
2138  {
2139  if ((C_WrapHeaders < 78) || (C_WrapHeaders > 998))
2140  wraplen = 78;
2141  else
2142  wraplen = C_WrapHeaders;
2143  }
2144  else if ((wraplen <= 0) || (wraplen > MuttIndexWindow->cols))
2145  wraplen = MuttIndexWindow->cols;
2146 
2147  if (tag)
2148  {
2149  /* if header is short enough, simply print it */
2150  if (!display && (mutt_strwidth(tag) + 2 + pfxw + mutt_strwidth(v) <= wraplen))
2151  {
2152  mutt_debug(LL_DEBUG5, "buf[%s%s: %s] is short enough\n", NONULL(pfx), tag, v);
2153  if (fprintf(fp, "%s%s: %s\n", NONULL(pfx), tag, v) <= 0)
2154  goto out;
2155  rc = 0;
2156  goto out;
2157  }
2158  else
2159  {
2160  rc = fold_one_header(fp, tag, v, pfx, wraplen, chflags);
2161  goto out;
2162  }
2163  }
2164 
2165  char *p = v;
2166  last = v;
2167  line = v;
2168  while (p && *p)
2169  {
2170  p = strchr(p, '\n');
2171 
2172  /* find maximum line width in current header */
2173  if (p)
2174  *p = '\0';
2175  w = mutt_mb_width(line, 0, display);
2176  if (w > max)
2177  max = w;
2178  if (p)
2179  *p = '\n';
2180 
2181  if (!p)
2182  break;
2183 
2184  line = ++p;
2185  if ((*p != ' ') && (*p != '\t'))
2186  {
2187  if (write_one_header(fp, pfxw, max, wraplen, pfx, last, p, chflags) < 0)
2188  goto out;
2189  last = p;
2190  max = 0;
2191  }
2192  }
2193 
2194  if (last && *last)
2195  if (write_one_header(fp, pfxw, max, wraplen, pfx, last, p, chflags) < 0)
2196  goto out;
2197 
2198  rc = 0;
2199 
2200 out:
2201  FREE(&v);
2202  return rc;
2203 }
short C_WrapHeaders
Config: Width to wrap headers in outgoing messages.
Definition: sendlib.c:95
#define NONULL(x)
Definition: string2.h:37
static char * unfold_header(char *s)
Unfold a wrapped email header.
Definition: sendlib.c:1991
int mutt_mb_width(const char *str, int col, bool display)
Measure a string&#39;s display width (in screen columns)
Definition: mbyte.c:139
const char * line
Definition: common.c:36
int mutt_strwidth(const char *s)
Measure a string&#39;s width in screen cells.
Definition: curs_lib.c:1254
struct MuttWindow * MuttIndexWindow
Index Window.
Definition: mutt_window.c:39
#define CH_DISPLAY
Display result to user.
Definition: copy.h:69
static int write_one_header(FILE *fp, int pfxw, int max, int wraplen, const char *pfx, const char *start, const char *end, CopyHeaderFlags chflags)
Write out one header line.
Definition: sendlib.c:2033
char * mutt_str_strdup(const char *str)
Copy a string, safely.
Definition: string.c:380
static int fold_one_header(FILE *fp, const char *tag, const char *value, const char *pfx, int wraplen, CopyHeaderFlags chflags)
Fold one header line.
Definition: sendlib.c:1892
#define FREE(x)
Definition: memory.h:40
#define mutt_debug(LEVEL,...)
Definition: logging.h:81
Log at debug level 5.
Definition: logging.h:60
bool C_Weed
Config: Filter headers when displaying/forwarding/printing/replying.
Definition: email_globals.c:40
int mutt_rfc822_write_header ( FILE *  fp,
struct Envelope env,
struct Body attach,
enum MuttWriteHeaderMode  mode,
bool  privacy,
bool  hide_protected_subject 
)

Write out one RFC822 header line.

Parameters
fpFile to write to
envEnvelope of email
attachAttachment
modeMode, see MuttWriteHeaderMode
privacyIf true, remove headers that might identify the user
hide_protected_subjectIf true, replace subject header
Return values
0Success
-1Failure

Note: all RFC2047 encoding should be done outside of this routine, except for the "real name." This will allow this routine to be used more than once, if necessary.

Likewise, all IDN processing should happen outside of this routine.

privacy true => will omit any headers which may identify the user. Output generated is suitable for being sent through anonymous remailer chains.

hide_protected_subject: replaces the Subject header with $crypt_protected_headers_subject in NORMAL or POSTPONE mode.

Definition at line 2229 of file sendlib.c.

2232 {
2233  char buf[1024];
2234  char *p = NULL, *q = NULL;
2235  bool has_agent = false; /* user defined user-agent header field exists */
2236 
2237  if ((mode == MUTT_WRITE_HEADER_NORMAL) && !privacy)
2238  fputs(mutt_date_make_date(buf, sizeof(buf)), fp);
2239 
2240  /* UseFrom is not consulted here so that we can still write a From:
2241  * field if the user sets it with the 'my_hdr' command */
2242  if (!TAILQ_EMPTY(&env->from) && !privacy)
2243  {
2244  buf[0] = '\0';
2245  mutt_addrlist_write(buf, sizeof(buf), &env->from, false);
2246  fprintf(fp, "From: %s\n", buf);
2247  }
2248 
2249  if (!TAILQ_EMPTY(&env->sender) && !privacy)
2250  {
2251  buf[0] = '\0';
2252  mutt_addrlist_write(buf, sizeof(buf), &env->sender, false);
2253  fprintf(fp, "Sender: %s\n", buf);
2254  }
2255 
2256  if (!TAILQ_EMPTY(&env->to))
2257  {
2258  fputs("To: ", fp);
2259  mutt_write_addrlist(&env->to, fp, 4, 0);
2260  }
2261  else if (mode == MUTT_WRITE_HEADER_EDITHDRS)
2262 #ifdef USE_NNTP
2263  if (!OptNewsSend)
2264 #endif
2265  fputs("To:\n", fp);
2266 
2267  if (!TAILQ_EMPTY(&env->cc))
2268  {
2269  fputs("Cc: ", fp);
2270  mutt_write_addrlist(&env->cc, fp, 4, 0);
2271  }
2272  else if (mode == MUTT_WRITE_HEADER_EDITHDRS)
2273 #ifdef USE_NNTP
2274  if (!OptNewsSend)
2275 #endif
2276  fputs("Cc:\n", fp);
2277 
2278  if (!TAILQ_EMPTY(&env->bcc))
2279  {
2280  if ((mode == MUTT_WRITE_HEADER_POSTPONE) || (mode == MUTT_WRITE_HEADER_EDITHDRS) ||
2281  ((mode == MUTT_WRITE_HEADER_NORMAL) && C_WriteBcc))
2282  {
2283  fputs("Bcc: ", fp);
2284  mutt_write_addrlist(&env->bcc, fp, 5, 0);
2285  }
2286  }
2287  else if (mode == MUTT_WRITE_HEADER_EDITHDRS)
2288 #ifdef USE_NNTP
2289  if (!OptNewsSend)
2290 #endif
2291  fputs("Bcc:\n", fp);
2292 
2293 #ifdef USE_NNTP
2294  if (env->newsgroups)
2295  fprintf(fp, "Newsgroups: %s\n", env->newsgroups);
2296  else if ((mode == MUTT_WRITE_HEADER_EDITHDRS) && OptNewsSend)
2297  fputs("Newsgroups:\n", fp);
2298 
2299  if (env->followup_to)
2300  fprintf(fp, "Followup-To: %s\n", env->followup_to);
2301  else if ((mode == MUTT_WRITE_HEADER_EDITHDRS) && OptNewsSend)
2302  fputs("Followup-To:\n", fp);
2303 
2304  if (env->x_comment_to)
2305  fprintf(fp, "X-Comment-To: %s\n", env->x_comment_to);
2306  else if ((mode == MUTT_WRITE_HEADER_EDITHDRS) && OptNewsSend && C_XCommentTo)
2307  fputs("X-Comment-To:\n", fp);
2308 #endif
2309 
2310  if (env->subject)
2311  {
2312  if (hide_protected_subject &&
2313  ((mode == MUTT_WRITE_HEADER_NORMAL) || (mode == MUTT_WRITE_HEADER_POSTPONE)))
2315  else
2316  mutt_write_one_header(fp, "Subject", env->subject, NULL, 0, CH_NO_FLAGS);
2317  }
2318  else if (mode == MUTT_WRITE_HEADER_EDITHDRS)
2319  fputs("Subject:\n", fp);
2320 
2321  /* save message id if the user has set it */
2322  if (env->message_id && !privacy)
2323  fprintf(fp, "Message-ID: %s\n", env->message_id);
2324 
2325  if (!TAILQ_EMPTY(&env->reply_to))
2326  {
2327  fputs("Reply-To: ", fp);
2328  mutt_write_addrlist(&env->reply_to, fp, 10, 0);
2329  }
2330  else if (mode == MUTT_WRITE_HEADER_EDITHDRS)
2331  fputs("Reply-To:\n", fp);
2332 
2333  if (!TAILQ_EMPTY(&env->mail_followup_to))
2334 #ifdef USE_NNTP
2335  if (!OptNewsSend)
2336 #endif
2337  {
2338  fputs("Mail-Followup-To: ", fp);
2339  mutt_write_addrlist(&env->mail_followup_to, fp, 18, 0);
2340  }
2341 
2342  if ((mode == MUTT_WRITE_HEADER_NORMAL) || (mode == MUTT_WRITE_HEADER_POSTPONE))
2343  {
2344  if (!STAILQ_EMPTY(&env->references))
2345  {
2346  fputs("References:", fp);
2347  mutt_write_references(&env->references, fp, 10);
2348  fputc('\n', fp);
2349  }
2350 
2351  /* Add the MIME headers */
2352  fputs("MIME-Version: 1.0\n", fp);
2353  mutt_write_mime_header(attach, fp);
2354  }
2355 
2356  if (!STAILQ_EMPTY(&env->in_reply_to))
2357  {
2358  fputs("In-Reply-To:", fp);
2359  mutt_write_references(&env->in_reply_to, fp, 0);
2360  fputc('\n', fp);
2361  }
2362 
2363  /* Add any user defined headers */
2364  struct ListNode *tmp = NULL;
2365  STAILQ_FOREACH(tmp, &env->userhdrs, entries)
2366  {
2367  p = strchr(tmp->data, ':');
2368  if (p)
2369  {
2370  q = p;
2371 
2372  *p = '\0';
2373 
2374  p = mutt_str_skip_email_wsp(p + 1);
2375  if (!*p)
2376  {
2377  *q = ':';
2378  continue; /* don't emit empty fields. */
2379  }
2380 
2381  /* check to see if the user has overridden the user-agent field */
2382  if (mutt_str_startswith(tmp->data, "user-agent", CASE_IGNORE))
2383  {
2384  has_agent = true;
2385  if (privacy)
2386  {
2387  *q = ':';
2388  continue;
2389  }
2390  }
2391 
2392  mutt_write_one_header(fp, tmp->data, p, NULL, 0, CH_NO_FLAGS);
2393  *q = ':';
2394  }
2395  }
2396 
2397  if ((mode == MUTT_WRITE_HEADER_NORMAL) && !privacy && C_UserAgent && !has_agent)
2398  {
2399  /* Add a vanity header */
2400  fprintf(fp, "User-Agent: NeoMutt/%s%s\n", PACKAGE_VERSION, GitVer);
2401  }
2402 
2403  return (ferror(fp) == 0) ? 0 : -1;
2404 }
WHERE bool C_WriteBcc
Config: Write out the &#39;Bcc&#39; field when preparing to send a mail.
Definition: globals.h:260
struct AddressList mail_followup_to
Email&#39;s &#39;mail-followup-to&#39;.
Definition: envelope.h:49
struct AddressList reply_to
Email&#39;s &#39;reply-to&#39;.
Definition: envelope.h:48
struct AddressList bcc
Email&#39;s &#39;Bcc&#39; list.
Definition: envelope.h:46
WHERE char * C_CryptProtectedHeadersSubject
Config: Use this as the subject for encrypted emails.
Definition: globals.h:100
bool C_UserAgent
Config: Add a &#39;User-Agent&#39; head to outgoing mail.
Definition: sendlib.c:94
A normal Email, write full header + MIME headers.
Definition: sendlib.h:64
A postponed Email, just the envelope info.
Definition: sendlib.h:65
struct ListHead userhdrs
user defined headers
Definition: envelope.h:69
size_t mutt_addrlist_write(char *buf, size_t buflen, const struct AddressList *al, bool display)
Write an Address to a buffer.
Definition: address.c:1134
char * mutt_date_make_date(char *buf, size_t buflen)
Write a date in RFC822 format to a buffer.
Definition: date.c:370
struct ListHead in_reply_to
in-reply-to header content
Definition: envelope.h:68
char * message_id
Message ID.
Definition: envelope.h:55
struct AddressList from
Email&#39;s &#39;From&#39; list.
Definition: envelope.h:43
struct AddressList cc
Email&#39;s &#39;Cc&#39; list.
Definition: envelope.h:45
char * x_comment_to
List of &#39;X-comment-to&#39; fields.
Definition: envelope.h:64
void mutt_write_references(const struct ListHead *r, FILE *fp, size_t trim)
Add the message references to a list.
Definition: sendlib.c:1803
const char * GitVer
#define CH_NO_FLAGS
No flags are set.
Definition: copy.h:50
"light" mode (used for edit_hdrs)
Definition: sendlib.h:66
Ignore case when comparing strings.
Definition: string2.h:68
char * mutt_str_skip_email_wsp(const char *s)
Skip over whitespace as defined by RFC5322.
Definition: string.c:776
#define STAILQ_FOREACH(var, head, field)
Definition: queue.h:350
void mutt_write_addrlist(struct AddressList *al, FILE *fp, int linelen, bool display)
wrapper around mutt_write_address()
Definition: sendlib.c:1757
size_t mutt_str_startswith(const char *str, const char *prefix, enum CaseSensitivity cs)
Check whether a string starts with a prefix.
Definition: string.c:168
char * data
Definition: list.h:35
char * subject
Email&#39;s subject.
Definition: envelope.h:52
char * newsgroups
List of newsgroups.
Definition: envelope.h:61
WHERE bool C_XCommentTo
Config: (nntp) Add &#39;X-Comment-To&#39; header that contains article author.
Definition: globals.h:281
char * followup_to
List of &#39;followup-to&#39; fields.
Definition: envelope.h:63
int mutt_write_mime_header(struct Body *a, FILE *fp)
Create a MIME header.
Definition: sendlib.c:359
#define STAILQ_EMPTY(head)
Definition: queue.h:346
struct AddressList to
Email&#39;s &#39;To&#39; list.
Definition: envelope.h:44
struct AddressList sender
Email&#39;s sender.
Definition: envelope.h:47
#define TAILQ_EMPTY(head)
Definition: queue.h:715
WHERE bool OptNewsSend
(pseudo) used to change behavior when posting
Definition: options.h:43
struct ListHead references
message references (in reverse order)
Definition: envelope.h:67
A List node for strings.
Definition: list.h:33
int mutt_write_one_header(FILE *fp, const char *tag, const char *value, const char *pfx, int wraplen, CopyHeaderFlags chflags)
Write one header line to a file.
Definition: sendlib.c:2124
static void encode_headers ( struct ListHead *  h)
static

RFC2047-encode a list of headers.

Parameters
hString List of headers

The strings are encoded in-place.

Definition at line 2412 of file sendlib.c.

2413 {
2414  char *tmp = NULL;
2415  char *p = NULL;
2416  int i;
2417 
2418  struct ListNode *np = NULL;
2419  STAILQ_FOREACH(np, h, entries)
2420  {
2421  p = strchr(np->data, ':');
2422  if (!p)
2423  continue;
2424 
2425  i = p - np->data;
2426  p = mutt_str_skip_email_wsp(p + 1);
2427  tmp = mutt_str_strdup(p);
2428 
2429  if (!tmp)
2430  continue;
2431 
2432  rfc2047_encode(&tmp, NULL, i + 2, C_SendCharset);
2433  mutt_mem_realloc(&np->data, i + 2 + mutt_str_strlen(tmp) + 1);
2434 
2435  sprintf(np->data + i + 2, "%s", tmp);
2436 
2437  FREE(&tmp);
2438  }
2439 }
size_t mutt_str_strlen(const char *a)
Calculate the length of a string, safely.
Definition: string.c:666
char * C_SendCharset
Config: Character sets for outgoing mail.
Definition: email_globals.c:38
void mutt_mem_realloc(void *ptr, size_t size)
Resize a block of memory on the heap.
Definition: memory.c:114
char * mutt_str_skip_email_wsp(const char *s)
Skip over whitespace as defined by RFC5322.
Definition: string.c:776
#define STAILQ_FOREACH(var, head, field)
Definition: queue.h:350
void rfc2047_encode(char **pd, const char *specials, int col, const char *charsets)
RFC-2047-encode a string.
Definition: rfc2047.c:625
char * data
Definition: list.h:35
char * mutt_str_strdup(const char *str)
Copy a string, safely.
Definition: string.c:380
#define FREE(x)
Definition: memory.h:40
A List node for strings.
Definition: list.h:33
const char* mutt_fqdn ( bool  may_hide_host)

Get the Fully-Qualified Domain Name.

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

Definition at line 2449 of file sendlib.c.

2450 {
2451  if (!C_Hostname || (C_Hostname[0] == '@'))
2452  return NULL;
2453 
2454  char *p = C_Hostname;
2455 
2456  if (may_hide_host && C_HiddenHost)
2457  {
2458  p = strchr(C_Hostname, '.');
2459  if (p)
2460  p++;
2461 
2462  // sanity check: don't hide the host if the fqdn is something like example.com
2463  if (!p || !strchr(p, '.'))
2464  p = C_Hostname;
2465  }
2466 
2467  return p;
2468 }
bool C_HiddenHost
Config: Don&#39;t use the hostname, just the domain, when generating the message id.
Definition: sendlib.c:84
WHERE char * C_Hostname
Config: Fully-qualified domain name of this machine.
Definition: globals.h:106
static char* gen_msgid ( void  )
static

Generate a unique Message ID.

Return values
ptrMessage ID
Note
The caller should free the string

Definition at line 2476 of file sendlib.c.

2477 {
2478  char buf[128];
2479  unsigned char rndid[MUTT_RANDTAG_LEN + 1];
2480 
2481  mutt_rand_base32(rndid, sizeof(rndid) - 1);
2482  rndid[MUTT_RANDTAG_LEN] = 0;
2483  const char *fqdn = mutt_fqdn(false);
2484  if (!fqdn)
2485  fqdn = NONULL(ShortHostname);
2486 
2487  struct tm tm = mutt_date_gmtime(MUTT_DATE_NOW);
2488  snprintf(buf, sizeof(buf), "<%d%02d%02d%02d%02d%02d.%s@%s>", tm.tm_year + 1900,
2489  tm.tm_mon + 1, tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec, rndid, fqdn);
2490  return mutt_str_strdup(buf);
2491 }
#define NONULL(x)
Definition: string2.h:37
#define MUTT_DATE_NOW
Constant representing the &#39;current time&#39;, see: mutt_date_gmtime(), mutt_date_localtime() ...
Definition: date.h:36
#define MUTT_RANDTAG_LEN
Definition: muttlib.h:44
struct tm mutt_date_gmtime(time_t t)
Converts calendar time to a broken-down time structure expressed in UTC timezone. ...
Definition: date.c:731
const char * mutt_fqdn(bool may_hide_host)
Get the Fully-Qualified Domain Name.
Definition: sendlib.c:2449
char * mutt_str_strdup(const char *str)
Copy a string, safely.
Definition: string.c:380
WHERE char * ShortHostname
Short version of the hostname.
Definition: globals.h:49
void mutt_rand_base32(void *buf, size_t buflen)
Fill a buffer with a base32-encoded random string.
Definition: muttlib.c:516
static void alarm_handler ( int  sig)
static

Async notification of an alarm signal.

Parameters
sigSignal, (SIGALRM)

Definition at line 2497 of file sendlib.c.

2498 {
2499  SigAlrm = 1;
2500 }
WHERE SIG_ATOMIC_VOLATILE_T SigAlrm
true after SIGALRM is received
Definition: globals.h:82
static int send_msg ( const char *  path,
char **  args,
const char *  msg,
char **  tempfile 
)
static

invoke sendmail in a subshell

Parameters
[in]pathPath to program to execute
[in]argsArguments to pass to program
[in]msgTemp file containing message to send
[out]tempfileIf sendmail is put in the background, this points to the temporary file containing the stdout of the child process. If it is NULL, stderr and stdout are not redirected.
Return values
0Success
>0Failure, return code from sendmail

Definition at line 2514 of file sendlib.c.

2515 {
2516  sigset_t set;
2517  int st;
2518 
2520 
2521  sigemptyset(&set);
2522  /* we also don't want to be stopped right now */
2523  sigaddset(&set, SIGTSTP);
2524  sigprocmask(SIG_BLOCK, &set, NULL);
2525 
2526  if ((C_SendmailWait >= 0) && tempfile)
2527  {
2528  char tmp[PATH_MAX];
2529 
2530  mutt_mktemp(tmp, sizeof(tmp));
2531  *tempfile = mutt_str_strdup(tmp);
2532  }
2533 
2534  pid_t pid = fork();
2535  if (pid == 0)
2536  {
2537  struct sigaction act, oldalrm;
2538 
2539  /* save parent's ID before setsid() */
2540  pid_t ppid = getppid();
2541 
2542  /* we want the delivery to continue even after the main process dies,
2543  * so we put ourselves into another session right away */
2544  setsid();
2545 
2546  /* next we close all open files */
2547  close(0);
2548 #ifdef OPEN_MAX
2549  for (int fd = tempfile ? 1 : 3; fd < OPEN_MAX; fd++)
2550  close(fd);
2551 #elif defined(_POSIX_OPEN_MAX)
2552  for (int fd = tempfile ? 1 : 3; fd < _POSIX_OPEN_MAX; fd++)
2553  close(fd);
2554 #else
2555  if (tempfile)
2556  {
2557  close(1);
2558  close(2);
2559  }
2560 #endif
2561 
2562  /* now the second fork() */
2563  pid = fork();
2564  if (pid == 0)
2565  {
2566  /* "msg" will be opened as stdin */
2567  if (open(msg, O_RDONLY, 0) < 0)
2568  {
2569  unlink(msg);
2570  _exit(S_ERR);
2571  }
2572  unlink(msg);
2573 
2574  if ((C_SendmailWait >= 0) && tempfile && *tempfile)
2575  {
2576  /* *tempfile will be opened as stdout */
2577  if (open(*tempfile, O_WRONLY | O_APPEND | O_CREAT | O_EXCL, 0600) < 0)
2578  _exit(S_ERR);
2579  /* redirect stderr to *tempfile too */
2580  if (dup(1) < 0)
2581  _exit(S_ERR);
2582  }
2583  else if (tempfile)
2584  {
2585  if (open("/dev/null", O_WRONLY | O_APPEND) < 0) /* stdout */
2586  _exit(S_ERR);
2587  if (open("/dev/null", O_RDWR | O_APPEND) < 0) /* stderr */
2588  _exit(S_ERR);
2589  }
2590 
2591  /* execvpe is a glibc extension */
2592  /* execvpe (path, args, mutt_envlist_getlist()); */
2593  execvp(path, args);
2594  _exit(S_ERR);
2595  }
2596  else if (pid == -1)
2597  {
2598  unlink(msg);
2599  FREE(tempfile);
2600  _exit(S_ERR);
2601  }
2602 
2603  /* C_SendmailWait > 0: interrupt waitpid() after C_SendmailWait seconds
2604  * C_SendmailWait = 0: wait forever
2605  * C_SendmailWait < 0: don't wait */
2606  if (C_SendmailWait > 0)
2607  {
2608  SigAlrm = 0;
2609  act.sa_handler = alarm_handler;
2610 #ifdef SA_INTERRUPT
2611  /* need to make sure waitpid() is interrupted on SIGALRM */
2612  act.sa_flags = SA_INTERRUPT;
2613 #else
2614  act.sa_flags = 0;
2615 #endif
2616  sigemptyset(&act.sa_mask);
2617  sigaction(SIGALRM, &act, &oldalrm);
2618  alarm(C_SendmailWait);
2619  }
2620  else if (C_SendmailWait < 0)
2621  _exit(0xff & EX_OK);
2622 
2623  if (waitpid(pid, &st, 0) > 0)
2624  {
2625  st = WIFEXITED(st) ? WEXITSTATUS(st) : S_ERR;
2626  if (C_SendmailWait && (st == (0xff & EX_OK)) && tempfile && *tempfile)
2627  {
2628  unlink(*tempfile); /* no longer needed */
2629  FREE(tempfile);
2630  }
2631  }
2632  else
2633  {
2634  st = ((C_SendmailWait > 0) && (errno == EINTR) && SigAlrm) ? S_BKG : S_ERR;
2635  if ((C_SendmailWait > 0) && tempfile && *tempfile)
2636  {
2637  unlink(*tempfile);
2638  FREE(tempfile);
2639  }
2640  }
2641 
2642  if (C_SendmailWait > 0)
2643  {
2644  /* reset alarm; not really needed, but... */
2645  alarm(0);
2646  sigaction(SIGALRM, &oldalrm, NULL);
2647  }
2648 
2649  if ((kill(ppid, 0) == -1) && (errno == ESRCH) && tempfile && *tempfile)
2650  {
2651  /* the parent is already dead */
2652  unlink(*tempfile);
2653  FREE(tempfile);
2654  }
2655 
2656  _exit(st);
2657  }
2658 
2659  sigprocmask(SIG_UNBLOCK, &set, NULL);
2660 
2661  if ((pid != -1) && (waitpid(pid, &st, 0) > 0))
2662  st = WIFEXITED(st) ? WEXITSTATUS(st) : S_ERR; /* return child status */
2663  else
2664  st = S_ERR; /* error */
2665 
2667 
2668  return st;
2669 }
#define S_ERR
Definition: string2.h:42
void mutt_sig_block_system(void)
Block signals before calling exec()
Definition: signal.c:183
WHERE SIG_ATOMIC_VOLATILE_T SigAlrm
true after SIGALRM is received
Definition: globals.h:82
#define S_BKG
Definition: string2.h:43
void mutt_sig_unblock_system(bool restore)
Restore previously blocked signals.
Definition: signal.c:207
static void alarm_handler(int sig)
Async notification of an alarm signal.
Definition: sendlib.c:2497
#define mutt_mktemp(buf, buflen)
Definition: muttlib.h:76
#define PATH_MAX
Definition: mutt.h:50
short C_SendmailWait
Config: Time to wait for sendmail to finish.
Definition: sendlib.c:91
char * mutt_str_strdup(const char *str)
Copy a string, safely.
Definition: string.c:380
#define FREE(x)
Definition: memory.h:40
#define EX_OK
Definition: sendlib.c:75
static char** add_args_one ( char **  args,
size_t *  argslen,
size_t *  argsmax,
struct Address addr 
)
static

Add an Address to a dynamic array.

Parameters
[out]argsArray to add to
[out]argslenNumber of entries in array
[out]argsmaxAllocated size of the array
[in]addrAddress to add
Return values
ptrUpdated array

Definition at line 2679 of file sendlib.c.

2680 {
2681  /* weed out group mailboxes, since those are for display only */
2682  if (addr->mailbox && !addr->group)
2683  {
2684  if (*argslen == *argsmax)
2685  mutt_mem_realloc(&args, (*argsmax += 5) * sizeof(char *));
2686  args[(*argslen)++] = addr->mailbox;
2687  }
2688  return args;
2689 }
char * mailbox
Mailbox and host address.
Definition: address.h:37
void mutt_mem_realloc(void *ptr, size_t size)
Resize a block of memory on the heap.
Definition: memory.c:114
bool group
Group mailbox?
Definition: address.h:38
static char** add_args ( char **  args,
size_t *  argslen,
size_t *  argsmax,
struct AddressList *  al 
)
static

Add a list of Addresses to a dynamic array.

Parameters
[out]argsArray to add to
[out]argslenNumber of entries in array
[out]argsmaxAllocated size of the array
[in]alAddresses to add
Return values
ptrUpdated array

Definition at line 2699 of file sendlib.c.

2700 {
2701  if (!al)
2702  return args;
2703 
2704  struct Address *a = NULL;
2705  TAILQ_FOREACH(a, al, entries)
2706  {
2707  args = add_args_one(args, argslen, argsmax, a);
2708  }
2709  return args;
2710 }
#define TAILQ_FOREACH(var, head, field)
Definition: queue.h:719
An email address.
Definition: address.h:34
static char ** add_args_one(char **args, size_t *argslen, size_t *argsmax, struct Address *addr)
Add an Address to a dynamic array.
Definition: sendlib.c:2679
static char** add_option ( char **  args,
size_t *  argslen,
size_t *  argsmax,
char *  s 
)
static

Add a string to a dynamic array.

Parameters
[out]argsArray to add to
[out]argslenNumber of entries in array
[out]argsmaxAllocated size of the array
[in]sstring to add
Return values
ptrUpdated array
Note
The array may be realloc()'d

Definition at line 2722 of file sendlib.c.

2723 {
2724  if (*argslen == *argsmax)
2725  mutt_mem_realloc(&args, (*argsmax += 5) * sizeof(char *));
2726  args[(*argslen)++] = s;
2727  return args;
2728 }
void mutt_mem_realloc(void *ptr, size_t size)
Resize a block of memory on the heap.
Definition: memory.c:114
int mutt_invoke_sendmail ( struct AddressList *  from,
struct AddressList *  to,
struct AddressList *  cc,
struct AddressList *  bcc,
const char *  msg,
int  eightbit 
)

Run sendmail.

Parameters
fromThe sender
toRecipients
ccRecipients
bccRecipients
msgFile containing message
eightbitMessage contains 8bit chars
Return values
0Success
-1Failure

Definition at line 2741 of file sendlib.c.

2744 {
2745  char *ps = NULL, *path = NULL, *s = NULL, *childout = NULL;
2746  char **args = NULL;
2747  size_t argslen = 0, argsmax = 0;
2748  char **extra_args = NULL;
2749  int i;
2750 
2751 #ifdef USE_NNTP
2752  if (OptNewsSend)
2753  {
2754  char cmd[1024];
2755 
2756  mutt_expando_format(cmd, sizeof(cmd), 0, MuttIndexWindow->cols,
2758  if (!*cmd)
2759  {
2760  i = nntp_post(Context->mailbox, msg);
2761  unlink(msg);
2762  return i;
2763  }
2764 
2765  s = mutt_str_strdup(cmd);
2766  }
2767  else
2768 #endif
2770 
2771  /* ensure that $sendmail is set to avoid a crash. http://dev.mutt.org/trac/ticket/3548 */
2772  if (!s)
2773  {
2774  mutt_error(_("$sendmail must be set in order to send mail"));
2775  return -1;
2776  }
2777 
2778  ps = s;
2779  i = 0;
2780  while ((ps = strtok(ps, " ")))
2781  {
2782  if (argslen == argsmax)
2783  mutt_mem_realloc(&args, sizeof(char *) * (argsmax += 5));
2784 
2785  if (i)
2786  {
2787  if (mutt_str_strcmp(ps, "--") == 0)
2788  break;
2789  args[argslen++] = ps;
2790  }
2791  else
2792  {
2793  path = mutt_str_strdup(ps);
2794  ps = strrchr(ps, '/');
2795  if (ps)
2796  ps++;
2797  else
2798  ps = path;
2799  args[argslen++] = ps;
2800  }
2801  ps = NULL;
2802  i++;
2803  }
2804 
2805 #ifdef USE_NNTP
2806  if (!OptNewsSend)
2807  {
2808 #endif
2809  size_t extra_argslen = 0;
2810  /* If C_Sendmail contained a "--", we save the recipients to append to
2811  * args after other possible options added below. */
2812  if (ps)
2813  {
2814  ps = NULL;
2815  size_t extra_argsmax = 0;
2816  while ((ps = strtok(ps, " ")))
2817  {
2818  if (extra_argslen == extra_argsmax)
2819  mutt_mem_realloc(&extra_args, sizeof(char *) * (extra_argsmax += 5));
2820 
2821  extra_args[extra_argslen++] = ps;
2822  ps = NULL;
2823  }
2824  }
2825 
2826  if (eightbit && C_Use8bitmime)
2827  args = add_option(args, &argslen, &argsmax, "-B8BITMIME");
2828 
2829  if (C_UseEnvelopeFrom)
2830  {
2832  {
2833  args = add_option(args, &argslen, &argsmax, "-f");
2834  args = add_args_one(args, &argslen, &argsmax, C_EnvelopeFromAddress);
2835  }
2836  else if (!TAILQ_EMPTY(from) && !TAILQ_NEXT(TAILQ_FIRST(from), entries))
2837  {
2838  args = add_option(args, &argslen, &argsmax, "-f");
2839  args = add_args(args, &argslen, &argsmax, from);
2840  }
2841  }
2842 
2843  if (C_DsnNotify)
2844  {
2845  args = add_option(args, &argslen, &argsmax, "-N");
2846  args = add_option(args, &argslen, &argsmax, C_DsnNotify);
2847  }
2848  if (C_DsnReturn)
2849  {
2850  args = add_option(args, &argslen, &argsmax, "-R");
2851  args = add_option(args, &argslen, &argsmax, C_DsnReturn);
2852  }
2853  args = add_option(args, &argslen, &argsmax, "--");
2854  for (i = 0; i < extra_argslen; i++)
2855  args = add_option(args, &argslen, &argsmax, extra_args[i]);
2856  args = add_args(args, &argslen, &argsmax, to);
2857  args = add_args(args, &argslen, &argsmax, cc);
2858  args = add_args(args, &argslen, &argsmax, bcc);
2859 #ifdef USE_NNTP
2860  }
2861 #endif
2862 
2863  if (argslen == argsmax)
2864  mutt_mem_realloc(&args, sizeof(char *) * (++argsmax));
2865 
2866  args[argslen++] = NULL;
2867 
2868  /* Some user's $sendmail command uses gpg for password decryption,
2869  * and is set up to prompt using ncurses pinentry. If we
2870  * mutt_endwin() it leaves other users staring at a blank screen.
2871  * So instead, just force a hard redraw on the next refresh. */
2872  if (!OptNoCurses)
2874 
2875  i = send_msg(path, args, msg, OptNoCurses ? NULL : &childout);
2876  if (i != (EX_OK & 0xff))
2877  {
2878  if (i != S_BKG)
2879  {
2880  const char *e = mutt_str_sysexit(i);
2881  mutt_error(_("Error sending message, child exited %d (%s)"), i, NONULL(e));
2882  if (childout)
2883  {
2884  struct stat st;
2885 
2886  if ((stat(childout, &st) == 0) && (st.st_size > 0))
2887  mutt_do_pager(_("Output of the delivery process"), childout,
2888  MUTT_PAGER_NO_FLAGS, NULL);
2889  }
2890  }
2891  }
2892  else if (childout)
2893  unlink(childout);
2894 
2895  FREE(&childout);
2896  FREE(&path);
2897  FREE(&s);
2898  FREE(&args);
2899  FREE(&extra_args);
2900 
2901  if (i == (EX_OK & 0xff))
2902  i = 0;
2903  else if (i == S_BKG)
2904  i = 1;
2905  else
2906  i = -1;
2907  return i;
2908 }
The "current" mailbox.
Definition: context.h:39
void mutt_expando_format(char *buf, size_t buflen, size_t col, int cols, const char *src, format_t *callback, unsigned long data, MuttFormatFlags flags)
Expand expandos (x) in a string.
Definition: muttlib.c:841
char * C_Sendmail
Config: External command to send email.
Definition: sendlib.c:90
#define NONULL(x)
Definition: string2.h:37
static int send_msg(const char *path, char **args, const char *msg, char **tempfile)
invoke sendmail in a subshell
Definition: sendlib.c:2514
#define TAILQ_FIRST(head)
Definition: queue.h:717
int nntp_post(struct Mailbox *m, const char *msg)
Post article.
Definition: nntp.c:1964
static char ** add_args(char **args, size_t *argslen, size_t *argsmax, struct AddressList *al)
Add a list of Addresses to a dynamic array.
Definition: sendlib.c:2699
#define _(a)
Definition: message.h:28
WHERE bool OptNoCurses
(pseudo) when sending in batch mode
Definition: options.h:45
#define S_BKG
Definition: string2.h:43
#define MUTT_FORMAT_NO_FLAGS
No flags are set.
Definition: format_flags.h:30
bool C_Use8bitmime
Config: Use 8-bit messages and ESMTP to send messages.
Definition: sendlib.c:92
struct Mailbox * mailbox
Definition: context.h:53
char * C_Inews
Config: (nntp) External command to post news articles.
Definition: sendlib.c:85
void mutt_mem_realloc(void *ptr, size_t size)
Resize a block of memory on the heap.
Definition: memory.c:114
const char * mutt_str_sysexit(int err_num)
Return a string matching an error code.
Definition: string.c:112
static char ** add_option(char **args, size_t *argslen, size_t *argsmax, char *s)
Add a string to a dynamic array.
Definition: sendlib.c:2722
bool C_UseEnvelopeFrom
Config: Set the envelope sender of the message.
Definition: sendlib.c:93
struct MuttWindow * MuttIndexWindow
Index Window.
Definition: mutt_window.c:39
WHERE char * C_DsnReturn
Config: What to send as a notification of message delivery or delay.
Definition: globals.h:103
int mutt_do_pager(const char *banner, const char *tempfile, PagerFlags do_color, struct Pager *info)
Display some page-able text to the user.
Definition: curs_lib.c:582
char * mutt_str_strdup(const char *str)
Copy a string, safely.
Definition: string.c:380
#define mutt_error(...)
Definition: logging.h:84
WHERE struct Address * C_EnvelopeFromAddress
Config: Manually set the sender for outgoing messages.
Definition: globals.h:92
#define FREE(x)
Definition: memory.h:40
#define TAILQ_NEXT(elm, field)
Definition: queue.h:816
#define TAILQ_EMPTY(head)
Definition: queue.h:715
WHERE bool OptNewsSend
(pseudo) used to change behavior when posting
Definition: options.h:43
const char * nntp_format_str(char *buf, size_t buflen, size_t col, int cols, char op, const char *src, const char *prec, const char *if_str, const char *else_str, unsigned long data, MuttFormatFlags flags)
Expand the newsrc filename - Implements format_t.
Definition: newsrc.c:909
void mutt_need_hard_redraw(void)
Force a hard refresh.
Definition: curs_lib.c:121
int mutt_str_strcmp(const char *a, const char *b)
Compare two strings, safely.
Definition: string.c:615
WHERE char * C_DsnNotify
Config: Request notification for message delivery or delay.
Definition: globals.h:102
static char ** add_args_one(char **args, size_t *argslen, size_t *argsmax, struct Address *addr)
Add an Address to a dynamic array.
Definition: sendlib.c:2679
#define EX_OK
Definition: sendlib.c:75
#define MUTT_PAGER_NO_FLAGS
No flags are set.
Definition: pager.h:43
void mutt_prepare_envelope ( struct Envelope env,
bool  final 
)

Prepare an email header.

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

Encode all the headers prior to sending the email.

For postponing (!final) do the necessary encodings only

Definition at line 2919 of file sendlib.c.

2920 {
2921  if (final)
2922  {
2923  if (!TAILQ_EMPTY(&env->bcc) && TAILQ_EMPTY(&env->to) && TAILQ_EMPTY(&env->cc))
2924  {
2925  /* some MTA's will put an Apparently-To: header field showing the Bcc:
2926  * recipients if there is no To: or Cc: field, so attempt to suppress
2927  * it by using an empty To: field. */
2928  struct Address *to = mutt_addr_new();
2929  to->group = true;
2930  mutt_addrlist_append(&env->to, to);
2932 
2933  char buf[1024];
2934  buf[0] = '\0';
2935  mutt_addr_cat(buf, sizeof(buf), "undisclosed-recipients", AddressSpecials);
2936 
2937  to->mailbox = mutt_str_strdup(buf);
2938  }
2939 
2940  mutt_set_followup_to(env);
2941 
2942  if (!env->message_id)
2943  env->message_id = gen_msgid();
2944  }
2945 
2946  /* Take care of 8-bit => 7-bit conversion. */
2948  encode_headers(&env->userhdrs);
2949 }
void rfc2047_encode_envelope(struct Envelope *env)
Encode the fields of an Envelope.
Definition: rfc2047.c:809
static char * gen_msgid(void)
Generate a unique Message ID.
Definition: sendlib.c:2476
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:46
struct ListHead userhdrs
user defined headers
Definition: envelope.h:69
struct Address * mutt_addr_new(void)
Create a new Address.
Definition: address.c:384
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:55
struct AddressList cc
Email&#39;s &#39;Cc&#39; list.
Definition: envelope.h:45
void mutt_set_followup_to(struct Envelope *env)
Set followup-to field.
Definition: send.c:1182
bool group
Group mailbox?
Definition: address.h:38
char * mutt_str_strdup(const char *str)
Copy a string, safely.
Definition: string.c:380
struct AddressList to
Email&#39;s &#39;To&#39; list.
Definition: envelope.h:44
#define TAILQ_EMPTY(head)
Definition: queue.h:715
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:668
static void encode_headers(struct ListHead *h)
RFC2047-encode a list of headers.
Definition: sendlib.c:2412
void mutt_addrlist_append(struct AddressList *al, struct Address *a)
Append an Address to an AddressList.
Definition: address.c:1371
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 2958 of file sendlib.c.

2959 {
2960  struct ListNode *item = NULL;
2961  STAILQ_FOREACH(item, &env->userhdrs, entries)
2962  {
2963  rfc2047_decode(&item->data);
2964  }
2965 
2967 
2968  /* back conversions */
2970 }
struct AddressList mail_followup_to
Email&#39;s &#39;mail-followup-to&#39;.
Definition: envelope.h:49
void mutt_addrlist_clear(struct AddressList *al)
Unlink and free all Address in an AddressList.
Definition: address.c:1351
struct ListHead userhdrs
user defined headers
Definition: envelope.h:69
void rfc2047_decode_envelope(struct Envelope *env)
Decode the fields of an Envelope.
Definition: rfc2047.c:789
void rfc2047_decode(char **pd)
Decode any RFC2047-encoded header fields.
Definition: rfc2047.c:649
#define STAILQ_FOREACH(var, head, field)
Definition: queue.h:350
char * data
Definition: list.h:35
A List node for strings.
Definition: list.h:33
static int bounce_message ( FILE *  fp,
struct Email e,
struct AddressList *  to,
const char *  resent_from,
struct AddressList *  env_from 
)
static

Bounce an email message.

Parameters
fpHandle of message
eEmail
toAddress to bounce to
resent_fromAddress of new sender
env_fromEnvelope of original sender
Return values
0Success
-1Failure

Definition at line 2982 of file sendlib.c.

2984 {
2985  if (!e)
2986  return -1;
2987 
2988  int rc = 0;
2989  char tempfile[PATH_MAX];
2990 
2991  mutt_mktemp(tempfile, sizeof(tempfile));
2992  FILE *fp_tmp = mutt_file_fopen(tempfile, "w");
2993  if (fp_tmp)
2994  {
2995  char date[128];
2997 
2998  if (!C_BounceDelivered)
2999  chflags |= CH_WEED_DELIVERED;
3000 
3001  fseeko(fp, e->offset, SEEK_SET);
3002  fprintf(fp_tmp, "Resent-From: %s", resent_from);
3003  fprintf(fp_tmp, "\nResent-%s", mutt_date_make_date(date, sizeof(date)));
3004  char *msgid_str = gen_msgid();
3005  fprintf(fp_tmp, "Resent-Message-ID: %s\n", msgid_str);
3006  FREE(&msgid_str);
3007  fputs("Resent-To: ", fp_tmp);
3008  mutt_write_addrlist(to, fp_tmp, 11, 0);
3009  mutt_copy_header(fp, e, fp_tmp, chflags, NULL);
3010  fputc('\n', fp_tmp);
3011  mutt_file_copy_bytes(fp, fp_tmp, e->content->length);
3012  if (mutt_file_fclose(&fp_tmp) != 0)
3013  {
3014  mutt_perror(tempfile);
3015  unlink(tempfile);
3016  return -1;
3017  }
3018 #ifdef USE_SMTP
3019  if (C_SmtpUrl)
3020  rc = mutt_smtp_send(env_from, to, NULL, NULL, tempfile, e->content->encoding == ENC_8BIT);
3021  else
3022 #endif
3023  rc = mutt_invoke_sendmail(env_from, to, NULL, NULL, tempfile,
3024  e->content->encoding == ENC_8BIT);
3025  }
3026 
3027  return rc;
3028 }
WHERE char * C_SmtpUrl
Config: (smtp) Url of the SMTP server.
Definition: globals.h:140
#define mutt_perror(...)
Definition: logging.h:85
static char * gen_msgid(void)
Generate a unique Message ID.
Definition: sendlib.c:2476
struct Body * content
List of MIME parts.
Definition: email.h:90
8-bit text
Definition: mime.h:50
char * mutt_date_make_date(char *buf, size_t buflen)
Write a date in RFC822 format to a buffer.
Definition: date.c:370
int mutt_copy_header(FILE *fp_in, struct Email *e, FILE *fp_out, CopyHeaderFlags chflags, const char *prefix)
Copy Email header.
Definition: copy.c:389
#define CH_WEED_DELIVERED
Weed eventual Delivered-To headers.
Definition: copy.h:64
int mutt_invoke_sendmail(struct AddressList *from, struct AddressList *to, struct AddressList *cc, struct AddressList *bcc, const char *msg, int eightbit)
Run sendmail.
Definition: sendlib.c:2741
int mutt_file_fclose(FILE **fp)
Close a FILE handle (and NULL the pointer)
Definition: file.c:149
unsigned int encoding
content-transfer-encoding
Definition: body.h:66
#define mutt_mktemp(buf, buflen)
Definition: muttlib.h:76
LOFF_T length
length (in bytes) of attachment
Definition: body.h:45
#define PATH_MAX
Definition: mutt.h:50
#define CH_XMIT
Transmitting this message? (Ignore Lines: and Content-Length:)
Definition: copy.h:54
int mutt_file_copy_bytes(FILE *fp_in, FILE *fp_out, size_t size)
Copy some content from one file to another.
Definition: file.c:237
void mutt_write_addrlist(struct AddressList *al, FILE *fp, int linelen, bool display)
wrapper around mutt_write_address()
Definition: sendlib.c:1757
LOFF_T offset
Where in the stream does this message begin?
Definition: email.h:83
bool C_BounceDelivered
Config: Add &#39;Delivered-To&#39; to bounced messages.
Definition: sendlib.c:81
#define CH_NOQFROM
Ignore ">From " line.
Definition: copy.h:66
uint32_t CopyHeaderFlags
Flags for mutt_copy_header(), e.g. CH_UPDATE.
Definition: copy.h:49
#define FREE(x)
Definition: memory.h:40
int mutt_smtp_send(const struct AddressList *from, const struct AddressList *to, const struct AddressList *cc, const struct AddressList *bcc, const char *msgfile, bool eightbit)
Send a message using SMTP.
Definition: smtp.c:730
FILE * mutt_file_fopen(const char *path, const char *mode)
Call fopen() safely.
Definition: file.c:584
#define CH_NONEWLINE
Don&#39;t output terminating newline after the header.
Definition: copy.h:59
int mutt_bounce_message ( FILE *  fp,
struct Email e,
struct AddressList *  to 
)

Bounce an email message.

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

Definition at line 3038 of file sendlib.c.

3039 {
3040  if (!fp || !e || !to || TAILQ_EMPTY(to))
3041  return -1;
3042 
3043  const char *fqdn = mutt_fqdn(true);
3044  char resent_from[256];
3045  char *err = NULL;
3046 
3047  resent_from[0] = '\0';
3048  struct Address *from = mutt_default_from();
3049  struct AddressList from_list = TAILQ_HEAD_INITIALIZER(from_list);
3050  mutt_addrlist_append(&from_list, from);
3051 
3052  /* mutt_default_from() does not use $realname if the real name is not set
3053  * in $from, so we add it here. The reason it is not added in
3054  * mutt_default_from() is that during normal sending, we execute
3055  * send-hooks and set the realname last so that it can be changed based
3056  * upon message criteria. */
3057  if (!from->personal)
3059 
3060  mutt_addrlist_qualify(&from_list, fqdn);
3061 
3062  rfc2047_encode_addrlist(&from_list, "Resent-From");
3063  if (mutt_addrlist_to_intl(&from_list, &err))
3064  {
3065  mutt_error(_("Bad IDN %s while preparing resent-from"), err);
3066  FREE(&err);
3067  mutt_addrlist_clear(&from_list);
3068  return -1;
3069  }
3070  mutt_addrlist_write(resent_from, sizeof(resent_from), &from_list, false);
3071 
3072 #ifdef USE_NNTP
3073  OptNewsSend = false;
3074 #endif
3075 
3076  /* prepare recipient list. idna conversion appears to happen before this
3077  * function is called, since the user receives confirmation of the address
3078  * list being bounced to. */
3079  struct AddressList resent_to = TAILQ_HEAD_INITIALIZER(resent_to);
3080  mutt_addrlist_copy(&resent_to, to, false);
3081  rfc2047_encode_addrlist(&resent_to, "Resent-To");
3082  int rc = bounce_message(fp, e, &resent_to, resent_from, &from_list);
3083  mutt_addrlist_clear(&resent_to);
3084  mutt_addrlist_clear(&from_list);
3085 
3086  return rc;
3087 }
static int bounce_message(FILE *fp, struct Email *e, struct AddressList *to, const char *resent_from, struct AddressList *env_from)
Bounce an email message.
Definition: sendlib.c:2982
void mutt_addrlist_clear(struct AddressList *al)
Unlink and free all Address in an AddressList.
Definition: address.c:1351
void mutt_addrlist_copy(struct AddressList *dst, const struct AddressList *src, bool prune)
Copy a list of addresses into another list.
Definition: address.c:724
#define _(a)
Definition: message.h:28
An email address.
Definition: address.h:34
size_t mutt_addrlist_write(char *buf, size_t buflen, const struct AddressList *al, bool display)
Write an Address to a buffer.
Definition: address.c:1134
void rfc2047_encode_addrlist(struct AddressList *al, const char *tag)
Encode any RFC2047 headers, where required, in an Address list.
Definition: rfc2047.c:748
struct Address * mutt_default_from(void)
Get a default &#39;from&#39; Address.
Definition: send.c:1302
const char * mutt_fqdn(bool may_hide_host)
Get the Fully-Qualified Domain Name.
Definition: sendlib.c:2449
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:637
int mutt_addrlist_to_intl(struct AddressList *al, char **err)
Convert an Address list to Punycode.
Definition: address.c:1186
char * mutt_str_strdup(const char *str)
Copy a string, safely.
Definition: string.c:380
#define mutt_error(...)
Definition: logging.h:84
#define FREE(x)
Definition: memory.h:40
WHERE char * C_Realname
Config: Real name of the user.
Definition: globals.h:136
#define TAILQ_EMPTY(head)
Definition: queue.h:715
WHERE bool OptNewsSend
(pseudo) used to change behavior when posting
Definition: options.h:43
#define TAILQ_HEAD_INITIALIZER(head)
Definition: queue.h:631
void mutt_addrlist_append(struct AddressList *al, struct Address *a)
Append an Address to an AddressList.
Definition: address.c:1371
static void set_noconv_flags ( struct Body b,
bool  flag 
)
static

Set/reset the "x-mutt-noconv" flag.

Parameters
bBody of email
flagIf true, set the flag, otherwise remove it

Definition at line 3094 of file sendlib.c.

3095 {
3096  for (; b; b = b->next)
3097  {
3098  if ((b->type == TYPE_MESSAGE) || (b->type == TYPE_MULTIPART))
3099  set_noconv_flags(b->parts, flag);
3100  else if ((b->type == TYPE_TEXT) && b->noconv)
3101  {
3102  if (flag)
3103  mutt_param_set(&b->parameter, "x-mutt-noconv", "yes");
3104  else
3105  mutt_param_delete(&b->parameter, "x-mutt-noconv");
3106  }
3107  }
3108 }
bool noconv
Don&#39;t do character set conversion.
Definition: body.h:73
struct Body * next
next attachment in the list
Definition: body.h:53
Type: &#39;text/*&#39;.
Definition: mime.h:38
void mutt_param_set(struct ParameterList *p, const char *attribute, const char *value)
Set a Parameter.
Definition: parameter.c:110
struct Body * parts
parts of a multipart or message/rfc822
Definition: body.h:54
unsigned int type
content-type primary type
Definition: body.h:65
Type: &#39;message/*&#39;.
Definition: mime.h:35
Type: &#39;multipart/*&#39;.
Definition: mime.h:37
static void set_noconv_flags(struct Body *b, bool flag)
Set/reset the "x-mutt-noconv" flag.
Definition: sendlib.c:3094
void mutt_param_delete(struct ParameterList *p, const char *attribute)
Delete a matching Parameter.
Definition: parameter.c:142
struct ParameterList parameter
parameters of the content-type
Definition: body.h:39
int mutt_write_multiple_fcc ( const char *  path,
struct Email e,
const char *  msgid,
bool  post,
char *  fcc,
char **  finalpath 
)

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
Return values
0Success
-1Failure

Definition at line 3121 of file sendlib.c.

3123 {
3124  char fcc_tok[PATH_MAX];
3125  char fcc_expanded[PATH_MAX];
3126 
3127  mutt_str_strfcpy(fcc_tok, path, sizeof(fcc_tok));
3128 
3129  char *tok = strtok(fcc_tok, ",");
3130  if (!tok)
3131  return -1;
3132 
3133  mutt_debug(LL_DEBUG1, "Fcc: initial mailbox = '%s'\n", tok);
3134  /* mutt_expand_path already called above for the first token */
3135  int status = mutt_write_fcc(tok, e, msgid, post, fcc, finalpath);
3136  if (status != 0)
3137  return status;
3138 
3139  while ((tok = strtok(NULL, ",")))
3140  {
3141  if (!*tok)
3142  continue;
3143 
3144  /* Only call mutt_expand_path if tok has some data */
3145  mutt_debug(LL_DEBUG1, "Fcc: additional mailbox token = '%s'\n", tok);
3146  mutt_str_strfcpy(fcc_expanded, tok, sizeof(fcc_expanded));
3147  mutt_expand_path(fcc_expanded, sizeof(fcc_expanded));
3148  mutt_debug(LL_DEBUG1, " Additional mailbox expanded = '%s'\n", fcc_expanded);
3149  status = mutt_write_fcc(fcc_expanded, e, msgid, post, fcc, finalpath);
3150  if (status != 0)
3151  return status;
3152  }
3153 
3154  return 0;
3155 }
char * mutt_expand_path(char *buf, size_t buflen)
Create the canonical path.
Definition: muttlib.c:128
#define PATH_MAX
Definition: mutt.h:50
size_t mutt_str_strfcpy(char *dest, const char *src, size_t dsize)
Copy a string into a buffer (guaranteeing NUL-termination)
Definition: string.c:750
Log at debug level 1.
Definition: logging.h:56
#define mutt_debug(LEVEL,...)
Definition: logging.h:81
int mutt_write_fcc(const char *path, struct Email *e, const char *msgid, bool post, char *fcc, char **finalpath)
Write email to FCC mailbox.
Definition: sendlib.c:3168
int mutt_write_fcc ( const char *  path,
struct Email e,
const char *  msgid,
bool  post,
char *  fcc,
char **  finalpath 
)

Write email to FCC mailbox.

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

Definition at line 3168 of file sendlib.c.

3170 {
3171  struct Message *msg = NULL;
3172  char tempfile[PATH_MAX];
3173  FILE *fp_tmp = NULL;
3174  int rc = -1;
3175  bool need_mailbox_cleanup = false;
3176  struct stat st;
3177  char buf[128];
3178  MsgOpenFlags onm_flags;
3179 
3180  if (post)
3181  set_noconv_flags(e->content, true);
3182 
3183 #ifdef RECORD_FOLDER_HOOK
3184  mutt_folder_hook(path, NULL);
3185 #endif
3186  struct Mailbox *m_fcc = mx_path_resolve(path);
3187  bool old_append = m_fcc->append;
3188  struct Context *ctx_fcc = mx_mbox_open(m_fcc, MUTT_APPEND | MUTT_QUIET);
3189  if (!ctx_fcc)
3190  {
3191  mutt_debug(LL_DEBUG1, "unable to open mailbox %s in append-mode, aborting\n", path);
3192  mailbox_free(&m_fcc);
3193  goto done;
3194  }
3195 
3196  /* We need to add a Content-Length field to avoid problems where a line in
3197  * the message body begins with "From " */
3198  if ((ctx_fcc->mailbox->magic == MUTT_MMDF) || (ctx_fcc->mailbox->magic == MUTT_MBOX))
3199  {
3200  mutt_mktemp(tempfile, sizeof(tempfile));
3201  fp_tmp = mutt_file_fopen(tempfile, "w+");
3202  if (!fp_tmp)
3203  {
3204  mutt_perror(tempfile);
3205  mx_mbox_close(&ctx_fcc);
3206  goto done;
3207  }
3208  /* remember new mail status before appending message */
3209  need_mailbox_cleanup = true;
3210  stat(path, &st);
3211  }
3212 
3213  e->read = !post; /* make sure to put it in the 'cur' directory (maildir) */
3214  onm_flags = MUTT_ADD_FROM;
3215  if (post)
3216  onm_flags |= MUTT_SET_DRAFT;
3217  msg = mx_msg_open_new(ctx_fcc->mailbox, e, onm_flags);
3218  if (!msg)
3219  {
3220  mutt_file_fclose(&fp_tmp);
3221  mx_mbox_close(&ctx_fcc);
3222  goto done;
3223  }
3224 
3225  /* post == 1 => postpone message.
3226  * post == 0 => Normal mode. */
3230 
3231  /* (postponement) if this was a reply of some sort, <msgid> contains the
3232  * Message-ID: of message replied to. Save it using a special X-Mutt-
3233  * header so it can be picked up if the message is recalled at a later
3234  * point in time. This will allow the message to be marked as replied if
3235  * the same mailbox is still open. */
3236  if (post && msgid)
3237  fprintf(msg->fp, "X-Mutt-References: %s\n", msgid);
3238 
3239  /* (postponement) save the Fcc: using a special X-Mutt- header so that
3240  * it can be picked up when the message is recalled */
3241  if (post && fcc)
3242  fprintf(msg->fp, "X-Mutt-Fcc: %s\n", fcc);
3243 
3244  if ((ctx_fcc->mailbox->magic == MUTT_MMDF) || (ctx_fcc->mailbox->magic == MUTT_MBOX))
3245  fprintf(msg->fp, "Status: RO\n");
3246 
3247  /* mutt_rfc822_write_header() only writes out a Date: header with
3248  * mode == 0, i.e. _not_ postponement; so write out one ourself */
3249  if (post)
3250  fprintf(msg->fp, "%s", mutt_date_make_date(buf, sizeof(buf)));
3251 
3252  /* (postponement) if the mail is to be signed or encrypted, save this info */
3253  if (((WithCrypto & APPLICATION_PGP) != 0) && post && (e->security & APPLICATION_PGP))
3254  {
3255  fputs("X-Mutt-PGP: ", msg->fp);
3256  if (e->security & SEC_ENCRYPT)
3257  fputc('E', msg->fp);
3258  if (e->security & SEC_OPPENCRYPT)
3259  fputc('O', msg->fp);
3260  if (e->security & SEC_SIGN)
3261  {
3262  fputc('S', msg->fp);
3263  if (C_PgpSignAs)
3264  fprintf(msg->fp, "<%s>", C_PgpSignAs);
3265  }
3266  if (e->security & SEC_INLINE)
3267  fputc('I', msg->fp);
3268  fputc('\n', msg->fp);
3269  }
3270 
3271  /* (postponement) if the mail is to be signed or encrypted, save this info */
3272  if (((WithCrypto & APPLICATION_SMIME) != 0) && post && (e->security & APPLICATION_SMIME))
3273  {
3274  fputs("X-Mutt-SMIME: ", msg->fp);
3275  if (e->security & SEC_ENCRYPT)
3276  {
3277  fputc('E', msg->fp);
3278  if (C_SmimeEncryptWith)
3279  fprintf(msg->fp, "C<%s>", C_SmimeEncryptWith);
3280  }
3281  if (e->security & SEC_OPPENCRYPT)
3282  fputc('O', msg->fp);
3283  if (e->security & SEC_SIGN)
3284  {
3285  fputc('S', msg->fp);
3286  if (C_SmimeSignAs)
3287  fprintf(msg->fp, "<%s>", C_SmimeSignAs);
3288  }
3289  if (e->security & SEC_INLINE)
3290  fputc('I', msg->fp);
3291  fputc('\n', msg->fp);
3292  }
3293 
3294 #ifdef MIXMASTER
3295  /* (postponement) if the mail is to be sent through a mixmaster
3296  * chain, save that information */
3297 
3298  if (post && !STAILQ_EMPTY(&e->chain))
3299  {
3300  fputs("X-Mutt-Mix:", msg->fp);
3301  struct ListNode *p = NULL;
3302  STAILQ_FOREACH(p, &e->chain, entries)
3303  {
3304  fprintf(msg->fp, " %s", (char *) p->data);
3305  }
3306 
3307  fputc('\n', msg->fp);
3308  }
3309 #endif
3310 
3311  if (fp_tmp)
3312  {
3313  mutt_write_mime_body(e->content, fp_tmp);
3314 
3315  /* make sure the last line ends with a newline. Emacs doesn't ensure this
3316  * will happen, and it can cause problems parsing the mailbox later. */
3317  fseek(fp_tmp, -1, SEEK_END);
3318  if (fgetc(fp_tmp) != '\n')
3319  {
3320  fseek(fp_tmp, 0, SEEK_END);
3321  fputc('\n', fp_tmp);
3322  }
3323 
3324  fflush(fp_tmp);
3325  if (ferror(fp_tmp))
3326  {
3327  mutt_debug(LL_DEBUG1, "%s: write failed\n", tempfile);
3328  mutt_file_fclose(&fp_tmp);
3329  unlink(tempfile);
3330  mx_msg_commit(ctx_fcc->mailbox, msg); /* XXX really? */
3331  mx_msg_close(ctx_fcc->mailbox, &msg);
3332  mx_mbox_close(&ctx_fcc);
3333  goto done;
3334  }
3335 
3336  /* count the number of lines */
3337  int lines = 0;
3338  char line_buf[1024];
3339  rewind(fp_tmp);
3340  while (fgets(line_buf, sizeof(line_buf), fp_tmp))
3341  lines++;
3342  fprintf(msg->fp, "Content-Length: " OFF_T_FMT "\n", (LOFF_T) ftello(fp_tmp));
3343  fprintf(msg->fp, "Lines: %d\n\n", lines);
3344 
3345  /* copy the body and clean up */
3346  rewind(fp_tmp);
3347  rc = mutt_file_copy_stream(fp_tmp, msg->fp);
3348  if (fclose(fp_tmp) != 0)
3349  rc = -1;
3350  /* if there was an error, leave the temp version */
3351  if (rc == 0)
3352  unlink(tempfile);
3353  }
3354  else
3355  {
3356  fputc('\n', msg->fp); /* finish off the header */
3357  rc = mutt_write_mime_body(e->content, msg->fp);
3358  }
3359 
3360  if (mx_msg_commit(ctx_fcc->mailbox, msg) != 0)
3361  rc = -1;
3362  else if (finalpath)
3363  *finalpath = mutt_str_strdup(msg->committed_path);
3364  mx_msg_close(ctx_fcc->mailbox, &msg);
3365  mx_mbox_close(&ctx_fcc);
3366 
3367  if (!post && need_mailbox_cleanup)
3368  mutt_mailbox_cleanup(path, &st);
3369 
3370  if (post)
3371  set_noconv_flags(e->content, false);
3372 
3373 done:
3374  m_fcc->append = old_append;
3375 #ifdef RECORD_FOLDER_HOOK
3376  /* We ran a folder hook for the destination mailbox,
3377  * now we run it for the user's current mailbox */
3378  if (Context && Context->mailbox->path)
3380 #endif
3381 
3382  return rc;
3383 }
#define MUTT_APPEND
Open mailbox for appending messages.
Definition: mx.h:53
The "current" mailbox.
Definition: context.h:39
#define mutt_perror(...)
Definition: logging.h:85
int mx_mbox_close(struct Context **ptr)
Save changes and close mailbox.
Definition: mx.c:561
void mutt_mailbox_cleanup(const char *path, struct stat *st)
Restore the timestamp of a mailbox.
Definition: mutt_mailbox.c:353
A normal Email, write full header + MIME headers.
Definition: sendlib.h:64
bool mutt_should_hide_protected_subject(struct Email *e)
Should NeoMutt hide the protected subject?
Definition: crypt.c:1037
struct Body * content
List of MIME parts.
Definition: email.h:90
A postponed Email, just the envelope info.
Definition: sendlib.h:65
struct Context * mx_mbox_open(struct Mailbox *m, OpenMailboxFlags flags)
Open a mailbox and parse it.
Definition: mx.c:264
#define SEC_INLINE
Email has an inline signature.
Definition: ncrypt.h:128
#define SEC_ENCRYPT
Email is encrypted.
Definition: ncrypt.h:121
char * mutt_date_make_date(char *buf, size_t buflen)
Write a date in RFC822 format to a buffer.
Definition: date.c:370
#define MUTT_SET_DRAFT
set the message draft flag
Definition: mx.h:66
int mutt_rfc822_write_header(FILE *fp, struct Envelope *env, struct Body *attach, enum MuttWriteHeaderMode mode, bool privacy, bool hide_protected_subject)
Write out one RFC822 header line.
Definition: sendlib.c:2229
int mx_msg_close(struct Mailbox *m, struct Message **msg)
Close a message.
Definition: mx.c:1092
void mutt_folder_hook(const char *path, const char *desc)
Perform a folder hook.
Definition: hook.c:515
bool read
Email is read.
Definition: email.h:51
struct Mailbox * mailbox
Definition: context.h:53
void mailbox_free(struct Mailbox **ptr)
Free a Mailbox.
Definition: mailbox.c:56
enum MailboxType magic
Mailbox type.
Definition: mailbox.h:117
int mutt_file_fclose(FILE **fp)
Close a FILE handle (and NULL the pointer)
Definition: file.c:149
struct Envelope * env
Envelope information.
Definition: email.h:89
struct Message * mx_msg_open_new(struct Mailbox *m, struct Email *e, MsgOpenFlags flags)
Open a new message.
Definition: mx.c:961
#define mutt_mktemp(buf, buflen)
Definition: muttlib.h:76
#define SEC_SIGN
Email is signed.
Definition: ncrypt.h:122
A local copy of an email.
Definition: mx.h:82
A mailbox.
Definition: mailbox.h:93
#define PATH_MAX
Definition: mutt.h:50
int mutt_write_mime_body(struct Body *a, FILE *fp)
Write a MIME part.
Definition: sendlib.c:511
WHERE char * C_SmimeEncryptWith
Config: Algorithm for encryption.
Definition: globals.h:168
&#39;mmdf&#39; Mailbox type
Definition: mailbox.h:49
bool append
Mailbox is opened in append mode.
Definition: mailbox.h:125
#define MUTT_QUIET
Do not print any messages.
Definition: mx.h:55
#define STAILQ_FOREACH(var, head, field)
Definition: queue.h:350
SecurityFlags security
bit 0-8: flags, bit 9,10: application.
Definition: email.h:39
WHERE bool C_CryptProtectedHeadersRead
Config: Display protected headers (Memory Hole) in the pager.
Definition: globals.h:268
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: ncrypt.h:129
&#39;mbox&#39; Mailbox type
Definition: mailbox.h:48
#define APPLICATION_PGP
Use PGP to encrypt/sign.
Definition: ncrypt.h:130
char * committed_path
the final path generated by mx_msg_commit()
Definition: mx.h:86
char * data
Definition: list.h:35
Log at debug level 1.
Definition: logging.h:56
int mutt_file_copy_stream(FILE *fp_in, FILE *fp_out)
Copy the contents of one file into another.
Definition: file.c:267
char * mutt_str_strdup(const char *str)
Copy a string, safely.
Definition: string.c:380
int mx_msg_commit(struct Mailbox *m, struct Message *msg)
Commit a message to a folder - Wrapper for MxOps::msg_commit()
Definition: mx.c:1071
FILE * fp
pointer to the message data
Definition: mx.h:84
struct Mailbox * mx_path_resolve(const char *path)
XXX.
Definition: mx.c:1544
static void set_noconv_flags(struct Body *b, bool flag)
Set/reset the "x-mutt-noconv" flag.
Definition: sendlib.c:3094
#define STAILQ_EMPTY(head)
Definition: queue.h:346
#define mutt_debug(LEVEL,...)
Definition: logging.h:81
WHERE char * C_PgpSignAs
Config: Use this alternative key for signing messages.
Definition: globals.h:163
FILE * mutt_file_fopen(const char *path, const char *mode)
Call fopen() safely.
Definition: file.c:584
WHERE char * C_SmimeSignAs
Config: Use this alternative key for signing messages.
Definition: globals.h:167
A List node for strings.
Definition: list.h:33
#define MUTT_ADD_FROM
add a From_ line
Definition: mx.h:65
#define WithCrypto
Definition: ncrypt.h:156
#define APPLICATION_SMIME
Use SMIME to encrypt/sign.
Definition: ncrypt.h:131

Variable Documentation

bool C_Allow8bit

Config: Allow 8-bit messages, don't use quoted-printable or base64.

Definition at line 79 of file sendlib.c.

char* C_AttachCharset

Config: When attaching files, use one of these character sets.

Definition at line 80 of file sendlib.c.

bool C_BounceDelivered

Config: Add 'Delivered-To' to bounced messages.

Definition at line 81 of file sendlib.c.

bool C_EncodeFrom

Config: Encode 'From ' as 'quote-printable' at the beginning of lines.

Definition at line 82 of file sendlib.c.

bool C_ForwardDecrypt

Config: Decrypt the message when forwarding it.

Definition at line 83 of file sendlib.c.

bool C_HiddenHost

Config: Don't use the hostname, just the domain, when generating the message id.

Definition at line 84 of file sendlib.c.

char* C_Inews

Config: (nntp) External command to post news articles.

Definition at line 85 of file sendlib.c.

bool C_MimeForwardDecode

Config: Decode the forwarded message before attaching it.

Definition at line 86 of file sendlib.c.

bool C_MimeSubject

Config: (nntp) Encode the article subject in base64.

encode subject line with RFC2047

Definition at line 87 of file sendlib.c.

char* C_MimeTypeQueryCommand

Config: External command to determine the MIME type of an attachment.

Definition at line 88 of file sendlib.c.

bool C_MimeTypeQueryFirst

Config: Run the C_MimeTypeQueryCommand before the mime.types lookup.

Definition at line 89 of file sendlib.c.

char* C_Sendmail

Config: External command to send email.

Definition at line 90 of file sendlib.c.

short C_SendmailWait

Config: Time to wait for sendmail to finish.

Definition at line 91 of file sendlib.c.

bool C_Use8bitmime

Config: Use 8-bit messages and ESMTP to send messages.

Definition at line 92 of file sendlib.c.

bool C_UseEnvelopeFrom

Config: Set the envelope sender of the message.

Definition at line 93 of file sendlib.c.

bool C_UserAgent

Config: Add a 'User-Agent' head to outgoing mail.

Definition at line 94 of file sendlib.c.

short C_WrapHeaders

Config: Width to wrap headers in outgoing messages.

Definition at line 95 of file sendlib.c.