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