9 date 95.12.06.23.46.23; author jromine; state Exp;
14 date 92.12.15.00.20.22; author jromine; state Exp;
19 date 92.12.03.16.50.27; author jromine; state Exp;
24 date 92.12.03.16.28.56; author jromine; state Exp;
29 date 92.11.04.01.03.50; author jromine; state Exp;
34 date 92.01.31.22.28.01; author jromine; state Exp;
39 date 90.12.19.10.02.16; author mh; state Exp;
44 date 90.12.19.09.42.20; author mh; state Exp;
49 date 90.04.05.15.02.27; author sources; state Exp;
54 date 90.03.23.13.55.40; author sources; state Exp;
59 date 90.03.23.13.44.45; author sources; state Exp;
64 date 90.03.22.17.11.16; author sources; state Exp;
69 date 90.03.22.17.06.05; author sources; state Exp;
74 date 90.03.22.15.33.44; author sources; state Exp;
79 date 90.03.22.15.11.11; author sources; state Exp;
84 date 90.03.22.15.10.28; author sources; state Exp;
89 date 90.03.22.15.03.10; author sources; state Exp;
94 date 90.03.21.23.23.43; author sources; state Exp;
99 date 90.02.06.13.32.04; author sources; state Exp;
104 date 90.02.06.13.31.45; author sources; state Exp;
115 @fix: use int for msgstats
118 @/* sortm.c - sort messages in a folder by date/time */
119 /* 21Apr90 do subject sorts too - from V. Jacobson */
121 static char ident[] = "@@(#)$Id: sortm.c,v 1.19 1992/12/15 00:20:22 jromine Exp jromine $";
125 #include "../zotnet/tws.h"
129 #include <sys/types.h>
130 #include <sys/stat.h>
135 #if defined(SYS5) && defined(AUX)
136 #define u_short ushort
141 static struct swit switches[] = {
143 "datefield field", 0,
146 "textfield field", 0,
151 "subject", -3, /* backward-compatibility */
170 unsigned long s_clock;
174 static struct smsg *smsgs;
177 char *subjsort = (char *)0; /* sort on subject if != 0 */
178 u_long datelimit = 0;
179 int submajor = 0; /* if true, sort on subject-major */
183 static int getws (char *datesw, int msg, struct smsg *smsg);
188 static int dsort(), read_hdrs (), subsort(), txtsort();
189 static void rename_chain(), rename_msgs();
213 setlocale(LC_ALL, "");
215 invo_name = r1bindex (argv[0], '/');
216 if ((cp = m_find (invo_name)) != NULL) {
217 ap = brkstring (cp = getcpy (cp), " ", "\n");
218 ap = copyip (ap, arguments);
222 (void) copyip (argv + 1, ap);
225 while (cp = *argp++) {
227 switch (smatch (++cp, switches)) {
229 ambigsw (cp, switches);
232 adios (NULLCP, "-%s unknown", cp);
234 (void) sprintf(buf, "%s [+folder] [msgs] [switches]",
236 help (buf, switches);
241 adios (NULLCP, "only one date field at a time");
242 if (!(datesw = *argp++) || *datesw == '-')
243 adios (NULLCP, "missing argument to %s", argp[-2]);
248 adios (NULLCP, "only one text field at a time");
249 if (!(subjsort = *argp++) || *subjsort == '-')
250 adios (NULLCP, "missing argument to %s", argp[-2]);
254 subjsort = "subject";
257 subjsort = (char *)0;
261 if (!(cp = *argp++) || *cp == '-')
262 adios (NULLCP, "missing argument to %s", argp[-2]);
264 cp++; /* skip any leading zeros */
265 if (!*cp) { /* hit end of string */
266 submajor++; /* sort subject-major */
269 if (!isdigit(*cp) || !(datelimit = atoi(cp)))
270 adios (NULLCP, "impossible limit %s", cp);
271 datelimit *= 60*60*24;
274 submajor = 0; /* use date-major, but */
275 datelimit = 0; /* use no limit */
285 if (*cp == '+' || *cp == '@@') {
287 adios (NULLCP, "only one folder at a time!");
289 folder = path (cp + 1, *cp == '+' ? TFOLDER : TSUBCWF);
295 if (!m_find ("path"))
296 free (path ("./", TFOLDER));
298 msgs[msgp++] = "all";
302 folder = m_getfolder ();
303 maildir = m_maildir (folder);
305 if (chdir (maildir) == NOTOK)
306 adios (maildir, "unable to change directory to");
307 if (!(mp = m_gmsg (folder)))
308 adios (NULLCP, "unable to read folder %s", folder);
310 adios (NULLCP, "no messages in %s", folder);
312 for (msgnum = 0; msgnum < msgp; msgnum++)
313 if (!m_convert (mp, msgs[msgnum]))
317 if ((nmsgs = read_hdrs (mp, datesw)) <= 0)
318 adios (NULLCP, "no messages to sort");
321 * sort a list of pointers to our "messages to be sorted".
323 dlist = (struct smsg **) malloc ((nmsgs+1) * sizeof(*dlist));
325 adios (NULLCP, "couldn't allocate sort memory");
326 for (i = 0; i < nmsgs; i++)
327 dlist[i] = &smsgs[i];
330 if (verbose) /* announce what we're doing */
332 printf ("sorting by %s-major %s-minor\n",
333 submajor ? subjsort : datesw,
334 submajor ? datesw : subjsort);
336 printf ("sorting by datefield %s\n", datesw);
338 /* first sort by date, or by subject-major, date-minor */
339 qsort ((char *) dlist, nmsgs, sizeof(*dlist),
340 submajor && subjsort ? txtsort : dsort);
343 * if we're sorting on subject, we need another list
344 * in subject order, then a merge pass to collate the
347 if (!submajor && subjsort) { /* already date sorted */
350 register struct smsg ***il,
354 slist = (struct smsg **) malloc ((nmsgs+1) * sizeof(*slist));
356 adios (NULLCP, "couldn't allocate sort memory");
357 bcopy ((char *)dlist, (char *)slist, (nmsgs+1)*sizeof(*slist));
358 qsort ((char *)slist, nmsgs, sizeof(*slist), subsort);
361 * make an inversion list so we can quickly find
362 * the collection of messages with the same subj
363 * given a message number.
365 il = (struct smsg ***) calloc (mp->hghsel+1, sizeof(*il));
367 adios (NULLCP, "couldn't allocate msg list");
368 for (i = 0; i < nmsgs; i++)
369 il[slist[i]->s_msg] = &slist[i];
371 * make up the final list, chronological but with
372 * all the same subjects grouped together.
374 flist = (struct smsg **) malloc ((nmsgs+1) * sizeof(*flist));
376 adios (NULLCP, "couldn't allocate msg list");
378 for (dp = dlist; *dp;) {
379 register struct smsg **s = il[(*dp++)->s_msg];
381 /* see if we already did this guy */
387 * take the next message(s) if there is one,
388 * its subject isn't null and its subject
389 * is the same as this one and it's not too
392 while (*s && (*s)->s_subj[0] &&
393 strcmp((*s)->s_subj, s[-1]->s_subj) == 0 &&
395 (*s)->s_clock - s[-1]->s_clock <= datelimit)) {
405 rename_msgs (mp, dlist);
407 m_replace (pfolder, folder);
414 read_hdrs (mp, datesw)
415 register struct msgs *mp;
416 register char *datesw;
420 register struct smsg *s;
422 twscopy (&tb, dtwstime ());
424 smsgs = (struct smsg *)
425 calloc ((unsigned) (mp->hghsel - mp->lowsel + 2),
428 adios (NULLCP, "unable to allocate sort storage");
431 for (msgnum = mp->lowsel; msgnum <= mp->hghsel; msgnum++) {
432 if (mp->msgstats[msgnum] & SELECTED) {
433 if (getws (datesw, msgnum, s)) {
444 getws (datesw, msg, smsg)
445 register char *datesw;
447 register struct smsg *smsg;
454 register struct tws *tw;
455 register char *datecomp = NULLCP,
459 if ((in = fopen (msgnam = m_name (msg), "r")) == NULL) {
460 admonish (msgnam, "unable to read message");
463 for (compnum = 1, state = FLD;;) {
464 switch (state = m_getfld (state, nam, buf, sizeof buf, in)) {
469 if (uleq (nam, datesw)) {
470 datecomp = add (buf, datecomp);
471 while (state == FLDPLUS) {
472 state = m_getfld (state, nam, buf, sizeof buf, in);
473 datecomp = add (buf, datecomp);
475 if (!subjsort || subjcomp)
478 else if (subjsort && uleq (nam, subjsort)) {
479 subjcomp = add (buf, subjcomp);
480 while (state == FLDPLUS) {
481 state = m_getfld (state, nam, buf, sizeof buf, in);
482 subjcomp = add (buf, subjcomp);
488 /* just flush this guy */
489 while (state == FLDPLUS)
490 state = m_getfld (state, nam, buf, sizeof buf, in);
501 if (state == LENERR || state == FMTERR)
502 admonish (NULLCP, "format error in message %d (header #%d)",
512 adios (NULLCP, "internal error -- you lose");
517 if (!datecomp || (tw = dparsetime (datecomp)) == NULL) {
520 admonish (NULLCP, "can't parse %s field in message %d",
523 /* use the modify time of the file as its date */
524 (void) fstat (fileno (in), &st);
525 smsg->s_clock = st.st_mtime;
528 smsg->s_clock = twclock (tw);
533 * try to make the subject "canonical": delete
534 * leading "re:", everything but letters & smash
535 * letters to lower case.
543 if (strcmp (subjsort, "subject") == 0)
550 *cp2++ = isupper(c) ? tolower(c) : c;
558 *cp2++ = isupper(c) ? tolower(c) : c;
566 smsg->s_subj = subjcomp;
580 register struct smsg **a,
583 if ((*a)->s_clock < (*b)->s_clock)
585 else if ((*a)->s_clock > (*b)->s_clock)
587 else if ((*a)->s_msg < (*b)->s_msg)
598 register struct smsg **a,
603 if (i = strcmp ((*a)->s_subj, (*b)->s_subj))
606 return (dsort (a, b));
611 register struct smsg **a,
616 if (i = strcmp ((*a)->s_subj, (*b)->s_subj))
618 else if ((*a)->s_msg < (*b)->s_msg)
624 static void rename_chain (mp, mlist, msg, endmsg)
625 register struct msgs *mp;
637 nxt = mlist[msg] - smsgs; /* mlist[msg] is a ptr into smsgs */
638 mlist[msg] = (struct smsg *)0;
639 old = smsgs[nxt].s_msg;
640 new = smsgs[msg].s_msg;
641 (void) strcpy (oldname, m_name (old));
642 newname = m_name (new);
644 printf ("message %d becomes message %d\n", old, new);
646 if (rename (oldname, newname) == NOTOK)
647 adios (newname, "unable to rename %s to", oldname);
649 mp->msgstats[new] = mp->msgstats[old];
650 if (mp->curmsg == old)
658 /* if (nxt != endmsg); */
659 /* rename_chain (mp, mlist, nxt, endmsg); */
663 rename_msgs (mp, mlist)
664 register struct msgs *mp;
665 register struct smsg **mlist;
674 register struct smsg *sp;
676 (void) strcpy (tmpfil, m_name (mp->hghmsg + 1));
678 for (i = 0; i < nmsgs; i++) {
679 if (! (sp = mlist[i]))
680 continue; /* did this one */
684 continue; /* this one doesn't move */
687 * the guy that was msg j is about to become msg i.
688 * rename 'j' to make a hole, then recursively rename
689 * guys to fill up the hole.
691 old = smsgs[j].s_msg;
692 new = smsgs[i].s_msg;
693 (void) strcpy (f1, m_name (old));
696 printf ("renaming message chain from %d to %d\n", old, new);
698 if (rename (f1, tmpfil) == NOTOK)
699 adios (tmpfil, "unable to rename %s to ", f1);
700 stats = mp->msgstats[old];
702 rename_chain (mp, mlist, j, i);
703 if (rename (tmpfil, m_name(new)) == NOTOK)
704 adios (m_name(new), "unable to rename %s to", tmpfil);
706 mp->msgstats[new] = stats;
707 mp->msgflags |= SEQMOD;
720 static char ident[] = "@@(#)$Id: sortm.c,v 1.18 1992/12/03 16:50:27 jromine Exp jromine $";
729 @put u_short ifdef under #if AUX
734 static char ident[] = "@@(#)$Id: sortm.c,v 1.17 1992/12/03 16:28:56 jromine Exp jromine $";
741 @u_short AUX changes from Jim Guyton
746 static char ident[] = "@@(#)$Id: sortm.c,v 1.16 1992/11/04 01:03:50 jromine Exp jromine $";
760 static char ident[] = "@@(#)$Id: sortm.c,v 1.15 1992/01/31 22:28:01 jromine Exp jromine $";
772 static char ident[] = "@@(#)$Id: sortm.c,v 1.14 1990/12/19 10:02:16 mh Exp jromine $";
780 if ((c == 'r' || c == 'R') &&
781 (cp[0] == 'e' || cp[0] == 'E') &&
789 @convert to tail recursion
790 remove unused variable
796 static char ident[] = "@@(#)$Id: sortm.c,v 1.13 90/12/19 09:42:20 mh Exp Locker: mh $";
810 @sortm could lose a message if interrupted.
816 static char ident[] = "@@(#)$Id: sortm.c,v 1.12 90/04/05 15:02:27 sources Exp Locker: mh $";
819 nxt = mlist[msg] - smsgs;
821 old = smsgs[nxt].s_msg;
822 new = smsgs[msg].s_msg;
823 (void) strcpy (oldname, m_name (old));
824 newname = m_name (new);
826 printf ("message %d becomes message %d\n", old, new);
829 if (rename (oldname, newname) == NOTOK)
830 adios (newname, "unable to rename %s to", oldname);
833 mp->msgstats[new] = mp->msgstats[old];
834 if (mp->curmsg == old)
839 rename_chain (mp, mlist, nxt, endmsg);
852 static char ident[] = "@@(#)$Id:$";
855 (void) strcpy (tmpfil, m_scratch ("", invo_name));
861 @allow numeric strings
870 @use arbitrary textfield not just "subject"
881 *cp2++ = islower(c)? c : tolower(c);
911 int subjsort; /* sort on subject if != 0 */
912 u_long datelimit = ~0;
915 static int dsort(), read_hdrs (), subsort();
926 datelimit = ~0; /* should be MAXINT ? */
929 qsort ((char *) dlist, nmsgs, sizeof(*dlist), dsort);
936 (*s)->s_clock - s[-1]->s_clock <= datelimit) {
939 else if (subjsort && uleq (nam, "subject")) {
944 if ((c == 'r' || c == 'R') &&
945 (cp[0] == 'e' || cp[0] == 'E') &&
966 printf ("message %s becomes message %s\n", old, new);
972 @typo and add -nosubject
978 rename_chain (mp, mlist, msg, endmsg)
985 printf ("message %s becomes message %s\n", f2, f1);
1016 adios (NULLCP, "impossible limit %d", outputlinelen);
1022 @make -verbose messages more standard
1034 int subjsort; /* sort on subject if != 0 */
1035 u_long datelimit = ~0;
1039 adios (NULLCP, "missing argument to %s", argp[-2]);
1040 if (! isdigit(*cp) || !(datelimit = atoi(cp)))
1041 adios (NULLCP, "non-zero number must follow %s", argp[-2]);
1048 @big rewrite -- sort by subject too!
1053 printf (" %s becomes %s\n", oldname, newname);
1056 printf ("renaming chain from %d to %d\n", old, new);
1073 "datefield field", 0,
1098 static int msgsort ();
1100 static struct tws *getws ();
1102 static int read_dates();
1103 static file_dates();
1129 *arguments[MAXARGS],
1138 ambigsw (cp, switches);
1141 adios (NULLCP, "-%s unknown", cp);
1143 (void) sprintf (buf, "%s [+folder] [msgs] [switches]",
1145 help (buf, switches);
1151 adios (NULLCP, "only one date field at a time!");
1152 if (!(datesw = *argp++) || *datesw == '-')
1153 adios (NULLCP, "missing argument to %s", argp[-2]);
1171 if (mp -> hghmsg == 0)
1174 if ((i = read_dates (mp, datesw)) <= 0)
1176 qsort ((char *) smsgs, i, sizeof *smsgs, msgsort);
1177 file_dates (mp, verbosw);
1185 static int read_dates (mp, datesw)
1186 register struct msgs *mp;
1187 register char *datesw;
1193 register struct tws *tw;
1196 smsgs = (struct smsg *)
1197 calloc ((unsigned) (mp -> hghsel - mp -> lowsel + 2),
1201 for (msgnum = mp -> lowsel; msgnum <= mp -> hghsel; msgnum++) {
1203 if (mp -> msgstats[msgnum] & SELECTED) {
1204 if ((tw = getws (datesw, msgnum)) == NULL)
1205 tw = msgnum != mp -> lowsel ? &((s - 1) -> s_tws) : &tb;
1208 if (mp -> msgstats[msgnum] & EXISTS)
1212 s -> s_msg = msgnum;
1213 twscopy (&s -> s_tws, tw);
1225 static struct tws *getws (datesw, msg)
1226 register char *datesw;
1247 for (compnum = 1, state = FLD, hp = NULL;;) {
1255 free (hp), hp = NULL;
1256 hp = add (buf, NULLCP);
1262 if (uleq (nam, datesw))
1265 if (state != FLDEOF)
1272 admonish (NULLCP, "no %s field in message %d", datesw, msg);
1277 if (state == LENERR || state == FMTERR)
1279 "format error in message %d(header #%d)",
1288 adios (NULLCP, "internal error -- you lose");
1291 if ((tw = dparsetime (hp)) == NULL)
1292 admonish (NULLCP, "unable to parse %s field in message %d",
1306 static int msgsort (a, b)
1307 register struct smsg *a,
1311 return twsort (&a -> s_tws, &b -> s_tws);
1317 static file_dates (mp, verbosw)
1318 register struct msgs *mp;
1331 for (i = 0; j = smsgs[i++].s_msg;)
1333 (void) strcpy (f1, m_name (i));
1334 (void) strcpy (f2, m_name (j));
1335 if (mp -> msgstats[i] & EXISTS) {
1337 printf ("swap messages %s and %s\n", f2, f1);
1340 if (rename (f1, tmpfil) == NOTOK) {
1341 admonish (tmpfil, "unable to rename %s to ", f1);
1346 if (rename (f2, f1) == NOTOK) {
1347 admonish (f1, "unable to rename %s to", f2);
1352 if (rename (tmpfil, f2) == NOTOK) {
1353 admonish (f2, "unable to rename %s to", tmpfil);
1358 for (k = i; smsgs[k].s_msg; k++)
1359 if (smsgs[k].s_msg == i) {
1366 printf ("message %s becomes message %s\n", f2, f1);
1369 if (rename (f2, f1) == NOTOK) {
1370 admonish (f1, "unable to rename %s to ", f2);
1376 smsgs[i - 1].s_msg = i;
1377 stats = mp -> msgstats[i];
1378 mp -> msgstats[i] = mp -> msgstats[j];
1379 mp -> msgstats[j] = stats;
1380 if (mp -> curmsg == j)
1382 mp -> msgflags |= SEQMOD;
1397 struct tws *getws ();