URI: 
       tmime.c - mixmaster - mixmaster 3.0 patched for libressl
  HTML git clone git://parazyd.org/mixmaster.git
   DIR Log
   DIR Files
   DIR Refs
   DIR README
       ---
       tmime.c (19743B)
       ---
            1 /* Mixmaster version 3.0  --  (C) 1999 - 2006 Anonymizer Inc. and others.
            2 
            3    Mixmaster may be redistributed and modified under certain conditions.
            4    This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF
            5    ANY KIND, either express or implied. See the file COPYRIGHT for
            6    details.
            7 
            8    MIME functions
            9    $Id: mime.c 934 2006-06-24 13:40:39Z rabbi $ */
           10 
           11 
           12 #include "mix3.h"
           13 #include <ctype.h>
           14 #include <string.h>
           15 
           16 #define hex(i) (isdigit(i) ? (i) - '0' : tolower(i) - 'a' + 10)
           17 
           18 #define hexdigit(i) ((byte)(i < 10 ? i + '0' : i - 10 + 'A'))
           19 
           20 static void encode_word(BUFFER *in)
           21 {
           22   BUFFER *out;
           23   int i;
           24 
           25   out = buf_new();
           26   for (i = 0; i < in->length; i++)
           27     if (in->data[i] < 32 || in->data[i] >= 127 || in->data[i] == '='
           28         || in->data[i] == '?' || in->data[i] == '_') {
           29       buf_appendc(out, '=');
           30       buf_appendc(out, hexdigit(in->data[i] / 16));
           31       buf_appendc(out, hexdigit(in->data[i] % 16));
           32     } else if (in->data[i] == ' ')
           33       buf_appendc(out, '_');
           34     else
           35       buf_appendc(out, in->data[i]);
           36   buf_move(in, out);
           37   buf_free(out);
           38 }
           39 
           40 void body_encode(BUFFER *in, int transport, BUFFER *hdr)
           41 {
           42   BUFFER *out;
           43   int c, l=0, encoding = 0;
           44   out = buf_new();
           45 
           46   buf_clear(hdr);
           47 
           48   l = in->ptr;
           49   while ((c = buf_getc(in)) != -1 && encoding != 2) {
           50     if (c >= 160)
           51       encoding = 1;
           52     else if (c == ' ') {
           53       if (buf_getc(in) == '\n')
           54         encoding = 1;
           55       buf_ungetc(in);
           56     } else if ((c < 32 && c != ' ' && c != '\n' && c != '\t') ||
           57                (c >= 127 && c < 160)) {
           58       encoding = 2;
           59     }
           60   }
           61   in->ptr = l;
           62 
           63   if (encoding == 2) {
           64     buf_sets(hdr, "Content-Transfer-Encoding: base64\n");
           65     encode(in, 76);
           66   } else {
           67 
           68 #if 0
           69     if (encoding == 0)
           70       buf_sets(hdr, "Content-Transfer-Encoding: 7bit\n");
           71 #endif
           72     if (encoding != 0 && transport == MIME_8BIT)
           73       buf_sets(hdr, "Content-Transfer-Encoding: 8bit\n");
           74     if (encoding == 0 || transport == MIME_8BIT) {
           75       buf_rest(out, in); /* transparent */
           76       buf_move(in, out);
           77     } else {
           78       buf_sets(hdr, "Content-Transfer-Encoding: quoted-printable\n");
           79       l = 0;
           80       while ((c = buf_getc(in)) != -1) {
           81         if (c == '\n') {
           82           buf_nl(out);
           83           l = 0;
           84         }
           85         else if (c < 32 || c >= 127 || c == '=') {
           86           if (l > 73) {
           87             buf_appends(out, "=\n");
           88             l = 0;
           89           }
           90           buf_appendc(out, '=');
           91           buf_appendc(out, hexdigit(c / 16));
           92           buf_appendc(out, hexdigit(c % 16));
           93           l += 3;
           94         } else if (c == ' ') {
           95           if (buf_getc(in) == '\n') {
           96             buf_appendc(out, '=');
           97             buf_appendc(out, hexdigit(c / 16));
           98             buf_appendc(out, hexdigit(c % 16));
           99             buf_nl(out);
          100             l = 0;
          101           } else {
          102             buf_appendc(out, c);
          103             buf_ungetc(in);
          104             l++;
          105           }
          106         } else {
          107           buf_appendc(out, c);
          108           l++;
          109         }
          110       }
          111       buf_move(in, out);
          112     }
          113   }
          114   buf_free(out);
          115 }
          116 
          117 int mail_encode(BUFFER *in, int encoding)
          118 {
          119   BUFFER *out, *line, *tmp;
          120 
          121   out = buf_new();
          122   line = buf_new();
          123   tmp = buf_new();
          124 
          125   while (buf_getline(in, line) == 0) {
          126     hdr_encode(line, 255);
          127     buf_cat(out, line);
          128     buf_nl(out);
          129   }
          130   if (in->ptr < in->length) {
          131     /* no newline if only encoding header lines */
          132     if (encoding == 0) {
          133       buf_nl(out);
          134       buf_rest(out, in);
          135     }
          136     else {
          137       body_encode(in, encoding, line);
          138       buf_cat(out, line);
          139       buf_nl(out);
          140       buf_cat(out, in);
          141     }
          142   }
          143   buf_move(in, out);
          144   buf_free(line);
          145   buf_free(tmp);
          146   buf_free(out);
          147   return (0);
          148 }
          149 
          150 int hdr_encode(BUFFER *in, int n)
          151 {
          152   int i;
          153   int encodeword = 0, encode = 0;
          154   BUFFER *out, *word, *space;
          155 
          156   out = buf_new();
          157   word = buf_new();
          158   space = buf_new();
          159   for (i = 0; i <= in->length; i++) {
          160     if (isspace(in->data[i]) || in->data[i] == '\0') {
          161       if (word->length) {
          162         if (encodeword) {
          163           if (encode == 0) {
          164             buf_cat(out, space);
          165             buf_clear(space);
          166             buf_appends(out, "=?");
          167             buf_appends(out, MIMECHARSET);
          168             buf_appends(out, "?Q?");
          169             encode = 1;
          170           } else {
          171             buf_cat(space, word);
          172             buf_move(word, space);
          173           }
          174           encode_word(word);
          175         }
          176         if (encode && !encodeword) {
          177           encode = 0;
          178           buf_appends(out, "?=");
          179         }
          180         buf_cat(out, space);
          181         buf_cat(out, word);
          182         encodeword = 0;
          183         buf_clear(space);
          184         buf_clear(word);
          185       }
          186       buf_appendc(space, in->data[i]);
          187     } else {
          188       if (in->data[i] < 32 || in->data[i] >= 127)
          189         encodeword = 1;
          190       buf_appendc(word, in->data[i]);
          191     }
          192   }
          193   if (encode)
          194     buf_appends(out, "?=");
          195 
          196   buf_move(in, out);
          197   while (n > 0 && in->length - in->ptr > n) {
          198     for (i = 1; i < in->length - in->ptr; i++)
          199       if (isspace(in->data[in->length - i]))
          200         break;
          201     buf_get(in, out, in->length - i);
          202     buf_appends(out, "\n\t");
          203   }
          204   buf_rest(out, in);
          205   buf_move(in, out);
          206   buf_free(out);
          207   buf_free(space);
          208   buf_free(word);
          209   return (0);
          210 }
          211 
          212 void addprintable(BUFFER *out, int c)
          213 {
          214   if (c == '\n')
          215     buf_appendc(out, (char) c);
          216   else if (c == '\t')
          217     buf_appends(out, "        ");
          218   else if (c == '\014')
          219     buf_appends(out, "^L");
          220   else if (c == '\r') ;
          221   else if (c <= 31 || (c >= 128 && c <= 128 + 31))
          222     buf_appendc(out, '?');
          223   else
          224     buf_appendc(out, (char) c);
          225 }
          226 
          227 void addprintablebuf(BUFFER *out, BUFFER *in)
          228 {
          229   int c;
          230 
          231   while ((c = buf_getc(in)) != -1)
          232     addprintable(out, c);
          233 }
          234 
          235 int decode_line(BUFFER *line)
          236 {
          237   BUFFER *out;
          238   unsigned int i;
          239   int c, softbreak = 0;
          240 
          241   out = buf_new();
          242   for (i = 0; line->data[i] != '\0'; i++) {
          243     if (line->data[i] == '=') {
          244       if (isxdigit(line->data[i + 1]) && isxdigit(line->data[i + 2])) {
          245         c = hex(line->data[i + 1]) * 16 + hex(line->data[i + 2]);
          246         i += 2;
          247         addprintable(out, c);
          248       } else if (line->data[i + 1] == '\0') {
          249         softbreak = 1;
          250         break;
          251       }
          252     } else
          253       addprintable(out, line->data[i]);
          254   }
          255 
          256   buf_move(line, out);
          257   buf_free(out);
          258   return (softbreak);
          259 }
          260 
          261 int decode_header(BUFFER *in)
          262 {
          263   int encoded = 0;
          264   int c;
          265   int err = 0;
          266   int last = 0;
          267   BUFFER *out;
          268 
          269   out = buf_new();
          270   for (in->ptr = 0; in->data[in->ptr] != '\0'; in->ptr++) {
          271     if (encoded == 'q' && in->data[in->ptr] == '=' &&
          272         isxdigit(in->data[in->ptr + 1])
          273         && isxdigit(in->data[in->ptr + 2])) {
          274       c = hex(in->data[in->ptr + 1]) * 16 + hex(in->data[in->ptr + 2]);
          275       in->ptr += 2;
          276       addprintable(out, c);
          277     } else if (encoded == 'q' && in->data[in->ptr] == '_')
          278       buf_appendc(out, ' ');
          279     else if (in->data[in->ptr] == '=' && in->data[in->ptr + 1] == '?' &&
          280              in->data[in->ptr + 2] != '\0') {
          281       if (last > 0 && out->length > last) {
          282         out->data[last] = '\0';
          283         out->length = last;
          284       }
          285       in->ptr++;
          286       while (in->data[++in->ptr] != '?')
          287         if (in->data[in->ptr] == 0) {
          288           err = -1;
          289           goto end;
          290         }
          291       if (in->data[in->ptr + 1] != '\0' && in->data[in->ptr + 2] == '?') {
          292         encoded = tolower(in->data[in->ptr + 1]);
          293         in->ptr += 2;
          294         if (encoded == 'b') {
          295           BUFFER *tmp;
          296 
          297           tmp = buf_new();
          298           decode(in, tmp);
          299           addprintablebuf(out, tmp);
          300           last = out->length;
          301           buf_free(tmp);
          302         } else if (encoded != 'q')
          303           err = 1;
          304       } else {
          305         err = -1;
          306         goto end;
          307       }
          308     } else if (encoded && in->data[in->ptr] == '?' &&
          309                in->data[in->ptr + 1] == '=') {
          310       in->ptr++;
          311       last = out->length;
          312       encoded = 0;
          313     } else {
          314       addprintable(out, in->data[in->ptr]);
          315       if (!encoded || !isspace(in->data[in->ptr]))
          316         last = out->length;
          317     }
          318   }
          319 end:
          320   if (err == -1)
          321     buf_set(out, in);
          322 
          323   buf_move(in, out);
          324   buf_free(out);
          325   return (err);
          326 }
          327 
          328 #define delimclose 2
          329 
          330 int boundary(BUFFER *line, BUFFER *boundary)
          331 {
          332   int c;
          333 
          334   if (boundary->length == 0 || !bufleft(line, "--") ||
          335       !strleft(line->data + 2, boundary->data))
          336     return (0);
          337   line->ptr = boundary->length + 2;
          338   for (;;) {
          339     c = buf_getc(line);
          340     if (c == -1)
          341       return (1);
          342     if (c == '-' && buf_getc(line) == '-')
          343       return (delimclose);
          344     if (!isspace(c))
          345       return (0);
          346   }
          347 }
          348 
          349 #define pgpenc 1
          350 #define pgpsig 2
          351 
          352 /*
          353  * decodes non-multipart quoted printable message
          354  */
          355 int qp_decode_message(BUFFER *msg)
          356 {
          357   BUFFER *out, *line, *field, *content;
          358   out     = buf_new();
          359   line    = buf_new();
          360   field   = buf_new();
          361   content = buf_new();
          362 
          363   buf_rewind(msg);
          364 
          365   /* copy over headers without decoding */
          366   while (buf_getheader(msg, field, content) == 0) {
          367     if (bufieq(field, "content-transfer-encoding")
          368         && bufieq(content, "quoted-printable")) {
          369       continue;                 /* no longer quoted-printable */
          370     } else {
          371       buf_appendheader(out, field, content);
          372     }
          373   }
          374 
          375   buf_nl(out);
          376 
          377   /* copy over body, quoted-printable decoding as we go */
          378   while (buf_getline(msg, line) != -1) {
          379     int softbreak;
          380     softbreak = decode_line(line);
          381     buf_cat(out, line);
          382     if (!softbreak)
          383       buf_nl(out);
          384   }
          385   buf_move(msg, out);
          386   buf_free(out);
          387   buf_free(line);
          388   buf_free(field);
          389   buf_free(content);
          390   return 0;
          391 }
          392 
          393 
          394 int entity_decode(BUFFER *msg, int message, int mptype, BUFFER *data)
          395 {
          396   BUFFER *out, *line, *field, *content, *type, *subtype, *disposition,
          397       *mboundary, *part, *sigdata;
          398   int ret = 0, ptype = 0, partno = 0;
          399   int p, encoded = 0;
          400 
          401   out = buf_new();
          402   line = buf_new();
          403   field = buf_new();
          404   content = buf_new();
          405   type = buf_new();
          406   subtype = buf_new();
          407   disposition = buf_new();
          408   mboundary = buf_new();
          409   part = buf_new();
          410   sigdata = buf_new();
          411 
          412   if (message && bufileft(msg, "From ")) {
          413     buf_getline(msg, out); /* envelope from */
          414     buf_nl(out);
          415   }
          416 
          417   while (buf_getheader(msg, field, content) == 0) {
          418     if (bufieq(field, "content-transfer-encoding") &&
          419         bufieq(content, "quoted-printable"))
          420       encoded = 'q';
          421     if (bufieq(field, "content-type")) {
          422       get_type(content, type, subtype);
          423       if (bufieq(type, "multipart"))
          424         get_parameter(content, "boundary", mboundary);
          425       if (bufieq(type, "multipart") && bufieq(subtype, "encrypted")) {
          426         get_parameter(content, "protocol", line);
          427         if (bufieq(line, "application/pgp-encrypted"))
          428           ptype = pgpenc;
          429       }
          430       if (bufieq(type, "multipart") && bufieq(subtype, "signed")) {
          431         get_parameter(content, "protocol", line);
          432         if (bufieq(line, "application/pgp-signature"))
          433           ptype = pgpsig;
          434       }
          435     }
          436     if (bufieq(field, "content-disposition"))
          437       buf_set(disposition, content);
          438     if (message) {
          439       decode_header(content);
          440       buf_appendheader(out, field, content);
          441     }
          442   }
          443 
          444   if (message)
          445     buf_nl(out);
          446 
          447   if (bufifind(disposition, "attachment")) {
          448     buf_appendf(out, "[-- %b attachment", type);
          449     get_parameter(disposition, "filename", line);
          450     if (line->length)
          451        buf_appendf(out, " (%b)", line);
          452     buf_appends(out, " --]\n");
          453   }
          454 
          455   if (mboundary->length) {
          456   /* multipart */
          457     while (buf_getline(msg, line) > -1 && !boundary(line, mboundary))
          458       ; /* ignore preamble */
          459     while (buf_getline(msg, line) != -1) {
          460       p = boundary(line, mboundary);
          461       if (p) {
          462         if (part->data[part->length - 1] == '\n')
          463           part->data[--(part->length)] = '\0';
          464         partno++;
          465         if (ptype == pgpsig && partno == 1)
          466           buf_set(sigdata, part);
          467         ret += entity_decode(part, 0, ptype, sigdata);
          468         buf_cat(out, part);
          469         buf_clear(part);
          470         if (p == delimclose)
          471           break;
          472         if (bufieq(subtype, "alternative") && ret > 0)
          473           break;
          474         if (bufieq(subtype, "mixed"))
          475           buf_appends(out,
          476                       "[-------------------------------------------------------------------------]\n");
          477       } else {
          478         buf_cat(part, line);
          479         buf_nl(part);
          480       }
          481     }
          482   } else if (mptype == pgpenc && bufieq(type, "application") &&
          483              bufieq(subtype, "pgp-encrypted")) {
          484     /* application/pgp-encrypted part of multipart/encrypted */
          485     ; /* skip */
          486   } else if (mptype == pgpenc && bufieq(type, "application") &&
          487              bufieq(subtype, "octet-stream")) {
          488     /* application/octet-stream part of multipart/encrypted */
          489     int ok = 0;
          490     buf_getline(msg, line);
          491     if (bufleft(line, info_beginpgp)) {
          492       if (buffind(line, "(SIGNED)")) {
          493           buf_getline(msg, line);
          494           buf_appends(out, "[-- OpenPGP message with signature --]\n");
          495           if (bufleft(line, info_pgpsig))
          496             buf_appendf(out, "[%s]\n",
          497                         line->data + sizeof(info_pgpsig) - 1);
          498           else
          499             buf_appends(out, "[Signature invalid]\n");
          500       } else
          501         buf_appends(out, "[-- OpenPGP message --]\n");
          502       while (buf_getline(msg, line) != -1) {
          503         if (bufleft(line, info_endpgp)) {
          504           ret += entity_decode(part, 0, 0, NULL);
          505           buf_cat(out, part);
          506           buf_appends(out, "[-- End OpenPGP message --]\n");
          507           ok = 1, ret++;
          508           break;
          509         }
          510         buf_cat(part, line);
          511         buf_nl(part);
          512       }
          513     }
          514     if (!ok) {
          515       buf_appends(out, "[-- Bad OpenPGP message --]\n");
          516       buf_cat(out, msg);
          517     }
          518   } else if (mptype == pgpsig && bufeq(type, "application") &&
          519              bufieq(subtype, "pgp-signature")) {
          520     buf_rest(part, msg);
          521 #ifdef USE_PGP
          522     if (pgp_decrypt(part, NULL, data, PGPPUBRING, NULL) == PGP_SIGOK)
          523       buf_appendf(out, "[-- OpenPGP signature from:\n    %b --]\n", data);
          524     else
          525       buf_appends(out, "[-- Invalid OpenPGP signature --]\n");
          526 #else /* USE_PGP */
          527     buf_appends(out, "[-- No OpenPGP support --]\n");
          528 #endif /* !USE_PGP */
          529   } else if (type->length == 0 || bufieq(type, "text")) {
          530     while (buf_getline(msg, line) != -1) {
          531       int softbreak;
          532       softbreak = encoded ? decode_line(line) : 0;
          533       buf_cat(out, line);
          534       if (!softbreak)
          535         buf_nl(out);
          536     }
          537     ret++;
          538   } else {
          539     buf_appendf(out, "[-- %b/%b message part --]\n", type, subtype);
          540     buf_cat(out, msg);
          541   }
          542 
          543   buf_move(msg, out);
          544   buf_free(line);
          545   buf_free(out);
          546   buf_free(field);
          547   buf_free(content);
          548   buf_free(type);
          549   buf_free(subtype);
          550   buf_free(disposition);
          551   buf_free(mboundary);
          552   buf_free(part);
          553   buf_free(sigdata);
          554   return (0);
          555 }
          556 
          557 void mimedecode(BUFFER *msg)
          558 {
          559   entity_decode(msg, 1, 0, NULL);
          560 }
          561 
          562 int attachfile(BUFFER *message, BUFFER *filename)
          563 {
          564   BUFFER *type, *attachment;
          565   FILE *f;
          566   int ret = -1;
          567 
          568   type = buf_new();
          569   attachment = buf_new();
          570 
          571   if ((bufiright(filename, ".txt") || !bufifind(filename, ".")) &&(strlen(DEFLTENTITY) != 0))
          572     buf_sets(type, DEFLTENTITY);
          573   else if (bufiright(filename, ".htm") || bufiright(filename, ".html"))
          574     buf_sets(type, "text/html");
          575   else if (bufiright(filename, ".jpeg"))
          576     buf_sets(type, "image/jpeg");
          577   else if (bufiright(filename, ".gif"))
          578     buf_sets(type, "image/gif");
          579   else if (bufiright(filename, ".pcm"))
          580     buf_sets(type, "audio/basic");
          581   else if (bufiright(filename, ".mpg") || bufiright(filename, ".mpeg"))
          582     buf_sets(type, "video/mpeg");
          583   else if (bufiright(filename, ".ps"))
          584     buf_sets(type, "application/postscript");
          585   else
          586     buf_sets(type, "application/octet-stream");
          587 
          588   f = fopen(filename->data, "r");
          589   if (f) {
          590     buf_read(attachment, f);
          591     fclose(f);
          592     ret = mime_attach(message, attachment, type);
          593   }
          594 
          595   buf_free(attachment);
          596   buf_free(type);
          597   return(ret);
          598 }
          599 
          600 int mime_attach(BUFFER *message, BUFFER *attachment, BUFFER *attachtype)
          601 {
          602   BUFFER *out, *part, *line, *type, *subtype, *mboundary, *field, *content;
          603   int mimeheader = 0, multipart = 0, versionheader = 0;
          604 
          605   out = buf_new();
          606   line = buf_new();
          607   part = buf_new();
          608   type = buf_new();
          609   subtype = buf_new();
          610   mboundary = buf_new();
          611   field = buf_new();
          612   content = buf_new();
          613 
          614   buf_rewind(message);
          615   while (buf_getheader(message, field, content) == 0) {
          616     if (bufieq(field, "mime-version"))
          617       versionheader = 1;
          618     if (bufieq(field, "content-type")) {
          619       get_type(content, type, subtype);
          620       if (bufieq(type, "multipart") && bufieq(subtype, "mixed")) {
          621         multipart = 1;
          622         get_parameter(content, "boundary", mboundary);
          623       }
          624     }
          625     if (bufileft(field, "content-"))
          626       mimeheader = 1;
          627   }
          628 
          629   if (mimeheader && !multipart) {
          630     buf_rewind(message);
          631     while (buf_getheader(message, field, content) == 0) {
          632       if (bufileft(field, "content-"))
          633         buf_appendheader(part, field, content);
          634       else
          635         buf_appendheader(out, field, content);
          636     }
          637   } else {
          638     buf_ungetc(message);
          639     buf_append(out, message->data, message->ptr);
          640     buf_getc(message);
          641   }
          642 
          643   if (!versionheader)
          644     buf_appends(out, "MIME-Version: 1.0\n");
          645 
          646   if (!multipart) {
          647     buf_setrnd(mboundary, 18);
          648     encode(mboundary, 0);
          649     buf_appendf(out, "Content-Type: multipart/mixed; boundary=\"%b\"\n",
          650                 mboundary);
          651   }
          652   buf_nl(out);
          653 
          654   if (multipart) {
          655     while (buf_getline(message, line) != -1) {
          656       if (boundary(line, mboundary) == delimclose)
          657         break;
          658       buf_cat(out, line);
          659       buf_nl(out);
          660     }
          661   } else {
          662     buf_appendf(out, "--%b\n", mboundary);
          663     if (part->length) {
          664       buf_cat(out, part); /* body part header */
          665     }
          666     else {
          667       if (strlen(DEFLTENTITY))
          668         buf_appendf(out, "Content-Type: %s\n", DEFLTENTITY);
          669     }
          670 
          671     buf_nl(out);
          672     buf_cat(out, message);
          673     buf_nl(out);
          674   }
          675 
          676   buf_appendf(out, "--%b\n", mboundary);
          677   buf_appendf(out, "Content-Type: %b\n", attachtype);
          678 
          679   body_encode(attachment, MIME_8BIT, line);
          680   buf_cat(out, line);
          681   buf_nl(out);
          682   buf_cat(out, attachment);
          683   buf_appendf(out, "\n--%b--\n", mboundary);
          684 
          685   buf_move(message, out);
          686 
          687   buf_free(out);
          688   buf_free(line);
          689   buf_free(part);
          690   buf_free(type);
          691   buf_free(subtype);
          692   buf_free(mboundary);
          693   buf_free(field);
          694   buf_free(content);
          695   return (1);
          696 }
          697 
          698 static int entity_encode(BUFFER *message, BUFFER *out, BUFFER *messagehdr,
          699                          int encoding)
          700 {
          701   BUFFER *field, *content, *mboundary, *part, *line, *line2, *tmp;
          702 
          703   field = buf_new();
          704   content = buf_new();
          705   mboundary = buf_new();
          706   part = buf_new();
          707   line = buf_new();
          708   line2 = buf_new();
          709   tmp = buf_new();
          710 
          711   buf_rewind(message);
          712   buf_clear(out);
          713   buf_clear(messagehdr);
          714 
          715   while (buf_getheader(message, field, content) == 0) {
          716     if (bufileft(field, "content-"))
          717       buf_appendheader(out, field, content);
          718     else if (messagehdr)
          719       buf_appendheader(messagehdr, field, content);
          720 
          721     if (bufieq(field, "content-type")) {
          722       get_type(content, line, tmp);
          723       if (bufieq(line, "multipart"))
          724         get_parameter(content, "boundary", mboundary);
          725     }
          726   }
          727 
          728   buf_nl(out);
          729   if (mboundary->length) {
          730       while (buf_getline(message, line) != -1) {
          731         buf_cat(out, line);
          732         buf_nl(out);
          733         if (boundary(line, mboundary))
          734           break;
          735       }
          736       while (buf_getline(message, line) != -1) {
          737           if (boundary(line, mboundary)) {
          738             entity_encode(part, tmp, line2, encoding);
          739             buf_cat(out, line2);
          740             buf_cat(out, tmp);
          741             buf_cat(out, line);
          742             buf_nl(out);
          743             buf_clear(part);
          744             if (boundary(line, mboundary) == delimclose)
          745               break;
          746           } else {
          747             buf_cat(part, line);
          748             buf_nl(part);
          749           }
          750       }
          751   } else
          752     buf_rest(out, message);
          753   buf_rewind(out);
          754   mail_encode(out, encoding);
          755 
          756   buf_free(field);
          757   buf_free(content);
          758   buf_free(mboundary);
          759   buf_free(part);
          760   buf_free(line);
          761   buf_free(line2);
          762   buf_free(tmp);
          763   return (1);
          764 }
          765 
          766 int pgpmime_sign(BUFFER *message, BUFFER *uid, BUFFER *pass, char *secring)
          767 {
          768 #ifndef USE_PGP
          769   return (-1)
          770 #else /* end of not USE_PGP */
          771   BUFFER *out, *body, *mboundary, *algo;
          772   int err;
          773 
          774   out = buf_new();
          775   body = buf_new();
          776   mboundary = buf_new();
          777   algo = buf_new();
          778 
          779   pgp_signhashalgo(algo, uid, secring, pass);
          780 
          781   entity_encode(message, body, out, MIME_7BIT);
          782 
          783   buf_setrnd(mboundary, 18);
          784   encode(mboundary, 0);
          785   buf_appendf(out, "Content-Type: multipart/signed; boundary=\"%b\";\n",
          786               mboundary);
          787   buf_appendf(out,
          788               "\tmicalg=pgp-%b; protocol=\"application/pgp-signature\"\n",
          789               algo);
          790   buf_nl(out);
          791 
          792   buf_appendf(out, "--%b\n", mboundary);
          793   buf_cat(out, body);
          794   buf_nl(out);
          795   buf_appendf(out, "--%b\n", mboundary);
          796 
          797   err = pgp_encrypt(PGP_SIGN | PGP_TEXT | PGP_DETACHEDSIG, body, NULL,
          798                     uid, pass, NULL, secring);
          799 
          800   buf_appends(out, "Content-Type: application/pgp-signature\n");
          801   buf_nl(out);
          802   buf_cat(out, body);
          803   buf_nl(out);
          804   buf_appendf(out, "--%b--\n", mboundary);
          805   if (err == 0)
          806     buf_move(message, out);
          807 
          808   buf_free(out);
          809   buf_free(body);
          810   buf_free(mboundary);
          811   buf_free(algo);
          812   return (err);
          813 #endif /* else if USE_PGP */
          814 }