Back to index

courier  0.68.2
faxconvert.c
Go to the documentation of this file.
00001 /*
00002 ** Copyright 2002-2009 Double Precision, Inc.
00003 ** See COPYING for distribution information.
00004 */
00005 
00006 #include "config.h"
00007 #include "courier.h"
00008 #include "faxconvert.h"
00009 #include "comfax.h"
00010 #include <stdio.h>
00011 #include <stdlib.h>
00012 #include <fcntl.h>
00013 #include <unistd.h>
00014 #include <errno.h>
00015 #include <signal.h>
00016 
00017 #include "rfc822/rfc822.h"
00018 #include "rfc822/rfc822hdr.h"
00019 #include "rfc822/rfc2047.h"
00020 #include "rfc2045/rfc2045.h"
00021 #include "rfc2045/rfc2045charset.h"
00022 #include "numlib/numlib.h"
00023 #include "gpglib/gpglib.h"
00024 #include "unicode/unicode.h"
00025 
00026 #include <sys/types.h>
00027 #include <sys/stat.h>
00028 #if HAVE_SYS_WAIT_H
00029 #include <sys/wait.h>
00030 #endif
00031 #ifndef WEXITSTATUS
00032 #define WEXITSTATUS(stat_val) ((unsigned)(stat_val) >> 8)
00033 #endif
00034 #ifndef WIFEXITED
00035 #define WIFEXITED(stat_val) (((stat_val) & 255) == 0)
00036 #endif
00037 
00038 #if HAVE_DIRENT_H
00039 #include <dirent.h>
00040 #define NAMLEN(dirent) strlen((dirent)->d_name)
00041 #else
00042 #define dirent direct
00043 #define NAMLEN(dirent) (dirent)->d_namlen
00044 #if HAVE_SYS_NDIR_H
00045 #include <sys/ndir.h>
00046 #endif
00047 #if HAVE_SYS_DIR_H
00048 #include <sys/dir.h>
00049 #endif
00050 #if HAVE_NDIR_H
00051 #include <ndir.h>
00052 #endif
00053 #endif
00054 
00055 
00056 #include "filterbindir.h"
00057 #include "faxtmpdir.h"
00058 
00059 #define SUBTMPDIR FAXTMPDIR "/.tmp"
00060 
00061 void rfc2045_error(const char *errmsg)
00062 {
00063        fprintf(stderr, "faxconvert: %s\n", errmsg);
00064        exit(1);
00065 }
00066 
00067 struct faxconvert_info {
00068        int fd;
00069        unsigned partnum;
00070        struct rfc2045 *topp;
00071        int npages;
00072        int flags;
00073 
00074        struct rfc2045 *cover_page_part;
00075        int cover_page_fd;
00076 
00077        struct faxconvert_unknown_list *unknown_list;
00078 } ;
00079 
00080 struct faxconvert_unknown_list {
00081        struct faxconvert_unknown_list *next;
00082        char *content_type;
00083 } ;
00084 
00085 /*
00086 ** Remove a directory's contents.
00087 */
00088 
00089 void rmdir_contents(const char *dir)
00090 {
00091        DIR *p=opendir(dir);
00092        struct dirent *de;
00093 
00094        if (!p)
00095               return;
00096 
00097        while ((de=readdir(p)) != 0)
00098        {
00099               char *b;
00100               const char *c=de->d_name;
00101 
00102               if (strcmp(c, ".") == 0 || strcmp(c, "..") == 0)
00103                      continue;
00104 
00105               b=courier_malloc(strlen(dir) + strlen(c) + 2);
00106 
00107               strcat(strcat(strcpy(b, dir), "/"), c);
00108               unlink(b);
00109               free(b);
00110        }
00111        closedir(p);
00112 }
00113 
00114 static int faxconvert_recursive(struct rfc2045 *, struct faxconvert_info *);
00115 static int convert_cover_page(struct rfc2045 *, struct faxconvert_info *,
00116                            int, int *);
00117 
00118 int faxconvert(const char *filename, int flags, int *ncoverpages)
00119 {
00120        int fd=open(filename, O_RDONLY);
00121        struct rfc2045 *rfc2045p;
00122        int rc;
00123        struct faxconvert_info info;
00124 
00125        /* Open the MIME message, and parse it */
00126 
00127        if (fd < 0)
00128        {
00129               perror(filename);
00130               return (-1);
00131        }
00132 
00133        if (fcntl(fd, F_SETFD, FD_CLOEXEC) < 0)   /* I'm a lazy SOB */
00134        {
00135               perror(filename);
00136               close(fd);
00137               return (-1);
00138        }
00139 
00140        rfc2045p=rfc2045_fromfd(fd);
00141 
00142        if (!rfc2045p)
00143        {
00144               perror(filename);
00145               return (-1);
00146        }
00147 
00148        /*
00149        ** Ok, clean out SUBTMPDIR and FAXTMPDIR.  We run each filter and tell
00150        ** it to spit its output into SUBTMPDIR, then, we scan SUBTMPDIR,
00151        ** pick up whatever we find there, and move it to FAXTMPDIR.
00152        */
00153 
00154        rmdir_contents( SUBTMPDIR );
00155        rmdir_contents( FAXTMPDIR);
00156 
00157        info.topp=rfc2045p;
00158        info.fd=fd;
00159        info.partnum=0;
00160        info.cover_page_part=NULL;
00161        info.cover_page_fd= -1;
00162        info.npages=0;
00163        info.unknown_list=0;
00164        info.flags=flags;
00165        rc=faxconvert_recursive(rfc2045p, &info);
00166 
00167        /* Generate a cover page, now */
00168 
00169        if (rc == 0)
00170        {
00171               if (info.cover_page_part == NULL)
00172               {
00173                      fprintf(stderr, "Error: no cover page (empty document)?\n");
00174                      rc= -1;
00175               }
00176               else
00177               {
00178                      rc= convert_cover_page(info.cover_page_part,
00179                                           &info,
00180                                           info.cover_page_fd,
00181                                           ncoverpages);
00182               }
00183        }
00184 
00185        rfc2045_free(rfc2045p);
00186        close(fd);
00187        rmdir_contents(SUBTMPDIR);
00188        return (rc);
00189 }
00190 
00191 /*
00192 ** Recursively parse the message's MIME structure, and convert each MIME
00193 ** section to FAX format.
00194 */
00195 
00196 static int start_filter(const char *, pid_t *);
00197 static int end_filter(const char *, pid_t);
00198 
00199 static int decode_filter(const char *, size_t, void *);
00200 
00201 static int do_filter(struct rfc2045 *, const char *, int,
00202                    struct faxconvert_info *, int);
00203 
00204 /* Determine if we have a filter for the given content type */
00205 
00206 static char *get_filter_prog(const char *content_type)
00207 {
00208        char *filterprog, *p;
00209        const char *dummy;
00210 
00211        /*
00212        ** The name of each filter is just its MIME type, with / and .
00213        ** replaced by -, and with '.filter' appended.
00214        */
00215 
00216        filterprog=courier_malloc(strlen(content_type)
00217                               +sizeof(FILTERBINDIR)+20);
00218 
00219        strcpy(filterprog, FILTERBINDIR "/");
00220 
00221        p=filterprog+sizeof(FILTERBINDIR);
00222        for (dummy=content_type; *dummy; dummy++)
00223        {
00224               *p++ = *dummy == '.' || *dummy == '/' ? '-':*dummy;
00225        }
00226        *p=0;
00227        strcat(filterprog, ".filter");
00228 
00229        if (access(filterprog, X_OK) < 0)
00230        {
00231               free(filterprog);
00232               filterprog=NULL;
00233        }
00234        return (filterprog);
00235 }
00236 
00237 static int faxconvert_recursive(struct rfc2045 *m,
00238                              struct faxconvert_info *info)
00239 {
00240        const char *content_type, *dummy;
00241        char *filterprog;
00242        int rc;
00243 
00244        rfc2045_mimeinfo(m, &content_type, &dummy, &dummy);
00245 
00246        if (strcmp(content_type, "multipart/mixed") == 0)
00247        {
00248               /* Spit out all attachments, one after another */
00249 
00250               for (m=m->firstpart; m; m=m->next)
00251               {
00252                      if (m->isdummy)
00253                             continue;
00254 
00255                      rc=faxconvert_recursive(m, info);
00256                      if (rc)
00257                             return (rc);
00258               }
00259               return (0);
00260        }
00261 
00262        if (strcmp(content_type, "multipart/alternative") == 0)
00263        {
00264               struct rfc2045 *bestm=NULL;
00265 
00266               /* Search for MIME content we understand */
00267 
00268               for (m=m->firstpart; m; m=m->next)
00269               {
00270                      const char *content_type, *dummy;
00271 
00272                      if (m->isdummy)
00273                             continue;
00274 
00275                      rfc2045_mimeinfo(m, &content_type, &dummy, &dummy);
00276 
00277                      if (strncasecmp(content_type, "multipart/", 10) ||
00278                          get_filter_prog(content_type))
00279                             bestm=m;
00280               }
00281 
00282               if (bestm)
00283                      return ( faxconvert_recursive(bestm, info));
00284        }
00285 
00286        if (strcmp(content_type, "multipart/related") == 0)
00287        {
00288               char *sid=rfc2045_related_start(m);
00289               struct rfc2045 *q;
00290 
00291               /* Punt - find the main content, and hope for the best */
00292 
00293               for (q=m->firstpart; q; q=q->next)
00294               {
00295                      const char *cid;
00296 
00297                      if (q->isdummy)      continue;
00298 
00299                      cid=rfc2045_content_id(q);
00300 
00301                      if (sid && *sid && strcmp(sid, cid))
00302                      {
00303                             struct rfc2045 *qq;
00304 
00305                             qq=libmail_gpgmime_is_multipart_signed(q);
00306 
00307                             if (!qq) continue;
00308 
00309                             /* Don't give up just yet */
00310 
00311                             cid=rfc2045_content_id(qq);
00312 
00313                             if (sid && *sid && strcmp(sid, cid))
00314                                    continue;
00315                      }
00316                      break;
00317               }
00318               if (sid)      free(sid);
00319 
00320               if (q)
00321                      return ( faxconvert_recursive(q, info));
00322        }
00323 
00324        if (strcmp(content_type, "multipart/signed") == 0)
00325        {
00326               struct rfc2045 *q;
00327 
00328               /* Punt - ignore the signature */
00329 
00330               for (q=m->firstpart; q; q=q->next)
00331               {
00332                      if (q->isdummy)      continue;
00333 
00334                      break;
00335               }
00336 
00337               if (q)
00338                      return ( faxconvert_recursive(q, info));
00339        }
00340 
00341        if (info->partnum == 0)     /* Cover page? */
00342        {
00343               if (strcmp(content_type, "text/plain") == 0)
00344               {
00345                      /* Yes - we have text/plain content */
00346 
00347                      ++info->partnum;
00348                      info->cover_page_part=m;
00349                      info->cover_page_fd=info->fd;
00350                      return (0);
00351               }
00352 
00353               /* No - too bad */
00354 
00355               info->cover_page_part=m;
00356               info->cover_page_fd= -1;
00357               ++info->partnum;
00358        }
00359        else if (info->flags & FAX_COVERONLY)
00360               return (0);   /* Ignore the rest of the message */
00361 
00362        filterprog=get_filter_prog(content_type);
00363 
00364        if (!filterprog && !(info->flags & FAX_OKUNKNOWN))
00365        {
00366 
00367               fprintf(stderr,
00368                      "This message contains an attachment with the document type of\n"
00369                      "\"%s\".  This document type cannot be faxed.\n",
00370                      content_type);
00371               return (-1);
00372        }
00373 
00374        if (!filterprog)
00375        {
00376               struct faxconvert_unknown_list *l, **p;
00377 
00378               if ((l=malloc(sizeof(*l))) == NULL ||
00379                   (l->content_type=strdup(content_type)) == NULL)
00380               {
00381                      perror("malloc");
00382                      exit(1);
00383               }
00384 
00385               for (p= &info->unknown_list; *p; p=&(*p)->next)
00386                      ;
00387 
00388               *p=l;
00389               l->next=NULL;
00390               rc=0;
00391        }
00392        else
00393        {
00394               rc=do_filter(m, filterprog, info->fd, info, 0);
00395               free(filterprog);
00396        }
00397        ++info->partnum;
00398        return (rc);
00399 }
00400 
00401 static int cmp_flist(const void *a, const void *b)
00402 {
00403        return (strcmp( (*(struct sort_file_list **)a)->filename,
00404                      (*(struct sort_file_list **)b)->filename));
00405 }
00406 
00407 /*
00408 ** Read all non-hidden entries in a directory.  Return the list in
00409 ** sorted order.
00410 */
00411 
00412 struct sort_file_list *read_dir_sort_filenames(const char *dirname,
00413                                           const char *fnpfix)
00414 {
00415        struct sort_file_list *l=NULL, **ll, *lll;
00416        unsigned cnt=0, i;
00417        DIR *dirp;
00418 
00419        if ((dirp=opendir(dirname)) != NULL)
00420        {
00421               struct dirent *de;
00422 
00423               while ((de=readdir(dirp)) != NULL)
00424               {
00425                      if (de->d_name[0] == '.')
00426                             continue;
00427 
00428                      lll=(struct sort_file_list *)
00429                             courier_malloc(sizeof(struct sort_file_list)
00430                                           + 1 + strlen(fnpfix)
00431                                           + strlen(de->d_name));
00432 
00433                      strcat(strcpy(lll->filename=(char *)(lll+1),
00434                                   fnpfix), de->d_name);
00435                      lll->next=l;
00436                      l=lll;
00437                      ++cnt;
00438               }
00439               closedir(dirp);
00440        }
00441        if (!cnt)
00442               return (NULL);
00443 
00444        ll=(struct sort_file_list **)courier_malloc(sizeof(l) * cnt);
00445        cnt=0;
00446        for (lll=l; lll; lll=lll->next)
00447               ll[cnt++]=lll;
00448        qsort(ll, cnt, sizeof(*ll), cmp_flist);
00449 
00450        l=ll[0];
00451        l->next=NULL;
00452 
00453        for (i=1; i<cnt; i++)
00454        {
00455               ll[i-1]->next=ll[i];
00456               ll[i]->next=NULL;
00457        }
00458        free(ll);
00459        return (l);
00460 }
00461 
00462 /*
00463 ** Convert a single MIME section into FAX format, by running the appropriate
00464 ** filter.
00465 */
00466 
00467 static int do_filter(struct rfc2045 *m,          /* The MIME section */
00468                    const char *filterprog,       /* The filter */
00469                    int fd,                /* The message */
00470                    struct faxconvert_info *info, /* Housekeeping */
00471                    int is_cover_page)     /* We're generated text/plain cover */
00472 {
00473        pid_t pidnum=0;
00474        int filter_fd;
00475        off_t start_pos, start_body, end_pos, dummy2;
00476        int n, rc;
00477        struct sort_file_list *l, *ll;
00478 
00479        char filenamebuf[sizeof(FAXTMPDIR)+NUMBUFSIZE*2+60];
00480 
00481        filter_fd=start_filter(filterprog, &pidnum);
00482        if (filter_fd < 0)
00483               return (-1);
00484 
00485        if (is_cover_page)
00486               while (info->unknown_list != 0)
00487               {
00488                      char *buf;
00489 
00490                      static const char msg[]="Document type \"%s\" cannot be faxed\n"
00491                             "----------------------------------------------------------------\n\n";
00492                      struct faxconvert_unknown_list *u=info->unknown_list;
00493 
00494                      info->unknown_list=u->next;
00495 
00496                      buf=malloc(sizeof(msg) + strlen(u->content_type));
00497                      if (!buf)
00498                      {
00499                             perror("malloc");
00500                             return (-1);
00501                      }
00502                      sprintf(buf, msg, u->content_type);
00503                      free(u->content_type);
00504                      free(u);
00505 
00506                      decode_filter(buf, strlen(buf), &filter_fd);
00507               }
00508 
00509        if (fd >= 0)  /* See convert_cover_page() */
00510        {
00511               /*
00512               ** Decode the MIME section, push the decoded data to the
00513               ** filtering script.
00514               */
00515               rfc2045_mimepos(m, &start_pos, &end_pos, &start_body, &dummy2,
00516                             &dummy2);
00517 
00518               rfc2045_cdecode_start(m, decode_filter, &filter_fd);
00519 
00520               if (lseek(fd, start_body, SEEK_SET) < 0)
00521               {
00522                      perror("seek");
00523                      close(filter_fd);
00524                      end_filter(filterprog, pidnum);
00525                      return (-1);
00526               }
00527 
00528               while (start_body < end_pos)
00529               {
00530                      char buffer[BUFSIZ];
00531                      int n=read(fd, buffer,
00532                                end_pos - start_body < BUFSIZ
00533                                ? end_pos - start_body:BUFSIZ);
00534 
00535                      if (n == 0)
00536                             errno=EIO;
00537                      if (n <= 0)
00538                      {
00539                             perror("read");
00540                             close(filter_fd);
00541                             end_filter(filterprog, pidnum);
00542                             return (-1);
00543                      }
00544 
00545                      start_body += n;
00546                      n=rfc2045_cdecode(m, buffer, n);
00547                      if (n)
00548                      {
00549                             close(filter_fd);
00550                             end_filter(filterprog, pidnum);
00551                             return (n);
00552                      }
00553               }
00554 
00555               n=rfc2045_cdecode_end(m);
00556               if (n)
00557               {
00558                      close(filter_fd);
00559                      end_filter(filterprog, pidnum);
00560                      return (n);
00561               }
00562        }
00563 
00564        close(filter_fd);
00565        n=end_filter(filterprog, pidnum);
00566        if (n)
00567               return (n);
00568 
00569        /*
00570        ** Read the filter's results, sort them, compile them.
00571        */
00572 
00573        l=read_dir_sort_filenames(SUBTMPDIR, "");
00574 
00575        if (!l)
00576        {
00577               fprintf(stderr, "%s: failed to convert input data.\n",
00578                      filterprog);
00579               return (-1);
00580        }
00581 
00582        n=0;
00583 
00584        rc=0;
00585        while (l)
00586        {
00587               char *p;
00588 
00589               sprintf(filenamebuf, "%s/f%04d-%04d.g3", FAXTMPDIR,
00590                      info->partnum, ++n);
00591 
00592               p=courier_malloc(sizeof(SUBTMPDIR) + 1 + strlen(l->filename));
00593               strcat(strcpy(p, SUBTMPDIR "/"), l->filename);
00594 
00595               if (rename(p, filenamebuf))
00596               {
00597                      perror(p);
00598                      rc= -1;
00599               }
00600               free(p);
00601               ll=l->next;
00602               free(l);
00603               l=ll;
00604               ++info->npages;
00605        }
00606        return (rc);
00607 }
00608 
00609 /*
00610 ** Start the filter process as a child process.
00611 */
00612 
00613 static int start_filter(const char *prog, pid_t *pidptr)
00614 {
00615        pid_t p;
00616        int pipefd[2];
00617 
00618        /* Prepare an empty directory for the filter. */
00619 
00620        rmdir_contents(SUBTMPDIR);
00621        mkdir(SUBTMPDIR, 0700);
00622 
00623        if (pipe(pipefd) < 0)
00624        {
00625               perror("pipe");
00626               return (-1);
00627        }
00628 
00629        p=fork();
00630        if (p < 0)
00631        {
00632               close(pipefd[0]);
00633               close(pipefd[1]);
00634               perror("fork");
00635               return (-1);
00636        }
00637 
00638        if (p == 0)
00639        {
00640               close(0);
00641               if (dup(pipefd[0]) < 0)
00642               {
00643                      perror("dup");
00644                      exit(1);
00645               }
00646               close(pipefd[0]);
00647               close(pipefd[1]);
00648               execl(prog, prog, SUBTMPDIR, (char *)NULL);
00649               perror(prog);
00650               exit(1);
00651        }
00652 
00653        *pidptr=p;
00654        close(pipefd[0]);
00655        return (pipefd[1]);
00656 }
00657 
00658 
00659 /*
00660 ** Helper function writes MIME-decoded content to the filter process.
00661 */
00662 
00663 static int decode_filter(const char *p, size_t n, void *vp)
00664 {
00665        int fd=*(int *)vp;
00666 
00667        while (n)
00668        {
00669               int k=write(fd, p, n);
00670 
00671               if (k == 0)
00672                      errno=EIO;
00673               if (k <= 0)
00674               {
00675                      perror("write");
00676                      return (-1);
00677               }
00678 
00679               p += k;
00680               n -= k;
00681        }
00682        return (0);
00683 }
00684 
00685 /*
00686 ** Wait for the filter process to finish, return its exit status.
00687 */
00688 
00689 static int end_filter(const char *filterprog, pid_t p)
00690 {
00691        int waitstat;
00692        pid_t p2;
00693 
00694        while ((p2=wait(&waitstat)) != p)
00695        {
00696               if (p2 >= 0)
00697                      continue;
00698               if (errno != EINTR)
00699               {
00700                      perror("wait");
00701                      return (-1);
00702               }
00703        }
00704 
00705        if (WIFEXITED(waitstat))
00706        {
00707               waitstat=WEXITSTATUS(waitstat);
00708 
00709               if (waitstat == 0)
00710                      return (0);
00711        }
00712 
00713        fprintf(stderr, "%s: terminated with exit status %d\n",
00714               filterprog, waitstat);
00715        return (-1);
00716 }
00717 
00718 /*
00719 ** Generate cover page.
00720 */
00721 
00722 static char *convnames(const char *);
00723 
00724 static int convert_cover_page(struct rfc2045 *rfcp,
00725                            struct faxconvert_info *info,
00726                            int fd, int *ncoverpages)
00727      /*
00728      ** fd >= 0 if there's initial text/plain content that can go on the
00729      ** cover page.  fd < 0 if there is no text/plain content to go on the
00730      ** cover page.
00731      */
00732 {
00733        int fd2;
00734        FILE *fp;
00735        struct rfc822hdr hbuf;
00736        off_t start_pos, start_body, end_pos, dummy2;
00737        char *hfrom=NULL, *hto=NULL, *hdate=NULL, *hsubject=NULL, *p;
00738        size_t save_pages;
00739        int rc;
00740 
00741        char npages[NUMBUFSIZE];
00742        
00743        if ((fd2=dup(info->fd)) < 0)
00744        {
00745               perror("dup");
00746               return (-1);
00747        }
00748 
00749        rfc2045_mimepos(info->topp, &start_pos, &end_pos, &start_body, &dummy2,
00750                      &dummy2);
00751 
00752        if ((fp=fdopen(fd2, "r")) == NULL
00753            || fseek(fp, start_pos, SEEK_SET) < 0)
00754        {
00755               if (fp)
00756                      fclose(fp);
00757               close(fd2);
00758               perror("fdopen");
00759               return (-1);
00760        }
00761 
00762        /*
00763        ** Read the message's headers, use it to create the cover page.
00764        */
00765 
00766        rfc822hdr_init(&hbuf, BUFSIZ);
00767        while (rfc822hdr_read(&hbuf, fp, &start_pos, start_body) == 0)
00768        {
00769               rfc822hdr_fixname(&hbuf);
00770               rfc822hdr_collapse(&hbuf);
00771 
00772               if (strcmp(hbuf.header, "from") == 0)
00773               {
00774                      if (hfrom)
00775                             free(hfrom);
00776                      hfrom=strcpy(courier_malloc(strlen(hbuf.value)+1),
00777                                  hbuf.value);
00778               }
00779 
00780               if (strcmp(hbuf.header, "to") == 0 ||
00781                   strcmp(hbuf.header, "cc") == 0)
00782               {
00783                      if (hto)
00784                      {
00785                             p=courier_malloc(strlen(hto)+
00786                                            strlen(hbuf.value)+2);
00787                             strcat(strcat(strcpy(p, hto), ","),
00788                                    hbuf.value);
00789                             free(hto);
00790                             hto=p;
00791                      }
00792                      else
00793                      {
00794                             hto=strcpy(courier_malloc(strlen(hbuf.value)
00795                                                    +1), hbuf.value);
00796                      }
00797               }
00798 
00799               if (strcmp(hbuf.header, "subject") == 0)
00800               {
00801                      if (hsubject)
00802                             free(hsubject);
00803 
00804                      hsubject=rfc822_display_hdrvalue_tobuf(hbuf.header,
00805                                                         hbuf.value,
00806                                                         unicode_default_chset(),
00807                                                         NULL, NULL);
00808 
00809                      if (!hsubject)
00810                             hsubject=strdup(hbuf.value);
00811               }
00812 
00813               if (strcmp(hbuf.header, "date") == 0)
00814               {
00815                      if (hdate)
00816                             free(hdate);
00817                      hdate=strcpy(courier_malloc(strlen(hbuf.value)+1),
00818                                  hbuf.value);
00819               }
00820 
00821        }
00822        rfc822hdr_free(&hbuf);
00823 
00824        /*
00825        ** The cover page scripts read the cover page information from the
00826        ** environment.
00827        */
00828 
00829        p=convnames(hfrom);
00830        hfrom=courier_malloc(strlen(p)+sizeof("FROM="));
00831        strcat(strcpy(hfrom, "FROM="), p);
00832        free(p);
00833        putenv(hfrom);
00834 
00835        p=convnames(hto);
00836        hto=courier_malloc(strlen(p)+sizeof("TO="));
00837        strcat(strcpy(hto, "TO="), p);
00838        free(p);
00839        putenv(hto);
00840 
00841        p=courier_malloc(sizeof("SUBJECT=")+strlen(hsubject ? hsubject:""));
00842        strcat(strcpy(p, "SUBJECT="), hsubject ? hsubject:"");
00843        if (hsubject)
00844               free(hsubject);
00845 
00846        putenv(p);
00847 
00848        p=courier_malloc(sizeof("DATE=")+strlen(hdate ? hdate:""));
00849        strcat(strcpy(p, "DATE="), hdate ? hdate:"");
00850        if (hdate)
00851               free(hdate);
00852        putenv(p);
00853 
00854        libmail_str_size_t(info->npages, npages);
00855 
00856        save_pages = info->npages;
00857 
00858        p=courier_malloc(sizeof("PAGES=")+strlen(npages));
00859        strcat(strcpy(p, "PAGES="), npages);
00860        putenv(p);
00861 
00862        info->partnum=0;
00863        rc=do_filter(rfcp, FILTERBINDIR "/coverpage", fd, info, 1);
00864 
00865        /* Ass-backwards way to figure out # of cover pages */
00866        *ncoverpages = info->npages - save_pages;
00867        return (rc);
00868 }
00869 
00870 /*
00871 ** Grab the names from the RFC 822/2045/2047-formatted header */
00872 
00873 static void cnt_names(const char *ptr, size_t cnt, void *vp)
00874 {
00875        int *ip=(int *)vp;
00876        size_t i;
00877 
00878        for (i=0; i<cnt; i++)
00879        {
00880               if (ptr[i] == '\n')
00881                      ++*ip;
00882               ++*ip;
00883        }
00884 }
00885 
00886 static void save_names(const char *ptr, size_t cnt, void *vp)
00887 {
00888        char **ip=(char **)vp;
00889        size_t i;
00890 
00891        for (i=0; i<cnt; i++)
00892        {
00893               if (ptr[i] == '\n')
00894               {
00895                      *(*ip)++ = ',';
00896                      *(*ip)++ = ' ';
00897               }
00898               else
00899               {
00900                      *(*ip)++ = ptr[i];
00901               }
00902        }
00903 }
00904 
00905 static char *convnames(const char *pp)
00906 {
00907        struct rfc822t *t;
00908        struct rfc822a *a;
00909        int al;
00910        char *q, *p=NULL;
00911 
00912        t=rfc822t_alloc_new(pp ? pp:"", NULL, NULL);
00913        if (!t)
00914        {
00915               perror("malloc");
00916               exit(1);
00917        }
00918        a=rfc822a_alloc(t);
00919        if (!a)
00920        {
00921               perror("malloc");
00922               exit(1);
00923        }
00924 
00925        al=1;
00926 
00927        if (rfc822_display_namelist(a, unicode_default_chset(),
00928                                 cnt_names, &al) == 0)
00929        {
00930               q=p=courier_malloc(al+1);
00931 
00932               if (rfc822_display_namelist(a, unicode_default_chset(),
00933                                        save_names, &q) == 0)
00934               {
00935                      if (q - p >= 2 && q[-1] == ' ' && q[-2] == ',')
00936                             /* Trailing comma */
00937                             q -= 2;
00938 
00939                      *q=0;
00940               }
00941        }
00942        rfc822a_free(a);
00943        rfc822t_free(t);
00944        return (p);
00945 }
00946 
00947 #if 0
00948 int main(int argc, char **argv)
00949 {
00950        if (argc < 2)
00951               exit(0);
00952        signal(SIGCHLD, SIG_DFL);
00953        signal(SIGPIPE, SIG_IGN);
00954        faxconvert(argv[1]);
00955        exit(0);
00956        return (0);
00957 }
00958 #endif