/* sortm.c - sort messages in a folder by date/time */ #include "../h/mh.h" #include "../zotnet/tws.h" #include /* */ static struct swit switches[] = { #define DATESW 0 "datefield field", 0, #define VERBSW 1 "verbose", 0, #define NVERBSW 2 "noverbose", 0, #define HELPSW 3 "help", 4, NULL, NULL }; /* */ struct smsg { int s_msg; struct tws s_tws; }; static struct smsg *smsgs; int msgsort (); struct tws *getws (); long time (); /* */ /* ARGSUSED */ main (argc, argv) int argc; char **argv; { int verbosw = 0, msgp = 0, i, msgnum; char *cp, *maildir, *datesw = NULL, *folder = NULL, buf[100], **ap, **argp, *arguments[MAXARGS], *msgs[MAXARGS]; struct msgs *mp; invo_name = r1bindex (argv[0], '/'); if ((cp = m_find (invo_name)) != NULL) { ap = brkstring (cp = getcpy (cp), " ", "\n"); ap = copyip (ap, arguments); } else ap = arguments; (void) copyip (argv + 1, ap); argp = arguments; /* */ while (cp = *argp++) { if (*cp == '-') switch (smatch (++cp, switches)) { case AMBIGSW: ambigsw (cp, switches); done (1); case UNKWNSW: adios (NULLCP, "-%s unknown", cp); case HELPSW: (void) sprintf (buf, "%s [+folder] [msgs] [switches]", invo_name); help (buf, switches); done (1); case DATESW: if (datesw) adios (NULLCP, "only one date field at a time!"); if (!(datesw = *argp++) || *datesw == '-') adios (NULLCP, "missing argument to %s", argp[-2]); continue; case VERBSW: verbosw++; continue; case NVERBSW: verbosw = 0; continue; } if (*cp == '+' || *cp == '@') { if (folder) adios (NULLCP, "only one folder at a time!"); else folder = path (cp + 1, *cp == '+' ? TFOLDER : TSUBCWF); } else msgs[msgp++] = cp; } /* */ if (!m_find ("path")) free (path ("./", TFOLDER)); if (!msgp) msgs[msgp++] = "all"; if (!datesw) datesw = "Date"; if (!folder) folder = m_getfolder (); maildir = m_maildir (folder); if (chdir (maildir) == NOTOK) adios (maildir, "unable to change directory to"); if (!(mp = m_gmsg (folder))) adios (NULLCP, "unable to read folder %s", folder); if (mp -> hghmsg == 0) adios (NULLCP, "no messages in %s", folder); for (msgnum = 0; msgnum < msgp; msgnum++) if (!m_convert (mp, msgs[msgnum])) done (1); m_setseq (mp); if ((i = read_dates (mp, datesw)) <= 0) adios (NULLCP, "no messages to sort"); qsort ((char *) smsgs, i, sizeof *smsgs, msgsort); file_dates (mp, verbosw); m_replace (pfolder, folder); m_sync (mp); m_update (); done (0); } /* */ static int read_dates (mp, datesw) register struct msgs *mp; register char *datesw; { int msgnum; struct tws tb; register struct smsg *s; register struct tws *tw; twscopy (&tb, dtwstime ()); smsgs = (struct smsg *) calloc ((unsigned) (mp -> hghsel - mp -> lowsel + 2), sizeof *smsgs); if (smsgs == NULL) adios (NULLCP, "unable to allocate sort storage"); s = smsgs; for (msgnum = mp -> lowsel; msgnum <= mp -> hghsel; msgnum++) { tw = NULL; if (mp -> msgstats[msgnum] & SELECTED) { if ((tw = getws (datesw, msgnum)) == NULL) tw = msgnum != mp -> lowsel ? &((s - 1) -> s_tws) : &tb; } else if (mp -> msgstats[msgnum] & EXISTS) tw = &tb; if (tw) { s -> s_msg = msgnum; twscopy (&s -> s_tws, tw); s++; } } s -> s_msg = 0; return (s - smsgs); } /* */ static struct tws *getws (datesw, msg) register char *datesw; int msg; { int compnum, state; register char *hp, *msgnam; char buf[BUFSIZ], nam[NAMESZ]; register struct tws *tw; register FILE *in; if ((in = fopen (msgnam = m_name (msg), "r")) == NULL) { admonish (msgnam, "unable to read message"); return NULL; } /* */ for (compnum = 1, state = FLD, hp = NULL;;) { switch (state = m_getfld (state, nam, buf, sizeof buf, in)) { case FLD: case FLDEOF: case FLDPLUS: compnum++; if (hp != NULL) free (hp), hp = NULL; hp = add (buf, NULLCP); while (state == FLDPLUS) { state = m_getfld (state, nam, buf, sizeof buf, in); hp = add (buf, hp); } if (uleq (nam, datesw)) break; if (state != FLDEOF) continue; case BODY: case BODYEOF: case FILEEOF: admonish (NULLCP, "no %s field in message %d", datesw, msg); case LENERR: case FMTERR: if (state == LENERR || state == FMTERR) admonish (NULLCP, "format error in message %d(header #%d)", msg, compnum); if (hp != NULL) free (hp); (void) fclose (in); return NULL; default: adios (NULLCP, "internal error -- you lose"); } break; } if ((tw = dparsetime (hp)) == NULL) admonish (NULLCP, "unable to parse %s field in message %d", datesw, msg); if (hp != NULL) free (hp); (void) fclose (in); return tw; } /* */ static int msgsort (a, b) register struct smsg *a, *b; { return twsort (&a -> s_tws, &b -> s_tws); } /* */ static file_dates (mp, verbosw) register struct msgs *mp; int verbosw; { register int i, j, k; short stats; char f1[BUFSIZ], f2[BUFSIZ], tmpfil[BUFSIZ]; (void) strcpy (tmpfil, m_scratch ("", invo_name)); for (i = 0; j = smsgs[i++].s_msg;) if (i != j) { (void) strcpy (f1, m_name (i)); (void) strcpy (f2, m_name (j)); if (mp -> msgstats[i] & EXISTS) { if (verbosw) printf ("swap messages %s and %s\n", f2, f1); if (rename (f1, tmpfil) == NOTOK) { admonish (tmpfil, "unable to rename %s to ", f1); continue; } if (rename (f2, f1) == NOTOK) { admonish (f1, "unable to rename %s to", f2); continue; } if (rename (tmpfil, f2) == NOTOK) { admonish (f2, "unable to rename %s to", tmpfil); continue; } for (k = i; smsgs[k].s_msg; k++) if (smsgs[k].s_msg == i) { smsgs[k].s_msg = j; break; } } else { if (verbosw) printf ("message %s becomes message %s\n", f2, f1); if (rename (f2, f1) == NOTOK) { admonish (f1, "unable to rename %s to ", f2); continue; } } smsgs[i - 1].s_msg = i; stats = mp -> msgstats[i]; mp -> msgstats[i] = mp -> msgstats[j]; mp -> msgstats[j] = stats; if (mp -> curmsg == j) m_setcur (mp, i); mp -> msgflags |= SEQMOD; } }