mixmaster

mixmaster 3.0 patched for libressl
git clone git://parazyd.org/mixmaster.git
Log | Files | Refs | README

mime.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 }