2 * Heirloom mailx - a mail user agent derived from Berkeley Mail.
4 * Copyright (c) 2000-2004 Gunnar Ritter, Freiburg i. Br., Germany.
7 * Copyright (c) 1980, 1993
8 * The Regents of the University of California. All rights reserved.
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 * 3. All advertising materials mentioning features or use of this software
19 * must display the following acknowledgement:
20 * This product includes software developed by the University of
21 * California, Berkeley and its contributors.
22 * 4. Neither the name of the University nor the names of its contributors
23 * may be used to endorse or promote products derived from this software
24 * without specific prior written permission.
26 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
27 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
28 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
29 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
30 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
31 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
32 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
33 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
34 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
35 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
41 static char sccsid
[] = "@(#)send.c 2.86 (gritter) 2/4/08";
52 * Mail -- a mail program
54 * Mail to mail folders and displays.
63 static void onpipe(int signo
);
64 extern void brokpipe(int signo
);
65 static int sendpart(struct message
*zmp
, struct mimepart
*ip
, FILE *obuf
,
66 struct ignoretab
*doign
, char *prefix
, size_t prefixlen
,
67 enum sendaction action
, off_t
*stats
, int level
);
68 static struct mimepart
*parsemsg(struct message
*mp
, enum parseflags pf
);
69 static enum okay
parsepart(struct message
*zmp
, struct mimepart
*ip
,
70 enum parseflags pf
, int level
);
71 static void parsemultipart(struct message
*zmp
, struct mimepart
*ip
,
72 enum parseflags pf
, int level
);
73 static void newpart(struct mimepart
*ip
, struct mimepart
**np
, off_t offs
,
75 static void endpart(struct mimepart
**np
, off_t xoffs
, long lines
);
76 static void parse822(struct message
*zmp
, struct mimepart
*ip
,
77 enum parseflags pf
, int level
);
78 static void parsepkcs7(struct message
*zmp
, struct mimepart
*ip
,
79 enum parseflags pf
, int level
);
80 static size_t out(char *buf
, size_t len
, FILE *fp
,
81 enum conversion convert
, enum sendaction action
,
82 char *prefix
, size_t prefixlen
, off_t
*stats
,
83 char **restp
, size_t *restsizep
);
84 static void addstats(off_t
*stats
, off_t lines
, off_t bytes
);
85 static FILE *newfile(struct mimepart
*ip
, int *ispipe
,
86 sighandler_type
*oldpipe
);
87 static char *getpipecmd(char *content
);
88 static FILE *getpipefile(char *cmd
, FILE **qbuf
, int quote
);
89 static void pipecpy(FILE *pipebuf
, FILE *outbuf
, FILE *origobuf
,
90 char *prefix
, size_t prefixlen
, off_t
*stats
);
91 static void statusput(const struct message
*mp
, FILE *obuf
,
92 char *prefix
, off_t
*stats
);
93 static void xstatusput(const struct message
*mp
, FILE *obuf
,
94 char *prefix
, off_t
*stats
);
95 static void put_from_(FILE *fp
, struct mimepart
*ip
);
97 static sigjmp_buf pipejmp
;
103 siglongjmp(pipejmp
, 1);
107 * Send message described by the passed pointer to the
108 * passed output buffer. Return -1 on error.
109 * Adjust the status: field if need be.
110 * If doign is given, suppress ignored header fields.
111 * prefix is a string to prepend to each output line.
112 * action = data destination (SEND_MBOX,_TOFILE,_TODISP,_QUOTE,_DECRYPT).
113 * stats[0] is line count, stats[1] is character count. stats may be NULL.
114 * Note that stats[0] is valid for SEND_MBOX only.
117 send(struct message
*mp
, FILE *obuf
, struct ignoretab
*doign
,
118 char *prefix
, enum sendaction action
, off_t
*stats
)
122 size_t prefixlen
, sz
;
128 if (mp
== dot
&& action
!= SEND_TOSRCH
&& action
!= SEND_TOFLTR
)
131 stats
[0] = stats
[1] = 0;
133 * Compute the prefix string, without trailing whitespace
135 if (prefix
!= NULL
) {
137 for (cp
= prefix
; *cp
; cp
++)
138 if (!blankchar(*cp
& 0377))
140 prefixlen
= cp2
== 0 ? 0 : cp2
- prefix
+ 1;
144 * First line is the From_ line, so no headers there to worry about.
146 if ((ibuf
= setinput(&mb
, mp
, NEED_BODY
)) == NULL
)
150 if (mp
->m_flag
& MNOFROM
) {
151 if (doign
!= allignore
&& doign
!= fwdignore
&&
152 action
!= SEND_RFC822
)
153 sz
= fprintf(obuf
, "%sFrom %s %s\n",
154 prefix
? prefix
: "",
155 fakefrom(mp
), fakedate(mp
->m_time
));
157 if (prefix
&& doign
!= allignore
&& doign
!= fwdignore
&&
158 action
!= SEND_RFC822
) {
160 sz
+= strlen(prefix
);
162 while (count
&& (c
= getc(ibuf
)) != EOF
) {
163 if (doign
!= allignore
&& doign
!= fwdignore
&&
164 action
!= SEND_RFC822
) {
174 addstats(stats
, 1, sz
);
176 if (action
!= SEND_MBOX
&& action
!= SEND_RFC822
&& action
!= SEND_SHOW
)
177 pf
|= PARSE_DECRYPT
|PARSE_PARTS
;
178 if ((ip
= parsemsg(mp
, pf
)) == NULL
)
180 return sendpart(mp
, ip
, obuf
, doign
, prefix
, prefixlen
, action
, stats
,
185 sendpart(struct message
*zmp
, struct mimepart
*ip
, FILE *obuf
,
186 struct ignoretab
*doign
, char *prefix
, size_t prefixlen
,
187 enum sendaction action
, off_t
*stats
, int level
)
190 size_t linesize
= 0, linelen
, count
, len
;
191 int dostat
, infld
= 0, ignoring
= 1, isenc
;
192 char *cp
, *cp2
, *start
;
195 FILE *ibuf
= NULL
, *pbuf
= obuf
, *qbuf
= obuf
, *origobuf
= obuf
;
196 char *tcs
, *pipecmd
= NULL
;
197 enum conversion convert
;
198 sighandler_type oldpipe
= SIG_DFL
;
214 if (ip
->m_mimecontent
== MIME_PKCS7
&& ip
->m_multipart
&&
215 action
!= SEND_MBOX
&& action
!= SEND_RFC822
&&
221 if (!is_ign("status", 6, doign
))
223 if (!is_ign("x-status", 8, doign
))
228 if ((ibuf
= setinput(&mb
, (struct message
*)ip
, NEED_BODY
)) == NULL
)
231 if (ip
->m_mimecontent
== MIME_DISCARD
)
233 if ((ip
->m_flag
&MNOFROM
) == 0)
234 while (count
&& (c
= getc(ibuf
)) != EOF
) {
240 convert
= action
== SEND_TODISP
|| action
== SEND_TODISP_ALL
||
241 action
== SEND_QUOTE
|| action
== SEND_QUOTE_ALL
||
242 action
== SEND_TOSRCH
|| action
== SEND_TOFLTR
?
243 CONV_FROMHDR
: CONV_NONE
;
244 while (foldergets(&line
, &linesize
, &count
, &linelen
, ibuf
)) {
246 if (line
[0] == '\n') {
248 * If line is blank, we've reached end of
249 * headers, so force out status: field
250 * and note that we are no longer in header
254 statusput(zmp
, obuf
, prefix
, stats
);
256 xstatusput(zmp
, obuf
, prefix
, stats
);
257 if (doign
!= allignore
)
258 out("\n", 1, obuf
, CONV_NONE
, SEND_MBOX
,
259 prefix
, prefixlen
, stats
,
264 if (infld
&& blankchar(line
[0]&0377)) {
266 * If this line is a continuation (via space or tab)
267 * of a previous header field, determine if the start
268 * of the line is a MIME encoded word.
271 for (cp
= line
; blankchar(*cp
&0377); cp
++);
272 if (cp
> line
&& linelen
- (cp
- line
) > 8 &&
273 cp
[0] == '=' && cp
[1] == '?')
278 * Pick up the header field if we have one.
280 for (cp
= line
; (c
= *cp
&0377) && c
!= ':' &&
281 !spacechar(c
); cp
++);
283 while (spacechar(*cp
&0377))
285 if (cp
[0] != ':' && level
== 0 && lineno
== 1) {
287 * Not a header line, force out status:
288 * This happens in uucp style mail where
289 * there are no headers at all.
292 statusput(zmp
, obuf
, prefix
, stats
);
294 xstatusput(zmp
, obuf
, prefix
, stats
);
295 if (doign
!= allignore
)
296 out("\n", 1, obuf
, CONV_NONE
, SEND_MBOX
,
297 prefix
, prefixlen
, stats
,
302 * If it is an ignored field and
303 * we care about such things, skip it.
306 *cp2
= 0; /* temporarily null terminate */
307 if (doign
&& is_ign(line
, cp2
- line
, doign
))
309 else if (asccasecmp(line
, "status") == 0) {
311 * If the field is "status," go compute
312 * and print the real Status: field
315 statusput(zmp
, obuf
, prefix
, stats
);
319 } else if (asccasecmp(line
, "x-status") == 0) {
321 * If the field is "status," go compute
322 * and print the real Status: field
325 xstatusput(zmp
, obuf
, prefix
, stats
);
335 * Determine if the end of the line is a MIME encoded word.
338 if (count
&& (c
= getc(ibuf
)) != EOF
) {
340 if (linelen
> 0 && line
[linelen
-1] == '\n')
341 cp
= &line
[linelen
-2];
343 cp
= &line
[linelen
-1];
344 while (cp
>= line
&& whitechar(*cp
&0377))
346 if (cp
- line
> 8 && cp
[0] == '=' &&
355 if (action
== SEND_TODISP
||
356 action
== SEND_TODISP_ALL
||
357 action
== SEND_QUOTE
||
358 action
== SEND_QUOTE_ALL
||
359 action
== SEND_TOSRCH
||
360 action
== SEND_TOFLTR
) {
362 * Strip blank characters if two MIME-encoded
363 * words follow on continuing lines.
366 while (len
>0&&blankchar(*start
&0377)) {
371 if (len
> 0 && start
[len
-1] == '\n')
373 while (len
> 0 && blankchar(start
[len
-1]&0377))
376 out(start
, len
, obuf
, convert
,
377 action
, prefix
, prefixlen
, stats
,
387 skip
: switch (ip
->m_mimecontent
) {
394 case SEND_TODISP_ALL
:
397 put_from_(obuf
, ip
->m_multipart
);
404 put_from_(obuf
, ip
->m_multipart
);
413 if (action
== SEND_TOFLTR
)
417 case MIME_TEXT_PLAIN
:
420 case SEND_TODISP_ALL
:
423 pipecmd
= getpipecmd(ip
->m_ct_type_plain
);
430 if (action
!= SEND_DECRYPT
)
434 if (action
!= SEND_MBOX
&& action
!= SEND_RFC822
&&
435 action
!= SEND_SHOW
&& ip
->m_multipart
)
441 case SEND_TODISP_ALL
:
444 if ((pipecmd
= getpipecmd(ip
->m_ct_type_plain
)) != NULL
)
446 if (level
== 0 && count
) {
447 cp
= "[Binary content]\n\n";
448 out(cp
, strlen(cp
), obuf
, CONV_NONE
, SEND_MBOX
,
449 prefix
, prefixlen
, stats
,
465 case MIME_ALTERNATIVE
:
466 if ((action
== SEND_TODISP
|| action
== SEND_QUOTE
) &&
467 value("print-alternatives") == NULL
)
468 for (np
= ip
->m_multipart
; np
; np
= np
->m_nextpart
)
469 if (np
->m_mimecontent
== MIME_TEXT_PLAIN
) {
470 if (sendpart(zmp
, np
, obuf
,
483 case SEND_TODISP_ALL
:
492 if ((action
== SEND_TODISP
||
493 action
== SEND_TODISP_ALL
) &&
494 ip
->m_multipart
!= NULL
&&
495 ip
->m_multipart
->m_mimecontent
== MIME_DISCARD
&&
496 ip
->m_multipart
->m_nextpart
== NULL
) {
497 cp
= "[Missing multipart boundary - "
498 "use \"show\" to display "
499 "the raw message]\n\n";
500 out(cp
, strlen(cp
), obuf
, CONV_NONE
, SEND_MBOX
,
501 prefix
, prefixlen
, stats
,
504 for (np
= ip
->m_multipart
; np
; np
= np
->m_nextpart
) {
505 if (np
->m_mimecontent
== MIME_DISCARD
&&
506 action
!= SEND_DECRYPT
)
510 if (np
->m_partstring
&&
511 strcmp(np
->m_partstring
,
515 if ((obuf
= newfile(np
, &ispipe
,
520 case SEND_TODISP_ALL
:
522 if ((ip
->m_mimecontent
== MIME_MULTI
||
528 len
= strlen(np
->m_partstring
) +
532 "%sPart %s:\n", level
||
533 strcmp(np
->m_partstring
,
537 out(cp
, strlen(cp
), obuf
,
538 CONV_NONE
, SEND_MBOX
,
557 if (sendpart(zmp
, np
, obuf
,
558 doign
, prefix
, prefixlen
,
559 action
, stats
, level
+1) < 0)
561 else if (action
== SEND_QUOTE
)
563 if (action
== SEND_TOFILE
&& obuf
!= origobuf
) {
567 safe_signal(SIGPIPE
, SIG_IGN
);
569 safe_signal(SIGPIPE
, oldpipe
);
581 * Copy out message body
583 if (doign
== allignore
&& level
== 0) /* skip final blank line */
585 switch (ip
->m_mimeenc
) {
595 convert
= CONV_FROMQP
;
598 switch (ip
->m_mimecontent
) {
600 case MIME_TEXT_PLAIN
:
602 convert
= CONV_FROMB64_T
;
605 convert
= CONV_FROMB64
;
611 if (action
== SEND_DECRYPT
|| action
== SEND_MBOX
||
612 action
== SEND_RFC822
|| action
== SEND_SHOW
)
616 if ((action
== SEND_TODISP
|| action
== SEND_TODISP_ALL
||
617 action
== SEND_QUOTE
|| action
== SEND_QUOTE_ALL
||
618 action
== SEND_TOSRCH
) &&
619 (ip
->m_mimecontent
== MIME_TEXT_PLAIN
||
620 ip
->m_mimecontent
== MIME_TEXT_HTML
||
621 ip
->m_mimecontent
== MIME_TEXT
)) {
622 if (iconvd
!= (iconv_t
)-1)
624 if (asccasecmp(tcs
, ip
->m_charset
) &&
625 asccasecmp(us_ascii
, ip
->m_charset
))
626 iconvd
= iconv_open_ft(tcs
, ip
->m_charset
);
628 iconvd
= (iconv_t
)-1;
630 #endif /* HAVE_ICONV */
631 if ((action
== SEND_TODISP
|| action
== SEND_TODISP_ALL
||
632 action
== SEND_QUOTE
|| action
== SEND_QUOTE_ALL
) &&
635 pbuf
= getpipefile(pipecmd
, &qbuf
,
636 action
== SEND_QUOTE
|| action
== SEND_QUOTE_ALL
);
637 action
= SEND_TOPIPE
;
639 oldpipe
= safe_signal(SIGPIPE
, onpipe
);
640 if (sigsetjmp(pipejmp
, 1))
646 while (!eof
&& foldergets(&line
, &linesize
, &count
, &linelen
, ibuf
)) {
648 while (convert
== CONV_FROMQP
&& linelen
>= 2 &&
649 line
[linelen
-2] == '=') {
651 size_t linesize2
, linelen2
;
655 if (foldergets(&line2
, &linesize2
, &count
, &linelen2
,
660 if (linelen
+ linelen2
+ 1 > linesize
)
661 line
= srealloc(line
, linesize
= linelen
+
663 memcpy(&line
[linelen
], line2
, linelen2
+1);
669 out(line
, linelen
, pbuf
, convert
, action
,
670 pbuf
== origobuf
? prefix
: NULL
,
671 pbuf
== origobuf
? prefixlen
: 0,
672 pbuf
== origobuf
? stats
: NULL
,
673 eof
? NULL
: &rest
, eof
? NULL
: &restsize
);
680 memmove(line
, rest
, restsize
);
687 safe_signal(SIGPIPE
, SIG_IGN
);
689 safe_signal(SIGPIPE
, oldpipe
);
691 pipecpy(qbuf
, obuf
, origobuf
, prefix
, prefixlen
, stats
);
694 if (iconvd
!= (iconv_t
)-1) {
696 iconvd
= (iconv_t
)-1;
702 static struct mimepart
*
703 parsemsg(struct message
*mp
, enum parseflags pf
)
707 ip
= csalloc(1, sizeof *ip
);
708 ip
->m_flag
= mp
->m_flag
;
709 ip
->m_have
= mp
->m_have
;
710 ip
->m_block
= mp
->m_block
;
711 ip
->m_offset
= mp
->m_offset
;
712 ip
->m_size
= mp
->m_size
;
713 ip
->m_xsize
= mp
->m_xsize
;
714 ip
->m_lines
= mp
->m_lines
;
715 ip
->m_xlines
= mp
->m_lines
;
716 if (parsepart(mp
, ip
, pf
, 0) != OKAY
)
722 parsepart(struct message
*zmp
, struct mimepart
*ip
, enum parseflags pf
,
727 ip
->m_ct_type
= hfield("content-type", (struct message
*)ip
);
728 if (ip
->m_ct_type
!= NULL
) {
729 ip
->m_ct_type_plain
= savestr(ip
->m_ct_type
);
730 if ((cp
= strchr(ip
->m_ct_type_plain
, ';')) != NULL
)
732 } else if (ip
->m_parent
&& ip
->m_parent
->m_mimecontent
== MIME_DIGEST
)
733 ip
->m_ct_type_plain
= "message/rfc822";
735 ip
->m_ct_type_plain
= "text/plain";
736 ip
->m_mimecontent
= mime_getcontent(ip
->m_ct_type_plain
);
738 ip
->m_charset
= mime_getparam("charset", ip
->m_ct_type
);
739 if (ip
->m_charset
== NULL
)
740 ip
->m_charset
= us_ascii
;
741 ip
->m_ct_transfer_enc
= hfield("content-transfer-encoding",
742 (struct message
*)ip
);
743 ip
->m_mimeenc
= ip
->m_ct_transfer_enc
?
744 mime_getenc(ip
->m_ct_transfer_enc
) : MIME_7B
;
745 if ((cp
= hfield("content-disposition", (struct message
*)ip
)) == 0 ||
746 (ip
->m_filename
= mime_getparam("filename", cp
)) == 0)
747 if (ip
->m_ct_type
!= NULL
)
748 ip
->m_filename
= mime_getparam("name", ip
->m_ct_type
);
749 if (pf
& PARSE_PARTS
) {
751 fprintf(stderr
, "MIME content too deeply nested.\n");
754 switch (ip
->m_mimecontent
) {
756 if (pf
& PARSE_DECRYPT
) {
757 parsepkcs7(zmp
, ip
, pf
, level
);
764 case MIME_ALTERNATIVE
:
766 parsemultipart(zmp
, ip
, pf
, level
);
769 parse822(zmp
, ip
, pf
, level
);
777 parsemultipart(struct message
*zmp
, struct mimepart
*ip
, enum parseflags pf
,
782 size_t linesize
= 0, linelen
, count
, boundlen
;
784 struct mimepart
*np
= NULL
;
789 if ((boundary
= mime_getboundary(ip
->m_ct_type
)) == NULL
)
791 boundlen
= strlen(boundary
);
792 if ((ibuf
= setinput(&mb
, (struct message
*)ip
, NEED_BODY
)) == NULL
)
795 while (foldergets(&line
, &linesize
, &count
, &linelen
, ibuf
))
799 newpart(ip
, &np
, offs
, NULL
);
800 while (foldergets(&line
, &linesize
, &count
, &linelen
, ibuf
)) {
801 if ((lines
> 0 || part
== 0) && linelen
>= boundlen
+ 1 &&
802 strncmp(line
, boundary
, boundlen
) == 0) {
803 if (line
[boundlen
] == '\n') {
806 endpart(&np
, offs
-boundlen
-2, lines
);
807 newpart(ip
, &np
, offs
-boundlen
-2, NULL
);
809 endpart(&np
, offs
, 2);
810 newpart(ip
, &np
, offs
, &part
);
812 } else if (line
[boundlen
] == '-' &&
813 line
[boundlen
+1] == '-' &&
814 line
[boundlen
+2] == '\n') {
817 endpart(&np
, offs
-boundlen
-4, lines
);
818 newpart(ip
, &np
, offs
-boundlen
-4, NULL
);
820 endpart(&np
, offs
+count
, 2);
829 endpart(&np
, offs
, lines
);
831 for (np
= ip
->m_multipart
; np
; np
= np
->m_nextpart
)
832 if (np
->m_mimecontent
!= MIME_DISCARD
)
833 parsepart(zmp
, np
, pf
, level
+1);
838 newpart(struct mimepart
*ip
, struct mimepart
**np
, off_t offs
, int *part
)
843 *np
= csalloc(1, sizeof **np
);
844 (*np
)->m_flag
= MNOFROM
;
845 (*np
)->m_have
= HAVE_HEADER
|HAVE_BODY
;
846 (*np
)->m_block
= mailx_blockof(offs
);
847 (*np
)->m_offset
= mailx_offsetof(offs
);
850 sz
= ip
->m_partstring
? strlen(ip
->m_partstring
) : 0;
852 (*np
)->m_partstring
= salloc(sz
);
853 if (ip
->m_partstring
)
854 snprintf((*np
)->m_partstring
, sz
, "%s.%u",
855 ip
->m_partstring
, *part
);
857 snprintf((*np
)->m_partstring
, sz
, "%u", *part
);
859 (*np
)->m_mimecontent
= MIME_DISCARD
;
860 (*np
)->m_parent
= ip
;
861 if (ip
->m_multipart
) {
862 for (pp
= ip
->m_multipart
; pp
->m_nextpart
; pp
= pp
->m_nextpart
);
863 pp
->m_nextpart
= *np
;
865 ip
->m_multipart
= *np
;
869 endpart(struct mimepart
**np
, off_t xoffs
, long lines
)
873 offs
= mailx_positionof((*np
)->m_block
, (*np
)->m_offset
);
874 (*np
)->m_size
= (*np
)->m_xsize
= xoffs
- offs
;
875 (*np
)->m_lines
= (*np
)->m_xlines
= lines
;
880 parse822(struct message
*zmp
, struct mimepart
*ip
, enum parseflags pf
,
890 if ((ibuf
= setinput(&mb
, (struct message
*)ip
, NEED_BODY
)) == NULL
)
894 while (count
&& ((c
= getc(ibuf
)) != EOF
)) {
904 np
= csalloc(1, sizeof *np
);
905 np
->m_flag
= MNOFROM
;
906 np
->m_have
= HAVE_HEADER
|HAVE_BODY
;
907 np
->m_block
= mailx_blockof(offs
);
908 np
->m_offset
= mailx_offsetof(offs
);
909 np
->m_size
= np
->m_xsize
= count
;
910 np
->m_lines
= np
->m_xlines
= lines
;
911 np
->m_partstring
= ip
->m_partstring
;
913 ip
->m_multipart
= np
;
914 substdate((struct message
*)np
);
915 np
->m_from
= fakefrom((struct message
*)np
);
916 parsepart(zmp
, np
, pf
, level
+1);
920 parsepkcs7(struct message
*zmp
, struct mimepart
*ip
, enum parseflags pf
,
923 struct message m
, *xmp
;
927 memcpy(&m
, ip
, sizeof m
);
928 to
= hfield("to", zmp
);
929 cc
= hfield("cc", zmp
);
930 if ((xmp
= smime_decrypt(&m
, to
, cc
, 0)) != NULL
) {
931 np
= csalloc(1, sizeof *np
);
932 np
->m_flag
= xmp
->m_flag
;
933 np
->m_have
= xmp
->m_have
;
934 np
->m_block
= xmp
->m_block
;
935 np
->m_offset
= xmp
->m_offset
;
936 np
->m_size
= xmp
->m_size
;
937 np
->m_xsize
= xmp
->m_xsize
;
938 np
->m_lines
= xmp
->m_lines
;
939 np
->m_xlines
= xmp
->m_xlines
;
940 np
->m_partstring
= ip
->m_partstring
;
941 if (parsepart(zmp
, np
, pf
, level
+1) == OKAY
) {
943 ip
->m_multipart
= np
;
949 out(char *buf
, size_t len
, FILE *fp
,
950 enum conversion convert
, enum sendaction action
,
951 char *prefix
, size_t prefixlen
, off_t
*stats
,
952 char **restp
, size_t *restsizep
)
959 if (action
== SEND_MBOX
|| action
== SEND_DECRYPT
) {
962 while (n
&& cp
[0] == '>')
964 if (n
>= 5 && cp
[0] == 'F' && cp
[1] == 'r' && cp
[2] == 'o' &&
965 cp
[3] == 'm' && cp
[4] == ' ') {
970 sz
+= mime_write(buf
, len
, fp
,
971 action
== SEND_MBOX
? CONV_NONE
: convert
,
972 action
== SEND_TODISP
|| action
== SEND_TODISP_ALL
||
973 action
== SEND_QUOTE
||
974 action
== SEND_QUOTE_ALL
?
976 action
== SEND_TOSRCH
|| action
== SEND_TOPIPE
?
978 action
== SEND_TOFLTR
?
980 action
== SEND_SHOW
?
985 if (stats
&& stats
[0] != -1) {
986 for (cp
= buf
; cp
< &buf
[sz
]; cp
++)
990 addstats(stats
, lines
, sz
);
995 addstats(off_t
*stats
, off_t lines
, off_t bytes
)
1005 * Get a file for an attachment.
1008 newfile(struct mimepart
*ip
, int *ispipe
, sighandler_type
*oldpipe
)
1010 char *f
= ip
->m_filename
;
1015 if (f
!= NULL
&& f
!= (char *)-1) {
1018 mime_fromhdr(&in
, &out
, TD_ISPR
);
1019 memcpy(f
, out
.s
, out
.l
);
1020 *(f
+ out
.l
) = '\0';
1023 if (value("interactive") != NULL
) {
1024 printf("Enter filename for part %s (%s)",
1025 ip
->m_partstring
? ip
->m_partstring
: "?",
1026 ip
->m_ct_type_plain
);
1027 f
= readtty(catgets(catd
, CATSET
, 173, ": "),
1028 f
!= (char *)-1 ? f
: NULL
);
1030 if (f
== NULL
|| f
== (char *)-1)
1035 cp
= value("SHELL");
1038 fp
= Popen(f
+1, "w", cp
, 1);
1043 *oldpipe
= safe_signal(SIGPIPE
, brokpipe
);
1047 if ((fp
= Fopen(f
, "w")) == NULL
)
1048 fprintf(stderr
, "Cannot open %s\n", f
);
1054 getpipecmd(char *content
)
1056 char *penv
, *cp
, *cq
, *pipecmd
;
1058 if (content
== NULL
)
1060 penv
= ac_alloc(strlen(content
) + 6);
1061 strcpy(penv
, "pipe-");
1065 *cp
++ = lowerconv(*cq
& 0377);
1067 pipecmd
= value(penv
);
1073 getpipefile(char *pipecmd
, FILE **qbuf
, int quote
)
1078 if (pipecmd
!= NULL
) {
1082 if ((*qbuf
= Ftemp(&tempPipe
, "Rp", "w+", 0600, 1))
1084 perror(catgets(catd
, CATSET
, 173, "tmpfile"));
1090 if ((shell
= value("SHELL")) == NULL
)
1092 if ((rbuf
= Popen(pipecmd
, "W", shell
, fileno(*qbuf
)))
1097 if (*qbuf
!= stdout
)
1105 pipecpy(FILE *pipebuf
, FILE *outbuf
, FILE *origobuf
,
1106 char *prefix
, size_t prefixlen
, off_t
*stats
)
1109 size_t linesize
= 0, linelen
, sz
, count
;
1113 count
= fsize(pipebuf
);
1114 while (fgetline(&line
, &linesize
, &count
, &linelen
, pipebuf
, 0)
1116 sz
= prefixwrite(line
, sizeof *line
, linelen
, outbuf
,
1118 if (outbuf
== origobuf
)
1119 addstats(stats
, 1, sz
);
1127 * Output a reasonable looking status field.
1130 statusput(const struct message
*mp
, FILE *obuf
, char *prefix
, off_t
*stats
)
1135 if (mp
->m_flag
& MREAD
)
1137 if ((mp
->m_flag
& MNEW
) == 0)
1141 fprintf(obuf
, "%sStatus: %s\n",
1142 prefix
== NULL
? "" : prefix
, statout
);
1143 addstats(stats
, 1, (prefix
? strlen(prefix
) : 0) + 9 + cp
- statout
);
1147 xstatusput(const struct message
*mp
, FILE *obuf
, char *prefix
, off_t
*stats
)
1150 char *xp
= xstatout
;
1152 if (mp
->m_flag
& MFLAGGED
)
1154 if (mp
->m_flag
& MANSWERED
)
1156 if (mp
->m_flag
& MDRAFTED
)
1160 fprintf(obuf
, "%sX-Status: %s\n",
1161 prefix
== NULL
? "" : prefix
, xstatout
);
1162 addstats(stats
, 1, (prefix
? strlen(prefix
) : 0) + 11 + xp
- xstatout
);
1166 put_from_(FILE *fp
, struct mimepart
*ip
)
1170 if (ip
&& ip
->m_from
)
1171 fprintf(fp
, "From %s %s\n", ip
->m_from
, fakedate(ip
->m_time
));
1174 fprintf(fp
, "From %s %s", myname
, ctime(&now
));
1179 * This is fgetline for mbox lines.
1182 foldergets(char **s
, size_t *size
, size_t *count
, size_t *llen
, FILE *stream
)
1186 if ((p
= fgetline(s
, size
, count
, llen
, stream
, 0)) == NULL
)
1190 while (*p
== '>') p
++;
1191 if (strncmp(p
, "From ", 5) == 0) {
1192 /* we got a masked From line */