-
/*
- * folder(s).c -- set/list the current message and/or folder
- * -- push/pop a folder onto/from the folder stack
- * -- list the folder stack
- *
- * $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.
- */
+** folder(s).c -- set/list the current message and/or folder
+** -- push/pop a folder onto/from the folder stack
+** -- list the folder stack
+**
+** This code is Copyright (c) 2002, 2008, 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/crawl_folders.h>
#include <h/utils.h>
#include <errno.h>
+#include <unistd.h>
+#include <locale.h>
+#include <sysexits.h>
static struct swit switches[] = {
-#define ALLSW 0
- { "all", 0 },
-#define NALLSW 1
- { "noall", 0 },
-#define CREATSW 2
- { "create", 0 },
-#define NCREATSW 3
- { "nocreate", 0 },
-#define FASTSW 4
- { "fast", 0 },
-#define NFASTSW 5
- { "nofast", 0 },
-#define HDRSW 6
- { "header", 0 },
-#define NHDRSW 7
- { "noheader", 0 },
-#define PACKSW 8
- { "pack", 0 },
-#define NPACKSW 9
- { "nopack", 0 },
-#define VERBSW 10
- { "verbose", 0 },
-#define NVERBSW 11
- { "noverbose", 0 },
-#define RECURSW 12
- { "recurse", 0 },
-#define NRECRSW 13
- { "norecurse", 0 },
-#define TOTALSW 14
- { "total", 0 },
-#define NTOTLSW 15
- { "nototal", 0 },
-#define LISTSW 16
- { "list", 0 },
-#define NLISTSW 17
- { "nolist", 0 },
-#define PRNTSW 18
- { "print", 0 },
-#define NPRNTSW 19
- { "noprint", -4 },
-#define PUSHSW 20
- { "push", 0 },
-#define POPSW 21
- { "pop", 0 },
-#define VERSIONSW 22
- { "version", 0 },
-#define HELPSW 23
- { "help", 0 },
- { NULL, 0 }
+#define ALLSW 0
+ { "all", 0 },
+#define NALLSW 1
+ { "noall", 2 },
+#define CREATSW 2
+ { "create", 0 },
+#define NCREATSW 3
+ { "nocreate", 2 },
+#define FASTSW 4
+ { "fast", 0 },
+#define NFASTSW 5
+ { "nofast", 2 },
+#define PACKSW 6
+ { "pack", 0 },
+#define NPACKSW 7
+ { "nopack", 2 },
+#define VERBSW 8
+ { "verbose", 0 },
+#define NVERBSW 9
+ { "noverbose", 2 },
+#define RECURSW 10
+ { "recurse", 0 },
+#define NRECRSW 11
+ { "norecurse", 2 },
+#define TOTALSW 12
+ { "total", 0 },
+#define NTOTLSW 13
+ { "nototal", 2 },
+#define LISTSW 14
+ { "list", 0 },
+#define NLISTSW 15
+ { "nolist", 2 },
+#define PRNTSW 16
+ { "print", 0 },
+#define NPRNTSW 17
+ { "noprint", -4 },
+#define PUSHSW 18
+ { "push", 0 },
+#define POPSW 19
+ { "pop", 0 },
+#define VERSIONSW 20
+ { "Version", 0 },
+#define HELPSW 21
+ { "help", 0 },
+ { NULL, 0 }
};
-static int fshort = 0; /* output only folder names */
-static int fcreat = 0; /* should we ask to create new folders? */
-static int fpack = 0; /* are we packing the folder? */
-static int fverb = 0; /* print actions taken while packing folder */
-static int fheader = 0; /* should we output a header? */
-static int frecurse = 0; /* recurse through subfolders */
-static int ftotal = 0; /* should we output the totals? */
-static int all = 0; /* should we output all folders */
+char *version=VERSION;
-static int total_folders = 0; /* total number of folders */
+static int fshort = 0; /* output only folder names */
+static int fcreat = 0; /* should we ask to create new folders? */
+static int fpack = 0; /* are we packing the folder? */
+static int fverb = 0; /* print actions taken while packing folder */
+static int frecurse = 0; /* recurse through subfolders */
+static int ftotal = 0; /* should we output the totals? */
+static int all = 0; /* should we output all folders */
-static int start = 0;
-static int foldp = 0;
+static int total_folders = 0; /* total number of folders */
static char *nmhdir;
static char *stack = "Folder-Stack";
static char folder[BUFSIZ];
-#define NUMFOLDERS 100
-
-/*
- * This is how many folders we currently can hold in the array
- * `folds'. We increase this amount by NUMFOLDERS at a time.
- */
-static int maxfolders;
-static char **folds;
-
/*
- * Structure to hold information about
- * folders as we scan them.
- */
+** Structure to hold information about
+** folders as we scan them.
+*/
struct FolderInfo {
- char *name;
- int nummsg;
- int curmsg;
- int lowmsg;
- int hghmsg;
- int others; /* others == 1 if other files in folder */
- int error; /* error == 1 for unreadable folder */
+ char *name;
+ int nummsg;
+ int curmsg;
+ int lowmsg;
+ int hghmsg;
+ int others; /* others == 1 if other files in folder */
+ int error; /* error == 1 for unreadable folder */
};
/*
- * Dynamically allocated space to hold
- * all the folder information.
- */
+** Dynamically allocated space to hold
+** all the folder information.
+*/
static struct FolderInfo *fi;
static int maxFolderInfo;
/*
- * static prototypes
- */
-static void dodir (char *);
-static int get_folder_info (char *, char *);
-static void print_folders (void);
-static int sfold (struct msgs *, char *);
-static void addir (char *);
-static void addfold (char *);
-static int compare (char *, char *);
-static void readonly_folders (void);
+** static prototypes
+*/
+static int get_folder_info(char *, char *);
+static crawl_callback_t get_folder_info_callback;
+static void print_folders(void);
+static int sfold(struct msgs *, char *);
+static void readonly_folders(void);
+static int folder_pack(struct msgs **, int);
int
-main (int argc, char **argv)
+main(int argc, char **argv)
{
- int printsw = 0, listsw = 0;
- int pushsw = 0, popsw = 0;
- char *cp, *dp, *msg = NULL, *argfolder = NULL;
- char **ap, **argp, buf[BUFSIZ], **arguments;
- struct stat st;
-
-#ifdef LOCALE
- setlocale(LC_ALL, "");
-#endif
- invo_name = r1bindex (argv[0], '/');
-
- /* read user profile/context */
- context_read();
-
- /*
- * If program was invoked with name ending
- * in `s', then add switch `-all'.
- */
- if (argv[0][strlen (argv[0]) - 1] == 's')
- all = 1;
-
- arguments = getarguments (invo_name, argc, argv, 1);
- argp = arguments;
-
- while ((cp = *argp++)) {
- if (*cp == '-') {
- switch (smatch (++cp, switches)) {
- case AMBIGSW:
- ambigsw (cp, switches);
- done (1);
- case UNKWNSW:
- adios (NULL, "-%s unknown", cp);
-
- case HELPSW:
- snprintf (buf, sizeof(buf), "%s [+folder] [msg] [switches]",
- invo_name);
- print_help (buf, switches, 1);
- done (1);
- case VERSIONSW:
- print_version(invo_name);
- done (1);
-
- case ALLSW:
- all = 1;
- continue;
-
- case NALLSW:
- all = 0;
- continue;
-
- case CREATSW:
- fcreat = 1;
- continue;
- case NCREATSW:
- fcreat = -1;
- continue;
-
- case FASTSW:
- fshort++;
- continue;
- case NFASTSW:
- fshort = 0;
- continue;
-
- case HDRSW:
- fheader = 1;
- continue;
- case NHDRSW:
- fheader = -1;
- continue;
-
- case PACKSW:
- fpack++;
- continue;
- case NPACKSW:
- fpack = 0;
- continue;
-
- case VERBSW:
- fverb++;
- continue;
- case NVERBSW:
- fverb = 0;
- continue;
-
- case RECURSW:
- frecurse++;
- continue;
- case NRECRSW:
- frecurse = 0;
- continue;
-
- case TOTALSW:
- ftotal = 1;
- continue;
- case NTOTLSW:
- ftotal = -1;
- continue;
-
- case PRNTSW:
- printsw = 1;
- continue;
- case NPRNTSW:
- printsw = 0;
- continue;
-
- case LISTSW:
- listsw = 1;
- continue;
- case NLISTSW:
- listsw = 0;
- continue;
-
- case PUSHSW:
- pushsw = 1;
- listsw = 1;
- popsw = 0;
- continue;
- case POPSW:
- popsw = 1;
- listsw = 1;
- pushsw = 0;
- continue;
- }
- }
- if (*cp == '+' || *cp == '@') {
- if (argfolder)
- adios (NULL, "only one folder at a time!");
- else
- argfolder = path (cp + 1, *cp == '+' ? TFOLDER : TSUBCWF);
- } else {
- if (msg)
- adios (NULL, "only one (current) message at a time!");
- else
- msg = cp;
- }
- }
-
- if (!context_find ("path"))
- free (path ("./", TFOLDER));
- nmhdir = concat (m_maildir (""), "/", NULL);
-
- /*
- * If we aren't working with the folder stack
- * (-push, -pop, -list) then the default is to print.
- */
- if (pushsw == 0 && popsw == 0 && listsw == 0)
- printsw++;
-
- /* Pushing a folder onto the folder stack */
- if (pushsw) {
- if (!argfolder) {
- /* If no folder is given, the current folder and */
- /* the top of the folder stack are swapped. */
- if ((cp = context_find (stack))) {
- dp = getcpy (cp);
- ap = brkstring (dp, " ", "\n");
- argfolder = getcpy(*ap++);
- } else {
- adios (NULL, "no other folder");
- }
- for (cp = getcpy (getfolder (1)); *ap; ap++)
- cp = add (*ap, add (" ", cp));
- free (dp);
- context_replace (stack, cp); /* update folder stack */
- } else {
- /* update folder stack */
- context_replace (stack,
- (cp = context_find (stack))
- ? concat (getfolder (1), " ", cp, NULL)
- : getcpy (getfolder (1)));
+ int printsw = 0, listsw = 0;
+ int pushsw = 0, popsw = 0;
+ char *cp, *dp, *msg = NULL, *argfolder = NULL;
+ char **ap, **argp, buf[BUFSIZ], **arguments;
+
+ setlocale(LC_ALL, "");
+ invo_name = mhbasename(argv[0]);
+
+ /* read user profile/context */
+ context_read();
+
+ /*
+ ** If program was invoked with name ending
+ ** in `s', then add switch `-all'.
+ */
+ if (argv[0][strlen(argv[0]) - 1] == 's')
+ all = 1;
+
+ arguments = getarguments(invo_name, argc, argv, 1);
+ argp = arguments;
+
+ while ((cp = *argp++)) {
+ if (*cp == '-') {
+ switch (smatch(++cp, switches)) {
+ case AMBIGSW:
+ ambigsw(cp, switches);
+ exit(EX_USAGE);
+ case UNKWNSW:
+ adios(EX_USAGE, NULL, "-%s unknown", cp);
+
+ case HELPSW:
+ snprintf(buf, sizeof(buf), "%s [+folder] [msg] [switches]", invo_name);
+ print_help(buf, switches, 1);
+ exit(argc == 2 ? EX_OK : EX_USAGE);
+ case VERSIONSW:
+ print_version(invo_name);
+ exit(argc == 2 ? EX_OK : EX_USAGE);
+
+ case ALLSW:
+ all = 1;
+ continue;
+
+ case NALLSW:
+ all = 0;
+ continue;
+
+ case CREATSW:
+ fcreat = 1;
+ continue;
+ case NCREATSW:
+ fcreat = -1;
+ continue;
+
+ case FASTSW:
+ fshort++;
+ continue;
+ case NFASTSW:
+ fshort = 0;
+ continue;
+
+ case PACKSW:
+ fpack++;
+ continue;
+ case NPACKSW:
+ fpack = 0;
+ continue;
+
+ case VERBSW:
+ fverb++;
+ continue;
+ case NVERBSW:
+ fverb = 0;
+ continue;
+
+ case RECURSW:
+ frecurse++;
+ continue;
+ case NRECRSW:
+ frecurse = 0;
+ continue;
+
+ case TOTALSW:
+ ftotal = 1;
+ continue;
+ case NTOTLSW:
+ ftotal = -1;
+ continue;
+
+ case PRNTSW:
+ printsw = 1;
+ continue;
+ case NPRNTSW:
+ printsw = 0;
+ continue;
+
+ case LISTSW:
+ listsw = 1;
+ continue;
+ case NLISTSW:
+ listsw = 0;
+ continue;
+
+ case PUSHSW:
+ pushsw = 1;
+ listsw = 1;
+ popsw = 0;
+ continue;
+ case POPSW:
+ popsw = 1;
+ listsw = 1;
+ pushsw = 0;
+ continue;
+ }
+ }
+ if (*cp == '+' || *cp == '@') {
+ if (argfolder)
+ adios(EX_USAGE, NULL, "only one folder at a time!");
+ else
+ argfolder = mh_xstrdup(expandfol(cp));
+ } else {
+ if (msg)
+ adios(EX_USAGE, NULL, "only one (current) message at a time!");
+ else
+ msg = cp;
+ }
}
- }
-
- /* Popping a folder off of the folder stack */
- if (popsw) {
- if (argfolder)
- adios (NULL, "sorry, no folders allowed with -pop");
- if ((cp = context_find (stack))) {
- dp = getcpy (cp);
- ap = brkstring (dp, " ", "\n");
- argfolder = getcpy(*ap++);
- } else {
- adios (NULL, "folder stack empty");
+
+ nmhdir = concat(toabsdir("+"), "/", NULL);
+
+ /*
+ ** If we aren't working with the folder stack
+ ** (-push, -pop, -list) then the default is to print.
+ */
+ if (pushsw == 0 && popsw == 0 && listsw == 0)
+ printsw++;
+
+ /* Pushing a folder onto the folder stack */
+ if (pushsw) {
+ if (!argfolder) {
+ /* If no folder is given, the current folder and */
+ /* the top of the folder stack are swapped. */
+ if ((cp = context_find(stack))) {
+ dp = mh_xstrdup(cp);
+ ap = brkstring(dp, " ", "\n");
+ argfolder = mh_xstrdup(*ap++);
+ } else {
+ adios(EX_USAGE, NULL, "no other folder");
+ }
+ for (cp = mh_xstrdup(getcurfol()); *ap; ap++)
+ cp = add(*ap, add(" ", cp));
+ mh_free0(&dp);
+ context_replace(stack, cp); /* update folder stack */
+ } else {
+ /* update folder stack */
+ context_replace(stack, (cp = context_find (stack)) ?
+ concat(getcurfol(), " ", cp, NULL) :
+ mh_xstrdup(getcurfol()));
+ }
}
- if (*ap) {
- /* if there's anything left in the stack */
- cp = getcpy (*ap++);
- for (; *ap; ap++)
- cp = add (*ap, add (" ", cp));
- context_replace (stack, cp); /* update folder stack */
- } else {
- context_del (stack); /* delete folder stack entry from context */
+
+ /* Popping a folder off of the folder stack */
+ if (popsw) {
+ if (argfolder)
+ adios(EX_USAGE, NULL, "sorry, no folders allowed with -pop");
+ if ((cp = context_find(stack))) {
+ dp = mh_xstrdup(cp);
+ ap = brkstring(dp, " ", "\n");
+ argfolder = mh_xstrdup(*ap++);
+ } else {
+ adios(EX_DATAERR, NULL, "folder stack empty");
+ }
+ if (*ap) {
+ /* if there's anything left in the stack */
+ cp = mh_xstrdup(*ap++);
+ for (; *ap; ap++)
+ cp = add(*ap, add(" ", cp));
+ context_replace(stack, cp); /* update folder stack */
+ } else {
+ /* delete folder stack entry from context */
+ context_del(stack);
+ }
+ mh_free0(&dp);
}
- free (dp);
- }
- if (pushsw || popsw) {
- cp = m_maildir(argfolder);
- if (access (cp, F_OK) == NOTOK)
- adios (cp, "unable to find folder");
- context_replace (pfolder, argfolder); /* update current folder */
- context_save (); /* save the context file */
- argfolder = NULL;
- }
-
- /* Listing the folder stack */
- if (listsw) {
- printf ("%s", argfolder ? argfolder : getfolder (1));
- if ((cp = context_find (stack))) {
- dp = getcpy (cp);
- for (ap = brkstring (dp, " ", "\n"); *ap; ap++)
- printf (" %s", *ap);
- free (dp);
+ if (pushsw || popsw) {
+ cp = toabsdir(argfolder);
+ if (access(cp, F_OK) == NOTOK)
+ adios(EX_DATAERR, cp, "unable to find folder");
+ /* update current folder */
+ context_replace(curfolder, argfolder);
+ context_save(); /* save the context file */
+ argfolder = NULL;
}
- printf ("\n");
- if (!printsw)
- done (0);
- }
+ /* Listing the folder stack */
+ if (listsw) {
+ printf("%s", argfolder ? argfolder : getcurfol());
+ if ((cp = context_find(stack))) {
+ dp = mh_xstrdup(cp);
+ for (ap = brkstring(dp, " ", "\n"); *ap; ap++)
+ printf(" %s", *ap);
+ mh_free0(&dp);
+ }
+ printf("\n");
- /* Allocate initial space to record folder names */
- maxfolders = NUMFOLDERS;
- folds = mh_xmalloc (maxfolders * sizeof(char *));
+ if (!printsw) {
+ exit(EX_OK);
+ }
+ }
- /* Allocate initial space to record folder information */
- maxFolderInfo = NUMFOLDERS;
- fi = mh_xmalloc (maxFolderInfo * sizeof(*fi));
+ /* Allocate initial space to record folder information */
+ maxFolderInfo = CRAWL_NUMFOLDERS;
+ fi = mh_xcalloc(maxFolderInfo, sizeof(*fi));
- /*
- * Scan the folders
- */
- if (all || ftotal > 0) {
/*
- * If no folder is given, do them all
- */
- if (!argfolder) {
- if (msg)
- admonish (NULL, "no folder given for message %s", msg);
- readonly_folders (); /* do any readonly folders */
- strncpy (folder, (cp = context_find (pfolder)) ? cp : "", sizeof(folder));
- dodir (".");
+ ** Scan the folders
+ */
+ /*
+ ** change directory to base of nmh directory for
+ ** crawl_folders
+ */
+ if (chdir(nmhdir) == NOTOK) {
+ adios(EX_OSERR, nmhdir, "unable to change directory to");
+ }
+ if (all || ftotal > 0) {
+ /*
+ ** If no folder is given, do them all
+ */
+ if (!argfolder) {
+ if (msg)
+ admonish(NULL, "no folder given for message %s", msg);
+ readonly_folders(); /* do any readonly folders */
+ strncpy(folder, (cp = context_find(curfolder)) ?
+ cp : "", sizeof(folder));
+ crawl_folders(".", get_folder_info_callback, NULL);
+ } else {
+ strncpy(folder, argfolder, sizeof(folder));
+ if (get_folder_info(argfolder, msg)) {
+ /* update current folder */
+ context_replace(curfolder, argfolder);
+ context_save();
+ }
+ /*
+ ** Since recurse wasn't done in get_folder_info(),
+ ** we still need to list all level-1 sub-folders.
+ */
+ if (!frecurse)
+ crawl_folders(folder, get_folder_info_callback,
+ NULL);
+ }
} else {
- strncpy (folder, argfolder, sizeof(folder));
- if (get_folder_info (argfolder, msg)) {
- context_replace (pfolder, argfolder);/* update current folder */
- context_save (); /* save the context file */
- }
- /*
- * Since recurse wasn't done in get_folder_info(),
- * we still need to list all level-1 sub-folders.
- */
- if (!frecurse)
- dodir (folder);
+ strncpy(folder, argfolder ? argfolder : getcurfol(),
+ sizeof(folder));
+
+ /*
+ ** Check if folder exists. If not, then see if
+ ** we should create it, or just exit.
+ */
+ create_folder(toabsdir(folder), fcreat, exit);
+
+ if (get_folder_info(folder, msg) && argfolder) {
+ /* update current folder */
+ context_replace(curfolder, argfolder);
+ }
}
- } else {
- strncpy (folder, argfolder ? argfolder : getfolder (1), sizeof(folder));
/*
- * Check if folder exists. If not, then see if
- * we should create it, or just exit.
- */
- create_folder (m_maildir (folder), fcreat, done);
-
- if (get_folder_info (folder, msg) && argfolder) {
- /* update current folder */
- context_replace (pfolder, argfolder);
- }
- }
-
- /*
- * Print out folder information
- */
- print_folders();
-
- context_save (); /* save the context file */
- return done (0);
-}
+ ** Print out folder information
+ */
+ print_folders();
-/*
- * Base routine for scanning a folder
- */
+ context_save();
+ return EX_OK;
+}
-static void
-dodir (char *dir)
+static int
+get_folder_info_body(char *fold, char *msg, boolean *crawl_children)
{
- int i;
- int os = start;
- int of = foldp;
- char buffer[BUFSIZ];
+ int i, retval = 1;
+ struct msgs *mp = NULL;
- start = foldp;
+ i = total_folders++;
- /* change directory to base of nmh directory */
- if (chdir (nmhdir) == NOTOK)
- adios (nmhdir, "unable to change directory to");
+ /*
+ ** if necessary, reallocate the space
+ ** for folder information
+ */
+ if (total_folders >= maxFolderInfo) {
+ maxFolderInfo += CRAWL_NUMFOLDERS;
+ fi = mh_xrealloc(fi, maxFolderInfo * sizeof(*fi));
+ }
+
+ fi[i].name = fold;
+ fi[i].nummsg = 0;
+ fi[i].curmsg = 0;
+ fi[i].lowmsg = 0;
+ fi[i].hghmsg = 0;
+ fi[i].others = 0;
+ fi[i].error = 0;
+
+ if ((ftotal > 0) || !fshort || msg || fpack) {
+ /*
+ ** create message structure and get folder info
+ */
+ if (!(mp = folder_read(fold))) {
+ admonish(NULL, "unable to read folder %s", fold);
+ return 0;
+ }
+
+ /* set the current message */
+ if (msg && !sfold(mp, msg))
+ retval = 0;
+
+ if (fpack) {
+ if (folder_pack(&mp, fverb) == -1) {
+ exit(EX_OK);
+ }
+ seq_save(mp); /* synchronize the sequences */
+ context_save(); /* save the context file */
+ }
+
+ /* record info for this folder */
+ if ((ftotal > 0) || !fshort) {
+ fi[i].nummsg = mp->nummsg;
+ fi[i].curmsg = mp->curmsg;
+ fi[i].lowmsg = mp->lowmsg;
+ fi[i].hghmsg = mp->hghmsg;
+ fi[i].others = other_files(mp);
+ }
- addir (strncpy (buffer, dir, sizeof(buffer)));
+ folder_free(mp); /* free folder/message structure */
+ }
- for (i = start; i < foldp; i++) {
- get_folder_info (folds[i], NULL);
- fflush (stdout);
- }
+ *crawl_children = (frecurse && (fshort || fi[i].others)
+ && (fi[i].error == 0));
+ return retval;
+}
- start = os;
- foldp = of;
+static boolean
+get_folder_info_callback(char *fold, void *baton)
+{
+ boolean crawl_children;
+ get_folder_info_body(fold, NULL, &crawl_children);
+ fflush(stdout);
+ return crawl_children;
}
static int
-get_folder_info (char *fold, char *msg)
+get_folder_info(char *fold, char *msg)
{
- int i, retval = 1;
- char *mailfile;
- struct msgs *mp = NULL;
-
- i = total_folders++;
-
- /*
- * if necessary, reallocate the space
- * for folder information
- */
- if (total_folders >= maxFolderInfo) {
- maxFolderInfo += NUMFOLDERS;
- fi = mh_xrealloc (fi, maxFolderInfo * sizeof(*fi));
- }
-
- fi[i].name = fold;
- fi[i].nummsg = 0;
- fi[i].curmsg = 0;
- fi[i].lowmsg = 0;
- fi[i].hghmsg = 0;
- fi[i].others = 0;
- fi[i].error = 0;
-
- mailfile = m_maildir (fold);
-
- if (!chdir (mailfile)) {
- if ((ftotal > 0) || !fshort || msg || fpack) {
- /*
- * create message structure and get folder info
- */
- if (!(mp = folder_read (fold))) {
- admonish (NULL, "unable to read folder %s", fold);
- return 0;
- }
-
- /* set the current message */
- if (msg && !sfold (mp, msg))
- retval = 0;
-
- if (fpack) {
- if (folder_pack (&mp, fverb) == -1)
- done (1);
- seq_save (mp); /* synchronize the sequences */
- context_save (); /* save the context file */
- }
-
- /* record info for this folder */
- if ((ftotal > 0) || !fshort) {
- fi[i].nummsg = mp->nummsg;
- fi[i].curmsg = mp->curmsg;
- fi[i].lowmsg = mp->lowmsg;
- fi[i].hghmsg = mp->hghmsg;
- fi[i].others = other_files (mp);
- }
-
- folder_free (mp); /* free folder/message structure */
- }
- } else {
- fi[i].error = 1;
- }
+ boolean crawl_children;
+ int retval;
- if (frecurse && (fshort || fi[i].others) && (fi[i].error == 0))
- dodir (fold);
- return retval;
+ retval = get_folder_info_body(fold, msg, &crawl_children);
+
+ if (crawl_children) {
+ crawl_folders(fold, get_folder_info_callback, NULL);
+ }
+return retval;
}
/*
- * Print folder information
- */
+** Print folder information
+*/
static void
-print_folders (void)
+print_folders(void)
{
- int i, len, hasempty = 0, curprinted;
- int maxlen = 0, maxnummsg = 0, maxlowmsg = 0;
- int maxhghmsg = 0, maxcurmsg = 0, total_msgs = 0;
- int nummsgdigits, lowmsgdigits;
- int hghmsgdigits, curmsgdigits;
- char tmpname[BUFSIZ];
-
- /*
- * compute a few values needed to for
- * printing various fields
- */
- for (i = 0; i < total_folders; i++) {
- /* length of folder name */
- len = strlen (fi[i].name);
- if (len > maxlen)
- maxlen = len;
-
- /* If folder has error, skip the rest */
- if (fi[i].error)
- continue;
-
- /* calculate total number of messages */
- total_msgs += fi[i].nummsg;
-
- /* maximum number of messages */
- if (fi[i].nummsg > maxnummsg)
- maxnummsg = fi[i].nummsg;
-
- /* maximum low message */
- if (fi[i].lowmsg > maxlowmsg)
- maxlowmsg = fi[i].lowmsg;
-
- /* maximum high message */
- if (fi[i].hghmsg > maxhghmsg)
- maxhghmsg = fi[i].hghmsg;
-
- /* maximum current message */
- if (fi[i].curmsg >= fi[i].lowmsg &&
- fi[i].curmsg <= fi[i].hghmsg &&
- fi[i].curmsg > maxcurmsg)
- maxcurmsg = fi[i].curmsg;
-
- /* check for empty folders */
- if (fi[i].nummsg == 0)
- hasempty = 1;
- }
- nummsgdigits = num_digits (maxnummsg);
- lowmsgdigits = num_digits (maxlowmsg);
- hghmsgdigits = num_digits (maxhghmsg);
- curmsgdigits = num_digits (maxcurmsg);
-
- if (hasempty && nummsgdigits < 2)
- nummsgdigits = 2;
-
- /*
- * Print the header
- */
- if (fheader > 0 || (all && !fshort && fheader >= 0))
- printf ("%-*s %*s %-*s; %-*s %*s\n",
- maxlen+1, "FOLDER",
- nummsgdigits + 13, "# MESSAGES",
- lowmsgdigits + hghmsgdigits + 4, " RANGE",
- curmsgdigits + 4, "CUR",
- 9, "(OTHERS)");
-
- /*
- * Print folder information
- */
- if (all || fshort || ftotal < 1) {
+ int i, len, hasempty = 0, curprinted;
+ int maxlen = 0, maxnummsg = 0, maxlowmsg = 0;
+ int maxhghmsg = 0, maxcurmsg = 0, total_msgs = 0;
+ int nummsgdigits, lowmsgdigits;
+ int hghmsgdigits, curmsgdigits;
+ char tmpname[BUFSIZ];
+
+ /*
+ ** compute a few values needed to for
+ ** printing various fields
+ */
for (i = 0; i < total_folders; i++) {
- if (fshort) {
- printf ("%s\n", fi[i].name);
- continue;
- }
-
- /* Add `+' to end of name, if folder is current */
- if (strcmp (folder, fi[i].name))
- snprintf (tmpname, sizeof(tmpname), "%s", fi[i].name);
- else
- snprintf (tmpname, sizeof(tmpname), "%s+", fi[i].name);
-
- if (fi[i].error) {
- printf ("%-*s is unreadable\n", maxlen+1, tmpname);
- continue;
- }
-
- printf ("%-*s ", maxlen+1, tmpname);
-
- curprinted = 0; /* remember if we print cur */
- if (fi[i].nummsg == 0) {
- printf ("has %*s messages%*s",
- nummsgdigits, "no",
- fi[i].others ? lowmsgdigits + hghmsgdigits + 5 : 0, "");
- } else {
- printf ("has %*d message%s (%*d-%*d)",
- nummsgdigits, fi[i].nummsg,
- (fi[i].nummsg == 1) ? " " : "s",
- lowmsgdigits, fi[i].lowmsg,
- hghmsgdigits, fi[i].hghmsg);
- if (fi[i].curmsg >= fi[i].lowmsg && fi[i].curmsg <= fi[i].hghmsg) {
- curprinted = 1;
- printf ("; cur=%*d", curmsgdigits, fi[i].curmsg);
+ /* length of folder name */
+ len = strlen(fi[i].name);
+ if (len > maxlen)
+ maxlen = len;
+
+ /* If folder has error, skip the rest */
+ if (fi[i].error)
+ continue;
+
+ /* calculate total number of messages */
+ total_msgs += fi[i].nummsg;
+
+ /* maximum number of messages */
+ if (fi[i].nummsg > maxnummsg)
+ maxnummsg = fi[i].nummsg;
+
+ /* maximum low message */
+ if (fi[i].lowmsg > maxlowmsg)
+ maxlowmsg = fi[i].lowmsg;
+
+ /* maximum high message */
+ if (fi[i].hghmsg > maxhghmsg)
+ maxhghmsg = fi[i].hghmsg;
+
+ /* maximum current message */
+ if (fi[i].curmsg >= fi[i].lowmsg &&
+ fi[i].curmsg <= fi[i].hghmsg &&
+ fi[i].curmsg > maxcurmsg)
+ maxcurmsg = fi[i].curmsg;
+
+ /* check for empty folders */
+ if (fi[i].nummsg == 0)
+ hasempty = 1;
+ }
+ nummsgdigits = num_digits(maxnummsg);
+ lowmsgdigits = num_digits(maxlowmsg);
+ hghmsgdigits = num_digits(maxhghmsg);
+ curmsgdigits = num_digits(maxcurmsg);
+
+ if (hasempty && nummsgdigits < 2)
+ nummsgdigits = 2;
+
+ /*
+ ** Print folder information
+ */
+ if (all || fshort || ftotal < 1) {
+ for (i = 0; i < total_folders; i++) {
+ if (fshort) {
+ printf("%s\n", fi[i].name);
+ continue;
+ }
+
+ /* Add `+' to end of name, if folder is current */
+ if (strcmp(folder, fi[i].name)!=0)
+ snprintf(tmpname, sizeof(tmpname), "%s",
+ fi[i].name);
+ else
+ snprintf(tmpname, sizeof(tmpname), "%s+",
+ fi[i].name);
+
+ if (fi[i].error) {
+ printf("%-*s is unreadable\n", maxlen+1,
+ tmpname);
+ continue;
+ }
+
+ printf("%-*s ", maxlen+1, tmpname);
+
+ curprinted = 0; /* remember if we print cur */
+ if (fi[i].nummsg == 0) {
+ printf("has %*s messages%*s", nummsgdigits, "no", fi[i].others ? lowmsgdigits + hghmsgdigits + 5 : 0, "");
+ } else {
+ printf("has %*d message%s (%*d-%*d)",
+ nummsgdigits, fi[i].nummsg,
+ (fi[i].nummsg == 1) ?
+ " " : "s",
+ lowmsgdigits, fi[i].lowmsg,
+ hghmsgdigits, fi[i].hghmsg);
+ if (fi[i].curmsg >= fi[i].lowmsg && fi[i].curmsg <= fi[i].hghmsg) {
+ curprinted = 1;
+ printf("; cur=%*d", curmsgdigits,
+ fi[i].curmsg);
+ }
+ }
+
+ if (fi[i].others)
+ printf(";%*s (others)", curprinted ?
+ 0 : curmsgdigits + 6, "");
+ printf("\n");
}
- }
+ }
- if (fi[i].others)
- printf (";%*s (others)", curprinted ? 0 : curmsgdigits + 6, "");
- printf (".\n");
+ /*
+ ** Print folder/message totals
+ */
+ if (ftotal > 0 || (all && !fshort && ftotal >= 0)) {
+ if (all)
+ printf("\n");
+ printf("TOTAL = %d message%c in %d folder%s\n",
+ total_msgs, total_msgs != 1 ? 's' : ' ',
+ total_folders, total_folders != 1 ? "s" : "");
}
- }
-
- /*
- * Print folder/message totals
- */
- if (ftotal > 0 || (all && !fshort && ftotal >= 0)) {
- if (all)
- printf ("\n");
- printf ("TOTAL = %d message%c in %d folder%s.\n",
- total_msgs, total_msgs != 1 ? 's' : ' ',
- total_folders, total_folders != 1 ? "s" : "");
- }
-
- fflush (stdout);
+
+ fflush(stdout);
}
/*
- * Set the current message and sychronize sequences
- */
+** Set the current message and sychronize sequences
+*/
static int
-sfold (struct msgs *mp, char *msg)
+sfold(struct msgs *mp, char *msg)
{
- /* parse the message range/sequence/name and set SELECTED */
- if (!m_convert (mp, msg))
- return 0;
-
- if (mp->numsel > 1) {
- admonish (NULL, "only one message at a time!");
- return 0;
- }
- seq_setprev (mp); /* set the previous-sequence */
- seq_setcur (mp, mp->lowsel);/* set current message */
- seq_save (mp); /* synchronize message sequences */
- context_save (); /* save the context file */
-
- return 1;
-}
-
+ /* parse the message range/sequence/name and set SELECTED */
+ if (!m_convert(mp, msg))
+ return 0;
-static void
-addir (char *name)
-{
- int nlink;
- char *base, *cp;
- struct stat st;
- struct dirent *dp;
- DIR * dd;
-
- cp = name + strlen (name);
- *cp++ = '/';
- *cp = '\0';
-
- /*
- * A hack to skip over a leading
- * "./" in folder names.
- */
- base = strcmp (name, "./") ? name : name + 2;
-
- /* short-cut to see if directory has any sub-directories */
- if (stat (name, &st) != -1 && st.st_nlink == 2)
- return;
-
- if (!(dd = opendir (name))) {
- admonish (name, "unable to read directory ");
- return;
- }
-
- /*
- * Keep track of the number of directories we've seen
- * so we can quit stat'ing early, if we've seen them all.
- */
- nlink = st.st_nlink;
-
- while (nlink && (dp = readdir (dd))) {
- if (!strcmp (dp->d_name, ".") || !strcmp (dp->d_name, "..")) {
- nlink--;
- continue;
- }
- if (cp + NLENGTH(dp) + 2 >= name + BUFSIZ)
- continue;
- strcpy (cp, dp->d_name);
- if (stat (name, &st) != -1 && S_ISDIR(st.st_mode)) {
- /*
- * Check if this was really a symbolic link pointing at
- * a directory. If not, then decrement link count.
- */
- if (lstat (name, &st) == -1)
- nlink--;
- addfold (base);
+ if (mp->numsel > 1) {
+ admonish(NULL, "only one message at a time!");
+ return 0;
}
- }
+ seq_setprev(mp); /* set the previous-sequence */
+ seq_setcur(mp, mp->lowsel); /* set current message */
+ seq_save(mp); /* synchronize message sequences */
+ context_save(); /* save the context file */
- closedir (dd);
- *--cp = '\0';
+ return 1;
}
+
/*
- * Add the folder name into the
- * list in a sorted fashion.
- */
+** Do the read only folders
+*/
static void
-addfold (char *fold)
+readonly_folders(void)
{
- register int i, j;
- register char *cp;
-
- /* if necessary, reallocate the space for folder names */
- if (foldp >= maxfolders) {
- maxfolders += NUMFOLDERS;
- folds = mh_xrealloc (folds, maxfolders * sizeof(char *));
- }
-
- cp = getcpy (fold);
- for (i = start; i < foldp; i++)
- if (compare (cp, folds[i]) < 0) {
- for (j = foldp - 1; j >= i; j--)
- folds[j + 1] = folds[j];
- foldp++;
- folds[i] = cp;
- return;
- }
-
- folds[foldp++] = cp;
+ int atrlen;
+ char atrcur[BUFSIZ];
+ struct node *np;
+
+ snprintf(atrcur, sizeof(atrcur), "atr-%s-", seq_cur);
+ atrlen = strlen(atrcur);
+
+ for (np = m_defs; np; np = np->n_next)
+ if (strncmp(np->n_name, atrcur, atrlen)==0 &&
+ strncmp(np->n_name+atrlen, nmhdir, strlen(nmhdir))!=0)
+ /* Why do we exclude absolute path names? --meillo */
+ get_folder_info(np->n_name + atrlen, NULL);
}
+/*
+** pack (renumber) the messages in a folder
+** into a contiguous range from 1 to n.
+** Return -1 if error, else return 0.
+*/
static int
-compare (char *s1, char *s2)
+folder_pack(struct msgs **mpp, int verbose)
{
- register int i;
+ int hole, msgnum, newcurrent = 0;
+ char newmsg[BUFSIZ], oldmsg[BUFSIZ];
+ struct msgs *mp;
- while (*s1 || *s2)
- if ((i = *s1++ - *s2++))
- return i;
+ mp = *mpp;
- return 0;
-}
+ /*
+ ** Just return if folder is empty.
+ */
+ if (mp->nummsg == 0)
+ return 0;
-/*
- * Do the read only folders
- */
+ /*
+ ** Make sure we have message status space allocated
+ ** for all numbers from 1 to current high message.
+ */
+ if (mp->lowoff > 1) {
+ if ((mp = folder_realloc(mp, 1, mp->hghmsg)))
+ *mpp = mp;
+ else {
+ advise(NULL, "unable to allocate folder storage");
+ return -1;
+ }
+ }
-static void
-readonly_folders (void)
-{
- int atrlen;
- char atrcur[BUFSIZ];
- register struct node *np;
+ for (msgnum = mp->lowmsg, hole = 1; msgnum <= mp->hghmsg; msgnum++) {
+ if (does_exist(mp, msgnum)) {
+ if (msgnum != hole) {
+ strncpy(newmsg, m_name(hole), sizeof(newmsg));
+ strncpy(oldmsg, m_name(msgnum), sizeof(oldmsg));
+ if (verbose)
+ printf("message %s becomes %s\n", oldmsg, newmsg);
+
+ /*
+ ** Invoke the external refile hook for each
+ ** message being renamed. This is done
+ ** before the file is renamed so that the
+ ** old message file is around for the hook.
+ */
+
+ snprintf(oldmsg, sizeof (oldmsg), "%s/%d",
+ mp->foldpath, msgnum);
+ snprintf(newmsg, sizeof (newmsg), "%s/%d",
+ mp->foldpath, hole);
+ ext_hook("ref-hook", oldmsg, newmsg);
+
+ /* move the message file */
+ if (rename(oldmsg, newmsg) == -1) {
+ advise(newmsg, "unable to rename %s to", oldmsg);
+ return -1;
+ }
+
+ /* check if this is the current message */
+ if (msgnum == mp->curmsg)
+ newcurrent = hole;
+
+ /* copy the attribute flags for this message */
+ copy_msg_flags(mp, hole, msgnum);
+
+ if (msgnum == mp->lowsel)
+ mp->lowsel = hole;
+ if (msgnum == mp->hghsel)
+ mp->hghsel = hole;
+
+ /*
+ ** mark that sequence information has
+ ** been modified
+ */
+ mp->msgflags |= SEQMOD;
+ }
+ hole++;
+ }
+ }
- snprintf (atrcur, sizeof(atrcur), "atr-%s-", current);
- atrlen = strlen (atrcur);
+ /* record the new number for the high/low message */
+ mp->lowmsg = 1;
+ mp->hghmsg = hole - 1;
- for (np = m_defs; np; np = np->n_next)
- if (ssequal (atrcur, np->n_name)
- && !ssequal (nmhdir, np->n_name + atrlen))
- get_folder_info (np->n_name + atrlen, NULL);
+ if (newcurrent)
+ seq_setcur(mp, newcurrent);
+
+ return 0;
}