1 /*@ S-nail - a mail user agent derived from Berkeley Mail.
2 *@ Handling of attachments.
4 * Copyright (c) 2000-2004 Gunnar Ritter, Freiburg i. Br., Germany.
5 * Copyright (c) 2012 - 2013 Steffen "Daode" Nurpmeso <sdaoden@users.sf.net>.
8 * Copyright (c) 1980, 1993
9 * The Regents of the University of California. All rights reserved.
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
14 * 1. Redistributions of source code must retain the above copyright
15 * notice, this list of conditions and the following disclaimer.
16 * 2. Redistributions in binary form must reproduce the above copyright
17 * notice, this list of conditions and the following disclaimer in the
18 * documentation and/or other materials provided with the distribution.
19 * 3. All advertising materials mentioning features or use of this software
20 * must display the following acknowledgement:
21 * This product includes software developed by the University of
22 * California, Berkeley and its contributors.
23 * 4. Neither the name of the University nor the names of its contributors
24 * may be used to endorse or promote products derived from this software
25 * without specific prior written permission.
27 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
28 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
29 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
30 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
31 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
32 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
33 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
34 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
35 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
36 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
42 /* We use calloc() for struct attachment */
45 /* Fill in some attachment fields; don't be interactive if number==0n */
46 static struct attachment
* _fill_in(struct attachment
*ap
,
47 char const *file
, ui_it number
);
49 /* Ask the user to edit file names and other data for the given attachment */
50 static struct attachment
* _read_attachment_data(struct attachment
*ap
,
53 /* Try to create temporary charset converted version */
55 static int _attach_iconv(struct attachment
*ap
);
58 static struct attachment
*
59 _fill_in(struct attachment
*ap
, char const *file
, ui_it number
)
62 * XXX The "attachment-ask-content-*" variables are left undocumented
63 * since they are for RFC connoisseurs only.
68 if ((file
= strrchr(file
, '/')) != NULL
)
73 ap
->a_content_type
= mime_classify_content_type_by_fileext(file
);
74 if (number
> 0 && value("attachment-ask-content-type")) {
75 snprintf(prefix
, sizeof prefix
, "#%u\tContent-Type: ", number
);
76 ap
->a_content_type
= readstr_input(prefix
, ap
->a_content_type
);
79 if (number
> 0 && value("attachment-ask-content-disposition")) {
80 snprintf(prefix
, sizeof prefix
,
81 "#%u\tContent-Disposition: ", number
);
82 ap
->a_content_disposition
= readstr_input(prefix
,
83 ap
->a_content_disposition
);
85 if (ap
->a_content_disposition
== NULL
)
86 ap
->a_content_disposition
= "attachment";
88 if (number
> 0 && value("attachment-ask-content-id")) {
89 snprintf(prefix
, sizeof prefix
, "#%u\tContent-ID: ", number
);
90 ap
->a_content_id
= readstr_input(prefix
, ap
->a_content_id
);
93 if (number
> 0 && value("attachment-ask-content-description")) {
94 snprintf(prefix
, sizeof prefix
,
95 "#%u\tContent-Description: ", number
);
96 ap
->a_content_description
= readstr_input(prefix
,
97 ap
->a_content_description
);
102 static struct attachment
*
103 _read_attachment_data(struct attachment
*ap
, ui_it number
)
106 char const *cslc
= NULL
/*cc uninit?*/, *cp
, *defcs
;
109 ap
= csalloc(1, sizeof *ap
);
110 else if (ap
->a_msgno
) {
111 char *ecp
= salloc(16);
112 snprintf(ecp
, 16, "#%u", (ui_it
)ap
->a_msgno
);
115 } else if (ap
->a_conv
== AC_TMPFILE
) {
117 ap
->a_conv
= AC_DEFAULT
;
120 snprintf(prefix
, sizeof prefix
, tr(50, "#%u\tfilename: "), number
);
122 if ((ap
->a_name
= readstr_input(prefix
, ap
->a_name
)) == NULL
) {
126 /* May be a message number */
127 if (ap
->a_name
[0] == '#') {
129 int msgno
= (int)strtol(ap
->a_name
+ 1, &ecp
, 10);
130 if (msgno
> 0 && msgno
<= msgCount
&& *ecp
== '\0') {
132 ap
->a_content_description
=
133 tr(513, "Attached message content");
134 if (options
& OPT_INTERACTIVE
)
135 printf(tr(2, "~@: added message #%u\n"),
140 if ((cp
= file_expand(ap
->a_name
)) != NULL
&&
141 access(cp
, R_OK
) == 0) {
148 ap
= _fill_in(ap
, cp
, number
);
151 * Character set of attachments: enum attach_conv
153 cslc
= charset_get_lc();
155 if (! (options
& OPT_INTERACTIVE
))
157 if ((cp
= ap
->a_content_type
) != NULL
&&
158 ascncasecmp(cp
, "text/", 5) != 0 &&
159 ! yorn(tr(162, "Filename doesn't indicate text "
160 "content - want to edit charsets? "))) {
161 ap
->a_conv
= AC_DEFAULT
;
165 charset_iter_reset(NULL
);
168 snprintf(prefix
, sizeof prefix
, tr(160, "#%u\tinput charset: "),
170 if ((defcs
= ap
->a_input_charset
) == NULL
)
172 cp
= ap
->a_input_charset
= readstr_input(prefix
, defcs
);
174 if (! (options
& OPT_INTERACTIVE
)) {
176 ap
->a_conv
= (cp
!= NULL
) ? AC_FIX_INCS
: AC_DEFAULT
;
181 snprintf(prefix
, sizeof prefix
, tr(161, "#%u\toutput (send) charset: "),
183 if ((defcs
= ap
->a_charset
) == NULL
)
184 defcs
= charset_iter_next();
185 defcs
= ap
->a_charset
= readstr_input(prefix
, defcs
);
187 if (cp
!= NULL
&& defcs
== NULL
) {
188 ap
->a_conv
= AC_FIX_INCS
;
191 if (cp
== NULL
&& defcs
== NULL
) {
192 ap
->a_conv
= AC_DEFAULT
;
193 ap
->a_input_charset
= cslc
;
194 ap
->a_charset
= charset_iter_current();
195 } else if (cp
== NULL
&& defcs
!= NULL
) {
196 ap
->a_conv
= AC_FIX_OUTCS
;
197 ap
->a_input_charset
= cslc
;
199 ap
->a_conv
= AC_TMPFILE
;
201 printf(tr(197, "Trying conversion from %s to %s\n"),
202 ap
->a_input_charset
, ap
->a_charset
);
203 if (_attach_iconv(ap
))
204 ap
->a_conv
= AC_TMPFILE
;
206 ap
->a_input_charset
= cp
;
207 ap
->a_charset
= defcs
;
212 if (options
& OPT_INTERACTIVE
)
213 printf(tr(19, "~@: added attachment \"%s\"\n"), ap
->a_name
);
220 _attach_iconv(struct attachment
*ap
)
222 struct str oul
= {NULL
, 0}, inl
= {NULL
, 0};
223 FILE *fo
= NULL
, *fi
= NULL
;
227 if ((icp
= n_iconv_open(ap
->a_charset
, ap
->a_input_charset
))
232 perror("iconv_open");
236 if ((fi
= Fopen(ap
->a_name
, "r")) == NULL
) {
243 if ((fo
= Ftemp(&inl
.s
, "aiconv", "w+", 0600, 1)) == NULL
) {
244 perror(tr(51, "temporary mail file"));
251 for (inl
.s
= NULL
, lbsize
= 0;;) {
252 if (fgetline(&inl
.s
, &lbsize
, &cnt
, &inl
.l
, fi
, 0) == NULL
) {
255 perror(tr(195, "I/O read error occurred"));
259 if (n_iconv_str(icp
, &oul
, &inl
, NULL
, FAL0
) != 0)
261 if ((inl
.l
=fwrite(oul
.s
, sizeof *oul
.s
, oul
.l
, fo
)) != oul
.l
) {
262 perror(tr(196, "I/O write error occurred"));
276 if (icp
!= (iconv_t
)-1)
280 fprintf(stderr
, tr(179, "Cannot convert from %s to %s\n"),
281 ap
->a_input_charset
, ap
->a_charset
);
288 #endif /* HAVE_ICONV */
291 add_attachment(struct attachment
*aphead
, char *file
, struct attachment
**newap
)
293 struct attachment
*nap
= NULL
, *ap
;
295 if ((file
= file_expand(file
)) == NULL
)
297 if (access(file
, R_OK
) != 0)
300 nap
= _fill_in(csalloc(1, sizeof *nap
), file
, 0);
303 if (aphead
!= NULL
) {
304 for (ap
= aphead
; ap
->a_flink
!= NULL
; ap
= ap
->a_flink
)
318 append_attachments(struct attachment
*aphead
, char *names
)
321 struct attachment
*xaph
, *nap
;
323 while ((cp
= strcomma(&names
, 1)) != NULL
) {
324 if ((xaph
= add_attachment(aphead
, cp
, &nap
)) != NULL
) {
326 if (options
& OPT_INTERACTIVE
)
327 printf(tr(19, "~@: added attachment \"%s\"\n"),
336 edit_attachments(struct attachment
*aphead
)
338 struct attachment
*ap
, *nap
;
341 /* Modify already present ones? */
342 for (ap
= aphead
; ap
!= NULL
; ap
= ap
->a_flink
) {
343 if (_read_attachment_data(ap
, attno
) != NULL
) {
348 if (ap
->a_blink
!= NULL
)
349 ap
->a_blink
->a_flink
= nap
;
353 nap
->a_blink
= ap
->a_blink
;
359 while ((nap
= _read_attachment_data(NULL
, attno
)) != NULL
) {
360 if ((ap
= aphead
) != NULL
) {
361 while (ap
->a_flink
!= NULL
)