home *** CD-ROM | disk | FTP | other *** search
/ Source Code 1992 March / Source_Code_CD-ROM_Walnut_Creek_March_1992.iso / usenet / altsrcs / 1 / 1723 < prev    next >
Text File  |  1990-12-28  |  21KB  |  803 lines

  1. Newsgroups: alt.sources
  2. From: ctl@OCF.Berkeley.EDU (Case Larsen)
  3. Subject: [comp.mail.mh] Re: XMH cache
  4. Message-ID: <1990Aug27.172616.19016@math.lsa.umich.edu>
  5. Date: Mon, 27 Aug 90 17:26:16 GMT
  6.  
  7. Archive-name: ctl-mh-cache-patch/27-Aug-90
  8. Original-posting-by: ctl@OCF.Berkeley.EDU (Case Larsen)
  9. Original-subject: Re: XMH cache
  10. Reposted-by: emv@math.lsa.umich.edu (Edward Vielmetti)
  11.  
  12. [Reposted from comp.mail.mh.
  13. Comments on this service to emv@math.lsa.umich.edu (Edward Vielmetti).]
  14.  
  15. In article <9008230524.AA07100@PROMETHEUS.MIT.EDU> Raeburn@MIT.EDU (Ken Raeburn) writes:
  16.  
  17.    Does anyone have patches (hacks, suggestions) that would allow
  18.    for maintenance of such a cache?  Does anyone else think it
  19.    would be a good idea for an addition to MH proper, as an extra
  20.    option (preferably runtime-selectable, I'd say)?
  21.  
  22. I've made a few hacks to MH 6.7 to allow caching of both the output
  23. of scan, and the initial directory scan of the folder which gathers
  24. various statistics like highest message, lowest message, deleted
  25. messages, etc.  The caching code uses ndbm to 1) speed access to any
  26. given scan output of a particular message, and 2) make insertions and
  27. deletions of new messages easy.
  28.  
  29. The only affected commands are 'folders', 'rmm', and 'scan'.  The only
  30. command with a runtime selectable option is 'scan'.  Use 'scan -fast'
  31. to cache the output and make use of cached output.  Caching on the
  32. other two commands is automatic, and doesn't consume very much disk
  33. space (a few Kbytes).  The limit of the scan line length is currently
  34. 80 characters.  The limit can be changed, but the longer your scan
  35. line length is, the more space the cache file takes.  For emacs users,
  36. if you use 'mh-e', you will want to change the 'scan' command to 
  37. 'scan -fast' in mh-e.el. 
  38.  
  39. Here is an example of the speedup you can expect.  This was on a
  40. folder of about 1000 messages.
  41. + /*
  42. +  * The 'fast' option uses ndbm to store the output of scan.  Speedup is
  43. +  * typically around 10 to 20 times on large folders.  As you see, the
  44. +  * first time takes a while to build the cache.  The subsequent times are
  45. +  * much quicker.
  46. +  *
  47. +  * dingo uip [887] time xscan -fast > & /dev/null
  48. +  * 18.380u 15.060s 1:02.58 53.4% 0+26k 1408+316io 1413pf+0w
  49. +  * dingo uip [888] time xscan -fast > & /dev/null
  50. +  * 1.120u 1.420s 0:03.58 70.9% 0+22k 53+0io 63pf+0w
  51. +  */
  52.  
  53. --
  54. Case Larsen
  55. ctl@OCF.Berkeley.EDU
  56. Open Computing Facility
  57.  
  58.  
  59. -------------cut here-------cut here-------cut here--------------------
  60. diff -cr mh-6.7/sbr/m_gmsg.c mh-6.7.new/sbr/m_gmsg.c
  61. *** mh-6.7/sbr/m_gmsg.c    Thu Apr 12 13:29:01 1990
  62. --- mh-6.7.new/sbr/m_gmsg.c    Tue Jul 31 10:28:01 1990
  63. ***************
  64. *** 3,11 ****
  65.   #include "../h/mh.h"
  66.   #include "../h/local.h"
  67.   #include <stdio.h>
  68.   
  69.   #define    NINFO    (MAXFOLDER / 5)    /* PLEASE be non-trivial... */
  70.   struct info {
  71.       int     msgno;
  72.       short   stats;
  73. --- 3,13 ----
  74.   #include "../h/mh.h"
  75.   #include "../h/local.h"
  76.   #include <stdio.h>
  77. + #include <fcntl.h>
  78.   
  79.   #define    NINFO    (MAXFOLDER / 5)    /* PLEASE be non-trivial... */
  80. + #define GMSG_CACHE ".m_gmsgcache"
  81.   struct info {
  82.       int     msgno;
  83.       short   stats;
  84. ***************
  85. *** 43,49 ****
  86. --- 45,67 ----
  87.       register    DIR * dd;
  88.   #endif SYS5DIR
  89.       struct stat st;
  90. +     int cache;
  91.   
  92. +     if ((cache = open(GMSG_CACHE,O_RDONLY)) >= 0) {
  93. +     int len;
  94. +     read(cache,&len,sizeof(len));
  95. +     mp = (struct msgs  *) malloc (len);
  96. +     if (mp == NULL)
  97. +       adios (NULLCP, "unable to allocate folder storage");
  98. +     read(cache,mp,len);
  99. +     mp->foldpath = name;
  100. +     m_getatr (mp);
  101. +     close(cache);
  102. +     return mp;
  103. +     }
  104. +     
  105. +     /* else do scan and save */
  106.       if ((dd = opendir (name = m_mailpath (name))) == NULL) {
  107.       free (name);
  108.       return NULL;
  109. ***************
  110. *** 191,196 ****
  111. --- 209,223 ----
  112.   #endif    MTR
  113.       for (tail = head; tail < rover; tail++)
  114.       mp -> msgstats[tail -> msgno] = tail -> stats;
  115. +     if ((cache = open(GMSG_CACHE,O_RDWR | O_CREAT, 0600)) >= 0) {
  116. +     int len;
  117. +     len = MSIZE(mp,mp->lowoff,mp->hghoff);
  118. +     write(cache,&len,sizeof(len));
  119. +     write(cache,mp,len);
  120. +     close(cache);
  121. +     }
  122.       m_getatr (mp);
  123.   
  124.       return mp;
  125. diff -cr mh-6.7/sbr/m_sync.c mh-6.7.new/sbr/m_sync.c
  126. *** mh-6.7/sbr/m_sync.c    Thu Apr 12 13:29:03 1990
  127. --- mh-6.7.new/sbr/m_sync.c    Tue Jul 31 13:02:44 1990
  128. ***************
  129. *** 1,4 ****
  130. --- 1,5 ----
  131.   /* m_sync.c - synchronize message sequences */
  132. + static char *RCSid="$Id: m_sync.c,v 1.2 90/07/31 10:27:25 case Exp Locker: case $";
  133.   
  134.   #include "../h/mh.h"
  135.   #include <stdio.h>
  136. ***************
  137. *** 7,13 ****
  138. --- 8,17 ----
  139.   #define    sigmask(s)    (1 << ((s) - 1))
  140.   #endif    not sigmask
  141.   
  142. + #include <fcntl.h>
  143.   
  144. + #define GMSG_CACHE ".m_gmsgcache"
  145.   /* decision logic
  146.       1.  public and folder readonly: make it private
  147.       2a. public: add it to the sequences file
  148. ***************
  149. *** 14,19 ****
  150. --- 18,31 ----
  151.       2b. private: add it to the profile
  152.    */
  153.   
  154. + /*
  155. +  *$Log:    m_sync.c,v $
  156. +  * Revision 1.2  90/07/31  10:27:25  case
  157. +  * Save incremental changes to msgs structure to GMSG_CACHE.
  158. +  * 
  159. +  * ctl:  Added logic for caching of message stats to speedup m_gmsg().
  160. +  */
  161. + void m_sync_cache();
  162.   
  163.   void m_sync (mp)
  164.   register struct msgs *mp;
  165. ***************
  166. *** 32,39 ****
  167.   #endif    BSD42
  168.   
  169.       if (!(mp -> msgflags & SEQMOD))
  170. !     return;
  171.       mp -> msgflags &= ~SEQMOD;
  172.   
  173.       m_getdefs ();
  174.       (void) sprintf (seq, "%s/%s", mp -> foldpath, mh_seq);
  175. --- 44,52 ----
  176.   #endif    BSD42
  177.   
  178.       if (!(mp -> msgflags & SEQMOD))
  179. !       return;
  180.       mp -> msgflags &= ~SEQMOD;
  181. +     m_sync_cache(mp);
  182.   
  183.       m_getdefs ();
  184.       (void) sprintf (seq, "%s/%s", mp -> foldpath, mh_seq);
  185. ***************
  186. *** 59,69 ****
  187.           if ((cp = m_seq (mp, mp -> msgattrs[i])) == NULL)
  188.           continue;
  189.           if (fp == NULL) {
  190. !         if ((fp = fopen (seq, "w")) == NULL
  191. !             && unlink (seq) != NOTOK 
  192. !             && (fp = fopen (seq, "w")) == NULL) {
  193. !             admonish (attr, "unable to write");
  194. !             goto priv;
  195.           }
  196.   #ifndef    BSD42
  197.           hstat = signal (SIGHUP, SIG_IGN);
  198. --- 72,88 ----
  199.           if ((cp = m_seq (mp, mp -> msgattrs[i])) == NULL)
  200.           continue;
  201.           if (fp == NULL) {
  202. !         fp = fopen (seq, "w");
  203. !         if (fp == NULL) {
  204. !             if (unlink (seq) != NOTOK ) {
  205. !             fp = fopen (seq, "w");
  206. !             } else {
  207. !             fp  = fopen(mh_seq,"w");
  208. !             }
  209. !             if (fp == NULL) {
  210. !             admonish (attr, "unable to write");
  211. !             goto priv;
  212. !             }
  213.           }
  214.   #ifndef    BSD42
  215.           hstat = signal (SIGHUP, SIG_IGN);
  216. ***************
  217. *** 95,98 ****
  218. --- 114,131 ----
  219.           (void) unlink (seq);
  220.   
  221.       mp -> msgflags = flags;
  222. + }
  223. + void m_sync_cache(mp)
  224. +      register struct msgs* mp;
  225. + {
  226. +     int cache;
  227. +     if ((cache = open(GMSG_CACHE,O_RDWR)) >= 0) {
  228. +     int len;
  229. +     len = MSIZE(mp,mp->lowoff,mp->hghoff);
  230. +     write(cache,&len,sizeof(len));
  231. +     write(cache,mp,len);
  232. +     close(cache);
  233. +     }
  234.   }
  235. diff -cr mh-6.7/uip/annosbr.c mh-6.7.new/uip/annosbr.c
  236. *** mh-6.7/uip/annosbr.c    Thu Apr 12 13:29:25 1990
  237. --- mh-6.7.new/uip/annosbr.c    Tue Jul 31 13:38:13 1990
  238. ***************
  239. *** 1,6 ****
  240.   /* annosbr.c - prepend annotation to messages */
  241.   #ifndef    lint
  242. ! static char ident[] = "@(#)$Id: annosbr.c,v 2.4 90/04/05 15:35:09 sources Exp $";
  243.   #endif    lint
  244.   
  245.   #include "../h/mh.h"
  246. --- 1,6 ----
  247.   /* annosbr.c - prepend annotation to messages */
  248.   #ifndef    lint
  249. ! static char ident[] = "@(#)$Id: annosbr.c,v 1.1 90/07/31 13:29:50 case Exp Locker: case $";
  250.   #endif    lint
  251.   
  252.   #include "../h/mh.h"
  253. ***************
  254. *** 9,15 ****
  255. --- 9,18 ----
  256.   #include <stdio.h>
  257.   #include <sys/types.h>
  258.   #include <sys/stat.h>
  259. + #include <ndbm.h>
  260. + #include <fcntl.h>
  261.   
  262. + #define DBMDIR ".mhcache"
  263.   
  264.   extern int  errno;
  265.   long lseek ();
  266. ***************
  267. *** 121,126 ****
  268.           return 1;
  269.       }
  270.       }
  271.       return 0;
  272.   }
  273. --- 124,141 ----
  274.           return 1;
  275.       }
  276.       }
  277. !     {
  278. !     /* annotate could change fmtsbr()'s output */
  279. !     int msgnum = atoi(file);
  280. !     DBM *scache = dbm_open(DBMDIR,O_RDWR, 0600);
  281. !     datum key;
  282. !     printf ("file: %s",file);
  283. !     if (scache != NULL) {
  284. !         key.dptr = (char *) &msgnum;
  285. !         key.dsize = sizeof(msgnum);
  286. !         dbm_delete(scache,key);
  287. !         dbm_close(scache);
  288. !     }
  289. !     }
  290.       return 0;
  291.   }
  292. diff -cr mh-6.7/uip/folder.c mh-6.7.new/uip/folder.c
  293. *** mh-6.7/uip/folder.c    Thu Apr 12 13:29:27 1990
  294. --- mh-6.7.new/uip/folder.c    Tue Jul 31 10:25:42 1990
  295. ***************
  296. *** 1,6 ****
  297.   /* folder(s).c - report on folders */
  298.   #ifndef    lint
  299. ! static char ident[] = "@(#)$Id: folder.c,v 2.4 90/04/05 14:56:54 sources Exp $";
  300.   #endif    lint
  301.   
  302.   #include "../h/mh.h"
  303. --- 1,6 ----
  304.   /* folder(s).c - report on folders */
  305.   #ifndef    lint
  306. ! static char ident[] = "@(#)$Id: folder.c,v 1.1 90/07/30 16:53:36 case Exp $";
  307.   #endif    lint
  308.   
  309.   #include "../h/mh.h"
  310. diff -cr mh-6.7/uip/inc.c mh-6.7.new/uip/inc.c
  311. *** mh-6.7/uip/inc.c    Thu Apr 12 13:29:28 1990
  312. --- mh-6.7.new/uip/inc.c    Tue Jul 31 14:16:30 1990
  313. ***************
  314. *** 1,6 ****
  315.   /* inc.c - incorporate messages from a maildrop into a folder */
  316.   #ifndef    lint
  317. ! static char ident[] = "@(#)$Id: inc.c,v 1.4 90/04/05 14:57:51 sources Exp $";
  318.   #endif    lint
  319.   
  320.   #include "../h/mh.h"
  321. --- 1,6 ----
  322.   /* inc.c - incorporate messages from a maildrop into a folder */
  323.   #ifndef    lint
  324. ! static char ident[] = "@(#)$Id: inc.c,v 1.1 90/07/31 14:15:49 case Exp Locker: case $";
  325.   #endif    lint
  326.   
  327.   #include "../h/mh.h"
  328. ***************
  329. *** 625,630 ****
  330. --- 625,631 ----
  331.               (void) fflush (stdout);
  332.   
  333.           msgnum++, mp -> hghmsg++;
  334. +         mp->nummsg++;
  335.           mp -> msgstats[msgnum] = EXISTS;
  336.   #ifdef    TMA
  337.           if (i == SCNENC) {
  338. diff -cr mh-6.7/uip/rmm.c mh-6.7.new/uip/rmm.c
  339. *** mh-6.7/uip/rmm.c    Thu Apr 12 13:29:37 1990
  340. --- mh-6.7.new/uip/rmm.c    Mon Jul 30 16:54:30 1990
  341. ***************
  342. *** 2,7 ****
  343. --- 2,9 ----
  344.   
  345.   #include "../h/mh.h"
  346.   #include <stdio.h>
  347. + #include <ndbm.h>
  348. + #include <fcntl.h>
  349.   
  350.   /*   */
  351.   
  352. ***************
  353. *** 11,16 ****
  354. --- 13,19 ----
  355.   
  356.       NULL, NULL
  357.   };
  358. + #define DBMDIR ".mhcache"
  359.   
  360.   /*   */
  361.   
  362. ***************
  363. *** 34,40 ****
  364.              *arguments[MAXARGS],
  365.              *msgs[MAXARGS];
  366.       struct msgs *mp;
  367.       invo_name = r1bindex (argv[0], '/');
  368.       if ((cp = m_find (invo_name)) != NULL) {
  369.       ap = brkstring (cp = getcpy (cp), " ", "\n");
  370. --- 37,44 ----
  371.              *arguments[MAXARGS],
  372.              *msgs[MAXARGS];
  373.       struct msgs *mp;
  374. !     DBM  *scache;
  375. !     datum key;
  376.       invo_name = r1bindex (argv[0], '/');
  377.       if ((cp = m_find (invo_name)) != NULL) {
  378.       ap = brkstring (cp = getcpy (cp), " ", "\n");
  379. ***************
  380. *** 124,129 ****
  381. --- 128,134 ----
  382.       execvp (rmmproc, vec);
  383.       adios (rmmproc, "unable to exec");
  384.       }
  385. +     scache = dbm_open(DBMDIR,O_RDWR, 0600);
  386.   
  387.       for (msgnum = mp -> lowsel; msgnum <= mp -> hghsel; msgnum++)
  388.       if (mp -> msgstats[msgnum] & SELECTED) {
  389. ***************
  390. *** 130,136 ****
  391.           (void) strcpy (buf, m_backup (dp = m_name (msgnum)));
  392.           if (rename (dp, buf) == NOTOK)
  393.           admonish (buf, "unable to rename %s to", dp);
  394.       }
  395.       done (0);
  396.   }
  397. --- 135,146 ----
  398.           (void) strcpy (buf, m_backup (dp = m_name (msgnum)));
  399.           if (rename (dp, buf) == NOTOK)
  400.           admonish (buf, "unable to rename %s to", dp);
  401. +         if (scache != NULL) {
  402. +         key.dptr = (char *)&msgnum;
  403. +         key.dsize = sizeof(msgnum);
  404. +         dbm_delete(scache,key);
  405. +         }
  406.       }
  407. !     if (scache != NULL) dbm_close(scache);
  408.       done (0);
  409.   }
  410. diff -cr mh-6.7/uip/scan.c mh-6.7.new/uip/scan.c
  411. *** mh-6.7/uip/scan.c    Thu Apr 12 13:29:37 1990
  412. --- mh-6.7.new/uip/scan.c    Wed Aug  8 11:06:10 1990
  413. ***************
  414. *** 1,6 ****
  415.   /* scan.c - display a one-line "scan" listing */
  416.   #ifndef    lint
  417. ! static char ident[] = "@(#)$Id: scan.c,v 1.8 90/04/05 14:59:58 sources Exp $";
  418.   #endif    lint
  419.   
  420.   #include "../h/mh.h"
  421. --- 1,6 ----
  422.   /* scan.c - display a one-line "scan" listing */
  423.   #ifndef    lint
  424. ! static char ident[] = "@(#)$Id: scan.c,v 1.3 90/07/31 10:24:27 case Exp Locker: case $";
  425.   #endif    lint
  426.   
  427.   #include "../h/mh.h"
  428. ***************
  429. *** 9,14 ****
  430. --- 9,16 ----
  431.   #include "../zotnet/tws.h"
  432.   #include <errno.h>
  433.   #include <stdio.h>
  434. + #include <ndbm.h>
  435. + #include <fcntl.h>
  436.   
  437.   /*   */
  438.   
  439. ***************
  440. *** 42,47 ****
  441. --- 44,62 ----
  442.   #define    HELPSW    10
  443.       "help", 4,
  444.   
  445. + #define FASTSW  11
  446. +     "fast", 4,
  447. + /*
  448. +  * The 'fast' option uses ndbm to store the output of scan.  Speedup is
  449. +  * typically around 10 to 20 times on large folders.  As you see, the
  450. +  * first time takes a while to build the cache.  The subsequent times are
  451. +  * much quicker.
  452. +  *
  453. +  * dingo uip [887] time xscan -fast > & /dev/null
  454. +  * 18.380u 15.060s 1:02.58 53.4% 0+26k 1408+316io 1413pf+0w
  455. +  * dingo uip [888] time xscan -fast > & /dev/null
  456. +  * 1.120u 1.420s 0:03.58 70.9% 0+22k 53+0io 63pf+0w
  457. +  */
  458.       NULL, NULL
  459.   };
  460.   
  461. ***************
  462. *** 52,58 ****
  463. --- 67,81 ----
  464.   extern struct msgs *fmt_current_folder;    
  465.   #endif
  466.   
  467. + typedef struct record {
  468. +     char scanout[80];
  469. + } Record;
  470. + #define SBUFSIZ 256
  471. + #define DBMDIR ".mhcache"
  472. + #define MAXPATHLEN 2048+1
  473.   
  474. + static struct format *fmt;
  475.   void    clear_screen ();
  476.   
  477.   /*   */
  478. ***************
  479. *** 68,73 ****
  480. --- 91,97 ----
  481.           revflag = 0,     /* used to be #ifdef BERK */
  482.           width = 0,
  483.               msgp = 0,
  484. +             fast = 0,
  485.           ontty,
  486.           state,
  487.               msgnum;
  488. ***************
  489. *** 86,92 ****
  490.              *msgs[MAXARGS];
  491.       struct msgs *mp;
  492.       FILE * in;
  493.       invo_name = r1bindex (argv[0], '/');
  494.       mts_init (invo_name);
  495.       if ((cp = m_find (invo_name)) != NULL) {
  496. --- 110,118 ----
  497.              *msgs[MAXARGS];
  498.       struct msgs *mp;
  499.       FILE * in;
  500. !     DBM  *scache;
  501. !     datum key, rec;
  502. !      
  503.       invo_name = r1bindex (argv[0], '/');
  504.       mts_init (invo_name);
  505.       if ((cp = m_find (invo_name)) != NULL) {
  506. ***************
  507. *** 150,155 ****
  508. --- 176,184 ----
  509.           case NREVSW:
  510.               revflag = 0;
  511.               continue;
  512. +         case FASTSW:
  513. +             fast = 1;
  514. +             continue;
  515.   
  516.           case FILESW:
  517.               if (!(cp = *argp++) || *cp == '-')
  518. ***************
  519. *** 217,256 ****
  520.   #endif
  521.   
  522.   /*   */
  523.       for (msgnum = revflag ? mp -> hghsel : mp -> lowsel;
  524.           (revflag ? msgnum >= mp -> lowsel : msgnum <= mp -> hghsel);
  525.           msgnum += revflag ? (-1) : 1)
  526. !     if (mp -> msgstats[msgnum] & SELECTED) {
  527. !         if ((in = fopen (cp = m_name (msgnum), "r")) == NULL) {
  528.   #ifdef    notdef
  529. !         if (errno != EACCES)
  530.   #endif
  531. !             admonish (cp, "unable to open message");
  532.   #ifdef    notdef
  533. !         else
  534. !             printf ("%*d  unreadable\n", DMAXFOLDER, msgnum);
  535.   #endif
  536. !         continue;
  537. !         }
  538.   
  539. !         if (hdrflag) {
  540. !         (void) time (&clock);
  541. !         printf ("Folder %-32s%s\n\n", folder,
  542. !             dasctime (dlocaltime (&clock), TW_NULL));
  543. !         }
  544. !         switch (state = scan (in, msgnum, 0, nfs, width,
  545. !             msgnum == mp -> curmsg,
  546. !             hdrflag, 0L, 1)) {
  547. !         case SCNMSG: 
  548. !         case SCNENC: 
  549. !         case SCNERR: 
  550.               break;
  551.   
  552. !         default: 
  553.               adios (NULLCP, "scan() botch (%d)", state);
  554.   
  555. !         case SCNEOF: 
  556.   #ifdef    notdef
  557.               printf ("%*d  empty\n", DMAXFOLDER, msgnum);
  558.   #else
  559. --- 246,350 ----
  560.   #endif
  561.   
  562.   /*   */
  563. !      if (fast) {
  564. !      scache = dbm_open(DBMDIR,O_RDWR | O_CREAT, 0600);
  565. !      if (scache == NULL) {
  566. !          perror("dbm");
  567. !          exit(1);
  568. !      }
  569. !      }
  570.       for (msgnum = revflag ? mp -> hghsel : mp -> lowsel;
  571.           (revflag ? msgnum >= mp -> lowsel : msgnum <= mp -> hghsel);
  572.           msgnum += revflag ? (-1) : 1)
  573. !     if ((mp -> msgstats[msgnum] & (SELECTED | EXISTS)) == (SELECTED | EXISTS)) {
  574. !         if (fast) {
  575. !         /* caching stuff here using (n)dbm 
  576. !            key on message number
  577. !            just keep a few of the fields around */
  578. !         key.dptr = (char *)&msgnum;
  579. !         key.dsize = sizeof(msgnum);
  580. !         rec = dbm_fetch(scache,key);
  581. !         if (hdrflag) {
  582. !             (void) time (&clock);
  583. !             printf ("Folder %-32s%s\n\n", folder,
  584. !                 dasctime (dlocaltime (&clock), TW_NULL));
  585. !         }
  586. !         if (rec.dptr == NULL) {
  587. !             int compnum;
  588. !             char    name[NAMESZ];
  589. !             char tmpbuf[NAMESZ];
  590. !             Record rectmp;
  591. !             char *scanout;
  592. !             rec.dptr = (char *)&rectmp;
  593. !             rec.dsize = sizeof(rectmp);
  594. !             rectmp.scanout[0] = '\0';
  595. !             if ((in = fopen (cp = m_name (msgnum), "r")) == NULL) {
  596. !             admonish (cp, "unable to open message");
  597. !             continue;
  598. !             }
  599. !             switch (state = scan (in, msgnum, 0, nfs, width,
  600. !                       msgnum == mp -> curmsg,
  601. !                       hdrflag, 0L, 0, 1, &scanout)) {
  602. !               case SCNMSG: 
  603. !               case SCNENC: 
  604. !               case SCNERR: 
  605. !             break;
  606. !             
  607. !             default: 
  608. !             adios (NULLCP, "scan() botch (%d)", state);
  609. !             
  610. !               case SCNEOF: 
  611.   #ifdef    notdef
  612. !             printf ("%*d  empty\n", DMAXFOLDER, msgnum);
  613. ! #else
  614. !             advise (NULLCP, "message %d: empty", msgnum);
  615.   #endif
  616. !             break;
  617. !             }
  618. !             hdrflag = 0;
  619. !             (void) fclose (in);
  620. !             strncpy(rectmp.scanout,scanout,sizeof(rectmp.scanout));
  621. !             if (strlen(scanout) >= sizeof(rectmp.scanout))
  622. !             rectmp.scanout[sizeof(rectmp.scanout)-1] = '\n';
  623. !             dbm_store(scache,key,rec,DBM_INSERT);
  624. !         }
  625. !         ((Record  *)rec.dptr)->scanout[4] =
  626. !           (mp->curmsg == msgnum) ? '+' : ' ';
  627. !         fputs(((Record *)rec.dptr)->scanout,stdout);
  628. !         if (ontty)
  629. !           (void) fflush (stdout);
  630. !         } else {
  631. !         if ((in = fopen (cp = m_name (msgnum), "r")) == NULL) {
  632.   #ifdef    notdef
  633. !             if (errno != EACCES)
  634.   #endif
  635. !               admonish (cp, "unable to open message");
  636. ! #ifdef    notdef
  637. !             else
  638. !               printf ("%*d  unreadable\n", DMAXFOLDER, msgnum);
  639. ! #endif
  640. !             continue;
  641. !         }
  642.   
  643. !         if (hdrflag) {
  644. !             (void) time (&clock);
  645. !             printf ("Folder %-32s%s\n\n", folder,
  646. !                 dasctime (dlocaltime (&clock), TW_NULL));
  647. !         }
  648. !         switch (state = scan (in, msgnum, 0, nfs, width,
  649. !                       msgnum == mp -> curmsg,
  650. !                       hdrflag, 0L, 1, 0, NULL)) {
  651. !           case SCNMSG: 
  652. !           case SCNENC: 
  653. !           case SCNERR: 
  654.               break;
  655.   
  656. !             default: 
  657.               adios (NULLCP, "scan() botch (%d)", state);
  658.   
  659. !           case SCNEOF: 
  660.   #ifdef    notdef
  661.               printf ("%*d  empty\n", DMAXFOLDER, msgnum);
  662.   #else
  663. ***************
  664. *** 257,268 ****
  665.               advise (NULLCP, "message %d: empty", msgnum);
  666.   #endif
  667.               break;
  668.           }
  669. -         hdrflag = 0;
  670. -         (void) fclose (in);
  671. -         if (ontty)
  672. -         (void) fflush (stdout);
  673.       }
  674.   #ifdef    VAN
  675.       m_sync (mp);    /* because formatsbr might have made changes */
  676.   #endif
  677. --- 351,365 ----
  678.               advise (NULLCP, "message %d: empty", msgnum);
  679.   #endif
  680.               break;
  681. +         }
  682. +         hdrflag = 0;
  683. +         (void) fclose (in);
  684. +         if (ontty)
  685. +           (void) fflush (stdout);
  686.           }
  687.       }
  688. +      if (fast && scache != NULL) dbm_close(scache);
  689.   #ifdef    VAN
  690.       m_sync (mp);    /* because formatsbr might have made changes */
  691.   #endif
  692. ***************
  693. *** 274,276 ****
  694. --- 371,375 ----
  695.   
  696.       done (0);
  697.   }
  698. diff -cr mh-6.7/uip/scansbr.c mh-6.7.new/uip/scansbr.c
  699. *** mh-6.7/uip/scansbr.c    Thu Apr 12 13:29:37 1990
  700. --- mh-6.7.new/uip/scansbr.c    Mon Jul 30 16:54:30 1990
  701. ***************
  702. *** 1,6 ****
  703.   /* scansbr.c - routines to help scan along... */
  704.   #ifndef    lint
  705. ! static char ident[] = "@(#)$Id: scansbr.c,v 1.5 90/04/05 14:57:59 sources Exp $";
  706.   #endif    lint
  707.   
  708.   #include "../h/mh.h"
  709. --- 1,6 ----
  710.   /* scansbr.c - routines to help scan along... */
  711.   #ifndef    lint
  712. ! static char ident[] = "@(#)$Id: scansbr.c,v 1.2 90/07/30 16:54:18 case Exp $";
  713.   #endif    lint
  714.   
  715.   #include "../h/mh.h"
  716. ***************
  717. *** 53,59 ****
  718.   
  719.   /* ARGSUSED */
  720.   
  721. ! int     scan (inb, innum, outnum, nfs, width, curflg, header, size, noisy)
  722.   char    *nfs;
  723.   int     innum,
  724.           outnum,
  725. --- 53,59 ----
  726.   
  727.   /* ARGSUSED */
  728.   
  729. ! int     scan (inb, innum, outnum, nfs, width, curflg, header, size, noisy,fast,scanout)
  730.   char    *nfs;
  731.   int     innum,
  732.           outnum,
  733. ***************
  734. *** 60,66 ****
  735.       width,
  736.           curflg,
  737.           header,
  738. !     noisy;
  739.   long    size;
  740.   register FILE   *inb;
  741.   {
  742. --- 60,68 ----
  743.       width,
  744.           curflg,
  745.           header,
  746. !     noisy,
  747. !         fast;
  748. ! char **scanout;
  749.   long    size;
  750.   register FILE   *inb;
  751.   {
  752. ***************
  753. *** 292,297 ****
  754. --- 294,301 ----
  755.       }
  756.       if (noisy)
  757.       (void) fputs (scanl, stdout);
  758. +     if (fast)
  759. +         *scanout = scanl; /* return formatted buffer */
  760.   
  761.       FINDCOMP (cptr, "encrypted");
  762.       encrypted = cptr && cptr -> c_text;
  763. diff -cr mh-6.7/uip/sendsbr.c mh-6.7.new/uip/sendsbr.c
  764. *** mh-6.7/uip/sendsbr.c    Thu Apr 12 13:29:37 1990
  765. --- mh-6.7.new/uip/sendsbr.c    Tue Jul 31 13:28:55 1990
  766. ***************
  767. *** 1,6 ****
  768.   /* sendsbr.c - routines to help WhatNow/Send along */
  769.   #ifndef    lint
  770. ! static char ident[] = "@(#)$Id: sendsbr.c,v 2.3 90/04/05 14:57:18 sources Exp $";
  771.   #endif    lint
  772.   
  773.   #include "../h/mh.h"
  774. --- 1,6 ----
  775.   /* sendsbr.c - routines to help WhatNow/Send along */
  776.   #ifndef    lint
  777. ! static char ident[] = "@(#)$Id: sendsbr.c,v 1.1 90/07/31 13:28:44 case Exp $";
  778.   #endif    lint
  779.   
  780.   #include "../h/mh.h"
  781. --
  782. Case Larsen
  783. ctl@OCF.berkeley.edu
  784.