1 /* mime-maker.c - Create MIME structures
2 * Copyright (C) 2016 g10 Code GmbH
4 * This file is part of GnuPG.
6 * GnuPG is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 3 of the License, or
9 * (at your option) any later version.
11 * GnuPG is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, see <https://www.gnu.org/licenses/>.
27 #include "mime-maker.h"
30 /* All valid characters in a header name. */
31 #define HEADER_NAME_CHARS ("abcdefghijklmnopqrstuvwxyz" \
32 "ABCDEFGHIJKLMNOPQRSTUVWXYZ" \
35 /* An object to store an header. Also used for a list of headers. */
38 struct header_s *next;
39 char *value; /* Malloced value. */
40 char name[1]; /* Name. */
42 typedef struct header_s *header_t;
45 /* An object to store a MIME part. A part is the header plus the
49 struct part_s *next; /* Next part in the current container. */
50 struct part_s *child; /* Child container. */
51 char *boundary; /* Malloced boundary string. */
52 header_t headers; /* List of headers. */
53 header_t *headers_tail;/* Address of last header in chain. */
54 size_t bodylen; /* Length of BODY. */
55 char *body; /* Malloced buffer with the body. This is the
56 * non-encoded value. */
57 unsigned int partid; /* The part ID. */
59 typedef struct part_s *part_t;
63 /* Definition of the mime parser object. */
64 struct mime_maker_context_s
66 void *cookie; /* Cookie passed to all callbacks. */
68 unsigned int verbose:1; /* Enable verbose mode. */
69 unsigned int debug:1; /* Enable debug mode. */
71 part_t mail; /* The MIME tree. */
74 unsigned int partid_counter; /* Counter assign part ids. */
76 int boundary_counter; /* Used to create easy to read boundaries. */
77 char *boundary_suffix; /* Random string used in the boundaries. */
79 struct b64state *b64state; /* NULL or malloced Base64 decoder state. */
81 /* Helper to convey the output stream to recursive functions. */
86 /* Create a new mime make object. COOKIE is a values woich will be
87 * used as first argument for all callbacks registered with this
90 mime_maker_new (mime_maker_t *r_maker, void *cookie)
96 ctx = xtrycalloc (1, sizeof *ctx);
98 return gpg_error_from_syserror ();
107 release_parts (part_t part)
111 part_t partnext = part->next;
112 while (part->headers)
114 header_t hdrnext = part->headers->next;
115 xfree (part->headers);
116 part->headers = hdrnext;
118 release_parts (part->child);
119 xfree (part->boundary);
127 /* Release a mime maker object. */
129 mime_maker_release (mime_maker_t ctx)
134 release_parts (ctx->mail);
135 xfree (ctx->boundary_suffix);
140 /* Set verbose and debug mode. */
142 mime_maker_set_verbose (mime_maker_t ctx, int level)
159 dump_parts (part_t part, int level)
163 for (; part; part = part->next)
165 log_debug ("%*s[part %u]\n", level*2, "", part->partid);
166 for (hdr = part->headers; hdr; hdr = hdr->next)
168 log_debug ("%*s%s: %s\n", level*2, "", hdr->name, hdr->value);
171 log_debug ("%*s[body %zu bytes]\n", level*2, "", part->bodylen);
174 log_debug ("%*s[container]\n", level*2, "");
175 dump_parts (part->child, level+1);
181 /* Dump the mime tree for debugging. */
183 mime_maker_dump_tree (mime_maker_t ctx)
185 dump_parts (ctx->mail, 0);
189 /* Find the parent node for NEEDLE starting at ROOT. */
191 find_parent (part_t root, part_t needle)
195 for (node = root->child; node; node = node->next)
199 if ((n = find_parent (node, needle)))
205 /* Find the part node from the PARTID. */
207 find_part (part_t root, unsigned int partid)
211 for (node = root->child; node; node = node->next)
213 if (node->partid == partid)
215 if ((n = find_part (node, partid)))
222 /* Create a boundary string. Outr codes is aware of the general
223 * structure of that string (gebins with "=-=") so that
224 * it can protect against accidentally-used boundaries within the
227 generate_boundary (mime_maker_t ctx)
229 if (!ctx->boundary_suffix)
233 gcry_create_nonce (buffer, sizeof buffer);
234 ctx->boundary_suffix = zb32_encode (buffer, 8 * sizeof buffer);
235 if (!ctx->boundary_suffix)
239 ctx->boundary_counter++;
240 return es_bsprintf ("=-=%02d-%s=-=",
241 ctx->boundary_counter, ctx->boundary_suffix);
245 /* Ensure that the context has a MAIL and CURRENT_PART object and
246 * return the parent object if available */
248 ensure_part (mime_maker_t ctx, part_t *r_parent)
252 ctx->mail = xtrycalloc (1, sizeof *ctx->mail);
257 return gpg_error_from_syserror ();
259 log_assert (!ctx->current_part);
260 ctx->current_part = ctx->mail;
261 ctx->current_part->headers_tail = &ctx->current_part->headers;
263 log_assert (ctx->current_part);
265 *r_parent = find_parent (ctx->mail, ctx->current_part);
271 /* Transform a header name into a standard capitalized format.
272 * "Content-Type". Conversion stops at the colon. */
274 capitalize_header_name (char *name)
276 unsigned char *p = name;
279 /* Special cases first. */
280 if (!ascii_strcasecmp (name, "MIME-Version"))
282 strcpy (name, "MIME-Version");
287 for (; *p && *p != ':'; p++)
293 if (*p >= 'a' && *p <= 'z')
297 else if (*p >= 'A' && *p <= 'Z')
303 /* Check whether a header with NAME has already been set into PART.
304 * NAME must be in canonical capitalized format. Return true or
307 have_header (part_t part, const char *name)
311 for (hdr = part->headers; hdr; hdr = hdr->next)
312 if (!strcmp (hdr->name, name))
318 /* Helper to add a header to a part. */
320 add_header (part_t part, const char *name, const char *value)
330 s = strchr (name, '=');
332 return gpg_error (GPG_ERR_INV_ARG);
337 namelen = strlen (name);
339 hdr = xtrymalloc (sizeof *hdr + namelen);
341 return gpg_error_from_syserror ();
343 memcpy (hdr->name, name, namelen);
344 hdr->name[namelen] = 0;
346 /* Check that the header name is valid. We allow all lower and
347 * uppercase letters and, except for the first character, digits and
349 if (strspn (hdr->name, HEADER_NAME_CHARS) != namelen
350 || strchr ("-0123456789", *hdr->name))
353 return gpg_error (GPG_ERR_INV_NAME);
356 capitalize_header_name (hdr->name);
357 hdr->value = xtrystrdup (value);
360 err = gpg_error_from_syserror ();
365 for (p = hdr->value + strlen (hdr->value) - 1;
367 && (*p == ' ' || *p == '\t' || *p == '\n' || *p == '\r'));
370 if (!(p >= hdr->value))
374 return gpg_error (GPG_ERR_INV_VALUE); /* Only spaces. */
379 *part->headers_tail = hdr;
380 part->headers_tail = &hdr->next;
389 /* Add a header with NAME and VALUE to the current mail. A LF in the
390 * VALUE will be handled automagically. If NULL is used for VALUE it
391 * is expected that the NAME has the format "NAME=VALUE" and VALUE is
394 * If no container has been added, the header will be used for the
395 * regular mail headers and not for a MIME part. If the current part
396 * is in a container and a body has been added, we append a new part
397 * to the current container. Thus for a non-MIME mail the caller
398 * needs to call this function followed by a call to add a body. When
399 * adding a Content-Type the boundary parameter must not be included.
402 mime_maker_add_header (mime_maker_t ctx, const char *name, const char *value)
407 /* Hack to use this function for a syntax check of NAME and VALUE. */
409 return add_header (NULL, name, value);
411 err = ensure_part (ctx, &parent);
414 part = ctx->current_part;
416 if ((part->body || part->child) && !parent)
418 /* We already have a body but no parent. Adding another part is
419 * thus not possible. */
420 return gpg_error (GPG_ERR_CONFLICT);
422 if (part->body || part->child)
424 /* We already have a body and there is a parent. We now append
425 * a new part to the current container. */
426 part = xtrycalloc (1, sizeof *part);
428 return gpg_error_from_syserror ();
429 part->partid = ++ctx->partid_counter;
430 part->headers_tail = &part->headers;
431 log_assert (!ctx->current_part->next);
432 ctx->current_part->next = part;
433 ctx->current_part = part;
436 /* If no NAME and no VALUE has been given we do not add a header.
437 * This can be used to create a new part without any header. */
441 /* If we add Content-Type, make sure that we have a MIME-version
442 * header first; this simply looks better. */
443 if (!ascii_strcasecmp (name, "Content-Type")
444 && !have_header (ctx->mail, "MIME-Version"))
446 err = add_header (ctx->mail, "MIME-Version", "1.0");
450 return add_header (part, name, value);
454 /* Helper for mime_maker_add_{body,stream}. */
456 add_body (mime_maker_t ctx, const void *data, size_t datalen)
461 err = ensure_part (ctx, &parent);
464 part = ctx->current_part;
466 return gpg_error (GPG_ERR_CONFLICT);
468 part->body = xtrymalloc (datalen? datalen : 1);
470 return gpg_error_from_syserror ();
471 part->bodylen = datalen;
473 memcpy (part->body, data, datalen);
479 /* Add STRING as body to the mail or the current MIME container. A
480 * second call to this function is not allowed.
482 * FIXME: We may want to have an append_body to add more data to a body.
485 mime_maker_add_body (mime_maker_t ctx, const char *string)
487 return add_body (ctx, string, strlen (string));
491 /* This is the same as mime_maker_add_body but takes a stream as
492 * argument. As of now the stream is copied to the MIME object but
493 * eventually we may delay that and read the stream only at the time
494 * it is needed. Note that the address of the stream object must be
495 * passed and that the ownership of the stream is transferred to this
496 * MIME object. To indicate the latter the function will store NULL
497 * at the ADDR_STREAM so that a caller can't use that object anymore
498 * except for es_fclose which accepts a NULL pointer. */
500 mime_maker_add_stream (mime_maker_t ctx, estream_t *stream_addr)
505 es_rewind (*stream_addr);
506 if (es_fclose_snatch (*stream_addr, &data, &datalen))
507 return gpg_error_from_syserror ();
509 return add_body (ctx, data, datalen);
513 /* Add a new MIME container. A container can be used instead of a
516 mime_maker_add_container (mime_maker_t ctx)
521 err = ensure_part (ctx, NULL);
524 part = ctx->current_part;
527 return gpg_error (GPG_ERR_CONFLICT); /* There is already a body. */
528 if (part->child || part->boundary)
529 return gpg_error (GPG_ERR_CONFLICT); /* There is already a container. */
531 /* Create a child node. */
532 part->child = xtrycalloc (1, sizeof *part->child);
534 return gpg_error_from_syserror ();
535 part->child->headers_tail = &part->child->headers;
537 part->boundary = generate_boundary (ctx);
540 err = gpg_error_from_syserror ();
547 part->partid = ++ctx->partid_counter;
548 ctx->current_part = part;
554 /* Finish the current container. */
556 mime_maker_end_container (mime_maker_t ctx)
561 err = ensure_part (ctx, &parent);
565 return gpg_error (GPG_ERR_CONFLICT); /* No container. */
567 parent = parent->next;
568 ctx->current_part = parent;
573 /* Return the part-ID of the current part. */
575 mime_maker_get_partid (mime_maker_t ctx)
577 if (ensure_part (ctx, NULL))
578 return 0; /* Ooops. */
579 return ctx->current_part->partid;
583 /* Write a header and handle emdedded LFs. If BOUNDARY is not NULL it
584 * is appended to the value. */
585 /* Fixme: Add automatic line wrapping. */
587 write_header (mime_maker_t ctx, const char *name, const char *value,
588 const char *boundary)
592 es_fprintf (ctx->outfp, "%s: ", name);
594 /* Note that add_header made sure that VALUE does not end with a LF.
595 * Thus we can assume that a LF is followed by non-whitespace. */
596 for (s = value; *s; s++)
599 es_fputs ("\r\n\t", ctx->outfp);
601 es_fputc (*s, ctx->outfp);
605 if (s > value && s[-1] != ';')
606 es_fputc (';', ctx->outfp);
607 es_fprintf (ctx->outfp, "\r\n\tboundary=\"%s\"", boundary);
610 es_fputs ("\r\n", ctx->outfp);
612 return es_ferror (ctx->outfp)? gpg_error_from_syserror () : 0;
617 write_gap (mime_maker_t ctx)
619 es_fputs ("\r\n", ctx->outfp);
620 return es_ferror (ctx->outfp)? gpg_error_from_syserror () : 0;
625 write_boundary (mime_maker_t ctx, const char *boundary, int last)
627 es_fprintf (ctx->outfp, "\r\n--%s%s\r\n", boundary, last?"--":"");
628 return es_ferror (ctx->outfp)? gpg_error_from_syserror () : 0;
632 /* Fixme: Apply required encoding. */
634 write_body (mime_maker_t ctx, const void *body, size_t bodylen)
638 for (s = body; bodylen; s++, bodylen--)
640 if (*s == '\n' && !(s > (const char *)body && s[-1] == '\r'))
641 es_fputc ('\r', ctx->outfp);
642 es_fputc (*s, ctx->outfp);
645 return es_ferror (ctx->outfp)? gpg_error_from_syserror () : 0;
649 /* Recursive worker for mime_maker_make. */
651 write_tree (mime_maker_t ctx, part_t parent, part_t part)
656 for (; part; part = part->next)
658 for (hdr = part->headers; hdr; hdr = hdr->next)
660 if (part->child && !strcmp (hdr->name, "Content-Type"))
661 err = write_header (ctx, hdr->name, hdr->value, part->boundary);
663 err = write_header (ctx, hdr->name, hdr->value, NULL);
667 err = write_gap (ctx);
672 err = write_body (ctx, part->body, part->bodylen);
678 log_assert (part->boundary);
679 err = write_boundary (ctx, part->boundary, 0);
681 err = write_tree (ctx, part, part->child);
683 err = write_boundary (ctx, part->boundary, 1);
690 log_assert (parent && parent->boundary);
691 err = write_boundary (ctx, parent->boundary, 0);
700 /* Add headers we always require. */
702 add_missing_headers (mime_maker_t ctx)
707 return gpg_error (GPG_ERR_NO_DATA);
708 if (!have_header (ctx->mail, "MIME-Version"))
710 /* Even if a Content-Type has never been set, we want to
711 * announce that we do MIME. */
712 err = add_header (ctx->mail, "MIME-Version", "1.0");
717 if (!have_header (ctx->mail, "Date"))
719 char *p = rfctimestamp (make_timestamp ());
721 err = gpg_error_from_syserror ();
723 err = add_header (ctx->mail, "Date", p);
736 /* Create message from the tree MIME and write it to FP. Note that
737 * the output uses only a LF and a later called sendmail(1) is
738 * expected to convert them to network line endings. */
740 mime_maker_make (mime_maker_t ctx, estream_t fp)
744 err = add_missing_headers (ctx);
749 err = write_tree (ctx, NULL, ctx->mail);
756 /* Create a stream object from the MIME part identified by PARTID and
757 * store it at R_STREAM. If PARTID identifies a container the entire
758 * tree is returned. Using that function may read stream objects
759 * which have been added as MIME bodies. The caller must close the
762 mime_maker_get_part (mime_maker_t ctx, unsigned int partid, estream_t *r_stream)
770 /* When the entire tree is requested, we make sure that all missing
771 * headers are applied. We don't do that if only a part is
772 * requested because the additional headers (like Date:) will only
773 * be added to part 0 headers anyway. */
776 err = add_missing_headers (ctx);
782 part = find_part (ctx->mail, partid);
784 /* For now we use a memory stream object; however it would also be
785 * possible to create an object created on the fly while the caller
786 * is reading the returned stream. */
787 fp = es_fopenmem (0, "w+b");
789 return gpg_error_from_syserror ();
792 err = write_tree (ctx, NULL, part);