Back to index

courier  0.68.2
reformime.c
Go to the documentation of this file.
00001 /*
00002 ** Copyright 1998 - 2011 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      <langinfo.h>
00016 
00017 #if    HAVE_STRINGS_H
00018 #include      <strings.h>
00019 #endif
00020 
00021 #if    HAVE_LOCALE_H
00022 #include      <locale.h>
00023 #endif
00024 
00025 #include      <stdlib.h>
00026 #include      <ctype.h>
00027 #include      <pwd.h>
00028 #include      <fcntl.h>
00029 #include      <signal.h>
00030 #include      "rfc2045.h"
00031 #include      "rfc822/rfc822.h"
00032 #include      "rfc822/rfc2047.h"
00033 #include      "rfc2045charset.h"
00034 #include      "unicode/unicode.h"
00035 
00036 #if HAVE_UNISTD_H
00037 #include      <unistd.h>
00038 #endif
00039 #if HAVE_SYS_WAIT_H
00040 #include      <sys/wait.h>
00041 #endif
00042 #include      "numlib/numlib.h"
00043 
00044 #if     HAS_GETHOSTNAME
00045 #else
00046 int gethostname(const char *, size_t);
00047 #endif
00048 
00049 extern int rfc2045_in_reformime;
00050 
00051 static const char *defchset;
00052 
00053 
00054 void rfc2045_error(const char *errmsg)
00055 {
00056        fprintf(stderr, "reformime: %s\n", errmsg);
00057        exit(1);
00058 }
00059 
00060 static void do_print_structure(struct rfc2045 *p, struct rfc2045id *id, void *ptr)
00061 {
00062        p=p;
00063        ptr=p;
00064 
00065        while (id)
00066        {
00067               printf("%d%c", id->idnum, id->next ? '.':'\n');
00068               id=id->next;
00069        }
00070 }
00071 
00072 static int decode_to_file(const char *p, size_t n, void *ptr)
00073 {
00074 FILE   *fp=(FILE *)ptr;
00075 
00076        while (n)
00077        {
00078               --n;
00079               if (putc((int)(unsigned char)*p++, fp) == EOF)
00080               {
00081                      perror("write");
00082                      exit(1);
00083               }
00084        }
00085        return (0);
00086 }
00087 
00088 void usage()
00089 {
00090        fprintf(stderr, "Usage: reformime [options]\n");
00091        fprintf(stderr, "    -d - parse a delivery status notification.\n");
00092        fprintf(stderr, "    -e - extract contents of MIME section.\n");
00093        fprintf(stderr, "    -x - extract MIME section to a file.\n");
00094        fprintf(stderr, "    -X - pipe MIME section to a program.\n");
00095        fprintf(stderr, "    -i - show MIME info.\n");
00096        fprintf(stderr, "    -s n.n.n.n[,n.n.n.n]* - specify MIME section(s).\n");
00097        fprintf(stderr, "    -r - rewrite message, filling in missing MIME headers.\n");
00098        fprintf(stderr, "    -r7 - also convert 8bit/raw encoding to quoted-printable, if possible.\n");
00099        fprintf(stderr, "    -r8 - also convert quoted-printable encoding to 8bit, if possible.\n");
00100        fprintf(stderr, "    -c charset - default charset for rewriting, -o, and -O.\n");
00101        fprintf(stderr, "    -m [file] [file]... - create a MIME message digest.\n");
00102        fprintf(stderr, "    -h \"header\" - decode RFC 2047-encoded header.\n");
00103        fprintf(stderr, "    -o \"header\" - encode unstructured header using RFC 2047.\n");
00104        fprintf(stderr, "    -O \"header\" - encode address list header using RFC 2047.\n");
00105 
00106        exit(1);
00107 }
00108 
00109 static char *tempname(const char *tempdir)
00110 {
00111 char   pidbuf[NUMBUFSIZE], timebuf[NUMBUFSIZE], hostnamebuf[256];
00112 static unsigned counter=0;
00113 time_t t;
00114 char   *p;
00115 
00116        libmail_str_pid_t(getpid(), pidbuf);
00117        time(&t);
00118        libmail_str_time_t(t, timebuf);
00119        hostnamebuf[sizeof(hostnamebuf)-1]=0;
00120        if (gethostname(hostnamebuf, sizeof(hostnamebuf)))
00121               hostnamebuf[0]=0;
00122        p=malloc(strlen(tempdir)+strlen(pidbuf)+strlen(timebuf)+
00123               strlen(hostnamebuf)+100);
00124        if (!p)       return (0);
00125        sprintf(p, "%s/%s.%s-%u.%s", tempdir, timebuf, pidbuf, counter++,
00126               hostnamebuf);
00127        return (p);
00128 }
00129 
00130 struct rfc2045 *read_message()
00131 {
00132 char   buf[BUFSIZ];
00133 struct rfc2045 *p=rfc2045_alloc_ac();
00134 FILE   *tempfp=0;
00135 int    l;
00136 
00137        if (fseek(stdin, 0L, SEEK_END) < 0 ||
00138               fseek(stdin, 0L, SEEK_SET) < 0)    /* Pipe, save to temp file */
00139        {
00140               tempfp=tmpfile();
00141        }
00142 
00143        while ((l=fread(buf, 1, sizeof(buf), stdin)) > 0)
00144        {
00145 
00146               rfc2045_parse(p, buf, l);
00147               if (tempfp && fwrite(buf, l, 1, tempfp) != 1)
00148               {
00149                      perror("fwrite");
00150                      exit(1);
00151               }
00152        }
00153        rfc2045_parse_partial(p);
00154 
00155        if (tempfp)   /* Replace stdin */
00156        {
00157               dup2(fileno(tempfp), 0);
00158               fclose(tempfp);
00159        }
00160        return (p);
00161 }
00162 
00163 void print_structure(struct rfc2045 *p)
00164 {
00165        rfc2045_decode(p, &do_print_structure, 0);
00166 }
00167 
00168 static void notfound(const char *p)
00169 {
00170        fprintf(stderr, "reformime: MIME section %s not found.\n", p);
00171        exit(1);
00172 }
00173 
00174 static void do_print_info(struct rfc2045 *s)
00175 {
00176 const char *content_type, *transfer_encoding, *charset;
00177 off_t start, end, body;
00178 char *content_name;
00179 off_t nlines, nbodylines;
00180 const char *p;
00181 
00182 char *disposition_name, *disposition_filename;
00183 
00184        rfc2045_mimeinfo(s, &content_type, &transfer_encoding, &charset);
00185        rfc2045_mimepos(s, &start, &end, &body, &nlines, &nbodylines);
00186 
00187        if (rfc2231_udecodeType(s, "name", NULL, &content_name) < 0)
00188        {
00189               perror("malloc");
00190               exit(1);
00191        }
00192 
00193        printf("content-type: %s\n", content_type);
00194        if (*content_name)
00195        {
00196               printf("content-name: %s\n", content_name);
00197        }
00198        free(content_name);
00199 
00200        printf("content-transfer-encoding: %s\n", transfer_encoding);
00201        printf("charset: %s\n", charset);
00202        if (s->content_disposition && *s->content_disposition)
00203               printf("content-disposition: %s\n", s->content_disposition);
00204 
00205        if ((rfc2231_udecodeDisposition(s, "name", NULL, &disposition_name) < 0
00206             && (disposition_name=strdup("")) == NULL)
00207            ||
00208            (rfc2231_udecodeDisposition(s, "filename", NULL,
00209                                    &disposition_filename) < 0
00210             && (disposition_filename=strdup("")) == NULL))
00211        {
00212               perror("malloc");
00213               exit(1);
00214        }
00215 
00216        if (*disposition_name)
00217               printf("content-disposition-name: %s\n", disposition_name);
00218 
00219        free(disposition_name);
00220 
00221        if (*disposition_filename)
00222        {
00223               printf("content-disposition-filename: %s\n",
00224                      disposition_filename);
00225        }
00226        free(disposition_filename);
00227 
00228        if (*(p=rfc2045_content_id(s)))
00229               printf("content-id: <%s>\n", p);
00230        if (*(p=rfc2045_content_description(s)))
00231        {
00232               char *s=rfc822_display_hdrvalue_tobuf("content-description",
00233                                                 p,
00234                                                 defchset,
00235                                                 NULL,
00236                                                 NULL);
00237 
00238               if (!s)
00239               {
00240                      perror("rfc2047_decode_unicode");
00241                      exit(1);
00242               }
00243               printf("content-description: %s\n", s);
00244               free(s);
00245        }
00246        if (*(p=rfc2045_content_language(s)))
00247               printf("content-language: %s\n", p);
00248        if (*(p=rfc2045_content_md5(s)))
00249               printf("content-md5: %s\n", p);
00250 
00251        printf("starting-pos: %lu\n", (unsigned long)start);
00252        printf("starting-pos-body: %lu\n", (unsigned long)body);
00253        printf("ending-pos: %lu\n", (unsigned long)end);
00254        printf("line-count: %lu\n", (unsigned long)nlines);
00255        printf("body-line-count: %lu\n", (unsigned long)nbodylines);
00256 }
00257 
00258 static void do_print_info_multiple(struct rfc2045 *p, struct rfc2045id *id,
00259               void *ptr)
00260 {
00261        printf("section: ");
00262        do_print_structure(p, id, ptr);
00263        do_print_info(p);
00264        printf("\n");
00265 }
00266 
00267 void print_info(struct rfc2045 *p, const char *mimesection)
00268 {
00269 struct rfc2045 *s;
00270 
00271        if (mimesection)
00272        {
00273               s=rfc2045_find(p, mimesection);
00274               if (!s)
00275                      notfound(mimesection);
00276               printf("section: %s\n", mimesection);
00277               do_print_info(s);
00278               return;
00279        }
00280        rfc2045_decode(p, &do_print_info_multiple, 0);
00281 }
00282 
00283 static void do_print_section(struct rfc2045 *s, FILE *fp)
00284 {
00285 off_t start, end, body;
00286 off_t nlines;
00287 off_t nbodylines;
00288 
00289        rfc2045_mimepos(s, &start, &end, &body, &nlines, &nbodylines);
00290 
00291        if (fseek(stdin, body, SEEK_SET) == -1)
00292        {
00293               perror("fseek");
00294               exit(1);
00295        }
00296 
00297        rfc2045_cdecode_start(s, &decode_to_file, fp);
00298        while (body < end)
00299        {
00300        char   buf[BUFSIZ];
00301        size_t n=sizeof(buf);
00302 
00303               if ((off_t)n > end-body)    n=end-body;
00304               n=fread(buf, 1, n, stdin);
00305               if (n == 0)
00306               {
00307                      perror("fread");
00308                      exit(1);
00309               }
00310               rfc2045_cdecode(s, buf, n);
00311               body += n;
00312        }
00313        rfc2045_cdecode_end(s);
00314 }
00315 
00316 void print_decode(struct rfc2045 *p, const char *mimesection)
00317 {
00318 struct rfc2045 *s;
00319 
00320        if (!mimesection)
00321               usage();
00322 
00323        s=rfc2045_find(p, mimesection);
00324        if (!s)
00325               notfound(mimesection);
00326 
00327        do_print_section(s, stdout);
00328 }
00329 
00330 void rewrite(struct rfc2045 *p, int rwmode)
00331 {
00332        struct rfc2045src *src;
00333 
00334        rfc2045_ac_check(p, rwmode);
00335 
00336        src=rfc2045src_init_fd(fileno(stdin));
00337 
00338        if (src == NULL || rfc2045_rewrite(p, src, fileno(stdout),
00339               "reformime (" RFC2045PKG " " RFC2045VER ")"))
00340        {
00341               perror("reformime");
00342               exit(1);
00343        }
00344        rfc2045src_deinit(src);
00345 }
00346 
00347 static char *get_suitable_filename(struct rfc2045 *r, const char *pfix,
00348        int ignore_filename)
00349 {
00350 char *disposition_name;
00351 char *disposition_filename;
00352 char   *filename_buf;
00353 char *content_name;
00354 char   *p, *q;
00355 char   *dyn_disp_name=0;
00356 
00357 const char *disposition_filename_s;
00358 
00359        if (rfc2231_udecodeDisposition(r, "name", NULL, &disposition_name) < 0)
00360               disposition_name=NULL;
00361 
00362        if (rfc2231_udecodeDisposition(r, "filename", NULL,
00363                                    &disposition_filename) < 0)
00364               disposition_filename=NULL;
00365 
00366        if (rfc2231_udecodeType(r, "name", NULL,
00367                             &content_name) < 0)
00368               content_name=NULL;
00369 
00370        disposition_filename_s=disposition_filename;
00371 
00372        if (!disposition_filename_s || !*disposition_filename_s)
00373               disposition_filename_s=disposition_name;
00374        if (!disposition_filename_s || !*disposition_filename_s)
00375               disposition_filename_s=content_name;
00376 
00377        filename_buf=strdup(disposition_filename_s ? disposition_filename_s:"");
00378 
00379        if (!filename_buf)
00380        {
00381               perror("strdup");
00382               exit(1);
00383        }
00384 
00385        if (content_name)           free(content_name);
00386        if (disposition_name)              free(disposition_name);
00387        if (disposition_filename)   free(disposition_filename);
00388 
00389        if (strlen(filename_buf) > 32)
00390        {
00391               p=filename_buf;
00392               q=filename_buf + strlen(filename_buf)-32;
00393               while ( (*p++ = *q++) != 0)
00394                      ;
00395        }
00396 
00397        /* Strip leading/trailing spaces */
00398 
00399        p=filename_buf;
00400        while (*p && isspace((int)(unsigned char)*p))
00401               ++p;
00402 
00403        q=filename_buf;
00404        while ((*q=*p) != 0)
00405        {
00406               ++p;
00407               ++q;
00408        }
00409 
00410        for (p=q=filename_buf; *p; p++)
00411               if (!isspace((int)(unsigned char)*p))
00412                      q=p+1;
00413        *q=0;
00414 
00415        disposition_filename_s=filename_buf;
00416 
00417        if (ignore_filename)
00418        {
00419        char   numbuf[NUMBUFSIZE];
00420        static size_t counter=0;
00421        const char *p=libmail_str_size_t(++counter, numbuf);
00422 
00423               dyn_disp_name=malloc(strlen(disposition_filename_s)
00424                      + strlen(p)+2);
00425               if (!dyn_disp_name)
00426               {
00427                      perror("malloc");
00428                      exit(1);
00429               }
00430               disposition_filename_s=strcat(strcat(strcpy(
00431                      dyn_disp_name, p), "-"),
00432                      disposition_filename_s);
00433        }
00434        else if (!disposition_filename_s || !*disposition_filename_s)
00435        {
00436               dyn_disp_name=tempname(".");
00437               disposition_filename_s=dyn_disp_name+2;   /* Skip over ./ */
00438        }
00439 
00440        p=malloc((pfix ? strlen(pfix):0)+strlen(disposition_filename_s)+1);
00441        if (!p)
00442        {
00443               perror("malloc");
00444               exit(1);
00445        }
00446        *p=0;
00447        if (pfix)     strcpy(p, pfix);
00448        q=p+strlen(p);
00449        for (strcpy(q, disposition_filename_s); *q; q++)
00450               if (!isalnum(*q) && *q != '.' && *q != '-')
00451                      *q='_';
00452 
00453        if (dyn_disp_name)   free(dyn_disp_name);
00454 
00455        if (!pfix)
00456        {
00457         const char *content_type_s;
00458         const char *content_transfer_encoding_s;
00459         const char *charset_s;
00460        int c;
00461        static char filenamebuf[256];
00462        char   *t;
00463        FILE   *tty;
00464 
00465               if ((tty=fopen("/dev/tty", "r+")) == 0)
00466               {
00467                      perror("/dev/tty");
00468                      exit(1);
00469               }
00470 
00471               rfc2045_mimeinfo(r, &content_type_s,
00472                      &content_transfer_encoding_s, &charset_s);
00473 
00474               fprintf (tty, "Extract %s? ", content_type_s);
00475               fflush(tty);
00476               c=getc(tty);
00477               if (c != '\n' && c != EOF)
00478               {
00479               int    cc;
00480 
00481                      while ((cc=getc(tty)) != '\n' && cc != EOF)
00482                             ;
00483               }
00484               if (c != 'y' && c != 'Y')
00485               {
00486                      free(p);
00487                      fclose(tty);
00488                      free(filename_buf);
00489                      return (0);
00490               }
00491               fprintf (tty, "Filename [%s]: ", p);
00492               if (fgets(filenamebuf, sizeof(filenamebuf)-1, tty) == NULL)
00493                      filenamebuf[0]=0;
00494 
00495               fclose(tty);
00496               t=strchr(filenamebuf, '\n');
00497               if (t) *t=0;
00498               else
00499               {
00500                      fprintf(stderr, "Filename too long.\n");
00501                      exit(1);
00502               }
00503               if (filenamebuf[0])
00504               {
00505                      free(p);
00506                      p=strdup(filenamebuf);
00507                      if (!p)
00508                      {
00509                             perror("malloc");
00510                             exit(1);
00511                      }
00512               }
00513        }
00514        free(filename_buf);
00515        return (p);
00516 }
00517 
00518 static void extract_file(struct rfc2045 *p,
00519        const char *filename, int argc, char **argv)
00520 {
00521 char   *f;
00522 FILE   *fp;
00523 int    ignore=0;
00524 
00525        for (;;)
00526        {
00527        int    fd;
00528 
00529               f=get_suitable_filename(p, filename, ignore);
00530               if (!f)       return;
00531 
00532               fd=open(f, O_WRONLY|O_CREAT|O_EXCL, 0666);
00533               if (fd < 0)
00534               {
00535                      if (errno == EEXIST)
00536                      {
00537                             printf("%s exists.\n", f);
00538                             free(f);
00539                             ignore=1;
00540                             continue;
00541                      }
00542 
00543                      perror(f);
00544                      exit(1);
00545               }
00546               fp=fdopen(fd, "w");
00547               if (!fp)
00548               {
00549                      perror("fdopen");
00550                      exit(1);
00551               }
00552               break;
00553        }
00554 
00555        do_print_section(p, fp);
00556        if (fflush(fp) || ferror(fp))
00557        {
00558               perror("write");
00559               exit(1);
00560        }
00561        fclose(fp);
00562        free(f);
00563 }
00564 
00565 static void extract_pipe(struct rfc2045 *p,
00566        const char *filename,
00567        int argc, char **argv)
00568 {
00569 char   *f=get_suitable_filename(p, "FILENAME=", 0);
00570 int    pipefd[2];
00571 pid_t  pid, p2;
00572 FILE   *fp;
00573 int    waitstat;
00574 
00575        if (argc == 0)
00576        {
00577               fprintf(stderr, "reformime: Invalid -X option.\n");
00578               exit(1);
00579        }
00580 
00581        if (pipe(pipefd))
00582        {
00583               perror("pipe");
00584               exit(1);
00585        }
00586 
00587        if ((fp=fdopen(pipefd[1], "w")) == 0)
00588        {
00589               perror("fdopen");
00590               exit(1);
00591        }
00592 
00593        while ((pid=fork()) == -1)
00594        {
00595               sleep(2);
00596        }
00597 
00598        if (pid == 0)
00599        {
00600         const char *content_type_s;
00601         const char *content_transfer_encoding_s;
00602         const char *charset_s;
00603 
00604               if (!f)       f="FILENAME=attachment.dat";
00605               putenv(f);
00606               rfc2045_mimeinfo(p, &content_type_s,
00607                      &content_transfer_encoding_s, &charset_s);
00608               f=malloc(strlen(content_type_s)
00609                      +sizeof("CONTENT_TYPE="));
00610               if (!f)
00611               {
00612                      perror("malloc");
00613                      exit(1);
00614               }
00615               strcat(strcpy(f, "CONTENT_TYPE="), content_type_s);
00616               putenv(f);
00617               dup2(pipefd[0], 0);
00618               close(pipefd[0]);
00619               close(pipefd[1]);
00620               execv(argv[0], argv);
00621               perror("exec");
00622               _exit(1);
00623        }
00624        close(pipefd[0]);
00625        signal(SIGPIPE, SIG_IGN);
00626        do_print_section(p, fp);
00627        signal(SIGPIPE, SIG_DFL);
00628        fclose(fp);
00629        close(pipefd[1]);
00630 
00631        while ((p2=wait(&waitstat)) != pid && p2 != -1)
00632               ;
00633        free(f);
00634 
00635        if ((p2 == pid) && WIFEXITED(waitstat))
00636        {
00637               if (WEXITSTATUS(waitstat) != 0)
00638               {
00639                      fprintf(stderr, "reformime: %s exited with status %d.\n",
00640                             argv[0], WEXITSTATUS(waitstat));
00641                      exit(WEXITSTATUS(waitstat) + 20);
00642               }
00643        }
00644 }
00645 
00646 static void extract_section(struct rfc2045 *top_rfcp, const char *mimesection,
00647        const char *extract_filename, int argc, char **argv,
00648        void   (*extract_func)(struct rfc2045 *, const char *,
00649               int, char **))
00650 {
00651        if (mimesection)
00652        {
00653               top_rfcp=rfc2045_find(top_rfcp, mimesection);
00654               if (!mimesection)
00655                      notfound(mimesection);
00656               if (top_rfcp->firstpart)
00657               {
00658                      fprintf(stderr, "reformime: MIME section %s is a compound section.\n", mimesection);
00659                      exit(1);
00660               }
00661               (*extract_func)(top_rfcp, extract_filename, argc, argv);
00662               return;
00663        }
00664 
00665        /* Recursive */
00666 
00667        if (top_rfcp->firstpart)
00668        {
00669               for (top_rfcp=top_rfcp->firstpart; top_rfcp;
00670                      top_rfcp=top_rfcp->next)
00671                      extract_section(top_rfcp, mimesection,
00672                             extract_filename, argc, argv, extract_func);
00673               return;
00674        }
00675 
00676        if (!top_rfcp->isdummy)
00677               (*extract_func)(top_rfcp, extract_filename, argc, argv);
00678 }
00679 
00680 static void print_dsn_recip(char *addr, char *action)
00681 {
00682 char *p, *q;
00683 
00684        if (!action || !addr)
00685        {
00686               if (action)   free(action);
00687               if (addr)     free(addr);
00688               return;
00689        }
00690 
00691        for (p=action; *p; ++p)
00692               *p=tolower((int)(unsigned char)*p);
00693 
00694        for (p=addr; *p && isspace((int)(unsigned char)*p); ++p)
00695               ;
00696 
00697        if (strncasecmp(p, "rfc822;", 7))
00698        {
00699               free(action);
00700               free(addr);
00701               return;
00702        }
00703        for (q=action; *q && isspace((int)(unsigned char)*q); ++q)
00704               ;
00705        p += 7;
00706        while (*p && isspace((int)(unsigned char)*p))
00707               ++p;
00708        printf("%s %s\n", q, p);
00709        free(action);
00710        free(addr);
00711 }
00712 
00713 static void dsn(struct rfc2045 *p, int do_orig)
00714 {
00715 const char *content_type_s;
00716 const char *content_transfer_encoding_s;
00717 const char *charset_s;
00718 off_t start_pos, end_pos, start_body;
00719 off_t dummy;
00720 const char *q;
00721 char   buf[BUFSIZ];
00722 unsigned i;
00723 int    ch;
00724 char *recip;
00725 char *action;
00726 char *orecip;
00727 
00728        rfc2045_mimeinfo(p, &content_type_s, &content_transfer_encoding_s,
00729               &charset_s);
00730        if (strcasecmp(content_type_s, "multipart/report") ||
00731               (q=rfc2045_getattr(p->content_type_attr, "report-type")) == 0 ||
00732               strcasecmp(q, "delivery-status") ||
00733               !p->firstpart || !p->firstpart->next ||
00734               !p->firstpart->next->next)
00735               _exit(1);
00736        p=p->firstpart->next->next;
00737        rfc2045_mimeinfo(p, &content_type_s, &content_transfer_encoding_s,
00738               &charset_s);
00739        rfc2045_mimepos(p, &start_pos, &end_pos, &start_body, &dummy, &dummy);
00740        if (strcasecmp(content_type_s, "message/delivery-status") ||
00741               fseek(stdin, start_body, SEEK_SET) == -1)
00742               _exit(1);
00743 
00744        i=0;
00745        recip=0;
00746        orecip=0;
00747        action=0;
00748        while (start_body < end_pos)
00749        {
00750               if ((ch=getchar()) == EOF)  break;
00751               ++start_body;
00752               if (i < sizeof(buf)-1)
00753                      buf[i++]= ch;
00754               if (ch != '\n')      continue;
00755               ch=getchar();
00756               if (ch != EOF)       ungetc(ch, stdin);
00757               if (ch != '\n' && isspace((int)(unsigned char)ch))
00758                      continue;
00759               buf[i-1]=0;
00760               if (buf[0] == 0)
00761               {
00762                      if (orecip)
00763                      {
00764                             if (recip)    free(recip);
00765                             recip=orecip;
00766                             orecip=0;
00767                      }
00768                      print_dsn_recip(recip, action);
00769                      recip=0;
00770                      action=0;
00771               }
00772               if (strncasecmp(buf, "Final-Recipient:", 16) == 0 &&
00773                      recip == 0)
00774               {
00775                      recip=strdup(buf+16);
00776                      if (!recip)
00777                      {
00778                             perror("strdup");
00779                             exit(2);
00780                      }
00781               }
00782               if (strncasecmp(buf, "Original-Recipient:", 19) == 0 &&
00783                      orecip == 0 && do_orig)
00784               {
00785                      orecip=strdup(buf+19);
00786                      if (!orecip)
00787                      {
00788                             perror("strdup");
00789                             exit(2);
00790                      }
00791               }
00792               if (strncasecmp(buf, "Action:", 7) == 0 && action == 0)
00793               {
00794                      action=strdup(buf+7);
00795                      if (!action)
00796                      {
00797                             perror("strdup");
00798                             exit(2);
00799                      }
00800               }
00801               i=0;
00802        }
00803        if (orecip)
00804        {
00805               if (recip)    free(recip);
00806               recip=orecip;
00807               orecip=0;
00808        }
00809        print_dsn_recip(recip, action);
00810 }
00811 
00812 static void mimedigest1(int, char **);
00813 static char mimebuf[BUFSIZ];
00814 
00815 static void mimedigest(int argc, char **argv)
00816 {
00817 char   *p;
00818 struct filelist { struct filelist *next; char *fn; } *first=0, *last=0;
00819 unsigned pcnt=0;
00820 char   **l;
00821 
00822        if (argc > 0)
00823        {
00824               mimedigest1(argc, argv);
00825               return;
00826        }
00827 
00828        while (fgets(mimebuf, sizeof(mimebuf), stdin))
00829        {
00830        struct filelist *q;
00831 
00832               if ((p=strchr(mimebuf, '\n')) != 0)       *p=0;
00833               q=malloc(sizeof(struct filelist));
00834               if (!q || !(q->fn=strdup(mimebuf)))
00835               {
00836                      perror("malloc");
00837                      exit(1);
00838               }
00839 
00840               if (last)     last->next=q;
00841               else   first=q;
00842               last=q;
00843               q->next=0;
00844               ++pcnt;
00845        }
00846        if (pcnt == 0)       return;
00847 
00848        if ( (l=malloc(sizeof (char *) * pcnt)) == 0)
00849        {
00850               perror("malloc");
00851        }
00852        pcnt=0;
00853 
00854        for (last=first; last; last=last->next)
00855               l[pcnt++]=last->fn;
00856 
00857        mimedigest1(pcnt, l);
00858 }
00859 
00860 static void mimedigest1(int argc, char **argv)
00861 {
00862 time_t t;
00863 char   boundarybuf[200];
00864 unsigned boundarycnt=0;
00865 int    i;
00866 FILE   *fp;
00867 
00868        time (&t);
00869 
00870        /* Search for a suitable boundary */
00871 
00872        do
00873        {
00874        int    l;
00875 
00876               sprintf(boundarybuf, "reformime_%lu_%u",
00877                      (unsigned long)t, ++boundarycnt);
00878 
00879               l=strlen(boundarybuf);
00880 
00881               for (i=0; i<argc; i++)
00882               {
00883               int    err=0;
00884 
00885                      if ((fp=fopen(argv[i], "r")) == 0)
00886                      {
00887                             perror(argv[i]);
00888                             exit(1);
00889                      }
00890 
00891                      while (fgets(mimebuf, sizeof(mimebuf), fp))
00892                      {
00893                             if (mimebuf[0] != '-' || mimebuf[1] != '-')
00894                                    continue;
00895 
00896                             if (strncasecmp(mimebuf+2, boundarybuf, l) == 0)
00897                             {
00898                                    err=1;
00899                                    break;
00900                             }
00901                      }
00902                      fclose(fp);
00903                      if (err)      break;
00904               }
00905        } while (i < argc);
00906               
00907        printf("Mime-Version:1.0\n"
00908               "Content-Type: multipart/digest; boundary=\"%s\"\n\n%s",
00909                      boundarybuf, RFC2045MIMEMSG);
00910 
00911        for (i=0; i<argc; i++)
00912        {
00913               if ((fp=fopen(argv[i], "r")) == 0)
00914               {
00915                      perror(argv[i]);
00916                      exit(1);
00917               }
00918 
00919               printf("\n--%s\nContent-Type: message/rfc822\n\n",
00920                      boundarybuf);
00921 
00922               while (fgets(mimebuf, sizeof(mimebuf), fp))
00923                      printf("%s", mimebuf);
00924               fclose(fp);
00925        }
00926 
00927        printf("\n--%s--\n", boundarybuf);
00928 }
00929 
00930 static void display_decoded_header(const char *ptr, size_t cnt, void *dummy)
00931 {
00932        if (cnt == 0)
00933               putchar('\n');
00934        else
00935               fwrite(ptr, cnt, 1, stdout);
00936 }
00937 
00938 static int doconvtoutf8_stdout(const char *ptr, size_t n, void *dummy)
00939 {
00940        if (fwrite(ptr, n, 1, stdout) != 1)
00941               return -1;
00942 
00943        return 0;
00944 }
00945 
00946 static int main2(const char *mimecharset, int argc, char **argv)
00947 {
00948 int    argn;
00949 char   optc;
00950 char   *optarg;
00951 char   *mimesection=0;
00952 char   *section=0;
00953 int    doinfo=0, dodecode=0, dorewrite=0, dodsn=0, domimedigest=0;
00954 int    dodecodehdr=0, dodecodeaddrhdr=0, doencodemime=0, doencodemimehdr=0;
00955 
00956 char   *decode_header="";
00957 struct rfc2045 *p;
00958 int    rwmode=0;
00959 int     convtoutf8=0;
00960 int    dovalidate=0;
00961 void   (*do_extract)(struct rfc2045 *, const char *, int, char **)=0;
00962 const char *extract_filename=0;
00963 int rc=0;
00964 
00965 
00966        rfc2045_in_reformime=1;
00967 
00968        for (argn=1; argn<argc; )
00969        {
00970               if (argv[argn][0] != '-')   break;
00971               optarg=0;
00972               optc=argv[argn][1];
00973               if (optc && argv[argn][2])  optarg=argv[argn]+2;
00974               ++argn;
00975               switch (optc) {
00976               case 'c':
00977                      if (!optarg && argn < argc)
00978                             optarg=argv[argn++];
00979                      if (optarg && *optarg)
00980                      {
00981                             char *p=libmail_u_convert_tobuf("",
00982                                                         optarg,
00983                                                         libmail_u_ucs4_native,
00984                                                         NULL);
00985 
00986                             if (!p)
00987                             {
00988                                    fprintf(stderr, "Unknown charset: %s\n",
00989                                           optarg);
00990                                    exit(1);
00991                             }
00992                             free(p);
00993                             mimecharset=optarg;
00994                      }
00995                      break;
00996 
00997               case 's':
00998                      if (!optarg && argn < argc)
00999                             optarg=argv[argn++];
01000                      if (optarg && *optarg)      section=strdup(optarg);
01001                      break;
01002               case 'i':
01003                      doinfo=1;
01004                      break;
01005               case 'e':
01006                      dodecode=1;
01007                      break;
01008               case 'r':
01009                      dorewrite=1;
01010                      if (optarg && *optarg == '7')
01011                             rwmode=RFC2045_RW_7BIT;
01012                      if (optarg && *optarg == '8')
01013                             rwmode=RFC2045_RW_8BIT;
01014                      break;
01015               case 'm':
01016                      domimedigest=1;
01017                      break;
01018               case 'd':
01019                      dodsn=1;
01020                      break;
01021               case 'D':
01022                      dodsn=2;
01023                      break;
01024               case 'x':
01025                      do_extract=extract_file;
01026                      if (optarg)
01027                             extract_filename=optarg;
01028                      break;
01029               case 'X':
01030                      do_extract=extract_pipe;
01031                      break;
01032               case 'V':
01033                      dovalidate=1;
01034                      break;
01035               case 'h':
01036                      if (!optarg && argn < argc)
01037                             optarg=argv[argn++];
01038                      if (optarg)
01039                      {
01040                             decode_header=optarg;
01041                      }
01042                      dodecodehdr=1;
01043                      break;
01044               case 'H':
01045                      if (!optarg && argn < argc)
01046                             optarg=argv[argn++];
01047                      if (optarg)
01048                      {
01049                             decode_header=optarg;
01050                      }
01051                      dodecodeaddrhdr=1;
01052                      break;
01053               case 'o':
01054                      if (!optarg && argn < argc)
01055                             optarg=argv[argn++];
01056                      if (optarg)
01057                      {
01058                             decode_header=optarg;
01059                      }
01060                      doencodemime=1;
01061                      break;
01062               case 'O':
01063                      if (!optarg && argn < argc)
01064                             optarg=argv[argn++];
01065                      if (optarg)
01066                      {
01067                             decode_header=optarg;
01068                      }
01069                      doencodemimehdr=1;
01070                      break;
01071               case 'u':
01072                      convtoutf8=1;
01073                      break;
01074               default:
01075                      usage();
01076               }
01077        }
01078 
01079        defchset=mimecharset;
01080 
01081        rfc2045_setdefaultcharset(defchset);
01082 
01083        if (domimedigest)
01084        {
01085               mimedigest(argc-argn, argv+argn);
01086               return (0);
01087        }
01088        else if (dodecodehdr)
01089        {
01090               if (rfc822_display_hdrvalue("Subject",
01091                                        decode_header,
01092                                        mimecharset,
01093                                        display_decoded_header,
01094                                        NULL,
01095                                        NULL) < 0)
01096               {
01097                      perror("rfc822_display_hdrvalue");
01098                      return (1);
01099               }
01100 
01101               printf("\n");
01102               return (0);
01103        }
01104        else if (dodecodeaddrhdr)
01105        {
01106               if (rfc822_display_hdrvalue("To",
01107                                        decode_header,
01108                                        mimecharset,
01109                                        display_decoded_header,
01110                                        NULL,
01111                                        NULL) < 0)
01112               {
01113                      perror("rfc822_display_hdrvalue");
01114                      return (1);
01115               }
01116 
01117               printf("\n");
01118               return (0);
01119        }
01120 
01121        if (doencodemime)
01122        {
01123               char *s=rfc2047_encode_str(decode_header, mimecharset,
01124                                       rfc2047_qp_allow_any);
01125 
01126               if (s)
01127               {
01128                      printf("%s\n", s);
01129                      free(s);
01130               }
01131               return (0);
01132        }
01133        if (doencodemimehdr)
01134        {
01135               struct rfc822t *t=rfc822t_alloc_new(decode_header, NULL, NULL);
01136               struct rfc822a *a=t ? rfc822a_alloc(t):NULL;
01137               char *s;
01138 
01139               if (a && (s=rfc2047_encode_header_addr(a, mimecharset)) != NULL)
01140               {
01141                      printf("%s\n", s);
01142                      free(s);
01143               }
01144 
01145               if (a) rfc822a_free(a);
01146               if (t) rfc822t_free(t);
01147               return (0);
01148        }
01149 
01150        p=read_message();
01151 
01152        if (doinfo)
01153        {
01154               mimesection = section ? strtok(section, ","):NULL;
01155               do {
01156                      print_info(p, mimesection);
01157                      if (do_extract)
01158                             extract_section(p, mimesection,
01159                                           extract_filename, argc-argn,
01160                                           argv+argn, do_extract);
01161                      if (mimesection)
01162                             mimesection = strtok(NULL,",");
01163               } while (mimesection != NULL);
01164        }
01165        else if (dodecode)
01166        {
01167               mimesection = strtok(section,",");
01168               do {
01169                      print_decode(p, mimesection);
01170                      mimesection = strtok(NULL,",");
01171               } while (mimesection != NULL);
01172        }
01173        else if (dorewrite)
01174               rewrite(p, rwmode);
01175        else if (dodsn)
01176               dsn(p, dodsn == 2);
01177        else if (do_extract)
01178        {
01179               mimesection = strtok(section,",");
01180               do {
01181                      extract_section(p, mimesection, extract_filename,
01182                                    argc-argn, argv+argn, do_extract);
01183                      mimesection = strtok(NULL,",");
01184               } while (mimesection != NULL);
01185        }
01186        else if (dovalidate)
01187        {
01188               rc=1;
01189 
01190               if (p->rfcviolation & RFC2045_ERR2COMPLEX)
01191                      printf("ERROR: MIME complexity.\n");
01192               else if (p->rfcviolation & RFC2045_ERRBADBOUNDARY)
01193                      printf("ERROR: Ambiguous  MIME boundary delimiters.\n");
01194               else rc=0;
01195 
01196        }
01197        else if (convtoutf8)
01198        {
01199               struct rfc2045src *src;
01200               struct rfc2045_decodemsgtoutf8_cb cb;
01201 
01202               memset(&cb, 0, sizeof(cb));
01203 
01204               cb.output_func=doconvtoutf8_stdout;
01205               cb.arg=NULL;
01206 
01207               src=rfc2045src_init_fd(0);
01208 
01209               if (src)
01210               {
01211                      rfc2045_decodemsgtoutf8(src, p, &cb);
01212                      rfc2045src_deinit(src);
01213               }
01214        }
01215        else
01216               print_structure(p);
01217        rfc2045_free(p);
01218        exit(rc);
01219        return (rc);
01220 }
01221 
01222 int main(int argc, char **argv)
01223 {
01224        int    rc;
01225 
01226        rc=main2(unicode_default_chset(), argc, argv);
01227        return rc;
01228 }