X-Git-Url: https://diplodocus.org/git/nmh/blobdiff_plain/f7c1a8a53c452b75aa84ff4bf9de7f47af7b881c..248c3a452003bc95088d9a1c4dec988696be2d7d:/uip/folder.c?ds=sidebyside diff --git a/uip/folder.c b/uip/folder.c index d4d98686..8ab6528b 100644 --- a/uip/folder.c +++ b/uip/folder.c @@ -1,99 +1,90 @@ - -/* - * folder(s).c -- set/list the current message and/or folder +/* folder.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 + * 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 -#include -#include - -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 } -}; - -static int fshort = 0; /* output only folder names */ +#include "h/mh.h" +#include "sbr/getarguments.h" +#include "sbr/concat.h" +#include "sbr/seq_setprev.h" +#include "sbr/seq_setcur.h" +#include "sbr/seq_save.h" +#include "sbr/smatch.h" +#include "sbr/ssequal.h" +#include "sbr/getcpy.h" +#include "sbr/m_convert.h" +#include "sbr/getfolder.h" +#include "sbr/folder_read.h" +#include "sbr/folder_pack.h" +#include "sbr/folder_free.h" +#include "sbr/context_save.h" +#include "sbr/context_replace.h" +#include "sbr/context_del.h" +#include "sbr/context_find.h" +#include "sbr/brkstring.h" +#include "sbr/ambigsw.h" +#include "sbr/path.h" +#include "sbr/print_version.h" +#include "sbr/print_help.h" +#include "sbr/error.h" +#include "sbr/crawl_folders.h" +#include "h/done.h" +#include "h/utils.h" +#include "sbr/m_maildir.h" + +#define FOLDER_SWITCHES \ + X("all", 0, ALLSW) \ + X("noall", 0, NALLSW) \ + X("create", 0, CREATSW) \ + X("nocreate", 0, NCREATSW) \ + X("fast", 0, FASTSW) \ + X("nofast", 0, NFASTSW) \ + X("header", 0, HDRSW) \ + X("noheader", 0, NHDRSW) \ + X("pack", 0, PACKSW) \ + X("nopack", 0, NPACKSW) \ + X("verbose", 0, VERBSW) \ + X("noverbose", 0, NVERBSW) \ + X("recurse", 0, RECURSW) \ + X("norecurse", 0, NRECRSW) \ + X("total", 0, TOTALSW) \ + X("nototal", 0, NTOTLSW) \ + X("list", 0, LISTSW) \ + X("nolist", 0, NLISTSW) \ + X("print", 0, PRNTSW) \ + X("noprint", 0, NPRNTSW) \ + X("push", 0, PUSHSW) \ + X("pop", 0, POPSW) \ + X("version", 0, VERSIONSW) \ + X("help", 0, HELPSW) \ + +#define X(sw, minchars, id) id, +DEFINE_SWITCH_ENUM(FOLDER); +#undef X + +#define X(sw, minchars, id) { sw, minchars, id }, +DEFINE_SWITCH_ARRAY(FOLDER, switches); +#undef X + +static bool fshort; /* 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 bool fpack; /* are we packing the folder? */ +static bool fverb; /* print actions taken while packing folder */ static int fheader = 0; /* should we output a header? */ -static int frecurse = 0; /* recurse through subfolders */ +static bool frecurse; /* recurse through subfolders */ static int ftotal = 0; /* should we output the totals? */ -static int all = 0; /* should we output all folders */ +static bool all; /* should we output all folders */ static int total_folders = 0; /* total number of folders */ -static int start = 0; -static int foldp = 0; - 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. @@ -118,38 +109,41 @@ static int maxFolderInfo; /* * static prototypes */ -static void dodir (char *); 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 addir (char *); -static void addfold (char *); -static int compare (char *, char *); static void readonly_folders (void); +/* + * Function for printing error message if folder does not exist with + * -nocreate. + */ +static void +nonexistent_folder (int status) +{ + NMH_UNUSED (status); + die("folder %s does not exist", folder); +} + int main (int argc, char **argv) { - int printsw = 0, listsw = 0; - int pushsw = 0, popsw = 0; + int printsw = -1; + bool listsw = false; + bool pushsw = false; + bool popsw = false; char *cp, *dp, *msg = NULL, *argfolder = NULL; char **ap, **argp, buf[BUFSIZ], **arguments; -#ifdef LOCALE - setlocale(LC_ALL, ""); -#endif - invo_name = r1bindex (argv[0], '/'); - - /* read user profile/context */ - context_read(); + if (nmh_init(argv[0], true, true)) { return 1; } /* * If program was invoked with name ending * in `s', then add switch `-all'. */ - if (argv[0][strlen (argv[0]) - 1] == 's') - all = 1; + all = has_suffix_c(argv[0], 's'); arguments = getarguments (invo_name, argc, argv, 1); argp = arguments; @@ -161,23 +155,23 @@ main (int argc, char **argv) ambigsw (cp, switches); done (1); case UNKWNSW: - adios (NULL, "-%s unknown", cp); + die("-%s unknown", cp); case HELPSW: snprintf (buf, sizeof(buf), "%s [+folder] [msg] [switches]", invo_name); print_help (buf, switches, 1); - done (1); + done (0); case VERSIONSW: print_version(invo_name); - done (1); + done (0); case ALLSW: - all = 1; + all = true; continue; case NALLSW: - all = 0; + all = false; continue; case CREATSW: @@ -188,10 +182,10 @@ main (int argc, char **argv) continue; case FASTSW: - fshort++; + fshort = true; continue; case NFASTSW: - fshort = 0; + fshort = false; continue; case HDRSW: @@ -202,24 +196,24 @@ main (int argc, char **argv) continue; case PACKSW: - fpack++; + fpack = true; continue; case NPACKSW: - fpack = 0; + fpack = false; continue; case VERBSW: - fverb++; + fverb = true; continue; case NVERBSW: - fverb = 0; + fverb = false; continue; case RECURSW: - frecurse++; + frecurse = true; continue; case NRECRSW: - frecurse = 0; + frecurse = false; continue; case TOTALSW: @@ -237,34 +231,32 @@ main (int argc, char **argv) continue; case LISTSW: - listsw = 1; + listsw = true; continue; case NLISTSW: - listsw = 0; + listsw = false; continue; case PUSHSW: - pushsw = 1; - listsw = 1; - popsw = 0; + pushsw = true; + listsw = true; + popsw = false; continue; case POPSW: - popsw = 1; - listsw = 1; - pushsw = 0; + popsw = true; + listsw = true; + pushsw = false; continue; } } if (*cp == '+' || *cp == '@') { if (argfolder) - adios (NULL, "only one folder at a time!"); - else - argfolder = pluspath (cp); + die("only one folder at a time!"); + argfolder = pluspath (cp); } else { if (msg) - adios (NULL, "only one (current) message at a time!"); - else - msg = cp; + die("only one (current) message at a time!"); + msg = cp; } } @@ -273,11 +265,13 @@ main (int argc, char **argv) nmhdir = concat (m_maildir (""), "/", NULL); /* - * If we aren't working with the folder stack - * (-push, -pop, -list) then the default is to print. + * If not directed via -print/-noprint, we print folder summary + * info unless if we're working with the folder stack (i.e., + * -push, -pop, or -list). */ - if (pushsw == 0 && popsw == 0 && listsw == 0) - printsw++; + if (printsw == -1) { + printsw = !(pushsw || popsw || listsw); + } /* Pushing a folder onto the folder stack */ if (pushsw) { @@ -285,13 +279,13 @@ main (int argc, char **argv) /* 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); + dp = mh_xstrdup(cp); ap = brkstring (dp, " ", "\n"); argfolder = getcpy(*ap++); } else { - adios (NULL, "no other folder"); + die("no other folder"); } - for (cp = getcpy (getfolder (1)); *ap; ap++) + for (cp = mh_xstrdup(getfolder(1)); *ap; ap++) cp = add (*ap, add (" ", cp)); free (dp); context_replace (stack, cp); /* update folder stack */ @@ -300,20 +294,20 @@ main (int argc, char **argv) context_replace (stack, (cp = context_find (stack)) ? concat (getfolder (1), " ", cp, NULL) - : getcpy (getfolder (1))); + : mh_xstrdup(getfolder(1))); } } /* Popping a folder off of the folder stack */ if (popsw) { if (argfolder) - adios (NULL, "sorry, no folders allowed with -pop"); + die("sorry, no folders allowed with -pop"); if ((cp = context_find (stack))) { - dp = getcpy (cp); + dp = mh_xstrdup(cp); ap = brkstring (dp, " ", "\n"); argfolder = getcpy(*ap++); } else { - adios (NULL, "folder stack empty"); + die("folder stack empty"); } if (*ap) { /* if there's anything left in the stack */ @@ -337,40 +331,40 @@ main (int argc, char **argv) /* Listing the folder stack */ if (listsw) { - printf ("%s", argfolder ? argfolder : getfolder (1)); + fputs(argfolder ? argfolder : getfolder (1), stdout); if ((cp = context_find (stack))) { - dp = getcpy (cp); + dp = mh_xstrdup(cp); for (ap = brkstring (dp, " ", "\n"); *ap; ap++) printf (" %s", *ap); free (dp); } - printf ("\n"); + putchar('\n'); if (!printsw) done (0); } - /* Allocate initial space to record folder names */ - maxfolders = NUMFOLDERS; - folds = mh_xmalloc (maxfolders * sizeof(char *)); - /* Allocate initial space to record folder information */ - maxFolderInfo = NUMFOLDERS; + maxFolderInfo = CRAWL_NUMFOLDERS; fi = mh_xmalloc (maxFolderInfo * sizeof(*fi)); /* * Scan the folders */ + /* change directory to base of nmh directory for crawl_folders */ + if (chdir (nmhdir) == NOTOK) + adios (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); + inform("no folder given for message %s, continuing...", msg); readonly_folders (); /* do any readonly folders */ - strncpy (folder, (cp = context_find (pfolder)) ? cp : "", sizeof(folder)); - dodir ("."); + cp = context_find(pfolder); + strncpy (folder, FENDNULL(cp), sizeof(folder)); + crawl_folders (".", get_folder_info_callback, NULL); } else { strncpy (folder, argfolder, sizeof(folder)); if (get_folder_info (argfolder, msg)) { @@ -382,7 +376,7 @@ main (int argc, char **argv) * we still need to list all level-1 sub-folders. */ if (!frecurse) - dodir (folder); + crawl_folders (folder, get_folder_info_callback, NULL); } } else { strncpy (folder, argfolder ? argfolder : getfolder (1), sizeof(folder)); @@ -391,7 +385,7 @@ main (int argc, char **argv) * Check if folder exists. If not, then see if * we should create it, or just exit. */ - create_folder (m_maildir (folder), fcreat, done); + create_folder (m_maildir (folder), fcreat, nonexistent_folder); if (get_folder_info (folder, msg) && argfolder) { /* update current folder */ @@ -402,46 +396,18 @@ main (int argc, char **argv) /* * Print out folder information */ - print_folders(); + if (printsw) + print_folders(); context_save (); /* save the context file */ done (0); return 1; } -/* - * Base routine for scanning a folder - */ - -static void -dodir (char *dir) -{ - int i; - int os = start; - int of = foldp; - - start = foldp; - - /* change directory to base of nmh directory */ - if (chdir (nmhdir) == NOTOK) - adios (nmhdir, "unable to change directory to"); - - addir (dir); - - for (i = start; i < foldp; i++) { - get_folder_info (folds[i], NULL); - fflush (stdout); - } - - start = os; - foldp = of; -} - static int -get_folder_info (char *fold, char *msg) +get_folder_info_body (char *fold, char *msg, bool *crawl_children) { int i, retval = 1; - char *mailfile; struct msgs *mp = NULL; i = total_folders++; @@ -451,7 +417,7 @@ get_folder_info (char *fold, char *msg) * for folder information */ if (total_folders >= maxFolderInfo) { - maxFolderInfo += NUMFOLDERS; + maxFolderInfo += CRAWL_NUMFOLDERS; fi = mh_xrealloc (fi, maxFolderInfo * sizeof(*fi)); } @@ -463,46 +429,69 @@ get_folder_info (char *fold, char *msg) fi[i].others = 0; fi[i].error = 0; - mailfile = m_maildir (fold); + if ((ftotal > 0) || !fshort || msg || fpack) { + /* + * create message structure and get folder info + */ + if (!(mp = folder_read (fold, fpack))) { + inform("unable to read folder %s, continuing...", fold); + *crawl_children = false; + return 0; + } - 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) { + *crawl_children = false; /* to please clang static analyzer */ + done (1); } + seq_save (mp); /* synchronize the sequences */ + context_save (); /* save the context file */ + } - /* set the current message */ - if (msg && !sfold (mp, msg)) - retval = 0; + /* 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); + } - if (fpack) { - if (folder_pack (&mp, fverb) == -1) - done (1); - seq_save (mp); /* synchronize the sequences */ - context_save (); /* save the context file */ - } + folder_free (mp); /* free folder/message structure */ + } - /* 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); - } + *crawl_children = (frecurse && (fshort || fi[i].others) + && (fi[i].error == 0)); + return retval; +} - folder_free (mp); /* free folder/message structure */ - } - } else { - fi[i].error = 1; +static bool +get_folder_info_callback (char *fold, void *baton) +{ + bool crawl_children; + NMH_UNUSED (baton); + + get_folder_info_body (fold, NULL, &crawl_children); + fflush (stdout); + return crawl_children; +} + +static int +get_folder_info (char *fold, char *msg) +{ + bool crawl_children; + int retval; + + retval = get_folder_info_body (fold, msg, &crawl_children); + + if (crawl_children) { + crawl_folders (fold, get_folder_info_callback, NULL); } - if (frecurse && (fshort || fi[i].others) && (fi[i].error == 0)) - dodir (fold); return retval; } @@ -513,7 +502,9 @@ get_folder_info (char *fold, char *msg) static void print_folders (void) { - int i, len, hasempty = 0, curprinted; + int i, len; + bool hasempty = false; + bool curprinted; int maxlen = 0, maxnummsg = 0, maxlowmsg = 0; int maxhghmsg = 0, maxcurmsg = 0, total_msgs = 0; int nummsgdigits, lowmsgdigits; @@ -557,7 +548,7 @@ print_folders (void) /* check for empty folders */ if (fi[i].nummsg == 0) - hasempty = 1; + hasempty = true; } nummsgdigits = num_digits (maxnummsg); lowmsgdigits = num_digits (maxlowmsg); @@ -584,7 +575,7 @@ print_folders (void) if (all || fshort || ftotal < 1) { for (i = 0; i < total_folders; i++) { if (fshort) { - printf ("%s\n", fi[i].name); + puts(fi[i].name); continue; } @@ -601,26 +592,26 @@ print_folders (void) printf ("%-*s ", maxlen+1, tmpname); - curprinted = 0; /* remember if we print cur */ + curprinted = false; /* 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)", + printf ("has %*d message%1s (%*d-%*d)", nummsgdigits, fi[i].nummsg, - (fi[i].nummsg == 1) ? " " : "s", + PLURALS(fi[i].nummsg), lowmsgdigits, fi[i].lowmsg, hghmsgdigits, fi[i].hghmsg); if (fi[i].curmsg >= fi[i].lowmsg && fi[i].curmsg <= fi[i].hghmsg) { - curprinted = 1; + curprinted = true; printf ("; cur=%*d", curmsgdigits, fi[i].curmsg); } } if (fi[i].others) printf (";%*s (others)", curprinted ? 0 : curmsgdigits + 6, ""); - printf (".\n"); + puts("."); } } @@ -629,17 +620,17 @@ print_folders (void) */ 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" : ""); + putchar('\n'); + printf ("TOTAL = %d message%s in %d folder%s.\n", + total_msgs, PLURALS(total_msgs), + total_folders, PLURALS(total_folders)); } fflush (stdout); } /* - * Set the current message and sychronize sequences + * Set the current message and synchronize sequences */ static int @@ -650,7 +641,7 @@ sfold (struct msgs *mp, char *msg) return 0; if (mp->numsel > 1) { - admonish (NULL, "only one message at a time!"); + inform("only one message at a time!, continuing..."); return 0; } seq_setprev (mp); /* set the previous-sequence */ @@ -662,83 +653,6 @@ sfold (struct msgs *mp, char *msg) } -static void -addir (char *name) -{ - char *prefix, *child; - struct stat st; - struct dirent *dp; - DIR * dd; - - if (!(dd = opendir (name))) { - admonish (name, "unable to read directory "); - return; - } - - if (strcmp (name, ".") == 0) { - prefix = getcpy (""); - } else { - prefix = concat (name, "/", (void *)NULL); - } - - while ((dp = readdir (dd))) { - if (!strcmp (dp->d_name, ".") || !strcmp (dp->d_name, "..")) { - continue; - } - child = concat (prefix, dp->d_name, (void *)NULL); - if (stat (child, &st) != -1 && S_ISDIR(st.st_mode)) { - /* addfold saves child in the list, don't free it */ - addfold (child); - } else { - free (child); - } - } - - closedir (dd); - free(prefix); -} - -/* - * Add the folder name into the - * list in a sorted fashion. - */ - -static void -addfold (char *fold) -{ - register int i, j; - - /* if necessary, reallocate the space for folder names */ - if (foldp >= maxfolders) { - maxfolders += NUMFOLDERS; - folds = mh_xrealloc (folds, maxfolders * sizeof(char *)); - } - - for (i = start; i < foldp; i++) - if (compare (fold, folds[i]) < 0) { - for (j = foldp - 1; j >= i; j--) - folds[j + 1] = folds[j]; - foldp++; - folds[i] = fold; - return; - } - - folds[foldp++] = fold; -} - - -static int -compare (char *s1, char *s2) -{ - register int i; - - while (*s1 || *s2) - if ((i = *s1++ - *s2++)) - return i; - - return 0; -} - /* * Do the read only folders */ @@ -748,7 +662,7 @@ readonly_folders (void) { int atrlen; char atrcur[BUFSIZ]; - register struct node *np; + struct node *np; snprintf (atrcur, sizeof(atrcur), "atr-%s-", current); atrlen = strlen (atrcur);