NeoMutt  2021-02-05-666-ge300cd
Teaching an old dog new tricks
DOXYGEN
body.c File Reference

Write a MIME Email Body to a file. More...

#include "config.h"
#include <stdbool.h>
#include <string.h>
#include "mutt/lib.h"
#include "email/lib.h"
#include "body.h"
#include "lib.h"
#include "ncrypt/lib.h"
#include "mutt_globals.h"
#include "muttlib.h"
+ Include dependency graph for body.c:

Go to the source code of this file.

Data Structures

struct  B64Context
 Cursor for the Base64 conversion. More...
 

Functions

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...
 
static void encode_quoted (struct FgetConv *fc, FILE *fp_out, bool istext)
 Encode text as quoted printable. 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, struct ConfigSubset *sub)
 Write a MIME part. More...
 

Detailed Description

Write a MIME Email Body to a file.

Authors
  • Richard Russon

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 body.c.

Function Documentation

◆ b64_init()

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 55 of file body.c.

56 {
57  memset(bctx->buffer, '\0', sizeof(bctx->buffer));
58  bctx->size = 0;
59  bctx->linelen = 0;
60 
61  return 0;
62 }
char buffer[3]
Definition: body.c:45
short size
Definition: body.c:46
short linelen
Definition: body.c:47
+ Here is the caller graph for this function:

◆ b64_flush()

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 69 of file body.c.

70 {
71  /* for some reasons, mutt_b64_encode expects the
72  * output buffer to be larger than 10B */
73  char encoded[11];
74  size_t ret;
75 
76  if (bctx->size == 0)
77  return;
78 
79  if (bctx->linelen >= 72)
80  {
81  fputc('\n', fp_out);
82  bctx->linelen = 0;
83  }
84 
85  /* ret should always be equal to 4 here, because bctx->size
86  * is a value between 1 and 3 (included), but let's not hardcode it
87  * and prefer the return value of the function */
88  ret = mutt_b64_encode(bctx->buffer, bctx->size, encoded, sizeof(encoded));
89  for (size_t i = 0; i < ret; i++)
90  {
91  fputc(encoded[i], fp_out);
92  bctx->linelen++;
93  }
94 
95  bctx->size = 0;
96 }
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: body.c:45
short size
Definition: body.c:46
short linelen
Definition: body.c:47
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ b64_putc()

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 104 of file body.c.

105 {
106  if (bctx->size == 3)
107  b64_flush(bctx, fp_out);
108 
109  bctx->buffer[bctx->size++] = c;
110 }
char buffer[3]
Definition: body.c:45
static void b64_flush(struct B64Context *bctx, FILE *fp_out)
Save the bytes to the file.
Definition: body.c:69
short size
Definition: body.c:46
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ encode_base64()

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 118 of file body.c.

119 {
120  struct B64Context bctx;
121  int ch, ch1 = EOF;
122 
123  b64_init(&bctx);
124 
125  while ((ch = mutt_ch_fgetconv(fc)) != EOF)
126  {
127  if (SigInt)
128  {
129  SigInt = false;
130  return;
131  }
132  if (istext && (ch == '\n') && (ch1 != '\r'))
133  b64_putc(&bctx, '\r', fp_out);
134  b64_putc(&bctx, ch, fp_out);
135  ch1 = ch;
136  }
137  b64_flush(&bctx, fp_out);
138  fputc('\n', fp_out);
139 }
WHERE SIG_ATOMIC_VOLATILE_T SigInt
true after SIGINT is received
Definition: mutt_globals.h:67
static int b64_init(struct B64Context *bctx)
Set up the base64 conversion.
Definition: body.c:55
static void b64_flush(struct B64Context *bctx, FILE *fp_out)
Save the bytes to the file.
Definition: body.c:69
static void b64_putc(struct B64Context *bctx, char c, FILE *fp_out)
Base64-encode one character.
Definition: body.c:104
Cursor for the Base64 conversion.
Definition: body.c:43
int mutt_ch_fgetconv(struct FgetConv *fc)
Convert a file&#39;s character set.
Definition: charset.c:912
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ encode_8bit()

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 146 of file body.c.

147 {
148  int ch;
149 
150  while ((ch = mutt_ch_fgetconv(fc)) != EOF)
151  {
152  if (SigInt)
153  {
154  SigInt = false;
155  return;
156  }
157  fputc(ch, fp_out);
158  }
159 }
WHERE SIG_ATOMIC_VOLATILE_T SigInt
true after SIGINT is received
Definition: mutt_globals.h:67
int mutt_ch_fgetconv(struct FgetConv *fc)
Convert a file&#39;s character set.
Definition: charset.c:912
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ encode_quoted()

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 167 of file body.c.

168 {
169  int c, linelen = 0;
170  char line[77], savechar;
171 
172  while ((c = mutt_ch_fgetconv(fc)) != EOF)
173  {
174  /* Wrap the line if needed. */
175  if ((linelen == 76) && ((istext && (c != '\n')) || !istext))
176  {
177  /* If the last character is "quoted", then be sure to move all three
178  * characters to the next line. Otherwise, just move the last
179  * character... */
180  if (line[linelen - 3] == '=')
181  {
182  line[linelen - 3] = 0;
183  fputs(line, fp_out);
184  fputs("=\n", fp_out);
185  line[linelen] = 0;
186  line[0] = '=';
187  line[1] = line[linelen - 2];
188  line[2] = line[linelen - 1];
189  linelen = 3;
190  }
191  else
192  {
193  savechar = line[linelen - 1];
194  line[linelen - 1] = '=';
195  line[linelen] = 0;
196  fputs(line, fp_out);
197  fputc('\n', fp_out);
198  line[0] = savechar;
199  linelen = 1;
200  }
201  }
202 
203  /* Escape lines that begin with/only contain "the message separator". */
204  if ((linelen == 4) && mutt_str_startswith(line, "From"))
205  {
206  mutt_str_copy(line, "=46rom", sizeof(line));
207  linelen = 6;
208  }
209  else if ((linelen == 4) && mutt_str_startswith(line, "from"))
210  {
211  mutt_str_copy(line, "=66rom", sizeof(line));
212  linelen = 6;
213  }
214  else if ((linelen == 1) && (line[0] == '.'))
215  {
216  mutt_str_copy(line, "=2E", sizeof(line));
217  linelen = 3;
218  }
219 
220  if ((c == '\n') && istext)
221  {
222  /* Check to make sure there is no trailing space on this line. */
223  if ((linelen > 0) && ((line[linelen - 1] == ' ') || (line[linelen - 1] == '\t')))
224  {
225  if (linelen < 74)
226  {
227  sprintf(line + linelen - 1, "=%2.2X", (unsigned char) line[linelen - 1]);
228  fputs(line, fp_out);
229  }
230  else
231  {
232  int savechar2 = line[linelen - 1];
233 
234  line[linelen - 1] = '=';
235  line[linelen] = 0;
236  fputs(line, fp_out);
237  fprintf(fp_out, "\n=%2.2X", (unsigned char) savechar2);
238  }
239  }
240  else
241  {
242  line[linelen] = 0;
243  fputs(line, fp_out);
244  }
245  fputc('\n', fp_out);
246  linelen = 0;
247  }
248  else if ((c != 9) && ((c < 32) || (c > 126) || (c == '=')))
249  {
250  /* Check to make sure there is enough room for the quoted character.
251  * If not, wrap to the next line. */
252  if (linelen > 73)
253  {
254  line[linelen++] = '=';
255  line[linelen] = 0;
256  fputs(line, fp_out);
257  fputc('\n', fp_out);
258  linelen = 0;
259  }
260  sprintf(line + linelen, "=%2.2X", (unsigned char) c);
261  linelen += 3;
262  }
263  else
264  {
265  /* Don't worry about wrapping the line here. That will happen during
266  * the next iteration when I'll also know what the next character is. */
267  line[linelen++] = c;
268  }
269  }
270 
271  /* Take care of anything left in the buffer */
272  if (linelen > 0)
273  {
274  if ((line[linelen - 1] == ' ') || (line[linelen - 1] == '\t'))
275  {
276  /* take care of trailing whitespace */
277  if (linelen < 74)
278  sprintf(line + linelen - 1, "=%2.2X", (unsigned char) line[linelen - 1]);
279  else
280  {
281  savechar = line[linelen - 1];
282  line[linelen - 1] = '=';
283  line[linelen] = 0;
284  fputs(line, fp_out);
285  fputc('\n', fp_out);
286  sprintf(line, "=%2.2X", (unsigned char) savechar);
287  }
288  }
289  else
290  line[linelen] = 0;
291  fputs(line, fp_out);
292  }
293 }
size_t mutt_str_startswith(const char *str, const char *prefix)
Check whether a string starts with a prefix.
Definition: string.c:160
size_t mutt_str_copy(char *dest, const char *src, size_t dsize)
Copy a string into a buffer (guaranteeing NUL-termination)
Definition: string.c:749
short linelen
Definition: body.c:47
int mutt_ch_fgetconv(struct FgetConv *fc)
Convert a file&#39;s character set.
Definition: charset.c:912
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ write_as_text_part()

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
trueThe Body should be written as text

Definition at line 300 of file body.c.

301 {
302  return mutt_is_text_part(b) ||
304 }
#define WithCrypto
Definition: lib.h:113
#define APPLICATION_PGP
Use PGP to encrypt/sign.
Definition: lib.h:87
bool mutt_is_text_part(struct Body *b)
Is this part of an email in plain text?
Definition: muttlib.c:434
SecurityFlags mutt_is_application_pgp(struct Body *b)
Does the message use PGP?
Definition: crypt.c:565
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_write_mime_body()

int mutt_write_mime_body ( struct Body a,
FILE *  fp,
struct ConfigSubset sub 
)

Write a MIME part.

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

Definition at line 314 of file body.c.

315 {
316  FILE *fp_in = NULL;
317  struct FgetConv *fc = NULL;
318 
319  if (a->type == TYPE_MULTIPART)
320  {
321  /* First, find the boundary to use */
322  const char *p = mutt_param_get(&a->parameter, "boundary");
323  if (!p)
324  {
325  mutt_debug(LL_DEBUG1, "no boundary parameter found\n");
326  mutt_error(_("No boundary parameter found [report this error]"));
327  return -1;
328  }
329  char boundary[128];
330  mutt_str_copy(boundary, p, sizeof(boundary));
331 
332  for (struct Body *t = a->parts; t; t = t->next)
333  {
334  fprintf(fp, "\n--%s\n", boundary);
335  if (mutt_write_mime_header(t, fp, sub) == -1)
336  return -1;
337  fputc('\n', fp);
338  if (mutt_write_mime_body(t, fp, sub) == -1)
339  return -1;
340  }
341  fprintf(fp, "\n--%s--\n", boundary);
342  return ferror(fp) ? -1 : 0;
343  }
344 
345  /* This is pretty gross, but it's the best solution for now... */
346  if (((WithCrypto & APPLICATION_PGP) != 0) && (a->type == TYPE_APPLICATION) &&
347  mutt_str_equal(a->subtype, "pgp-encrypted") && !a->filename)
348  {
349  fputs("Version: 1\n", fp);
350  return 0;
351  }
352 
353  fp_in = fopen(a->filename, "r");
354  if (!fp_in)
355  {
356  mutt_debug(LL_DEBUG1, "%s no longer exists\n", a->filename);
357  mutt_error(_("%s no longer exists"), a->filename);
358  return -1;
359  }
360 
361  if ((a->type == TYPE_TEXT) && (!a->noconv))
362  {
363  char send_charset[128];
364  fc = mutt_ch_fgetconv_open(fp_in, a->charset,
365  mutt_body_get_charset(a, send_charset, sizeof(send_charset)),
367  }
368  else
369  fc = mutt_ch_fgetconv_open(fp_in, 0, 0, MUTT_ICONV_NO_FLAGS);
370 
372  if (a->encoding == ENC_QUOTED_PRINTABLE)
374  else if (a->encoding == ENC_BASE64)
376  else if ((a->type == TYPE_TEXT) && (!a->noconv))
377  encode_8bit(fc, fp);
378  else
379  mutt_file_copy_stream(fp_in, fp);
381 
383  mutt_file_fclose(&fp_in);
384 
385  if (SigInt)
386  {
387  SigInt = false;
388  return -1;
389  }
390  return ferror(fp) ? -1 : 0;
391 }
bool mutt_str_equal(const char *a, const char *b)
Compare two strings.
Definition: string.c:904
char * filename
when sending a message, this is the file to which this structure refers
Definition: body.h:46
#define WithCrypto
Definition: lib.h:113
static bool write_as_text_part(struct Body *b)
Should the Body be written as a text MIME part.
Definition: body.c:300
#define mutt_error(...)
Definition: logging.h:88
WHERE SIG_ATOMIC_VOLATILE_T SigInt
true after SIGINT is received
Definition: mutt_globals.h:67
int mutt_write_mime_body(struct Body *a, FILE *fp, struct ConfigSubset *sub)
Write a MIME part.
Definition: body.c:314
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
#define MUTT_ICONV_NO_FLAGS
No flags are set.
Definition: charset.h:71
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
static void encode_base64(struct FgetConv *fc, FILE *fp_out, int istext)
Base64-encode some data.
Definition: body.c:118
int mutt_file_fclose(FILE **fp)
Close a FILE handle (and NULL the pointer)
Definition: file.c:153
static void encode_8bit(struct FgetConv *fc, FILE *fp_out)
Write the data as raw 8-bit data.
Definition: body.c:146
int mutt_write_mime_header(struct Body *a, FILE *fp, struct ConfigSubset *sub)
Create a MIME header.
Definition: header.c:764
char * mutt_body_get_charset(struct Body *b, char *buf, size_t buflen)
Get a body&#39;s character set.
Definition: body.c:131
unsigned int encoding
content-transfer-encoding, ContentEncoding
Definition: body.h:66
Base-64 encoded text.
Definition: mime.h:52
char * subtype
content-type subtype
Definition: body.h:37
#define APPLICATION_PGP
Use PGP to encrypt/sign.
Definition: lib.h:87
FILE * fp
Definition: charset.h:42
Type: &#39;text/*&#39;.
Definition: mime.h:38
struct Body * parts
parts of a multipart or message/rfc822
Definition: body.h:54
char * charset
Send mode: charset of attached file as stored on disk.
Definition: body.h:49
char * p
Definition: charset.h:46
#define mutt_debug(LEVEL,...)
Definition: logging.h:85
unsigned int type
content-type primary type, ContentType
Definition: body.h:65
Type: &#39;multipart/*&#39;.
Definition: mime.h:37
Log at debug level 1.
Definition: logging.h:40
size_t mutt_str_copy(char *dest, const char *src, size_t dsize)
Copy a string into a buffer (guaranteeing NUL-termination)
Definition: string.c:749
void mutt_ch_fgetconv_close(struct FgetConv **fc)
Close an fgetconv handle.
Definition: charset.c:892
int mutt_file_copy_stream(FILE *fp_in, FILE *fp_out)
Copy the contents of one file into another.
Definition: file.c:271
Quoted-printable text.
Definition: mime.h:51
char * mutt_param_get(const struct ParameterList *pl, const char *s)
Find a matching Parameter.
Definition: parameter.c:84
static void encode_quoted(struct FgetConv *fc, FILE *fp_out, bool istext)
Encode text as quoted printable.
Definition: body.c:167
struct ParameterList parameter
parameters of the content-type
Definition: body.h:39
Cursor for converting a file&#39;s encoding.
Definition: charset.h:40
Type: &#39;application/*&#39;.
Definition: mime.h:33
struct FgetConv * mutt_ch_fgetconv_open(FILE *fp, const char *from, const char *to, uint8_t flags)
Prepare a file for charset conversion.
Definition: charset.c:862
+ Here is the call graph for this function:
+ Here is the caller graph for this function: