NeoMutt
Teaching an old dog new tricks
DOXYGEN
Loading...
Searching...
No Matches
body.c File Reference

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

#include "config.h"
#include <stdbool.h>
#include "mutt/lib.h"
#include "email/lib.h"
#include "body.h"
#include "ncrypt/lib.h"
#include "globals.h"
#include "header.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 void b64_flush (struct B64Context *bctx, FILE *fp_out)
 Save the bytes to the file.
 
static void b64_putc (struct B64Context *bctx, char c, FILE *fp_out)
 Base64-encode one character.
 
static void encode_base64 (struct FgetConv *fc, FILE *fp_out, int istext)
 Base64-encode some data.
 
static void encode_8bit (struct FgetConv *fc, FILE *fp_out)
 Write the data as raw 8-bit data.
 
static void encode_quoted (struct FgetConv *fc, FILE *fp_out, bool istext)
 Encode text as quoted printable.
 
static bool write_as_text_part (struct Body *b)
 Should the Body be written as a text MIME part.
 
int mutt_write_mime_body (struct Body *a, FILE *fp, struct ConfigSubset *sub)
 Write a MIME part.
 

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

55{
56 /* for some reasons, mutt_b64_encode expects the
57 * output buffer to be larger than 10B */
58 char encoded[11] = { 0 };
59 size_t rc;
60
61 if (bctx->size == 0)
62 return;
63
64 if (bctx->linelen >= 72)
65 {
66 fputc('\n', fp_out);
67 bctx->linelen = 0;
68 }
69
70 /* rc should always be equal to 4 here, because bctx->size
71 * is a value between 1 and 3 (included), but let's not hardcode it
72 * and prefer the return value of the function */
73 rc = mutt_b64_encode(bctx->buffer, bctx->size, encoded, sizeof(encoded));
74 for (size_t i = 0; i < rc; i++)
75 {
76 fputc(encoded[i], fp_out);
77 bctx->linelen++;
78 }
79
80 bctx->size = 0;
81}
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
short linelen
Definition: body.c:46
char buffer[3]
Definition: body.c:44
short size
Definition: body.c:45
+ 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 89 of file body.c.

90{
91 if (bctx->size == 3)
92 b64_flush(bctx, fp_out);
93
94 bctx->buffer[bctx->size++] = c;
95}
static void b64_flush(struct B64Context *bctx, FILE *fp_out)
Save the bytes to the file.
Definition: body.c:54
+ 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 103 of file body.c.

104{
105 struct B64Context bctx = { 0 };
106 int ch, ch1 = EOF;
107
108 while ((ch = mutt_ch_fgetconv(fc)) != EOF)
109 {
110 if (SigInt)
111 {
112 SigInt = false;
113 return;
114 }
115 if (istext && (ch == '\n') && (ch1 != '\r'))
116 b64_putc(&bctx, '\r', fp_out);
117 b64_putc(&bctx, ch, fp_out);
118 ch1 = ch;
119 }
120 b64_flush(&bctx, fp_out);
121 fputc('\n', fp_out);
122}
SIG_ATOMIC_VOLATILE_T SigInt
true after SIGINT is received
Definition: globals.c:59
int mutt_ch_fgetconv(struct FgetConv *fc)
Convert a file's character set.
Definition: charset.c:978
static void b64_putc(struct B64Context *bctx, char c, FILE *fp_out)
Base64-encode one character.
Definition: body.c:89
Cursor for the Base64 conversion.
Definition: body.c:43
+ 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 129 of file body.c.

130{
131 int ch;
132
133 while ((ch = mutt_ch_fgetconv(fc)) != EOF)
134 {
135 if (SigInt)
136 {
137 SigInt = false;
138 return;
139 }
140 fputc(ch, fp_out);
141 }
142}
+ 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 150 of file body.c.

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

288{
289 return mutt_is_text_part(b) ||
291}
SecurityFlags mutt_is_application_pgp(struct Body *b)
Does the message use PGP?
Definition: crypt.c:537
bool mutt_is_text_part(struct Body *b)
Is this part of an email in plain text?
Definition: muttlib.c:450
#define APPLICATION_PGP
Use PGP to encrypt/sign.
Definition: lib.h:90
#define WithCrypto
Definition: lib.h:116
+ 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 301 of file body.c.

302{
303 FILE *fp_in = NULL;
304 struct FgetConv *fc = NULL;
305
306 if (a->type == TYPE_MULTIPART)
307 {
308 /* First, find the boundary to use */
309 const char *p = mutt_param_get(&a->parameter, "boundary");
310 if (!p)
311 {
312 mutt_debug(LL_DEBUG1, "no boundary parameter found\n");
313 mutt_error(_("No boundary parameter found [report this error]"));
314 return -1;
315 }
316 char boundary[128] = { 0 };
317 mutt_str_copy(boundary, p, sizeof(boundary));
318
319 for (struct Body *t = a->parts; t; t = t->next)
320 {
321 fprintf(fp, "\n--%s\n", boundary);
322 if (mutt_write_mime_header(t, fp, sub) == -1)
323 return -1;
324 fputc('\n', fp);
325 if (mutt_write_mime_body(t, fp, sub) == -1)
326 return -1;
327 }
328 fprintf(fp, "\n--%s--\n", boundary);
329 return ferror(fp) ? -1 : 0;
330 }
331
332 /* This is pretty gross, but it's the best solution for now... */
333 if (((WithCrypto & APPLICATION_PGP) != 0) && (a->type == TYPE_APPLICATION) &&
334 mutt_str_equal(a->subtype, "pgp-encrypted") && !a->filename)
335 {
336 fputs("Version: 1\n", fp);
337 return 0;
338 }
339
340 fp_in = fopen(a->filename, "r");
341 if (!fp_in)
342 {
343 mutt_debug(LL_DEBUG1, "%s no longer exists\n", a->filename);
344 mutt_error(_("%s no longer exists"), a->filename);
345 return -1;
346 }
347
348 if ((a->type == TYPE_TEXT) && (!a->noconv))
349 {
350 char send_charset[128] = { 0 };
351 fc = mutt_ch_fgetconv_open(fp_in, a->charset,
352 mutt_body_get_charset(a, send_charset, sizeof(send_charset)),
354 }
355 else
356 {
358 }
359
363 else if (a->encoding == ENC_BASE64)
365 else if ((a->type == TYPE_TEXT) && (!a->noconv))
366 encode_8bit(fc, fp);
367 else
370
372 mutt_file_fclose(&fp_in);
373
374 if (SigInt)
375 {
376 SigInt = false;
377 return -1;
378 }
379 return ferror(fp) ? -1 : 0;
380}
char * mutt_body_get_charset(struct Body *b, char *buf, size_t buflen)
Get a body's character set.
Definition: body.c:131
int mutt_file_copy_stream(FILE *fp_in, FILE *fp_out)
Copy the contents of one file into another.
Definition: file.c:262
int mutt_file_fclose(FILE **fp)
Close a FILE handle (and NULL the pointer)
Definition: file.c:152
#define mutt_error(...)
Definition: logging2.h:92
#define mutt_debug(LEVEL,...)
Definition: logging2.h:89
int mutt_write_mime_header(struct Body *a, FILE *fp, struct ConfigSubset *sub)
Create a MIME header.
Definition: header.c:758
@ LL_DEBUG1
Log at debug level 1.
Definition: logging2.h:43
@ ENC_BASE64
Base-64 encoded text.
Definition: mime.h:52
@ ENC_QUOTED_PRINTABLE
Quoted-printable text.
Definition: mime.h:51
@ TYPE_MULTIPART
Type: 'multipart/*'.
Definition: mime.h:37
@ TYPE_APPLICATION
Type: 'application/*'.
Definition: mime.h:33
@ TYPE_TEXT
Type: 'text/*'.
Definition: mime.h:38
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:928
void mutt_ch_fgetconv_close(struct FgetConv **ptr)
Close an fgetconv handle.
Definition: charset.c:960
#define MUTT_ICONV_NO_FLAGS
No flags are set.
Definition: charset.h:71
#define _(a)
Definition: message.h:28
bool mutt_str_equal(const char *a, const char *b)
Compare two strings.
Definition: string.c:798
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:150
static bool write_as_text_part(struct Body *b)
Should the Body be written as a text MIME part.
Definition: body.c:287
static void encode_base64(struct FgetConv *fc, FILE *fp_out, int istext)
Base64-encode some data.
Definition: body.c:103
int mutt_write_mime_body(struct Body *a, FILE *fp, struct ConfigSubset *sub)
Write a MIME part.
Definition: body.c:301
static void encode_8bit(struct FgetConv *fc, FILE *fp_out)
Write the data as raw 8-bit data.
Definition: body.c:129
void mutt_sig_allow_interrupt(bool allow)
Allow/disallow Ctrl-C (SIGINT)
Definition: signal.c:251
The body of an email.
Definition: body.h:36
struct Body * parts
parts of a multipart or message/rfc822
Definition: body.h:72
bool noconv
Don't do character set conversion.
Definition: body.h:46
char * charset
Send mode: charset of attached file as stored on disk.
Definition: body.h:78
struct ParameterList parameter
Parameters of the content-type.
Definition: body.h:62
struct Body * next
next attachment in the list
Definition: body.h:71
char * subtype
content-type subtype
Definition: body.h:60
unsigned int encoding
content-transfer-encoding, ContentEncoding
Definition: body.h:41
unsigned int type
content-type primary type, ContentType
Definition: body.h:40
char * filename
When sending a message, this is the file to which this structure refers.
Definition: body.h:58
Cursor for converting a file's encoding.
Definition: charset.h:41
FILE * fp
Definition: charset.h:42
char * p
Definition: charset.h:46
+ Here is the call graph for this function:
+ Here is the caller graph for this function: