1: /* sortm.c - sort messages in a folder by date/time */ 2: 3: #include "../h/mh.h" 4: #include "../zotnet/tws.h" 5: #include <stdio.h> 6: 7: /* */ 8: 9: static struct swit switches[] = { 10: #define DATESW 0 11: "datefield field", 0, 12: 13: #define VERBSW 1 14: "verbose", 0, 15: #define NVERBSW 2 16: "noverbose", 0, 17: 18: #define HELPSW 3 19: "help", 4, 20: 21: NULL, NULL 22: }; 23: 24: /* */ 25: 26: struct smsg { 27: int s_msg; 28: struct tws s_tws; 29: }; 30: 31: static struct smsg *smsgs; 32: 33: 34: int msgsort (); 35: 36: struct tws *getws (); 37: 38: 39: long time (); 40: 41: /* */ 42: 43: /* ARGSUSED */ 44: 45: main (argc, argv) 46: int argc; 47: char **argv; 48: { 49: int verbosw = 0, 50: msgp = 0, 51: i, 52: msgnum; 53: char *cp, 54: *maildir, 55: *datesw = NULL, 56: *folder = NULL, 57: buf[100], 58: **ap, 59: **argp, 60: *arguments[MAXARGS], 61: *msgs[MAXARGS]; 62: struct msgs *mp; 63: 64: invo_name = r1bindex (argv[0], '/'); 65: if ((cp = m_find (invo_name)) != NULL) { 66: ap = brkstring (cp = getcpy (cp), " ", "\n"); 67: ap = copyip (ap, arguments); 68: } 69: else 70: ap = arguments; 71: (void) copyip (argv + 1, ap); 72: argp = arguments; 73: 74: /* */ 75: 76: while (cp = *argp++) { 77: if (*cp == '-') 78: switch (smatch (++cp, switches)) { 79: case AMBIGSW: 80: ambigsw (cp, switches); 81: done (1); 82: case UNKWNSW: 83: adios (NULLCP, "-%s unknown", cp); 84: case HELPSW: 85: (void) sprintf (buf, "%s [+folder] [msgs] [switches]", 86: invo_name); 87: help (buf, switches); 88: done (1); 89: 90: case DATESW: 91: if (datesw) 92: adios (NULLCP, "only one date field at a time!"); 93: if (!(datesw = *argp++) || *datesw == '-') 94: adios (NULLCP, "missing argument to %s", argp[-2]); 95: continue; 96: 97: case VERBSW: 98: verbosw++; 99: continue; 100: case NVERBSW: 101: verbosw = 0; 102: continue; 103: } 104: if (*cp == '+' || *cp == '@') { 105: if (folder) 106: adios (NULLCP, "only one folder at a time!"); 107: else 108: folder = path (cp + 1, *cp == '+' ? TFOLDER : TSUBCWF); 109: } 110: else 111: msgs[msgp++] = cp; 112: } 113: 114: /* */ 115: 116: if (!m_find ("path")) 117: free (path ("./", TFOLDER)); 118: if (!msgp) 119: msgs[msgp++] = "all"; 120: if (!datesw) 121: datesw = "Date"; 122: if (!folder) 123: folder = m_getfolder (); 124: maildir = m_maildir (folder); 125: 126: if (chdir (maildir) == NOTOK) 127: adios (maildir, "unable to change directory to"); 128: if (!(mp = m_gmsg (folder))) 129: adios (NULLCP, "unable to read folder %s", folder); 130: if (mp -> hghmsg == 0) 131: adios (NULLCP, "no messages in %s", folder); 132: 133: for (msgnum = 0; msgnum < msgp; msgnum++) 134: if (!m_convert (mp, msgs[msgnum])) 135: done (1); 136: m_setseq (mp); 137: 138: if ((i = read_dates (mp, datesw)) <= 0) 139: adios (NULLCP, "no messages to sort"); 140: qsort ((char *) smsgs, i, sizeof *smsgs, msgsort); 141: file_dates (mp, verbosw); 142: 143: m_replace (pfolder, folder); 144: m_sync (mp); 145: m_update (); 146: 147: done (0); 148: } 149: 150: /* */ 151: 152: static int read_dates (mp, datesw) 153: register struct msgs *mp; 154: register char *datesw; 155: { 156: int msgnum; 157: struct tws tb; 158: register struct smsg *s; 159: register struct tws *tw; 160: 161: twscopy (&tb, dtwstime ()); 162: 163: smsgs = (struct smsg *) 164: calloc ((unsigned) (mp -> hghsel - mp -> lowsel + 2), 165: sizeof *smsgs); 166: if (smsgs == NULL) 167: adios (NULLCP, "unable to allocate sort storage"); 168: 169: s = smsgs; 170: for (msgnum = mp -> lowsel; msgnum <= mp -> hghsel; msgnum++) { 171: tw = NULL; 172: if (mp -> msgstats[msgnum] & SELECTED) { 173: if ((tw = getws (datesw, msgnum)) == NULL) 174: tw = msgnum != mp -> lowsel ? &((s - 1) -> s_tws) : &tb; 175: } 176: else 177: if (mp -> msgstats[msgnum] & EXISTS) 178: tw = &tb; 179: 180: if (tw) { 181: s -> s_msg = msgnum; 182: twscopy (&s -> s_tws, tw); 183: s++; 184: } 185: } 186: 187: s -> s_msg = 0; 188: return (s - smsgs); 189: } 190: 191: /* */ 192: 193: static struct tws *getws (datesw, msg) 194: register char *datesw; 195: int msg; 196: { 197: int compnum, 198: state; 199: register char *hp, 200: *msgnam; 201: char buf[BUFSIZ], 202: nam[NAMESZ]; 203: register struct tws *tw; 204: register FILE *in; 205: 206: if ((in = fopen (msgnam = m_name (msg), "r")) == NULL) { 207: admonish (msgnam, "unable to read message"); 208: return NULL; 209: } 210: 211: /* */ 212: 213: for (compnum = 1, state = FLD, hp = NULL;;) { 214: switch (state = m_getfld (state, nam, buf, sizeof buf, in)) { 215: case FLD: 216: case FLDEOF: 217: case FLDPLUS: 218: compnum++; 219: if (hp != NULL) 220: free (hp), hp = NULL; 221: hp = add (buf, NULLCP); 222: while (state == FLDPLUS) { 223: state = m_getfld (state, nam, buf, sizeof buf, in); 224: hp = add (buf, hp); 225: } 226: if (uleq (nam, datesw)) 227: break; 228: if (state != FLDEOF) 229: continue; 230: 231: case BODY: 232: case BODYEOF: 233: case FILEEOF: 234: admonish (NULLCP, "no %s field in message %d", datesw, msg); 235: 236: case LENERR: 237: case FMTERR: 238: if (state == LENERR || state == FMTERR) 239: admonish (NULLCP, 240: "format error in message %d(header #%d)", 241: msg, compnum); 242: if (hp != NULL) 243: free (hp); 244: (void) fclose (in); 245: return NULL; 246: 247: default: 248: adios (NULLCP, "internal error -- you lose"); 249: } 250: break; 251: } 252: 253: if ((tw = dparsetime (hp)) == NULL) 254: admonish (NULLCP, "unable to parse %s field in message %d", 255: datesw, msg); 256: 257: if (hp != NULL) 258: free (hp); 259: (void) fclose (in); 260: return tw; 261: } 262: 263: /* */ 264: 265: static int msgsort (a, b) 266: register struct smsg *a, 267: *b; 268: { 269: return twsort (&a -> s_tws, &b -> s_tws); 270: } 271: 272: /* */ 273: 274: static file_dates (mp, verbosw) 275: register struct msgs *mp; 276: int verbosw; 277: { 278: register int i, 279: j, 280: k; 281: short stats; 282: char f1[BUFSIZ], 283: f2[BUFSIZ], 284: tmpfil[BUFSIZ]; 285: 286: (void) strcpy (tmpfil, m_scratch ("", invo_name)); 287: 288: for (i = 0; j = smsgs[i++].s_msg;) 289: if (i != j) { 290: (void) strcpy (f1, m_name (i)); 291: (void) strcpy (f2, m_name (j)); 292: if (mp -> msgstats[i] & EXISTS) { 293: if (verbosw) 294: printf ("swap messages %s and %s\n", f2, f1); 295: 296: if (rename (f1, tmpfil) == NOTOK) { 297: admonish (tmpfil, "unable to rename %s to ", f1); 298: continue; 299: } 300: 301: if (rename (f2, f1) == NOTOK) { 302: admonish (f1, "unable to rename %s to", f2); 303: continue; 304: } 305: 306: if (rename (tmpfil, f2) == NOTOK) { 307: admonish (f2, "unable to rename %s to", tmpfil); 308: continue; 309: } 310: 311: for (k = i; smsgs[k].s_msg; k++) 312: if (smsgs[k].s_msg == i) { 313: smsgs[k].s_msg = j; 314: break; 315: } 316: } 317: else { 318: if (verbosw) 319: printf ("message %s becomes message %s\n", f2, f1); 320: 321: if (rename (f2, f1) == NOTOK) { 322: admonish (f1, "unable to rename %s to ", f2); 323: continue; 324: } 325: } 326: 327: smsgs[i - 1].s_msg = i; 328: stats = mp -> msgstats[i]; 329: mp -> msgstats[i] = mp -> msgstats[j]; 330: mp -> msgstats[j] = stats; 331: if (mp -> curmsg == j) 332: m_setcur (mp, i); 333: mp -> msgflags |= SEQMOD; 334: } 335: }