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 }