Back to index

courier  0.68.2
rfc2045rewrite.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      "rfc2045.h"
00010 #include      "rfc2045charset.h"
00011 #include      "rfc822/encode.h"
00012 #include      "rfc822/rfc822hdr.h"
00013 #if    HAVE_UNISTD_H
00014 #include      <unistd.h>
00015 #endif
00016 #include      <stdio.h>
00017 #include      <stdlib.h>
00018 #include      <ctype.h>
00019 #include       <string.h>
00020 #if    HAVE_STRINGS_H
00021 #include       <strings.h>
00022 #endif
00023 
00024 
00025 static char *rw_boundary_root;
00026 static int rw_boundary_cnt;
00027 static const char *rw_appname;
00028 
00029 static int fdout;
00030 static int (*fdout_func)(const char *, int, void *);
00031 static void *fdout_arg;
00032 
00033 static char fdout_buf[512];
00034 static char *fdout_ptr;
00035 static size_t fdout_left;
00036 static int conv_err;
00037 
00038 static int fdout_flush()
00039 {
00040 int    n=fdout_ptr-fdout_buf;
00041 int    i=0;
00042 char   *p=fdout_buf;
00043 
00044        while (n)
00045        {
00046               i=fdout_func ? (*fdout_func)(p, n, fdout_arg):
00047                             write(fdout, p, n);
00048               if (i <= 0)   return (-1);
00049               p += i;
00050               n -= i;
00051        }
00052        fdout_ptr=fdout_buf;
00053        fdout_left=sizeof(fdout_buf);
00054        return (0);
00055 }
00056 
00057 static int fdout_add(const char *p, size_t cnt)
00058 {
00059        while (cnt)
00060        {
00061               if (cnt < fdout_left)
00062               {
00063                      memcpy(fdout_ptr, p, cnt);
00064                      fdout_ptr += cnt;
00065                      fdout_left -= cnt;
00066                      return (0);
00067               }
00068               if (fdout_left == 0)
00069               {
00070                      if (fdout_flush())   return (-1);
00071                      continue;
00072               }
00073               memcpy(fdout_ptr, p, fdout_left);
00074               p += fdout_left;
00075               cnt -= fdout_left;
00076               fdout_ptr += fdout_left;
00077               fdout_left=0;
00078        }
00079        return (0);
00080 }
00081 
00082 static int do_8bit(const char *p, size_t cnt, void *ptr)
00083 {
00084        if (fdout_add(p, cnt))
00085               conv_err=1;
00086        return (0);
00087 }
00088 
00089 static int fdout_autoconverted(const char *oldte, const char *newte)
00090 {
00091        if (fdout_add("X-Mime-Autoconverted: from ", 27) ||
00092               fdout_add(oldte, strlen(oldte)) ||
00093               fdout_add(" to ", 4) ||
00094               fdout_add(newte, strlen(newte)) ||
00095               (rw_appname && (fdout_add(" by ", 4) ||
00096                      fdout_add(rw_appname, strlen(rw_appname)))) ||
00097               fdout_add("\n", 1))  return (-1);
00098        return (0);
00099 }
00100 
00101 static int fdout_value(const char *);
00102 
00103 static int fdout_attr(const struct rfc2045attr *a)
00104 {
00105        if (fdout_add(a->name, strlen(a->name)))  return (-1);
00106        if (a->value && (fdout_add("=", 1) || fdout_value(a->value)))
00107               return (-1);
00108        return (0);
00109 }
00110 
00111 static int fdout_value(const char *v)
00112 {
00113 size_t i,j;
00114 
00115        for (i=0; v[i]; i++)
00116        {
00117               if ( !isalnum((int)(unsigned char)v[i]) && v[i] != '-')
00118               {
00119                      if (fdout_add("\"", 1))     return (-1);
00120                      for (j=i=0; v[i]; i++)
00121                             if (v[i] == '\\' || v[i] == '"')
00122                             {
00123                                    if (fdout_add(v+j, i-j) ||
00124                                           fdout_add("\\", 1))
00125                                           return (-1);
00126                                    j=i;
00127                             }
00128                      if (fdout_add(v+j, i-j) || fdout_add("\"", 1))
00129                             return (-1);
00130                      return (0);
00131               }
00132        }
00133        return (fdout_add(v, i));
00134 }
00135 
00136 static int fdout_add_qp(const char *ptr, size_t cnt, void *dummy)
00137 {
00138        return (fdout_add(ptr, cnt));
00139 }
00140 
00141 static int qpe_do(const char *p, size_t i, void *ptr)
00142 {
00143        return libmail_encode( (struct libmail_encode_info *)ptr, p, i);
00144 }
00145 
00146 #define       TE(p)  ((p)->rw_transfer_encoding ? \
00147               (p)->rw_transfer_encoding: (p)->content_transfer_encoding)
00148 
00149 static int rwmime(struct rfc2045 *p)
00150 {
00151 static char mimever[]="Mime-Version: 1.0\n";
00152 const char *te;
00153 struct rfc2045attr *a;
00154 
00155        if (!p->parent)
00156               if (fdout_add(mimever, sizeof(mimever)-1))       return (-1);
00157 
00158        if (p->content_type)
00159        {
00160               if (fdout_add("Content-Type: ", 14) ||
00161                      fdout_add(p->content_type, strlen(p->content_type)))
00162                      return (-1);
00163 
00164               for (a=p->content_type_attr; a; a=a->next)
00165               {
00166                      if (!a->name || strcmp(a->name, "boundary") == 0)
00167                             continue;
00168                      if ( fdout_add("; ", 2) ||
00169                             fdout_attr(a))       return (-1);
00170               }
00171        }
00172 
00173        if (p->firstpart
00174               && p->firstpart->next /* ADDED 8/30/99, see below */)
00175        {
00176        char   buf[80];
00177 
00178               ++rw_boundary_cnt;
00179               sprintf(buf, "-%d", rw_boundary_cnt);
00180               if ( fdout_add("; boundary=\"", 12) ||
00181                      fdout_add(rw_boundary_root, strlen(rw_boundary_root)) ||
00182                      fdout_add(buf, strlen(buf)) ||
00183                      fdout_add("\"", 1))  return (-1);
00184        }
00185        if (fdout_add("\n", 1))     return (-1);
00186 
00187        /*
00188        ** Show content transfer encoding, unless this is a multipart
00189        ** section.
00190        */
00191 
00192        te=TE(p);
00193        if (te && p->firstpart == NULL)
00194        {
00195               if (fdout_add("Content-Transfer-Encoding: ", 27) ||
00196                      fdout_add(te, strlen(te)) ||
00197                      fdout_add("\n", 1))  return (-1);
00198        }
00199        return (0);
00200 }
00201 
00202 static int dorw(struct rfc2045 *p, struct rfc2045src *src)
00203 {
00204        int seen_mime=0;
00205        char   buf[BUFSIZ];
00206        struct libmail_encode_info qp_encode;
00207        int    bcnt;
00208        struct rfc2045headerinfo *hdr;
00209        char *name, *value;
00210 
00211        /* Slurp the untouchable portion of multipart/signed */
00212 
00213 #if 1
00214        if (p->parent && p->parent->content_type &&
00215            strcasecmp(p->parent->content_type, "multipart/signed") == 0 &&
00216            p->next)
00217        {
00218               off_t ps=p->startpos;
00219 
00220               if ((*src->seek_func)(ps, src->arg) == (off_t)-1)
00221                      return (-1);
00222 
00223               while (ps < p->endbody)
00224               {
00225                      ssize_t n;
00226 
00227                      if (p->endbody - ps > sizeof(buf))
00228                             n=sizeof(buf);
00229                      else   n=p->endbody-ps;
00230                      n=(*src->read_func)(buf, n, src->arg);
00231                      if (n <= 0)   return (-1);
00232 
00233                      if (fdout_add(buf, n))      return (-1);
00234                      ps += n;
00235               }
00236               return (0);
00237        }
00238 #endif
00239 
00240        if (p->parent)
00241        {
00242               seen_mime=1;
00243               if (rwmime(p))       return (-1);
00244        }
00245 
00246        hdr=rfc2045header_start(src, p);
00247 
00248        while (1)
00249        {
00250               if (rfc2045header_get(hdr, &name, &value,
00251                                   RFC2045H_NOLC | RFC2045H_KEEPNL) < 0)
00252               {
00253                      rfc2045header_end(hdr);
00254                      return (-1);
00255               }
00256 
00257               if (name == NULL)
00258                      break;
00259 
00260               if (RFC2045_ISMIME1DEF(p->mime_version) &&
00261                   rfc822hdr_namecmp(name, "mime-version") == 0 &&
00262                      !seen_mime)
00263               {
00264                      seen_mime=1;
00265                      rwmime(p);
00266                      continue;
00267               }
00268 
00269               if (!RFC2045_ISMIME1DEF(p->mime_version) ||
00270                   (rfc822hdr_namecmp(name, "mime-version") &&
00271                    rfc822hdr_namecmp(name, "content-type") &&
00272                    rfc822hdr_namecmp(name, "content-transfer-encoding")))
00273               {
00274                      if (fdout_add(name, strlen(name)) ||
00275                          fdout_add(": ", 2) ||
00276                          fdout_add(value, strlen(value)) ||
00277                          fdout_add("\n", 1))
00278                      {
00279                             rfc2045header_end(hdr);
00280                             return (-1);
00281                      }
00282               }
00283        }
00284        rfc2045header_end(hdr);
00285 
00286        if (RFC2045_ISMIME1DEF(p->mime_version))
00287        {
00288               if (!seen_mime)
00289                      if (rwmime(p))       return (-1);
00290 
00291               if (!p->firstpart && p->rw_transfer_encoding)
00292                      if (fdout_autoconverted(p->content_transfer_encoding,
00293                             p->rw_transfer_encoding))   return (-1);
00294        }
00295 
00296        if (fdout_add("\n", 1))     return (-1);
00297 
00298        if ((*src->seek_func)(p->startbody, src->arg) == (off_t)-1)
00299               return (-1);
00300 
00301        /* For non-multipart section, just print the body */
00302 
00303        if (!p->firstpart)
00304        {
00305        off_t  ps=p->startbody;
00306        int    convmode=0;
00307 
00308               if (p->rw_transfer_encoding)
00309               {
00310                      if ( strcasecmp(p->rw_transfer_encoding,
00311                             "quoted-printable") == 0)
00312                             convmode=RFC2045_RW_7BIT;
00313                      else
00314                             convmode=RFC2045_RW_8BIT;
00315               }
00316 
00317               conv_err=0;
00318               if (convmode == RFC2045_RW_7BIT)
00319               {
00320                      libmail_encode_start(&qp_encode,
00321                                         "quoted-printable",
00322                                         fdout_add_qp, NULL);
00323                      rfc2045_cdecode_start(p, &qpe_do, &qp_encode);
00324               }
00325 
00326               if (convmode == RFC2045_RW_8BIT)
00327               {
00328                      rfc2045_cdecode_start(p, &do_8bit, 0);
00329               }
00330 
00331               while (ps < p->endbody)
00332               {
00333               int    n;
00334 
00335                      if (p->endbody - ps > sizeof(buf))
00336                             n=sizeof(buf);
00337                      else   n=p->endbody-ps;
00338                      n=(*src->read_func)(buf, n, src->arg);
00339                      if (n <= 0)   return (-1);
00340                      if (convmode)
00341                             rfc2045_cdecode(p, buf, n);
00342                      else   if (fdout_add(buf, n))      conv_err=1;
00343                      ps += n;
00344                      if (conv_err) break;
00345               }
00346               if (convmode == RFC2045_RW_7BIT)
00347               {
00348                      rfc2045_cdecode_end(p);
00349                      if (libmail_encode_end(&qp_encode))
00350                             conv_err=1;
00351               }
00352               if (convmode == RFC2045_RW_8BIT)
00353               {
00354                      rfc2045_cdecode_end(p);
00355               }
00356               if (conv_err) return (-1);
00357               return (0);
00358        }
00359 
00360        bcnt=rw_boundary_cnt;
00361 
00362        /* Sam 8/30/99 fix - handle message/rfc822:
00363 
00364             --boundary
00365             Content-Type: message/rfc822
00366 
00367          --><-- we're here, DON'T add RFC2045MIMEMSG and rest of crap here
00368        */
00369        if (p->firstpart->next == 0)
00370        {
00371        int    rc;
00372 
00373               p->firstpart->parent=0;
00374               rc=dorw(p->firstpart, src);
00375               p->firstpart->parent=p;
00376               return (rc);
00377        }
00378 
00379        if (fdout_add(RFC2045MIMEMSG, sizeof(RFC2045MIMEMSG)-1))
00380               return (-1);
00381        for (p=p->firstpart; p; p=p->next)
00382        {
00383               if (p->isdummy)      continue;
00384               sprintf(buf, "\n--%s-%d\n", rw_boundary_root, bcnt);
00385               if (fdout_add(buf, strlen(buf)))   return (-1);
00386               if (dorw(p, src) != 0)      return(-1);
00387        }
00388        sprintf(buf, "\n--%s-%d--\n", rw_boundary_root, bcnt);
00389        if (fdout_add(buf, strlen(buf)))   return (-1);
00390        return (0);
00391 }
00392 
00393 static int rfc2045_rewrite_common(struct rfc2045 *, struct rfc2045src *src,
00394                               const char *);
00395 
00396 int rfc2045_rewrite(struct rfc2045 *p, struct rfc2045src *src, int fdout_arg,
00397                   const char *appname)
00398 {
00399        fdout=fdout_arg;
00400        fdout_func=0;
00401        return (rfc2045_rewrite_common(p, src, appname));
00402 }
00403 
00404 int rfc2045_rewrite_func(struct rfc2045 *p, struct rfc2045src *src,
00405        int (*funcarg)(const char *, int, void *), void *funcargarg,
00406        const char *appname)
00407 {
00408        fdout= -1;
00409        fdout_func=funcarg;
00410        fdout_arg=funcargarg;
00411        return (rfc2045_rewrite_common(p, src, appname));
00412 }
00413 
00414 static int rfc2045_rewrite_common(struct rfc2045 *p,
00415                                struct rfc2045src *src, const char *appname)
00416 {
00417        int    rc;
00418 
00419        rw_appname=appname;
00420 
00421        fdout_ptr=fdout_buf;
00422        fdout_left=sizeof(fdout_buf);
00423 
00424        rw_boundary_root=rfc2045_mk_boundary(p, src);
00425        if (rw_boundary_root == 0)
00426               rc= -1;
00427        else
00428        {
00429               rw_boundary_cnt=1;
00430               rc=dorw(p, src);
00431               free(rw_boundary_root);
00432        }
00433        if (rc == 0 && fdout_ptr > fdout_buf
00434            && fdout_ptr[-1] != '\n')
00435        {
00436               fdout_add("\n", 1);
00437        }
00438        if (rc == 0 && fdout_ptr > fdout_buf)
00439               rc=fdout_flush();
00440        return (rc);
00441 }