/*
* sortm.c -- sort messages in a folder by date/time
*
- * $Id$
- *
* This code is Copyright (c) 2002, by the authors of nmh. See the
* COPYRIGHT file in the root directory of the nmh distribution for
* complete copyright information.
#include <h/mh.h>
#include <h/tws.h>
-
-/*
- * We allocate space for messages (msgs array)
- * this number of elements at a time.
- */
-#define MAXMSGS 256
-
+#include <h/utils.h>
static struct swit switches[] = {
#define DATESW 0
{ "verbose", 0 },
#define NVERBSW 7
{ "noverbose", 0 },
-#define VERSIONSW 8
+#define ALLMSGS 8
+ { "all", 0 },
+#define NALLMSGS 9
+ { "noall", 0 },
+#define CHECKSW 10
+ { "check", 0 },
+#define NCHECKSW 11
+ { "nocheck", 0 },
+#define VERSIONSW 12
{ "version", 0 },
-#define HELPSW 9
+#define HELPSW 13
{ "help", 0 },
{ NULL, 0 }
};
int nmsgs;
char *subjsort = (char *) 0; /* sort on subject if != 0 */
-unsigned long datelimit = 0;
+time_t datelimit = 0;
int submajor = 0; /* if true, sort on subject-major */
int verbose;
+int allmsgs = 1;
+int check_failed = 0;
/* This keeps compiler happy on calls to qsort */
typedef int (*qsort_comp) (const void *, const void *);
int
main (int argc, char **argv)
{
- int nummsgs, maxmsgs, i, msgnum;
- char *cp, *maildir, *datesw = NULL;
+ int i, msgnum;
+ unsigned char *cp;
+ char *maildir, *datesw = NULL;
char *folder = NULL, buf[BUFSIZ], **argp;
- char **arguments, **msgs;
+ char **arguments;
+ struct msgs_array msgs = { 0, 0, NULL };
struct msgs *mp;
struct smsg **dlist;
+ int checksw = 0;
#ifdef LOCALE
setlocale(LC_ALL, "");
argp = arguments;
/*
- * Allocate the initial space to record message
- * names and ranges.
- */
- nummsgs = 0;
- maxmsgs = MAXMSGS;
- if (!(msgs = (char **) malloc ((size_t) (maxmsgs * sizeof(*msgs)))))
- adios (NULL, "unable to allocate storage");
-
- /*
* Parse arguments
*/
while ((cp = *argp++)) {
snprintf(buf, sizeof(buf), "%s [+folder] [msgs] [switches]",
invo_name);
print_help (buf, switches, 1);
- done (1);
+ done (0);
case VERSIONSW:
print_version(invo_name);
- done (1);
+ done (0);
case DATESW:
if (datesw)
case NVERBSW:
verbose = 0;
continue;
+
+ case ALLMSGS:
+ allmsgs = 1;
+ continue;
+ case NALLMSGS:
+ allmsgs = 0;
+ continue;
+
+ case CHECKSW:
+ checksw = 1;
+ continue;
+ case NCHECKSW:
+ checksw = 0;
+ continue;
}
}
if (*cp == '+' || *cp == '@') {
if (folder)
adios (NULL, "only one folder at a time!");
else
- folder = path (cp + 1, *cp == '+' ? TFOLDER : TSUBCWF);
- } else {
- /*
- * Check if we need to allocate more space
- * for message names/ranges.
- */
- if (nummsgs >= maxmsgs) {
- maxmsgs += MAXMSGS;
- if (!(msgs = (char **) realloc (msgs,
- (size_t) (maxmsgs * sizeof(*msgs)))))
- adios (NULL, "unable to reallocate msgs storage");
- }
- msgs[nummsgs++] = cp;
- }
+ folder = pluspath (cp);
+ } else
+ app_msgarg(&msgs, cp);
}
if (!context_find ("path"))
free (path ("./", TFOLDER));
- if (!nummsgs)
- msgs[nummsgs++] = "all";
+ if (!msgs.size) {
+ if (allmsgs) {
+ app_msgarg(&msgs, "all");
+ } else {
+ adios (NULL, "must specify messages to sort with -noall");
+ }
+ }
if (!datesw)
datesw = "date";
if (!folder)
adios (NULL, "no messages in %s", folder);
/* parse all the message ranges/sequences and set SELECTED */
- for (msgnum = 0; msgnum < nummsgs; msgnum++)
- if (!m_convert (mp, msgs[msgnum]))
+ for (msgnum = 0; msgnum < msgs.size; msgnum++)
+ if (!m_convert (mp, msgs.msgs[msgnum]))
done (1);
seq_setprev (mp); /* set the previous sequence */
if ((nmsgs = read_hdrs (mp, datesw)) <= 0)
adios (NULL, "no messages to sort");
+ if (checksw && check_failed) {
+ adios (NULL, "errors found, no messages sorted");
+ }
+
/*
* sort a list of pointers to our "messages to be sorted".
*/
- dlist = (struct smsg **) malloc ((nmsgs+1) * sizeof(*dlist));
- if (! dlist)
- adios (NULL, "couldn't allocate sort memory");
+ dlist = (struct smsg **) mh_xmalloc ((nmsgs+1) * sizeof(*dlist));
for (i = 0; i < nmsgs; i++)
dlist[i] = &smsgs[i];
dlist[nmsgs] = 0;
if (verbose) { /* announce what we're doing */
if (subjsort)
- printf ("sorting by %s-major %s-minor\n",
- submajor ? subjsort : datesw,
- submajor ? datesw : subjsort);
+ if (submajor)
+ printf ("sorting by %s\n", subjsort);
+ else
+ printf ("sorting by %s-major %s-minor\n", subjsort, datesw);
else
printf ("sorting by datefield %s\n", datesw);
}
struct smsg **slist, **flist;
register struct smsg ***il, **fp, **dp;
- slist = (struct smsg **) malloc ((nmsgs+1) * sizeof(*slist));
- if (! slist)
- adios (NULL, "couldn't allocate sort memory");
+ slist = (struct smsg **) mh_xmalloc ((nmsgs+1) * sizeof(*slist));
memcpy((char *)slist, (char *)dlist, (nmsgs+1)*sizeof(*slist));
qsort((char *)slist, nmsgs, sizeof(*slist), (qsort_comp) subsort);
* make up the final list, chronological but with
* all the same subjects grouped together.
*/
- flist = (struct smsg **) malloc ((nmsgs+1) * sizeof(*flist));
- if (! flist)
- adios (NULL, "couldn't allocate msg list");
+ flist = (struct smsg **) mh_xmalloc ((nmsgs+1) * sizeof(*flist));
fp = flist;
for (dp = dlist; *dp;) {
register struct smsg **s = il[(*dp++)->s_msg];
seq_save (mp); /* synchronize message sequences */
context_save (); /* save the context file */
folder_free (mp); /* free folder/message structure */
- return done (0);
+ done (0);
+ return 1;
}
static int
case FLDEOF:
case FLDPLUS:
compnum++;
- if (!strcasecmp (nam, datesw)) {
+ if (!mh_strcasecmp (nam, datesw)) {
datecomp = add (buf, datecomp);
while (state == FLDPLUS) {
state = m_getfld (state, nam, buf, sizeof(buf), in);
}
if (!subjsort || subjcomp)
break;
- } else if (subjsort && !strcasecmp (nam, subjsort)) {
+ } else if (subjsort && !mh_strcasecmp (nam, subjsort)) {
subjcomp = add (buf, subjcomp);
while (state == FLDPLUS) {
state = m_getfld (state, nam, buf, sizeof(buf), in);
case LENERR:
case FMTERR:
- if (state == LENERR || state == FMTERR)
+ if (state == LENERR || state == FMTERR) {
admonish (NULL, "format error in message %d (header #%d)",
msg, compnum);
+ check_failed = 1;
+ }
if (datecomp)
free (datecomp);
if (subjcomp)
admonish (NULL, "can't parse %s field in message %d", datesw, msg);
fstat (fileno (in), &st);
smsg->s_clock = st.st_mtime;
+ check_failed = 1;
} else {
smsg->s_clock = dmktime (tw);
}
* leading "re:", everything but letters & smash
* letters to lower case.
*/
- register char *cp, *cp2, c;
+ register char *cp, *cp2;
+ register unsigned char c;
cp = subjcomp;
cp2 = subjcomp;
- if (strcmp (subjsort, "subject") == 0)
+ if (strcmp (subjsort, "subject") == 0) {
while ((c = *cp)) {
if (! isspace(c)) {
if(uprf(cp, "re:"))
cp += 2;
- else {
- if (isalnum(c))
- *cp2++ = isupper(c) ? tolower(c) : c;
+ else
break;
- }
}
cp++;
}
+ }
+
while ((c = *cp++)) {
if (isalnum(c))
*cp2++ = isupper(c) ? tolower(c) : c;
-
}
+
*cp2 = '\0';
}
else
{
int nxt, old, new;
char *newname, oldname[BUFSIZ];
- char newbuf[MAXPATHLEN + 1];
+ char newbuf[PATH_MAX + 1];
for (;;) {
nxt = mlist[msg] - smsgs; /* mlist[msg] is a ptr into smsgs */
if (verbose)
printf ("message %d becomes message %d\n", old, new);
- if (rename (oldname, newname) == NOTOK)
- adios (newname, "unable to rename %s to", oldname);
-
(void)snprintf(oldname, sizeof (oldname), "%s/%d", mp->foldpath, old);
(void)snprintf(newbuf, sizeof (newbuf), "%s/%d", mp->foldpath, new);
ext_hook("ref-hook", oldname, newbuf);
+ if (rename (oldname, newname) == NOTOK)
+ adios (newname, "unable to rename %s to", oldname);
+
copy_msg_flags (mp, new, old);
if (mp->curmsg == old)
seq_setcur (mp, new);
int i, j, old, new;
seqset_t tmpset;
char f1[BUFSIZ], tmpfil[BUFSIZ];
- char newbuf[MAXPATHLEN + 1];
+ char newbuf[PATH_MAX + 1];
struct smsg *sp;
strncpy (tmpfil, m_name (mp->hghmsg + 1), sizeof(tmpfil));
if (verbose)
printf ("renaming message chain from %d to %d\n", old, new);
- if (rename (f1, tmpfil) == NOTOK)
- adios (tmpfil, "unable to rename %s to ", f1);
-
/*
- * Run the external hook to refile the old message as message
- * number 2147483647. This is our way of making a temporary
- * message number. I don't really like this.
+ * Run the external hook to refile the old message as the
+ * temporary message number that is off of the end of the
+ * messages in the folder.
*/
(void)snprintf(f1, sizeof (f1), "%s/%d", mp->foldpath, old);
- (void)snprintf(newbuf, sizeof (newbuf), "%s/2147483647", mp->foldpath);
+ (void)snprintf(newbuf, sizeof (newbuf), "%s/%d", mp->foldpath, mp->hghmsg + 1);
ext_hook("ref-hook", f1, newbuf);
+ if (rename (f1, tmpfil) == NOTOK)
+ adios (tmpfil, "unable to rename %s to ", f1);
+
get_msg_flags (mp, &tmpset, old);
rename_chain (mp, mlist, j, i);
- if (rename (tmpfil, m_name(new)) == NOTOK)
- adios (m_name(new), "unable to rename %s to", tmpfil);
/*
* Run the external hook to refile the temorary message number
(void)snprintf(f1, sizeof (f1), "%s/%d", mp->foldpath, new);
ext_hook("ref-hook", newbuf, f1);
+ if (rename (tmpfil, m_name(new)) == NOTOK)
+ adios (m_name(new), "unable to rename %s to", tmpfil);
+
set_msg_flags (mp, &tmpset, new);
mp->msgflags |= SEQMOD;
}