Back to index

courier  0.68.2
makemime.c
Go to the documentation of this file.
00001 /*
00002 ** Copyright 2000-2010 Double Precision, Inc.  See COPYING for
00003 ** distribution information.
00004 */
00005 
00006 #if    HAVE_CONFIG_H
00007 #include "rfc2045_config.h"
00008 #endif
00009 #include      <sys/types.h>
00010 #include      <sys/stat.h>
00011 #include      <time.h>
00012 #include      <stdio.h>
00013 #include      <errno.h>
00014 #include      <string.h>
00015 #include      <signal.h>
00016 #if    HAVE_STRINGS_H
00017 #include      <strings.h>
00018 #endif
00019 #if    HAVE_UNISTD_H
00020 #include      <unistd.h>
00021 #endif
00022 #include      <stdlib.h>
00023 #include      <ctype.h>
00024 #include      <pwd.h>
00025 #include      <fcntl.h>
00026 #include      <signal.h>
00027 #include      "rfc822/encode.h"
00028 #include      "rfc2045.h"
00029 #include      "rfc2045charset.h"
00030 #if HAVE_UNISTD_H
00031 #include      <unistd.h>
00032 #endif
00033 #if HAVE_SYS_WAIT_H
00034 #include      <sys/wait.h>
00035 #endif
00036 #include      "numlib/numlib.h"
00037 
00038 #if     HAS_GETHOSTNAME
00039 #else
00040 int gethostname(const char *, size_t);
00041 #endif
00042 
00043 
00044 struct arg_list {
00045        struct arg_list *next;
00046        char *arg;
00047        } ;
00048 
00049 /******************************************************************************
00050 
00051 Open some file or a pipe for reading and writing.
00052 
00053 ******************************************************************************/
00054 
00055 static FILE *openfile_or_pipe(const char *filename, const char *mode)
00056 {
00057 int    fd;
00058 FILE   *fp;
00059 
00060        if (strcmp(filename, "-") == 0)    /* stdin or stdout */
00061               fd=dup( strcmp(mode, "r") ? 1:0);
00062        else if (*filename == '&')
00063               fd=dup( atoi(filename+1));  /* file descriptor */
00064        else fd=open(filename, (strcmp(mode, "r") ? O_WRONLY|O_CREAT|O_TRUNC:
00065                      O_RDONLY), 0666);    /* or a file */
00066        if (fd < 0)
00067        {
00068               perror(filename);
00069               exit(1);
00070        }
00071        fp=fdopen(fd, mode);
00072        if (!fp)
00073        {
00074               perror("fdopen");
00075               exit(1);
00076        }
00077        return (fp);
00078 }
00079 
00080 /******************************************************************************
00081 
00082 Open some file.  If we get a pipe, open a temporary file, and drain pipe's
00083 contents into it.
00084 
00085 ******************************************************************************/
00086 
00087 static FILE *openfile(const char *filename)
00088 {
00089 FILE   *fp=openfile_or_pipe(filename, "r");
00090 int    fd=fileno(fp);
00091 off_t  orig_pos;
00092 
00093        if ((orig_pos=lseek(fd, 0L, SEEK_CUR)) == -1 ||
00094               lseek(fd, 0L, SEEK_END) == -1 ||
00095               lseek(fd, 0L, SEEK_CUR) == -1 ||
00096               lseek(fd, orig_pos, SEEK_SET) == -1)      /* Must be a pipe */
00097        {
00098        FILE *t=tmpfile();
00099        int    c;
00100 
00101               if (!t)
00102               {
00103                      perror("tmpfile");
00104                      exit(1);
00105               }
00106 
00107               while ((c=getc(fp)) != EOF)
00108                      putc(c, t);
00109               if (ferror(fp) || fflush(t)
00110                      || ferror(t) || fseek(t, 0L, SEEK_SET) == -1)
00111               {
00112                      perror("write");
00113                      exit(1);
00114               }
00115               fclose(fp);
00116               fp=t;
00117        }
00118        return (fp);
00119 }
00120 
00121 /******************************************************************************
00122 
00123 Build argv/argc from a file.
00124 
00125 ******************************************************************************/
00126 
00127 static void read_args(int *argcp, char ***argvp, const char *file)
00128 {
00129 FILE   *fp=openfile_or_pipe(file, "r");
00130 struct arg_list *argfirst=0, *arglast=0, *argp;
00131 char   buffer[BUFSIZ];
00132 char   *p;
00133 int    c;
00134 
00135        *argcp=0;
00136        while (fgets(buffer, sizeof(buffer), fp) != 0)
00137        {
00138        const  char *q;
00139 
00140               if ((p=strchr(buffer, '\n')) != 0)
00141                      *p=0;
00142               else while ((c=getc(fp)) != '\n' && c != EOF)
00143                      ;      /* Just dump the excess */
00144 
00145               /* Skip the filler. */
00146 
00147               q=buffer;
00148               while (*q && isspace((int)(unsigned char)*q))
00149                      ++q;
00150               if (!*q)      continue;
00151               if (*q == '#')       continue;
00152               if (strcmp(buffer, "-") == 0)      break;
00153 
00154               argp=(struct arg_list *)malloc(sizeof(struct arg_list)+1+
00155                      strlen(q));
00156               if (!argp)
00157               {
00158                      perror("malloc");
00159                      exit(1);
00160               }
00161               if (arglast)
00162                      arglast->next=argp;
00163               else
00164                      argfirst=argp;
00165               arglast=argp;
00166               ++*argcp;
00167               argp->next=0;
00168               argp->arg=strcpy((char *)(argp+1), q);
00169        }
00170 
00171        if ((*argvp=malloc(sizeof (char *) * (*argcp+1))) == 0)
00172        {
00173               perror("malloc");
00174               exit(1);
00175        }
00176        c=0;
00177        for (argp=argfirst; argp; argp=argp->next)
00178        {
00179               (*argvp)[c]= argp->arg;
00180               ++c;
00181        }
00182        (*argvp)[c]=0;
00183 }
00184 
00185 static void usage()
00186 {
00187        fprintf(stderr,
00188 "Usage:\n"
00189 "  makemime -c type [-o file] [-e encoding] [-C charset] [-N name] \\\n"
00190 "                   [-a \"Header: Contents\"] file\n"
00191 "           -m [ type ] [-o file] [-e encoding] [-a \"Header: Contents\"] file\n"
00192 "           -j [-o file] file1 file2\n"
00193 "           @file\n"
00194 "\n"
00195 "   file:  filename    - read or write from filename\n"
00196 "          -           - read or write from stdin or stdout\n"
00197 "          &n          - read or write from file descriptor n\n"
00198 "          \\( opts \\)  - read from child process, that generates [ opts ]\n"
00199               "\n");
00200 
00201        fprintf(stderr,
00202 "Options:\n"
00203 "\n"
00204 "  -c type         - create a new MIME section from \"file\" with this\n"
00205 "                    Content-Type: (default is application/octet-stream).\n"
00206 "  -C charset      - MIME charset of a new text/plain section.\n"
00207               "  -N name         - MIME content name of the new mime section.\n");
00208 
00209        fprintf(stderr,
00210 "  -m [ type ]     - create a multipart mime section from \"file\" of this\n"
00211 "                    Content-Type: (default is multipart/mixed).\n"
00212 "  -e encoding     - use the given encoding (7bit, 8bit, quoted-printable,\n"
00213 "                    or base64), instead of guessing.  Omit \"-e\" and use\n"
00214 "                    -c auto to set Content-Type: to text/plain or\n"
00215               "                    application/octet-stream based on picked encoding.\n");
00216 
00217        fprintf(stderr,
00218 "  -j file1 file2  - join mime section file2 to multipart section file1.\n"
00219 "  -o file         - write ther result to file, instead of stdout (not\n"
00220 "                    allowed in child processes).\n"
00221 "  -a header       - prepend an additional header to the output.\n"
00222 "\n"
00223 "  @file - read all of the above options from file, one option or\n"
00224 "          value on each line.\n"
00225        );
00226        exit (0);
00227 }
00228 
00229 /******************************************************************************
00230 
00231 The arguments are parsed into the following structure, as a tree.
00232 
00233 ******************************************************************************/
00234 struct mimestruct {
00235 
00236        /*
00237        ** One or two input files.  We initialize either file or child,
00238        ** depending on the source being a file, or a child process.
00239        ** Later, we open a file pointer in either case.
00240        */
00241 
00242        const char *inputfile1, *inputfile2;
00243        struct mimestruct *inputchild1, *inputchild2;
00244        FILE *inputfp1, *inputfp2;
00245        pid_t  child1, child2;
00246 
00247        /* Output file.  Defaults to "-", stdout */
00248 
00249        const char *outputfile;
00250        FILE   *outputfp;
00251 
00252               /* The handler and open functions */
00253 
00254        void (*handler_func)(struct mimestruct *);
00255        void (*open_func)(struct mimestruct *);
00256 
00257               /* The new mime type, and encoding (-e) */
00258        const char *mimetype;
00259        const char *mimeencoding;
00260        const char *textplaincharset;
00261        const char *contentname;
00262 
00263               /* A list of -a headers */
00264        struct arg_list *a_first, *a_last;
00265        } ;
00266 
00267 static void createsimplemime(struct mimestruct *);
00268 static void createmultipartmime(struct mimestruct *);
00269 static void joinmultipart(struct mimestruct *);
00270 
00271 static void opencreatesimplemime(struct mimestruct *);
00272 static void opencreatemultipartmime(struct mimestruct *);
00273 static void openjoinmultipart(struct mimestruct *);
00274 
00275 /******************************************************************************
00276 
00277 Recursively build the mimestruct tree.
00278 
00279 ******************************************************************************/
00280 
00281 struct mimestruct *parseargs(int *argcp, char ***argvp)
00282 {
00283 struct mimestruct *m=malloc(sizeof(struct mimestruct));
00284 int argc= *argcp;
00285 char **argv= *argvp;
00286 
00287        if (!m)
00288        {
00289               perror("malloc");
00290               exit(1);
00291        }
00292        memset(m, 0, sizeof(*m));
00293 
00294        if (argc == 0 || argv[0][0] != '-')       usage();
00295 
00296        if (strncmp(argv[0], "-c", 2) == 0)
00297        {
00298               m->handler_func= &createsimplemime;
00299               m->open_func= &opencreatesimplemime;
00300               if (argv[0][2])
00301               {
00302                      m->mimetype=argv[0]+2;
00303                      --argc;
00304                      ++argv;
00305               }
00306               else
00307               {
00308                      --argc;
00309                      ++argv;
00310                      if (argc && argv[0][0] != '-' && argv[0][0] != ')')
00311                      {
00312                             m->mimetype=argv[0];
00313                             --argc;
00314                             ++argv;
00315                      }
00316                      else
00317                             m->mimetype="application/octet-stream";
00318               }
00319 
00320               while (isspace((int)(unsigned char)*m->mimetype))
00321                      ++m->mimetype;
00322        }
00323        else if (strncmp(argv[0], "-m", 2) == 0)
00324        {
00325               m->handler_func= &createmultipartmime;
00326               m->open_func= &opencreatemultipartmime;
00327               if (argv[0][2])
00328               {
00329                      m->mimetype=argv[0]+2;
00330                      --argc;
00331                      ++argv;
00332               }
00333               else
00334               {
00335                      --argc;
00336                      ++argv;
00337                      if (argc && argv[0][0] != '-' && argv[0][0] != ')')
00338                      {
00339                             m->mimetype=argv[0];
00340                             --argc;
00341                             ++argv;
00342                      }
00343                      else
00344                             m->mimetype="multipart/mixed";
00345               }
00346               while (isspace((int)(unsigned char)*m->mimetype))
00347                      ++m->mimetype;
00348        }
00349        else if (strncmp(argv[0], "-j", 2) == 0)
00350        {
00351        const char *filename;
00352 
00353               m->handler_func= &joinmultipart;
00354               m->open_func= &openjoinmultipart;
00355               if (argv[0][2])
00356               {
00357                      filename=argv[0]+2;
00358                      --argc;
00359                      ++argv;
00360               }
00361               else
00362               {
00363                      --argc;
00364                      ++argv;
00365                      if (argc == 0)       usage();
00366                      filename=argv[0];
00367                      --argc;
00368                      ++argv;
00369               }
00370 
00371               while (isspace((int)(unsigned char)*filename))
00372                      ++filename;
00373 
00374               if (strcmp(filename, "(") == 0)
00375               {
00376                      m->inputchild2=parseargs(&argc, &argv);
00377                      if (argc == 0 || strcmp(argv[0], ")"))
00378                             usage();
00379                      --argc;
00380                      ++argv;
00381               }
00382               else
00383                      m->inputfile2=filename;
00384        }
00385        else
00386               usage();
00387 
00388        /* Handle common options */
00389 
00390        while (argc)
00391        {
00392               if (strncmp(argv[0], "-o", 2) == 0)
00393               {
00394               const char *f=argv[0]+2;
00395 
00396                      ++argv;
00397                      --argc;
00398                      if (*f == 0)
00399                      {
00400                             if (!argc)    usage();
00401                             f=argv[0];
00402                             ++argv;
00403                             --argc;
00404                      }
00405                      while (isspace((int)(unsigned char)*f))
00406                             ++f;
00407                      m->outputfile=f;
00408                      continue;
00409               }
00410 
00411               if (strncmp(argv[0], "-C", 2) == 0)
00412               {
00413                      char *f=argv[0]+2;
00414 
00415                      ++argv;
00416                      --argc;
00417 
00418 
00419                      if (*f == 0)
00420                      {
00421                             if (!argc)    usage();
00422                             f=argv[0];
00423                             ++argv;
00424                             --argc;
00425                      }
00426                      while (isspace((int)(unsigned char)*f))
00427                             ++f;
00428                      m->textplaincharset=f;
00429                      continue;
00430               }
00431 
00432               if (strncmp(argv[0], "-N", 2) == 0)
00433               {
00434                      char *f=argv[0]+2;
00435 
00436                      ++argv;
00437                      --argc;
00438 
00439 
00440                      if (*f == 0)
00441                      {
00442                             if (!argc)    usage();
00443                             f=argv[0];
00444                             ++argv;
00445                             --argc;
00446                      }
00447                      while (isspace((int)(unsigned char)*f))
00448                             ++f;
00449                      m->contentname=f;
00450                      continue;
00451               }
00452 
00453               if (strncmp(argv[0], "-e", 2) == 0)
00454               {
00455               char *f=argv[0]+2, *q;
00456 
00457                      ++argv;
00458                      --argc;
00459 
00460                      if (*f == 0)
00461                      {
00462                             if (!argc)    usage();
00463                             f=argv[0];
00464                             ++argv;
00465                             --argc;
00466                      }
00467 
00468                      for (q=f; *q; q++)
00469                             *q=tolower((int)(unsigned char)*q);
00470 
00471                      while (isspace((int)(unsigned char)*f))
00472                             ++f;
00473 
00474                      if (strcmp(f, "7bit") && strcmp(f, "8bit") &&
00475                             strcmp(f, "quoted-printable") &&
00476                             strcmp(f, "base64"))
00477                             usage();
00478 
00479                      m->mimeencoding=f;
00480                      continue;
00481               }
00482 
00483               if (strncmp(argv[0], "-a", 2) == 0)
00484               {
00485               char *f=argv[0]+2;
00486               struct arg_list *a;
00487 
00488                      ++argv;
00489                      --argc;
00490 
00491                      if (*f == 0)
00492                      {
00493                             if (!argc)    usage();
00494                             f=argv[0];
00495                             ++argv;
00496                             --argc;
00497                      }
00498 
00499                      while (isspace((int)(unsigned char)*f))
00500                             ++f;
00501 
00502                      a=malloc(sizeof(struct arg_list));
00503                      if (!a)
00504                      {
00505                             perror("malloc");
00506                             exit(1);
00507                      }
00508                      if (m->a_last)
00509                             m->a_last->next=a;
00510                      else   m->a_first=a;
00511                      m->a_last=a;
00512                      a->arg=f;
00513                      a->next=0;
00514                      continue;
00515               }
00516               break;
00517        }
00518 
00519        /* We must now have the input file argument */
00520 
00521        if (!argc)    usage();
00522 
00523        if (strcmp(argv[0], "(") == 0)
00524        {
00525               --argc;
00526               ++argv;
00527               m->inputchild1=parseargs(&argc, &argv);
00528               if (argc == 0 || strcmp(argv[0], ")"))
00529                      usage();
00530               --argc;
00531               ++argv;
00532        }
00533        else
00534        {
00535               m->inputfile1=argv[0];
00536               --argc;
00537               ++argv;
00538        }
00539 
00540        *argcp=argc;
00541        *argvp=argv;
00542        return (m);
00543 }
00544 
00545 /******************************************************************************
00546 
00547 After we're done, terminate with a zero exit code if all child processes also
00548 terminated with a zero exit code.  Otherwise, terminate with a non-zero exit
00549 code thus propagating any child's non-zero exit code to parent.
00550 
00551 ******************************************************************************/
00552 
00553 static void goodexit(struct mimestruct *m, int exitcode)
00554 {
00555        if (m->outputfp && (fflush(m->outputfp) || ferror(m->outputfp)))
00556        {
00557               perror("makemime");
00558               exit(1);
00559        }
00560 
00561        /*
00562        ** Drain any leftover input, so that the child doesn't get
00563        ** a SIGPIPE.
00564        */
00565 
00566        while (m->inputfp1 && !feof(m->inputfp1) && !ferror(m->inputfp1))
00567               getc(m->inputfp1);
00568 
00569        while (m->inputfp2 && !feof(m->inputfp2) && !ferror(m->inputfp2))
00570               getc(m->inputfp2);
00571 
00572        if (m->inputfp1)
00573        {
00574               if (ferror(m->inputfp1))
00575               {
00576                      perror("makemime");
00577                      exitcode=1;
00578               }
00579 
00580               fclose(m->inputfp1);
00581        }
00582        if (m->inputfp2)
00583        {
00584               if (ferror(m->inputfp2))
00585               {
00586                      perror("makemime");
00587                      exitcode=1;
00588               }
00589 
00590               fclose(m->inputfp2);
00591        }
00592 
00593        while (m->child1 > 0 && m->child2 > 0)
00594        {
00595        int    waitstat;
00596        pid_t  p=wait(&waitstat);
00597 
00598               if (p <= 0 && errno == ECHILD)     break;
00599 
00600               if (p == m->child1)
00601                      m->child1=0;
00602               else if (p == m->child2)
00603                      m->child2=0;
00604               else   continue;
00605               if (waitstat) exitcode=1;
00606        }
00607        exit(exitcode);
00608 }
00609 
00610 int main(int argc, char **argv)
00611 {
00612 struct mimestruct *m;
00613 
00614        signal(SIGCHLD, SIG_DFL);
00615        if (argc > 1 && argv[1][0] == '@')
00616               read_args(&argc, &argv, argv[1]+1);
00617        else if (argc > 1)
00618        {
00619               --argc;
00620               ++argv;
00621        }
00622 
00623        m=parseargs(&argc, &argv);
00624        if (argc)     usage();      /* Some arguments left */
00625 
00626        (*m->open_func)(m);
00627        (*m->handler_func)(m);
00628        goodexit(m, 0);
00629        return (0);
00630 }
00631 
00632 static int encode_outfp(const char *p, size_t n, void *vp)
00633 {
00634        if (fwrite(p, n, 1, *(FILE **)vp) != 1)
00635               return -1;
00636        return 0;
00637 }
00638 
00639 static int do_printRfc2231Attr(const char *param,
00640                             const char *value,
00641                             void *voidArg)
00642 {
00643        fprintf( ((struct mimestruct *)voidArg)->outputfp,
00644                ";\n  %s=%s", param, value);
00645        return 0;
00646 }
00647 
00648 static void createsimplemime(struct mimestruct *m)
00649 {
00650 struct arg_list *a;
00651 struct libmail_encode_info encode_info;
00652 const char *orig_charset=m->textplaincharset;
00653 
00654        /* Determine encoding by reading the file, as follows:
00655        **
00656        ** Default to 7bit.  Use 8bit if high-ascii bytes found.  Use
00657        ** quoted printable if lines more than 200 characters found.
00658        ** Use base64 if a null byte is found.
00659        */
00660 
00661        if (m->mimeencoding == 0)
00662        {
00663               long   orig_pos=ftell(m->inputfp1);
00664               int    binaryflag;
00665 
00666               if (orig_pos == -1)
00667               {
00668                      perror("ftell");
00669                      goodexit(m, 1);
00670               }
00671 
00672               m->mimeencoding=libmail_encode_autodetect_fpoff(m->inputfp1,
00673                                                         0,
00674                                                         0, -1,
00675                                                         &binaryflag);
00676 
00677               if (ferror(m->inputfp1)
00678                      || fseek(m->inputfp1, orig_pos, SEEK_SET)<0)
00679               {
00680                      perror("fseek");
00681                      goodexit(m, 1);
00682               }
00683 
00684               if (strcmp(m->mimetype, "auto") == 0)
00685                      m->mimetype=binaryflag
00686                             ? (orig_charset=0,
00687                                "application/octet-stream"):"text/plain";
00688        }
00689 
00690        for (a=m->a_first; a; a=a->next)
00691               fprintf(m->outputfp, "%s\n", a->arg);
00692 
00693        fprintf(m->outputfp, "Content-Type: %s", m->mimetype);
00694        if (orig_charset && *orig_charset)
00695        {
00696               const char *c;
00697 
00698               fprintf(m->outputfp, "; charset=\"");
00699               for (c=orig_charset; *c; c++)
00700               {
00701                      if (*c != '"' && *c != '\\')
00702                             putc(*c, m->outputfp);
00703               }
00704               fprintf(m->outputfp, "\"");
00705        }
00706 
00707        if (m->contentname && *m->contentname)
00708        {
00709               const char *chset=m->textplaincharset ? m->textplaincharset
00710                      : "iso-8859-1";
00711 
00712               rfc2231_attrCreate("name", m->contentname, chset, NULL,
00713                                do_printRfc2231Attr, m);
00714        }
00715 
00716        fprintf(m->outputfp, "\nContent-Transfer-Encoding: %s\n\n",
00717               m->mimeencoding);
00718 
00719        libmail_encode_start(&encode_info, m->mimeencoding,
00720                           &encode_outfp,
00721                           &m->outputfp);
00722        {
00723               char input_buf[BUFSIZ];
00724               int n;
00725 
00726               while ((n=fread(input_buf, 1, sizeof(input_buf),
00727                             m->inputfp1)) > 0)
00728               {
00729                      if ( libmail_encode(&encode_info, input_buf, n))
00730                             break;
00731               }
00732 
00733               libmail_encode_end(&encode_info);
00734        }
00735 }
00736 
00737 /******************************************************************************
00738 
00739 Satisfy paranoia by making sure that the MIME boundary we picked does not
00740 appear in the contents of the bounded section.
00741 
00742 ******************************************************************************/
00743 
00744 static int tryboundary(struct mimestruct *m, FILE *f, const char *bbuf)
00745 {
00746 char   buf[BUFSIZ];
00747 char   *p;
00748 int    l=strlen(bbuf);
00749 int    c;
00750 long   orig_pos=ftell(f);
00751 
00752        if (orig_pos == -1)
00753        {
00754               perror("ftell");
00755               goodexit(m, 1);
00756        }
00757 
00758        while ((p=fgets(buf, sizeof(buf), f)) != 0)
00759        {
00760               if (p[0] == '-' && p[1] == '-' &&
00761                      strncmp(p+2, bbuf, l) == 0)
00762                      break;
00763 
00764               if ((p=strchr(buf, '\n')) != 0)
00765                      *p=0;
00766               else while ((c=getc(f)) != EOF && c != '\n')
00767                      ;
00768        }
00769 
00770        if (ferror(f) || fseek(f, orig_pos, SEEK_SET)<0)
00771        {
00772               perror("fseek");
00773               goodexit(m, 1);
00774        }
00775 
00776        return (p ? 1:0);
00777 }
00778 
00779 /******************************************************************************
00780 
00781 Create a MIME boundary for some content.
00782 
00783 ******************************************************************************/
00784 
00785 static const char *mkboundary(struct mimestruct *m, FILE *f)
00786 {
00787 pid_t  pid=getpid();
00788 time_t t;
00789 static unsigned n=0;
00790 static char bbuf[NUMBUFSIZE*4];
00791 char   buf[NUMBUFSIZE];
00792 
00793        time(&t);
00794 
00795        do
00796        {
00797               strcpy(bbuf, "=_");
00798               strcat(bbuf, libmail_str_size_t(++n, buf));
00799               strcat(bbuf, "_");
00800               strcat(bbuf, libmail_str_time_t(t, buf));
00801               strcat(bbuf, "_");
00802               strcat(bbuf, libmail_str_pid_t(pid, buf));
00803        } while (tryboundary(m, f, bbuf));
00804        return (bbuf);
00805 }
00806 
00807 static void createmultipartmime(struct mimestruct *m)
00808 {
00809 const char *b=mkboundary(m, m->inputfp1);
00810 struct arg_list *a;
00811 int    c;
00812 
00813        if (m->mimeencoding == 0)
00814               m->mimeencoding="8bit";
00815 
00816        for (a=m->a_first; a; a=a->next)
00817               fprintf(m->outputfp, "%s\n", a->arg);
00818        fprintf(m->outputfp, "Content-Type: %s; boundary=\"%s\"\n"
00819                      "Content-Transfer-Encoding: %s\n\n"
00820                      RFC2045MIMEMSG
00821                      "\n--%s\n",
00822               m->mimetype, b,
00823               m->mimeencoding,
00824               b);
00825        while ((c=getc(m->inputfp1)) != EOF)
00826               putc(c, m->outputfp);
00827        fprintf(m->outputfp, "\n--%s--\n", b);
00828 }
00829 
00830 static void joinmultipart(struct mimestruct *m)
00831 {
00832 const char *new_boundary;
00833 char   *old_boundary=0;
00834 int    old_boundary_len=0;
00835 char   buffer[BUFSIZ];
00836 char   *p;
00837 int    c;
00838 
00839        do
00840        {
00841               new_boundary=mkboundary(m, m->inputfp1);
00842        } while (tryboundary(m, m->inputfp2, new_boundary));
00843 
00844        /* Copy the header */
00845 
00846        for (;;)
00847        {
00848               if (fgets(buffer, sizeof(buffer), m->inputfp2) == 0)
00849               {
00850                      buffer[0]=0;
00851                      break;
00852               }
00853 
00854               if (strcmp(buffer, "\r\n") == 0 ||
00855                   buffer[0] == '\n' || strncmp(buffer, "--", 2) == 0)
00856                      break;
00857 
00858               if (strncasecmp(buffer, "content-type:", 13))
00859               {
00860                      fprintf(m->outputfp, "%s", buffer);
00861                      if ((p=strchr(buffer, '\n')) != 0) continue;
00862                      while ((c=getc(m->inputfp2)) != EOF && c != '\n')
00863                             putc(c, m->outputfp);
00864                      continue;
00865               }
00866 
00867               if ((p=strchr(buffer, '\n')) == 0)
00868                      while ((c=getc(m->inputfp2)) != EOF && c != '\n')
00869                             ;
00870 
00871               p=strchr(buffer+13, ';');
00872               if (p) *p=0;
00873               fprintf(m->outputfp, "Content-Type:%s; boundary=\"%s\"\n",
00874                      buffer+13, new_boundary);
00875 
00876               for (;;)
00877               {
00878                      c=getc(m->inputfp2);
00879                      if (c != EOF) ungetc(c, m->inputfp2);
00880                      if (c == '\n' || !isspace((int)(unsigned char)c))
00881                             break;
00882                      while ((c=getc(m->inputfp2)) != EOF && c != '\n')
00883                             ;
00884               }
00885        }
00886 
00887        do
00888        {
00889               if (strncmp(buffer, "--", 2) == 0)
00890               {
00891                      if (old_boundary == 0)
00892                      {
00893                             old_boundary=malloc(strlen(buffer)+1);
00894                             if (!old_boundary)
00895                             {
00896                                    perror("malloc");
00897                                    exit(1);
00898                             }
00899                             strcpy(old_boundary, buffer);
00900                             if ((p=strchr(old_boundary, '\n')) != 0)
00901                             {
00902                                    if (p > old_boundary && p[-1] == '\r')
00903                                           --p;
00904                                    *p=0;
00905                             }
00906                             p=old_boundary+strlen(old_boundary);
00907                             if (p >= old_boundary+4 &&
00908                                    strcmp(p-2, "--") == 0)
00909                                    p[-2]=0;
00910                             old_boundary_len=strlen(old_boundary);
00911                      }
00912 
00913 
00914                      if (strncasecmp(buffer, old_boundary,
00915                             old_boundary_len) == 0)
00916                      {
00917                             if ((p=strchr(buffer, '\n')) != 0)
00918                                    *p=0;
00919                             else while ((c=getc(m->inputfp2)) != '\n'
00920                                    && c != EOF)
00921                                    ;
00922 
00923                             c=strlen(buffer);
00924                             if (c > 0 && buffer[c-1] == '\r')
00925                                    buffer[--c]=0;
00926 
00927                             if (c >= 4 && strcmp(buffer+(c-2), "--") == 0)
00928                                    break;
00929                             fprintf(m->outputfp, "--%s\n",
00930                                    new_boundary);
00931                             continue;
00932                      }
00933               }
00934               fprintf(m->outputfp, "%s", buffer);
00935               if ((p=strchr(buffer, '\n')) == 0)
00936                      while ((c=getc(m->inputfp2)) != '\n' && c != EOF)
00937                             ;
00938        } while (fgets(buffer, sizeof(buffer), m->inputfp2) != 0);
00939 
00940        fprintf(m->outputfp, "--%s\n", new_boundary);
00941 
00942        while ((c=getc(m->inputfp1)) != EOF)
00943               putc(c, m->outputfp);
00944 
00945        fprintf(m->outputfp, "\n--%s--\n", new_boundary);
00946        goodexit(m, 0);
00947 }
00948 
00949 /******************************************************************************
00950 
00951 Open input from a child process
00952 
00953 ******************************************************************************/
00954 
00955 static FILE *openchild(struct mimestruct *parent, struct mimestruct *child,
00956        pid_t  *pidptr,
00957        int usescratch)
00958 {
00959 int    pipefd[2];
00960 char   buf[NUMBUFSIZE];
00961 char   buf2[NUMBUFSIZE+1];
00962 FILE   *fp;
00963 
00964        if (pipe(pipefd) < 0)
00965        {
00966               perror("pipe");
00967               exit(1);
00968        }
00969 
00970        *pidptr=fork();
00971 
00972        if (*pidptr < 0)
00973        {
00974               perror("fork");
00975               exit(1);
00976        }
00977 
00978        if (*pidptr == 0)
00979        {
00980               /* Duplicate pipe on stdout */
00981 
00982               close(pipefd[0]);
00983               dup2(pipefd[1], 1);
00984               close(pipefd[1]);
00985 
00986               /* Close any input files opened by parent */
00987 
00988               if (parent->inputfp1)       fclose(parent->inputfp1);
00989               if (parent->inputfp2)       fclose(parent->inputfp2);
00990 
00991               /* Open, then execute the child process */
00992 
00993               (*child->open_func)(child);
00994               (*child->handler_func)(child);
00995               goodexit(child, 0);
00996        }
00997        close(pipefd[1]);
00998 
00999        /*
01000        ** Open the pipe by calling openfile(), automatically creating
01001        ** the scratch file, if necessary.
01002        */
01003 
01004        buf[0]='&';
01005        strcpy(buf+1, libmail_str_size_t(pipefd[0], buf2));
01006 
01007        fp= usescratch ? openfile(buf):openfile_or_pipe(buf, "r");
01008        close(pipefd[0]);    /* fd was duped by openfile */
01009        return (fp);
01010 }
01011 
01012 static void openoutput(struct mimestruct *m)
01013 {
01014        if (!m->outputfile)
01015               m->outputfile="-";
01016 
01017        m->outputfp= openfile_or_pipe(m->outputfile, "w");
01018 }
01019 
01020 static void openjoinmultipart(struct mimestruct *m)
01021 {
01022        /* number two is the multipart section */
01023        if (m->inputchild2)
01024               m->inputfp2=openchild(m, m->inputchild2, &m->child2, 1);
01025        else
01026               m->inputfp2=openfile(m->inputfile2);
01027 
01028 
01029        if (m->inputchild1)
01030               m->inputfp1=openchild(m, m->inputchild1, &m->child1, 1);
01031        else
01032               m->inputfp1=openfile(m->inputfile1);
01033        openoutput(m);
01034 }
01035 
01036 static void opencreatesimplemime(struct mimestruct *m)
01037 {
01038        if (m->inputchild1)
01039               m->inputfp1=openchild(m, m->inputchild1, &m->child1,
01040                      m->mimeencoding ? 0:1);
01041        else
01042               m->inputfp1= m->mimeencoding
01043                      ? openfile_or_pipe(m->inputfile1, "r")
01044                      : openfile(m->inputfile1);
01045        openoutput(m);
01046 }
01047 
01048 static void opencreatemultipartmime(struct mimestruct *m)
01049 {
01050        if (m->inputchild1)
01051               m->inputfp1=openchild(m, m->inputchild1, &m->child1, 1);
01052        else
01053               m->inputfp1=openfile_or_pipe(m->inputfile1, "r");
01054        openoutput(m);
01055 }
01056