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 }