0
|
1 /* refile.c - file messages away */
|
|
2 #ifndef lint
|
12
|
3 static char ident[] = "@(#)$Id: refile.c,v 1.2 2006/12/05 18:18:13 kono Exp $";
|
0
|
4 #endif /* lint */
|
|
5
|
|
6 #include "../h/mh.h"
|
|
7 #include <errno.h>
|
|
8 #include <stdio.h>
|
|
9 #include <sys/types.h>
|
|
10 #include <sys/stat.h>
|
|
11 #ifdef LOCALE
|
|
12 #include <locale.h>
|
|
13 #endif
|
|
14
|
|
15 /* */
|
|
16
|
|
17 static struct swit switches[] = {
|
|
18 #define DRAFTSW 0
|
|
19 "draft", 0,
|
|
20
|
|
21 #define LINKSW 1
|
|
22 "link", 0,
|
|
23 #define NLINKSW 2
|
|
24 "nolink", 0,
|
|
25
|
|
26 #define PRESSW 3
|
|
27 "preserve", 0,
|
|
28 #define NPRESSW 4
|
|
29 "nopreserve", 0,
|
|
30
|
|
31 #define SRCSW 5
|
|
32 "src +folder", 0,
|
|
33
|
|
34 #define FILESW 6
|
|
35 "file file", 0,
|
|
36
|
|
37 #define RPROCSW 7
|
|
38 "rmmproc program", 0,
|
|
39 #define NRPRCSW 8
|
|
40 "normmproc", 0,
|
|
41
|
|
42 #define HELPSW 9
|
|
43 "help", 4,
|
|
44
|
|
45 NULL, 0
|
|
46 };
|
|
47
|
|
48 /* */
|
|
49
|
|
50
|
|
51
|
|
52 static char maildir[BUFSIZ];
|
|
53
|
|
54
|
|
55 struct st_fold {
|
|
56 char *f_name;
|
|
57 struct msgs *f_mp;
|
|
58 };
|
|
59
|
|
60 static opnfolds(), clsfolds(), removeit();
|
|
61 /* */
|
|
62
|
|
63 /* ARGSUSED */
|
|
64
|
|
65 main (argc, argv)
|
|
66 int argc;
|
|
67 char **argv;
|
|
68 {
|
|
69 int linkf = 0,
|
|
70 prsrvf = 0,
|
|
71 filep = 0,
|
|
72 foldp = 0,
|
|
73 msgp = 0,
|
|
74 isdf = 0,
|
|
75 i,
|
|
76 msgnum;
|
|
77 char *cp,
|
|
78 *folder = NULL,
|
|
79 buf[100],
|
|
80 **ap,
|
|
81 **argp,
|
|
82 *arguments[MAXARGS],
|
|
83 *filevec[NFOLDERS + 2],
|
|
84 **files = &filevec[1], /* leave room for removeit:vec[0] */
|
|
85 *msgs[MAXARGS];
|
|
86 struct st_fold folders[NFOLDERS + 1];
|
|
87 struct msgs *mp;
|
|
88
|
|
89 #ifdef LOCALE
|
|
90 setlocale(LC_ALL, "");
|
|
91 #endif
|
|
92 #ifdef JAPAN
|
|
93 ml_init();
|
|
94 #endif /* JAPAN */
|
|
95 invo_name = r1bindex (argv[0], '/');
|
|
96 if ((cp = m_find (invo_name)) != NULL) {
|
|
97 ap = brkstring (cp = getcpy (cp), " ", "\n");
|
|
98 ap = copyip (ap, arguments);
|
|
99 }
|
|
100 else
|
|
101 ap = arguments;
|
|
102 (void) copyip (argv + 1, ap);
|
|
103 argp = arguments;
|
|
104
|
|
105 /* */
|
|
106
|
|
107 while (cp = *argp++) {
|
|
108 if (*cp == '-')
|
|
109 switch (smatch (++cp, switches)) {
|
|
110 case AMBIGSW:
|
|
111 ambigsw (cp, switches);
|
|
112 done (1);
|
|
113 case UNKWNSW:
|
|
114 adios (NULLCP, "-%s unknown\n", cp);
|
|
115 case HELPSW:
|
|
116 (void) sprintf (buf, "%s [msgs] [switches] +folder ...",
|
|
117 invo_name);
|
|
118 help (buf, switches);
|
|
119 done (1);
|
|
120
|
|
121 case LINKSW:
|
|
122 linkf++;
|
|
123 continue;
|
|
124 case NLINKSW:
|
|
125 linkf = 0;
|
|
126 continue;
|
|
127
|
|
128 case PRESSW:
|
|
129 prsrvf++;
|
|
130 continue;
|
|
131 case NPRESSW:
|
|
132 prsrvf = 0;
|
|
133 continue;
|
|
134
|
|
135 case SRCSW:
|
|
136 if (folder)
|
|
137 adios (NULLCP, "only one source folder at a time!");
|
|
138 if (!(cp = *argp++) || *cp == '-')
|
|
139 adios (NULLCP, "missing argument to %s", argp[-2]);
|
|
140 folder = path (*cp == '+' || *cp == '@' ? cp + 1 : cp,
|
|
141 *cp != '@' ? TFOLDER : TSUBCWF);
|
|
142 continue;
|
|
143 case DRAFTSW:
|
|
144 if (filep > NFOLDERS)
|
|
145 adios (NULLCP, "only %d files allowed!", NFOLDERS);
|
|
146 isdf = 0;
|
|
147 files[filep++] = getcpy (m_draft (NULLCP, NULLCP, 1, &isdf));
|
|
148 continue;
|
|
149 case FILESW:
|
|
150 if (filep > NFOLDERS)
|
|
151 adios (NULLCP, "only %d files allowed!", NFOLDERS);
|
|
152 if (!(cp = *argp++) || *cp == '-')
|
|
153 adios (NULLCP, "missing argument to %s", argp[-2]);
|
|
154 files[filep++] = path (cp, TFILE);
|
|
155 continue;
|
|
156
|
|
157 case RPROCSW:
|
|
158 if (!(rmmproc = *argp++) || *rmmproc == '-')
|
|
159 adios (NULLCP, "missing argument to %s", argp[-2]);
|
|
160 continue;
|
|
161 case NRPRCSW:
|
|
162 rmmproc = (char *)0;
|
|
163 continue;
|
|
164 }
|
|
165 if (*cp == '+' || *cp == '@') {
|
|
166 if (foldp > NFOLDERS)
|
|
167 adios (NULLCP, "only %d folders allowed!", NFOLDERS);
|
|
168 folders[foldp++].f_name =
|
|
169 path (cp + 1, *cp == '+' ? TFOLDER : TSUBCWF);
|
|
170 }
|
|
171 else
|
|
172 msgs[msgp++] = cp;
|
|
173 }
|
|
174
|
|
175 /* */
|
|
176
|
|
177 if (!m_find ("path"))
|
|
178 free (path ("./", TFOLDER));
|
|
179 if (foldp == 0)
|
|
180 adios (NULLCP, "no folder specified");
|
|
181
|
|
182 #ifdef WHATNOW
|
|
183 if (!msgp && !foldp && !filep && (cp = getenv ("mhdraft")) && *cp)
|
|
184 files[filep++] = cp;
|
|
185 #endif /* WHATNOW */
|
|
186
|
|
187 if (filep > 0) {
|
|
188 if (folder || msgp)
|
|
189 adios (NULLCP, "use -file or some messages, not both");
|
|
190 opnfolds (folders, foldp);
|
|
191 for (i = 0; i < filep; i++)
|
|
192 if (m_file (files[i], folders, foldp, prsrvf))
|
|
193 done (1);
|
|
194 if (!linkf)
|
|
195 removeit (NULLMP, filep, filevec);
|
|
196 done (0);
|
|
197 }
|
|
198
|
|
199 if (!msgp)
|
|
200 msgs[msgp++] = "cur";
|
|
201 if (!folder)
|
|
202 folder = m_getfolder ();
|
|
203 (void) strcpy (maildir, m_maildir (folder));
|
|
204
|
|
205 if (chdir (maildir) == NOTOK)
|
|
206 adios (maildir, "unable to change directory to");
|
|
207 if (!(mp = m_gmsg (folder)))
|
|
208 adios (NULLCP, "unable to read folder %s", folder);
|
|
209 if (mp -> hghmsg == 0)
|
|
210 adios (NULLCP, "no messages in %s", folder);
|
|
211
|
|
212 for (msgnum = 0; msgnum < msgp; msgnum++)
|
|
213 if (!m_convert (mp, msgs[msgnum]))
|
|
214 done (1);
|
|
215 m_setseq (mp);
|
|
216
|
|
217 opnfolds (folders, foldp);
|
|
218 for (msgnum = mp -> lowsel; msgnum <= mp -> hghsel; msgnum++)
|
|
219 if (mp -> msgstats[msgnum] & SELECTED) {
|
|
220 cp = getcpy (m_name (msgnum));
|
|
221 if (m_file (cp, folders, foldp, prsrvf))
|
|
222 done (1);
|
|
223 free (cp);
|
|
224 if (!linkf) {
|
|
225 #ifdef notdef
|
|
226 mp -> msgstats[msgnum] |= DELETED;
|
|
227 #endif /* notdef */
|
|
228 mp -> msgstats[msgnum] &= ~EXISTS;
|
|
229 }
|
|
230 }
|
|
231 if (!linkf)
|
|
232 mp -> msgflags |= SEQMOD;
|
|
233 clsfolds (folders, foldp);
|
|
234
|
|
235 m_replace (pfolder, folder);
|
|
236 if (mp -> hghsel != mp -> curmsg
|
|
237 && (mp -> numsel != mp -> nummsg || linkf))
|
|
238 m_setcur (mp, mp -> hghsel);
|
|
239 m_sync (mp);
|
|
240 m_update ();
|
|
241
|
|
242 if (!linkf)
|
|
243 removeit (mp, filep, filevec);
|
|
244
|
|
245 done (0);
|
|
246 }
|
|
247
|
|
248 /* */
|
|
249
|
|
250 static opnfolds (folders, nfolders)
|
|
251 register struct st_fold *folders;
|
|
252 int nfolders;
|
|
253 {
|
|
254 register char *cp;
|
|
255 char nmaildir[BUFSIZ];
|
|
256 register struct st_fold *fp,
|
|
257 *ep;
|
|
258 register struct msgs *mp;
|
|
259 struct stat st;
|
|
260
|
|
261 for (ep = (fp = folders) + nfolders; fp < ep; fp++) {
|
|
262 (void) chdir (m_maildir (""));
|
|
263 (void) strcpy (nmaildir, m_maildir (fp -> f_name));
|
|
264
|
|
265 if (stat (nmaildir, &st) == NOTOK) {
|
|
266 if (errno != ENOENT)
|
|
267 adios (nmaildir, "error on folder");
|
|
268 cp = concat ("Create folder \"", nmaildir, "\"? ", NULLCP);
|
|
269 if (!getanswer (cp))
|
|
270 done (1);
|
|
271 free (cp);
|
|
272 if (!makedir (nmaildir))
|
|
273 adios (NULLCP, "unable to create folder %s", nmaildir);
|
|
274 }
|
|
275
|
|
276 if (chdir (nmaildir) == NOTOK)
|
|
277 adios (nmaildir, "unable to change directory to");
|
|
278 if (!(mp = m_gmsg (fp -> f_name)))
|
|
279 adios (NULLCP, "unable to read folder %s", fp -> f_name);
|
|
280 mp -> curmsg = 0;
|
|
281
|
|
282 fp -> f_mp = mp;
|
|
283
|
|
284 (void) chdir (maildir);
|
|
285 }
|
|
286 }
|
|
287
|
|
288 /* */
|
|
289
|
|
290 static clsfolds (folders, nfolders)
|
|
291 register struct st_fold *folders;
|
|
292 int nfolders;
|
|
293 {
|
|
294 register struct st_fold *fp,
|
|
295 *ep;
|
|
296 register struct msgs *mp;
|
|
297
|
|
298 for (ep = (fp = folders) + nfolders; fp < ep; fp++) {
|
|
299 mp = fp -> f_mp;
|
|
300 m_setseq (mp);
|
|
301 m_sync (mp);
|
|
302 }
|
|
303 }
|
|
304
|
|
305 /* */
|
|
306
|
|
307 static removeit (mp, filep, files)
|
|
308 register struct msgs *mp;
|
|
309 register int filep;
|
|
310 register char **files;
|
|
311 {
|
|
312 register int i,
|
|
313 vecp;
|
|
314 register char *cp,
|
|
315 **vec;
|
|
316
|
|
317 if (rmmproc) {
|
|
318 if (filep > 0) {
|
|
319 vec = files++; /* filevec[1] */
|
|
320 files[filep] = NULL;
|
|
321 }
|
|
322 else {
|
|
323 if (mp -> numsel > MAXARGS - 2)
|
|
324 adios (NULLCP, "more than %d messages for %s exec",
|
|
325 MAXARGS - 2, rmmproc);
|
|
326 vec = (char **) calloc ((unsigned) (mp -> numsel + 2), sizeof *vec);
|
|
327 if (vec == NULL)
|
|
328 adios (NULLCP, "unable to allocate exec vector");
|
|
329 vecp = 1;
|
|
330 for (i = mp -> lowsel; i <= mp -> hghsel; i++)
|
|
331 if (mp -> msgstats[i] & SELECTED)
|
|
332 vec[vecp++] = getcpy (m_name (i));
|
|
333 vec[vecp] = NULL;
|
|
334 }
|
|
335
|
|
336 (void) fflush (stdout);
|
|
337 vec[0] = r1bindex (rmmproc, '/');
|
|
338 execvp (rmmproc, vec);
|
|
339 adios (rmmproc, "unable to exec");
|
|
340 }
|
|
341
|
|
342 if (filep > 0) {
|
|
343 files++; /* filevec[1] */
|
|
344 for (i = 0; i < filep; i++)
|
|
345 if (unlink (files[i]) == NOTOK)
|
|
346 admonish (files[i], "unable to unlink");
|
|
347 }
|
|
348 else
|
|
349 for (i = mp -> lowsel; i <= mp -> hghsel; i++)
|
|
350 if (mp -> msgstats[i] & SELECTED)
|
|
351 if (unlink (cp = m_name (i)) == NOTOK)
|
|
352 admonish (cp, "unable to unlink");
|
|
353 }
|
|
354
|
|
355 /* */
|
|
356
|
|
357 m_file (msg, folders, nfolders, prsrvf)
|
|
358 register char *msg;
|
|
359 struct st_fold *folders;
|
|
360 int nfolders,
|
|
361 prsrvf;
|
|
362 {
|
|
363 int in,
|
|
364 out,
|
|
365 linkerr,
|
|
366 msgnum;
|
|
367 register char *nmsg;
|
|
368 char newmsg[BUFSIZ];
|
|
369 register struct st_fold *fp,
|
|
370 *ep;
|
|
371 register struct msgs *mp;
|
|
372 struct stat st,
|
|
373 s1;
|
|
374
|
|
375 for (ep = (fp = folders) + nfolders; fp < ep; fp++) {
|
|
376 mp = fp -> f_mp;
|
|
377 if (prsrvf && (msgnum = m_atoi (nmsg = msg)) > 0) {
|
|
378 if (msgnum >= mp -> hghoff)
|
|
379 if (mp = m_remsg (mp, 0, msgnum + MAXFOLDER))
|
|
380 fp -> f_mp = mp;
|
|
381 else
|
|
382 adios (NULLCP, "unable to allocate folder storage");
|
|
383 if (!(mp -> msgstats[msgnum] & EXISTS)) {
|
|
384 mp -> msgstats[msgnum] |= EXISTS;
|
|
385 #ifdef notdef
|
|
386 mp -> msgstats[msgnum] &= ~DELETED;
|
|
387 #endif /* notdef */
|
|
388 mp -> nummsg++;
|
|
389 }
|
|
390 mp -> msgstats[msgnum] |= SELECTED;
|
|
391 if (msgnum > mp -> hghmsg)
|
|
392 mp -> hghmsg = msgnum;
|
|
393 }
|
|
394 else {
|
|
395 if (mp -> hghmsg >= mp -> hghoff)
|
|
396 if (mp = m_remsg (mp, 0, mp -> hghoff + MAXFOLDER))
|
|
397 fp -> f_mp = mp;
|
|
398 else
|
|
399 adios (NULLCP, "unable to allocate folder storage");
|
|
400
|
|
401 nmsg = m_name (msgnum = ++mp -> hghmsg);
|
|
402 mp -> nummsg++;
|
|
403 mp -> msgstats[msgnum] |= EXISTS | SELECTED;
|
|
404 }
|
|
405 if (mp -> lowmsg == 0)
|
|
406 mp -> lowmsg = msgnum;
|
|
407 if (mp -> lowsel == 0 || msgnum < mp -> lowsel)
|
|
408 mp -> lowsel = msgnum;
|
|
409 if (msgnum > mp -> hghsel)
|
|
410 mp -> hghsel = msgnum;
|
|
411
|
|
412 /* */
|
|
413
|
|
414 (void) sprintf (newmsg, "%s/%s", mp -> foldpath, nmsg);
|
|
415 if (link (msg, newmsg) == NOTOK) {
|
|
416 #ifndef EISREMOTE
|
|
417 linkerr = errno;
|
|
418 #else /* EISREMOTE */
|
|
419 if ((linkerr = errno) == EISREMOTE)
|
|
420 linkerr = EXDEV;
|
|
421 #endif /* EISREMOTE */
|
|
422 if (linkerr == EEXIST
|
|
423 || (linkerr == EXDEV && stat (newmsg, &st) != NOTOK)) {
|
|
424 if (linkerr != EEXIST
|
|
425 || stat (msg, &s1) == NOTOK
|
|
426 || stat (newmsg, &st) == NOTOK
|
|
427 || s1.st_ino != st.st_ino) {
|
|
428 advise (NULLCP, "message %s:%s already exists",
|
|
429 fp -> f_name, newmsg);
|
|
430 return 1;
|
|
431 }
|
|
432 continue;
|
|
433 }
|
|
434 if (linkerr == EXDEV) {
|
|
435 if ((in = open (msg, 0)) == NOTOK) {
|
|
436 advise (msg, "unable to open message %s");
|
|
437 return 1;
|
|
438 }
|
|
439 (void) fstat (in, &st);
|
|
440 if ((out = creat (newmsg, (int) st.st_mode & 0777))
|
|
441 == NOTOK) {
|
|
442 advise (newmsg, "unable to create");
|
|
443 (void) close (in);
|
|
444 return 1;
|
|
445 }
|
|
446 cpydata (in, out, msg, newmsg);
|
|
447 (void) close (in);
|
|
448 (void) close (out);
|
|
449 }
|
|
450 else {
|
|
451 advise (newmsg, "error linking %s to", msg);
|
|
452 return 1;
|
|
453 }
|
|
454 }
|
|
455 }
|
|
456
|
|
457 return 0;
|
|
458 }
|