1: /* folder(s).c - report on folders */
2:
3: #include "../h/mh.h"
4: #include <errno.h>
5: #include <stdio.h>
6: #include <sys/types.h>
7: #ifndef BSD42
8: #ifndef SYS5
9: #include <ndir.h>
10: #else SYS5
11: #include <dir.h>
12: #endif SYS5
13: #else BSD42
14: #include <sys/dir.h>
15: #endif BSD42
16: #include <sys/stat.h>
17:
18: /* */
19:
20: static struct swit switches[] = {
21: #define ALLSW 0
22: "all", 0,
23:
24: #define FASTSW 1
25: "fast", 0,
26: #define NFASTSW 2
27: "nofast", 0,
28:
29: #define HDRSW 3
30: "header", 0,
31: #define NHDRSW 4
32: "noheader", 0,
33:
34: #define PACKSW 5
35: "pack", 0,
36: #define NPACKSW 6
37: "nopack", 0,
38:
39: #define RECURSW 7
40: "recurse", 0,
41: #define NRECRSW 8
42: "norecurse", 0,
43:
44: #define TOTALSW 9
45: "total", 0,
46: #define NTOTLSW 10
47: "nototal", 0,
48:
49: #define PRNTSW 11
50: "print", 0,
51: #define NPRNTSW 12
52: "noprint", 0,
53: #define LISTSW 13
54: "list", 0,
55: #define NLISTSW 14
56: "nolist", 0,
57: #define PUSHSW 15
58: "push", 0,
59: #define POPSW 16
60: "pop", 0,
61:
62: #define HELPSW 17
63: "help", 4,
64:
65: NULL, NULL
66: };
67:
68: /* */
69:
70: extern int errno;
71:
72: static int fshort = 0;
73: static int fpack = 0;
74: static int = 0;
75: static int frecurse = 0;
76: static int ftotonly = 0;
77: static int msgtot = 0;
78: static int foldtot = 0;
79: static int start = 0;
80: static int foldp = 0;
81:
82: static char *mhdir;
83: static char *stack = "Folder-Stack";
84: static char folder[BUFSIZ];
85: static char *folds[NFOLDERS + 1];
86:
87: struct msgs *tfold ();
88:
89: /* */
90:
91: /* ARGSUSED */
92:
93: main (argc, argv)
94: char *argv[];
95: {
96: int all = 0,
97: printsw = 0,
98: listsw = 0,
99: pushsw = 0,
100: popsw = 0;
101: char *cp,
102: *dp,
103: *msg = NULL,
104: *argfolder = NULL,
105: **ap,
106: **argp,
107: buf[100],
108: *arguments[MAXARGS];
109: struct stat st;
110:
111: invo_name = r1bindex (argv[0], '/');
112: if (argv[0][strlen (argv[0]) - 1] == 's')
113: all++;
114: if ((cp = m_find (invo_name)) != NULL) {
115: ap = brkstring (cp = getcpy (cp), " ", "\n");
116: ap = copyip (ap, arguments);
117: }
118: else
119: ap = arguments;
120: (void) copyip (argv + 1, ap);
121: argp = arguments;
122:
123: /* */
124:
125: while (cp = *argp++) {
126: if (*cp == '-')
127: switch (smatch (++cp, switches)) {
128: case AMBIGSW:
129: ambigsw (cp, switches);
130: done (1);
131: case UNKWNSW:
132: adios (NULLCP, "-%s unknown", cp);
133: case HELPSW:
134: (void) sprintf (buf, "%s [+folder] [msg] [switches]",
135: invo_name);
136: help (buf, switches);
137: done (1);
138:
139: case ALLSW:
140: all++;
141: continue;
142:
143: case FASTSW:
144: fshort++;
145: continue;
146: case NFASTSW:
147: fshort = 0;
148: continue;
149:
150: case HDRSW:
151: fheader = -1;
152: continue;
153: case NHDRSW:
154: fheader++;
155: continue;
156:
157: case PACKSW:
158: fpack++;
159: continue;
160: case NPACKSW:
161: fpack = 0;
162: continue;
163:
164: case RECURSW:
165: frecurse++;
166: continue;
167: case NRECRSW:
168: frecurse = 0;
169: continue;
170:
171: case TOTALSW:
172: all++;
173: ftotonly++;
174: continue;
175: case NTOTLSW:
176: if (ftotonly)
177: all = 0;
178: ftotonly = 0;
179: continue;
180:
181: case PRNTSW:
182: printsw++;
183: continue;
184: case NPRNTSW:
185: printsw = 0;
186: continue;
187:
188: case LISTSW:
189: listsw++;
190: continue;
191: case NLISTSW:
192: listsw = 0;
193: continue;
194:
195: case PUSHSW:
196: pushsw++;
197: popsw = 0;
198: continue;
199: case POPSW:
200: popsw++;
201: pushsw = 0;
202: continue;
203: }
204: if (*cp == '+' || *cp == '@')
205: if (argfolder)
206: adios (NULLCP, "only one folder at a time!");
207: else
208: argfolder = path (cp + 1, *cp == '+' ? TFOLDER : TSUBCWF);
209: else
210: if (msg)
211: adios (NULLCP, "only one (current) message at a time!");
212: else
213: msg = cp;
214: }
215:
216: /* */
217:
218: if (!m_find ("path"))
219: free (path ("./", TFOLDER));
220: mhdir = concat (m_maildir (""), "/", NULLCP);
221:
222: if (pushsw == 0 && popsw == 0 && listsw == 0)
223: printsw++;
224: if (pushsw) {
225: if (!argfolder) {
226: if ((cp = m_find (stack)) == NULL
227: || (ap = brkstring (dp = getcpy (cp), " ", "\n")) == NULL
228: || (argfolder = *ap++) == NULL)
229: adios (NULLCP, "no other folder");
230: for (cp = getcpy (m_getfolder ()); *ap; ap++)
231: cp = add (*ap, add (" ", cp));
232: free (dp);
233: m_replace (stack, cp);
234: }
235: else
236: m_replace (stack,
237: (cp = m_find (stack))
238: ? concat (m_getfolder (), " ", cp, NULLCP)
239: : getcpy (m_getfolder ()));
240: }
241: if (popsw) {
242: if (argfolder)
243: adios (NULLCP, "sorry, no folders allowed with -pop");
244: if ((cp = m_find (stack)) == NULL
245: || (ap = brkstring (dp = getcpy (cp), " ", "\n")) == NULL
246: || (argfolder = *ap++) == NULL)
247: adios (NULLCP, "folder stack empty");
248: for (cp = NULL; *ap; ap++)
249: cp = cp ? add (*ap, add (" ", cp)) : getcpy (*ap);
250: free (dp);
251: if (cp)
252: m_replace (stack, cp);
253: else
254: (void) m_delete (stack);
255: }
256: if (pushsw || popsw) {
257: if (access (cp = m_maildir (argfolder), 0) == NOTOK)
258: adios (cp, "unable to find folder");
259: m_replace (pfolder, argfolder);
260: m_update ();
261: argfolder = NULL;
262: }
263: if (pushsw || popsw || listsw) {
264: printf ("%s", argfolder ? argfolder : m_getfolder ());
265: if (cp = m_find (stack)) {
266: for (ap = brkstring (dp = getcpy (cp), " ", "\n"); *ap; ap++)
267: printf (" %s", *ap);
268: free (dp);
269: }
270: printf ("\n");
271:
272: if (!printsw)
273: done (0);
274: }
275:
276: /* */
277:
278: if (all) {
279: fheader = 0;
280: if (argfolder || msg) {
281: (void) strcpy (folder, argfolder ? argfolder : m_getfolder ());
282:
283: if (pfold (argfolder, msg) && argfolder) {
284: m_replace (pfolder, argfolder);
285: m_update ();
286: }
287: if (!frecurse) /* counter-intuitive */
288: dodir (folder);
289: }
290: else {
291: dother ();
292:
293: (void) strcpy (folder, (cp = m_find (pfolder)) ? cp : "");
294: dodir (".");
295: }
296:
297: if (!fshort) {
298: if (!ftotonly)
299: printf ("\n\t\t ");
300: printf ("TOTAL= %*d message%c in %d folder%s.\n",
301: DMAXFOLDER, msgtot, msgtot != 1 ? 's' : ' ',
302: foldtot, foldtot != 1 ? "s" : "");
303: }
304: }
305: else {
306: fheader++;
307:
308: (void) strcpy (folder, argfolder ? argfolder : m_getfolder ());
309: if (stat (strcpy (buf, m_maildir (folder)), &st) == NOTOK) {
310: if (errno != ENOENT)
311: adios (buf, "error on folder");
312: cp = concat ("Create folder \"", buf, "\"? ", NULLCP);
313: if (!getanswer (cp))
314: done (1);
315: free (cp);
316: if (!makedir (buf))
317: adios (NULLCP, "unable to create folder %s", buf);
318: }
319:
320: if (pfold (folder, msg) && argfolder)
321: m_replace (pfolder, argfolder);
322: }
323:
324: m_update ();
325:
326: done (0);
327: }
328:
329: /* */
330:
331: static dodir (dir)
332: register char *dir;
333: {
334: int i;
335: int os = start;
336: int of = foldp;
337: char buffer[BUFSIZ];
338:
339: start = foldp;
340: if (chdir (mhdir) == NOTOK)
341: adios (mhdir, "unable to change directory to");
342:
343: addir (strcpy (buffer, dir));
344: for (i = start; i < foldp; i++)
345: (void) pfold (folds[i], NULLCP), (void) fflush (stdout);
346:
347: start = os;
348: foldp = of;
349: }
350:
351: /* */
352:
353: static int pfold (fold, msg)
354: register char *fold,
355: *msg;
356: {
357: int hack,
358: others,
359: retval = 1;
360: register char *mailfile;
361: register struct msgs *mp = NULL;
362:
363: mailfile = m_maildir (fold);
364: if (chdir (mailfile) == NOTOK) {
365: if (errno != EACCES)
366: admonish (mailfile, "unable to change directory to");
367: else
368: printf ("%22s%c unreadable\n",
369: fold, strcmp (folder, fold) ? ' ' : '+');
370: return 0;
371: }
372:
373: if (fshort) {
374: printf ("%s\n", fold);
375:
376: if (!msg && !fpack) {
377: if (frecurse)
378: dodir (fold);
379: return retval;
380: }
381: }
382:
383: if (!(mp = m_gmsg (fold))) {
384: admonish (NULLCP, "unable to read folder %s", fold);
385: return 0;
386: }
387:
388: if (msg && !sfold (mp, msg))
389: retval = 0;
390: if (fpack)
391: mp = tfold (mp);
392:
393: if (fshort)
394: goto out;
395: foldtot++;
396: msgtot += mp -> nummsg;
397:
398: if (ftotonly)
399: goto out;
400:
401: if (!fheader++)
402: printf ("\t\tFolder %*s# of messages (%*srange%*s); cur%*smsg (other files)\n",
403: DMAXFOLDER, "", DMAXFOLDER - 2, "", DMAXFOLDER - 2, "",
404: DMAXFOLDER - 2, "");
405:
406: printf ("%22s%c ", fold, strcmp (folder, fold) ? ' ' : '+');
407:
408: hack = 0;
409: if (mp -> hghmsg == 0)
410: printf ("has no messages%*s",
411: mp -> msgflags & OTHERS ? DMAXFOLDER * 2 + 4 : 0, "");
412: else {
413: printf ("has %*d message%s (%*d-%*d)",
414: DMAXFOLDER, mp -> nummsg, (mp -> nummsg == 1) ? " " : "s",
415: DMAXFOLDER, mp -> lowmsg, DMAXFOLDER, mp -> hghmsg);
416: if (mp -> curmsg >= mp -> lowmsg && mp -> curmsg <= mp -> hghmsg)
417: printf ("; cur=%*d", DMAXFOLDER, hack = mp -> curmsg);
418: }
419:
420: if (mp -> msgflags & OTHERS)
421: printf (";%*s (others)", hack ? 0 : DMAXFOLDER + 6, "");
422: printf (".\n");
423:
424: out: ;
425: others = mp -> msgflags & OTHERS;
426: m_fmsg (mp);
427:
428: if (frecurse && others)
429: dodir (fold);
430:
431: return retval;
432: }
433:
434: /* */
435:
436: static int sfold (mp, msg)
437: register struct msgs *mp;
438: char *msg;
439: {
440: if (!m_convert (mp, msg))
441: return 0;
442:
443: if (mp -> numsel > 1) {
444: admonish (NULLCP, "only one message at a time!");
445: return 0;
446: }
447: m_setseq (mp);
448: m_setcur (mp, mp -> lowsel);
449: m_sync (mp);
450: m_update ();
451:
452: return 1;
453: }
454:
455:
456: struct msgs *tfold (mp)
457: register struct msgs *mp;
458: {
459: register int hole,
460: msgnum;
461: char newmsg[BUFSIZ],
462: oldmsg[BUFSIZ];
463:
464: if (mp -> lowmsg > 1 && (mp = m_remsg (mp, 1, mp -> hghmsg)) == NULL)
465: adios (NULLCP, "unable to allocate folder storage");
466:
467: for (msgnum = mp -> lowmsg, hole = 1; msgnum <= mp -> hghmsg; msgnum++)
468: if (mp -> msgstats[msgnum] & EXISTS) {
469: if (msgnum != hole) {
470: (void) strcpy (newmsg, m_name (hole));
471: (void) strcpy (oldmsg, m_name (msgnum));
472: if (rename (oldmsg, newmsg) == NOTOK)
473: adios (newmsg, "unable to rename %s to", oldmsg);
474: if (msgnum == mp -> curmsg)
475: m_setcur (mp, mp -> curmsg = hole);
476: mp -> msgstats[hole] = mp -> msgstats[msgnum];
477: mp -> msgflags |= SEQMOD;
478: if (msgnum == mp -> lowsel)
479: mp -> lowsel = hole;
480: if (msgnum == mp -> hghsel)
481: mp -> hghsel = hole;
482: }
483: hole++;
484: }
485: if (mp -> nummsg > 0) {
486: mp -> lowmsg = 1;
487: mp -> hghmsg = hole - 1;
488: }
489: m_sync (mp);
490: m_update ();
491:
492: return mp;
493: }
494:
495: /* */
496:
497: static addir (name)
498: register char *name;
499: {
500: register char *base,
501: *cp;
502: struct stat st;
503: register struct direct *dp;
504: register DIR * dd;
505:
506: cp = name + strlen (name);
507: *cp++ = '/';
508: *cp = NULL;
509:
510: base = strcmp (name, "./") ? name : name + 2;/* hack */
511:
512: if ((dd = opendir (name)) == NULL) {
513: admonish (name, "unable to read directory ");
514: return;
515: }
516: while (dp = readdir (dd))
517: if (strcmp (dp -> d_name, ".") && strcmp (dp -> d_name, "..")) {
518: if (cp + dp -> d_namlen + 2 >= name + BUFSIZ)
519: continue;
520: (void) strcpy (cp, dp -> d_name);
521: if (stat (name, &st) != NOTOK && (st.st_mode & S_IFMT) == S_IFDIR)
522: addfold (base);
523: }
524: closedir (dd);
525:
526: *--cp = NULL;
527: }
528:
529: /* */
530:
531: static addfold (fold)
532: register char *fold;
533: {
534: register int i,
535: j;
536: register char *cp;
537:
538: if (foldp > NFOLDERS)
539: adios (NULLCP, "more than %d folders to report on", NFOLDERS);
540:
541: cp = getcpy (fold);
542: for (i = start; i < foldp; i++)
543: if (compare (cp, folds[i]) < 0) {
544: for (j = foldp - 1; j >= i; j--)
545: folds[j + 1] = folds[j];
546: foldp++;
547: folds[i] = cp;
548: return;
549: }
550:
551: folds[foldp++] = cp;
552: }
553:
554: /* */
555:
556: static int compare (s1, s2)
557: register char *s1,
558: *s2;
559: {
560: register int i;
561:
562: while (*s1 || *s2)
563: if (i = *s1++ - *s2++)
564: return i;
565:
566: return 0;
567: }
568:
569: /* */
570:
571: static dother () {
572: int atrlen;
573: char atrcur[BUFSIZ];
574: register struct node *np;
575:
576: (void) sprintf (atrcur, "atr-%s-", current);
577: atrlen = strlen (atrcur);
578:
579: m_getdefs ();
580: for (np = m_defs; np; np = np -> n_next)
581: if (ssequal (atrcur, np -> n_name)
582: && !ssequal (mhdir, np -> n_name + atrlen))
583: (void) pfold (np -> n_name + atrlen, NULLCP);
584: }