mime_detach.c revision 1.1 1 /* $NetBSD: mime_detach.c,v 1.1 2006/11/28 18:45:32 christos Exp $ */
2
3 /*-
4 * Copyright (c) 2006 The NetBSD Foundation, Inc.
5 * All rights reserved.
6 *
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Anon Ymous.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
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 NetBSD
21 * Foundation, Inc. and its contributors.
22 * 4. Neither the name of The NetBSD Foundation nor the names of its
23 * contributors may be used to endorse or promote products derived
24 * from this software without specific prior written permission.
25 *
26 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
27 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
28 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
29 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
30 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
31 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
32 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
33 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
34 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
35 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
36 * POSSIBILITY OF SUCH DAMAGE.
37 */
38
39
40 #ifdef MIME_SUPPORT
41
42 #include <sys/cdefs.h>
43 #ifndef __lint__
44 __RCSID("$NetBSD: mime_detach.c,v 1.1 2006/11/28 18:45:32 christos Exp $");
45 #endif /* not __lint__ */
46
47 #include <assert.h>
48 #include <err.h>
49 #include <fcntl.h>
50 #include <stdio.h>
51 #include <stdlib.h>
52
53 #include "def.h"
54 #include "extern.h"
55 #ifdef USE_EDITLINE
56 #include "complete.h"
57 #endif
58 #ifdef MIME_SUPPORT
59 #include "mime.h"
60 #include "mime_child.h"
61 #include "mime_codecs.h"
62 #include "mime_detach.h"
63 #endif
64
65
66 static struct {
67 int overwrite;
68 int batch;
69 int ask;
70 } detach_ctl;
71
72 PUBLIC int
73 mime_detach_control(void)
74 {
75 char *cp;
76
77 detach_ctl.batch = value(ENAME_MIME_DETACH_BATCH) != NULL;
78 detach_ctl.ask = detach_ctl.batch ? 0 : 1;
79 detach_ctl.overwrite = 0;
80
81 cp = value(ENAME_MIME_DETACH_OVERWRITE);
82 if (cp == NULL || strcasecmp(cp, "no") == 0)
83 detach_ctl.overwrite = 0;
84
85 else if (*cp== '\0' || strcasecmp(cp, "yes") == 0)
86 detach_ctl.overwrite = 1;
87
88 else if (strcasecmp(cp, "ask") == 0) {
89 detach_ctl.overwrite = 0;
90 detach_ctl.ask = 1;
91 }
92 else {
93 (void)printf("invalid %s setting: %s",
94 ENAME_MIME_DETACH_OVERWRITE, cp);
95 return -1;
96 }
97 return 0;
98 }
99
100 static char *
101 detach_get_fname(char *prompt, char *pathname)
102 {
103 if (!detach_ctl.batch) {
104 char *fname;
105 fname = my_gets(&elm.filec, prompt, pathname);
106 fname = skip_blank(fname); /* XXX - do this? */
107 if (*fname == '\0') /* ignore this attachment */
108 return NULL;
109 pathname = savestr(fname); /* save this or it gets trashed */
110 }
111 else if (detach_ctl.ask)
112 (void)printf("%s%s\n", prompt, pathname);
113
114 return pathname;
115 }
116
117 static enum {
118 DETACH_OPEN_OK,
119 DETACH_NEXT,
120 DETACH_RENAME,
121 DETACH_FAILED
122 }
123 detach_open_core(char *fname, const char *partstr)
124 {
125 int flags;
126 int fd;
127
128 flags = (detach_ctl.overwrite ? 0 : O_EXCL) | O_CREAT | O_TRUNC | O_WRONLY;
129
130 if ((fd = open(fname, flags, 0600)) != -1 &&
131 Fdopen(fd, "w") != NULL)
132 return DETACH_OPEN_OK;
133
134 if (detach_ctl.ask && fd == -1 && errno == EEXIST) {
135 char *p;
136 start:
137 (void)sasprintf(&p, "%-7s overwrite: Always/Never/once/next/rename (ANonr)[n]? ",
138 partstr, fname);
139 p = my_gets(&elm.string, p, NULL);
140 p = skip_blank(p);
141 switch (*p) {
142 case 'A': detach_ctl.overwrite = 1;
143 detach_ctl.batch = 1;
144 detach_ctl.ask = 0;
145 /* FALLTHROUGH */
146 case 'o':
147 if (Fopen(fname, "w") != NULL)
148 return DETACH_OPEN_OK;
149 break;
150
151 case 'N': detach_ctl.overwrite = 0;
152 detach_ctl.batch = 1;
153 detach_ctl.ask = 0;
154 /* FALLTHROUGH */
155 case '\0': /* default */
156 case 'n': /* Next */
157 return DETACH_NEXT;
158
159 default:
160 goto start;
161
162 case 'r': /* Rename */
163 return DETACH_RENAME;
164 }
165 }
166 warn(fname);
167 if (fd != -1)
168 (void)close(fd);
169
170 return DETACH_FAILED;
171 }
172
173 static char *
174 detach_open_target(struct mime_info *mip)
175 {
176 char *pathname;
177 char *prompt;
178
179 /*
180 * Get the suggested target pathname.
181 */
182 if (mip->mi_filename != NULL)
183 (void)sasprintf(&pathname, "%s/%s", mip->mi_detachdir, mip->mi_filename);
184 else {
185 if (mip->mi_detachall == 0)
186 return NULL;
187
188 (void)sasprintf(&pathname, "%s/msg-%s.part-%s.%s",
189 mip->mi_detachdir, mip->mi_msgstr,
190 mip->mi_partstr[0] ? mip->mi_partstr : "0",
191 mip->mi_subtype ? mip->mi_subtype : "unknown");
192 }
193
194 /*
195 * Make up the prompt
196 */
197 (void)sasprintf(&prompt, "%-7s filename: ", mip->mi_partstr);
198
199 /*
200 * The main loop.
201 */
202 do {
203 struct stat sb;
204 char *fname;
205
206 if ((fname = detach_get_fname(prompt, pathname)) == NULL)
207 return NULL;
208 /*
209 * Make sure we don't have the name of something other
210 * than a normal file!
211 */
212 if (stat(fname, &sb) == 0 && !S_ISREG(sb.st_mode)) {
213 (void)printf("not a regular file: %s", fname);
214 if (!detach_ctl.ask)
215 return NULL;
216 continue;
217 }
218 switch (detach_open_core(fname, mip->mi_partstr)) {
219 case DETACH_OPEN_OK:
220 return fname;
221 case DETACH_NEXT:
222 return NULL;
223 case DETACH_RENAME:
224 detach_ctl.batch = 0;
225 break;
226 case DETACH_FAILED:
227 break;
228 }
229 } while (!detach_ctl.batch);
230
231 return NULL;
232 }
233
234 /*
235 * The main entry point for detaching.
236 */
237 PUBLIC FILE *
238 mime_detach_parts(struct mime_info *mip)
239 {
240 mime_codec_t dec;
241 char *pathname;
242
243 if (mip->mi_ignore_body || mip->mp->m_blines == 0)
244 return NULL;
245
246 if ((dec = mime_fio_decoder(mip->mi_encoding)) == NULL &&
247 (dec = mime_fio_decoder(MIME_TRANSFER_7BIT)) == NULL)
248 assert(/*CONSTCOND*/ 0); /* this should never get hit! */
249
250 if ((pathname = detach_open_target(mip)) == NULL)
251 return NULL;
252
253 (void)printf("writing: %s\n", pathname);
254
255 /*
256 * XXX - should we do character set conversion here (done by
257 * run_decoder()), or just run dec()?
258 */
259 #if 0
260 mime_run_function(dec, pipe_end(mip), NULL);
261 #else
262 run_decoder(mip, dec);
263 #endif
264 return pipe_end(mip);
265 }
266
267 /*
268 * Set the message part number to be used when constructing a filename
269 * for detaching unnamed parts in detach_open_target(). When
270 * threading, this is not a single number, hence the string value.
271 */
272 PUBLIC void
273 mime_detach_msgnum(struct mime_info *mip, const char *msgstr)
274 {
275 for (/*EMPTY*/; mip; mip = mip->mi_flink)
276 mip->mi_msgstr = msgstr;
277 }
278
279 #endif /* MIME_SUPPORT */
280