tar: support -T - and -X -
[oweals/busybox.git] / mailutils / mime.c
index d309d7f7fd2e9668cf5653f06bf6f343739c136c..1e393ed31eec5971b630727e557c0d00a6e43668 100644 (file)
@@ -5,7 +5,7 @@
  *
  * Copyright (C) 2008 by Vladimir Dronnikov <dronnikov@gmail.com>
  *
- * Licensed under GPLv2, see file LICENSE in this tarball for details.
+ * Licensed under GPLv2, see file LICENSE in this source tree.
  */
 #include "libbb.h"
 #include "mail.h"
@@ -35,14 +35,92 @@ Options:
                     -c auto to set Content-Type: to text/plain or
                     application/octet-stream based on picked encoding.
   -j file1 file2  - join mime section file2 to multipart section file1.
-  -o file         - write ther result to file, instead of stdout (not
+  -o file         - write the result to file, instead of stdout (not
                     allowed in child processes).
   -a header       - prepend an additional header to the output.
 
   @file - read all of the above options from file, one option or
           value on each line.
+  {which version of makemime is this? What do we support?}
 */
 
+
+/* In busybox 1.15.0.svn, makemime generates output like this
+ * (empty lines are shown exactly!):
+{headers added with -a HDR}
+Mime-Version: 1.0
+Content-Type: multipart/mixed; boundary="24269534-2145583448-1655890676"
+
+--24269534-2145583448-1655890676
+Content-Type: {set by -c, e.g. text/plain}; charset={set by -C, e.g. us-ascii}
+Content-Disposition: inline; filename="A"
+Content-Transfer-Encoding: base64
+
+...file A contents...
+--24269534-2145583448-1655890676
+Content-Type: {set by -c, e.g. text/plain}; charset={set by -C, e.g. us-ascii}
+Content-Disposition: inline; filename="B"
+Content-Transfer-Encoding: base64
+
+...file B contents...
+--24269534-2145583448-1655890676--
+
+*/
+
+
+/* For reference: here is an example email to LKML which has
+ * 1st unnamed part (so it serves as an email body)
+ * and one attached file:
+...other headers...
+Content-Type: multipart/mixed; boundary="=-tOfTf3byOS0vZgxEWcX+"
+...other headers...
+Mime-Version: 1.0
+...other headers...
+
+
+--=-tOfTf3byOS0vZgxEWcX+
+Content-Type: text/plain
+Content-Transfer-Encoding: 7bit
+
+...email text...
+...email text...
+
+
+--=-tOfTf3byOS0vZgxEWcX+
+Content-Disposition: attachment; filename="xyz"
+Content-Type: text/plain; name="xyz"; charset="UTF-8"
+Content-Transfer-Encoding: 7bit
+
+...file contents...
+...file contents...
+
+--=-tOfTf3byOS0vZgxEWcX+--
+
+...random junk added by mailing list robots and such...
+*/
+
+/* man makemime:
+
+ * -c TYPE: create a (non-multipart) MIME section with Content-Type: TYPE
+ * makemime -c TYPE [-e ENCODING] [-o OUTFILE] [-C CHARSET] [-N NAME] [-a HEADER...] FILE
+ * The -C option sets the MIME charset attribute for text/plain content.
+ * The -N option sets the name attribute for Content-Type:
+ * Encoding must be one of the following: 7bit, 8bit, quoted-printable, or base64.
+
+ * -m multipart/TYPE: create a multipart MIME collection with Content-Type: multipart/TYPE
+ * makemime -m multipart/TYPE [-e ENCODING] [-o OUTFILE] [-a HEADER...] FILE
+ * Type must be either "multipart/mixed", "multipart/alternative", or some other MIME multipart content type.
+ * Additionally, encoding can only be "7bit" or "8bit", and will default to "8bit" if not specified.
+ * Finally, filename must be a MIME-formatted section, NOT a regular file.
+ * The -m option creates an initial multipart MIME collection, that contains only one MIME section, taken from filename.
+ * The collection is written to standard output, or the pipe or to outputfile.
+
+ * -j FILE1: add a section to a multipart MIME collection
+ * makemime -j FILE1 [-o OUTFILE] FILE2
+ * FILE1 must be a MIME collection that was previously created by the -m option.
+ * FILE2 must be a MIME section that was previously created by the -c option.
+ * The -j options adds the MIME section in FILE2 to the MIME collection in FILE1.
+ */
 int makemime_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
 int makemime_main(int argc UNUSED_PARAM, char **argv)
 {
@@ -51,14 +129,14 @@ int makemime_main(int argc UNUSED_PARAM, char **argv)
 #define boundary opt_output
 
        enum {
-               OPT_c = 1 << 0,         // Content-Type:
+               OPT_c = 1 << 0,         // create (non-multipart) section
                OPT_e = 1 << 1,         // Content-Transfer-Encoding. Ignored. Assumed base64
                OPT_o = 1 << 2,         // output to
                OPT_C = 1 << 3,         // charset
                OPT_N = 1 << 4,         // COMPAT
                OPT_a = 1 << 5,         // additional headers
-               OPT_m = 1 << 6,         // COMPAT
-               OPT_j = 1 << 7,         // COMPAT
+               //OPT_m = 1 << 6,         // create mutipart section
+               //OPT_j = 1 << 7,         // join section to multipart section
        };
 
        INIT_G();
@@ -66,8 +144,8 @@ int makemime_main(int argc UNUSED_PARAM, char **argv)
        // parse options
        opt_complementary = "a::";
        opts = getopt32(argv,
-               "c:e:o:C:N:a:m:j:",
-               &G.content_type, NULL, &opt_output, &G.opt_charset, NULL, &opt_headers, NULL, NULL
+               "c:e:o:C:N:a", //:m:j:",
+               &G.content_type, NULL, &opt_output, &G.opt_charset, NULL, &opt_headers //, NULL, NULL
        );
        //argc -= optind;
        argv += optind;
@@ -86,7 +164,8 @@ int makemime_main(int argc UNUSED_PARAM, char **argv)
 
        // make a random string -- it will delimit message parts
        srand(monotonic_us());
-       boundary = xasprintf("%d-%d-%d", rand(), rand(), rand());
+       boundary = xasprintf("%u-%u-%u",
+                       (unsigned)rand(), (unsigned)rand(), (unsigned)rand());
 
        // put multipart header
        printf(
@@ -120,7 +199,8 @@ int makemime_main(int argc UNUSED_PARAM, char **argv)
 static const char *find_token(const char *const string_array[], const char *key, const char *defvalue)
 {
        const char *r = NULL;
-       for (int i = 0; string_array[i] != 0; i++) {
+       int i;
+       for (i = 0; string_array[i] != NULL; i++) {
                if (strcasecmp(string_array[i], key) == 0) {
                        r = (char *)string_array[i+1];
                        break;
@@ -167,7 +247,7 @@ static int parse(const char *boundary, char **argv)
        // prepare unique string pattern
        uniq = xasprintf("%%llu.%u.%s", (unsigned)getpid(), safe_gethostname());
 
-//bb_info_msg("PARSE[%s]", terminator);
+//bb_info_msg("PARSE[%s]", uniq);
 
        while ((line = xmalloc_fgets_str(stdin, "\r\n\r\n")) != NULL) {
 
@@ -175,7 +255,7 @@ static int parse(const char *boundary, char **argv)
                // N.B. to avoid false positives let us seek to the _last_ occurance
                p = NULL;
                s = line;
-               while ((s=strcasestr(s, "Content-Type:")) != NULL)
+               while ((s = strcasestr(s, "Content-Type:")) != NULL)
                        p = s++;
                if (!p)
                        goto next;
@@ -224,18 +304,17 @@ static int parse(const char *boundary, char **argv)
                                pid = vfork();
                                if (0 == pid) {
                                        // child reads from fd[0]
-                                       xdup2(fd[0], STDIN_FILENO);
-                                       close(fd[0]); close(fd[1]);
+                                       close(fd[1]);
+                                       xmove_fd(fd[0], STDIN_FILENO);
                                        xsetenv("CONTENT_TYPE", type);
                                        xsetenv("CHARSET", charset);
                                        xsetenv("ENCODING", encoding);
                                        xsetenv("FILENAME", filename);
-                                       BB_EXECVP(*argv, argv);
-                                       _exit(EXIT_FAILURE);
+                                       BB_EXECVP_or_die(argv);
                                }
                                // parent dumps to fd[1]
                                close(fd[0]);
-                               fp = fdopen(fd[1], "w");
+                               fp = xfdopen_for_write(fd[1]);
                                signal(SIGPIPE, SIG_IGN); // ignore EPIPE
                        // or create a file for dump
                        } else {
@@ -249,9 +328,10 @@ static int parse(const char *boundary, char **argv)
 
                        // dump to fp
                        if (0 == strcasecmp(encoding, "base64")) {
-                               decode_base64(stdin, fp);
+                               read_base64(stdin, fp, '-');
                        } else if (0 != strcasecmp(encoding, "7bit")
-                               && 0 != strcasecmp(encoding, "8bit")) {
+                               && 0 != strcasecmp(encoding, "8bit")
+                       ) {
                                // quoted-printable, binary, user-defined are unsupported so far
                                bb_error_msg_and_die("no support of encoding '%s'", encoding);
                        } else {
@@ -266,11 +346,15 @@ static int parse(const char *boundary, char **argv)
                                // no means to truncate what we already have sent to the helper.
                                p = xmalloc_fgets_str(stdin, "\r\n");
                                while (p) {
-                                       if ((s = xmalloc_fgets_str(stdin, "\r\n")) == NULL)
+                                       s = xmalloc_fgets_str(stdin, "\r\n");
+                                       if (s == NULL)
                                                break;
-                                       if ('-' == s[0] && '-' == s[1]
-                                               && 0 == strncmp(s+2, boundary, boundary_len))
+                                       if ('-' == s[0]
+                                        && '-' == s[1]
+                                        && 0 == strncmp(s+2, boundary, boundary_len)
+                                       ) {
                                                break;
+                                       }
                                        fputs(p, fp);
                                        p = s;
                                }
@@ -294,7 +378,7 @@ static int parse(const char *boundary, char **argv)
                        if (opts & OPT_X) {
                                signal(SIGPIPE, SIG_DFL);
                                // exit if helper exited >0
-                               rc = wait4pid(pid);
+                               rc = (wait4pid(pid) & 0xff);
                                if (rc)
                                        return rc+20;
                        }
@@ -306,7 +390,7 @@ static int parse(const char *boundary, char **argv)
                        }
                }
  next:
-               free(line);
+               free(line);
        }
 
 //bb_info_msg("ENDPARSE[%s]", boundary);