home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 October / usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso / unix / volume1 / digest < prev    next >
Internet Message Format  |  1986-11-30  |  35KB

  1. From: cbosgd!plus5!hokey (Hokey)
  2. Date: 10 Mar 85 16:15:47 CST (Sun)
  3. To: moderators@cbosgd.ATT.UUCP
  4. Subject: shar of digest software
  5.  
  6.  
  7. # This is a shell archive.  Remove anything before this line,
  8. # then unpack it by saving it in a file and typing "sh file".
  9. #
  10. # Wrapped by hokey on Sun Mar 10 16:07:28 CST 1985
  11. # Contents:  OLD/ Digest/ Digest/README Digest/digest.c aliases request inbox
  12. #    hdr.mail hdr.news submit digest.info
  13.  
  14. echo mkdir - OLD
  15. mkdir OLD
  16. chmod u=rwx,g=rwx,o=rx OLD
  17.  
  18. echo mkdir - Digest
  19. mkdir Digest
  20. chmod u=rwx,g=rwx,o=rx Digest
  21.  
  22. echo x - Digest/README
  23. sed 's/^@//' > "Digest/README" <<'@//E*O*F Digest/README//'
  24. This program is used to build ARPA-style digests from a file full of
  25. UNIX mail messages.  The messages must have the standard UNIX "From"
  26. line (the one with no colon after the "From").  Features of the program
  27. are:
  28.  
  29.     + Automatic issue number maintenance
  30.     + All letters with same subject grouped together in digest
  31.     + Any letter with "Administrivia" as the subject will
  32.       always be first in the digest (these are usually messages
  33.       from the moderator).
  34.  
  35. Basically, here's what you do to set up a mailing list and everything
  36. from scratch.  This assumes that you have 4.2BSD and sendmail.  The
  37. strategy here is to make everything controllable by an average user,
  38. who does not have super-user privileges.  This method will let the user
  39. maintain the list of people to send the digest to.  The system aliases
  40. file DOES NOT have to be rebuilt whenever the mailing list changes.
  41.  
  42. 1. Create a directory in which you will keep all the digest materials.
  43. This directory should be searchable by everyone; you can make sure of
  44. this by using the command "chmod a+x directory-name".  For the purposes
  45. of discussion, we will call this directory "/mydir/digest".
  46.  
  47. 2. Change into your digest directory.  Create a file to receive incoming
  48. mail in.  This file should be world-writeable, so "chmod a+w filename".
  49. For the purposes of this discussion, we will call the file
  50. "/mydir/digest/inbox".
  51.  
  52. 3. Create another file, and put the list of all people you will be
  53. sending the digest to in it.  The names should be separated by commas,
  54. continuation lines should start with a tab.  An example is shown below.
  55. Personally, I find it easiest if you make each letter of the alphabet
  56. start on a new line; this makes it easy to keep the aliases in
  57. alphabetical order.  For the purpose of this discussion, we will call
  58. this file "mydir/digest/aliases".
  59.  
  60. 4. Now have the system administrator place the following lines in
  61. the system aliases file (/usr/lib/aliases):
  62.  
  63.         Digest-Name-Request:your_login_name
  64.         Digest-Name:/mydir/digest/inbox
  65.         Digest-Name-People: :include:/mydir/digest/aliases
  66.  
  67. 5. Now, create another file in your digest directory.  This file must be
  68. called "digest.info".  Into this file, you should put the following
  69. lines:
  70.  
  71.     Name-of-the-digest            # omit the word "Digest"
  72.     Your-Host-Name                # Where the digest lives
  73.     Your-Login-Name                # Who sends the digest
  74.     Digest-Name-People            # Who the digest is sent to
  75.     Volume N : Issue   M            # Maintained automatically
  76.     Day, dd Mon yy hh:mm:ss tzn        # Maintained automatically
  77.  
  78. ---------------- 
  79. EXAMPLE
  80. ---------------- 
  81. I run a digest called "Purdue-Networking-Digest".  Our local network
  82. here is called "ECN", and my mailing address is "davy@ECN". To submit to
  83. the digest, people send to "Purdue-Networking@ECN".  To send mail to me,
  84. they send to "Purdue-Networking-Request@ECN".  I mail the digest out to
  85. "Network-People@ECN".  Our system aliases file contains (my login is "davy"):
  86.  
  87. Purdue-Networking-Request:davy
  88. Purdue-Networking:/e/davy/digest/inbox
  89. Network-People: :include:/e/davy/digest/aliases
  90.  
  91. The file "/e/davy/digest/aliases" contains:
  92.  
  93. aak@CS-Mordred,aaz@Pucc-I,abe@Pucc-J,abv@Pucc-H,ac4@Pucc-H,ace@ECN,
  94.     acu@Pucc-J,ad0@Pucc-I,ad3@Pucc-H,aeh@Pucc-H,aeq@Pucc-H,aex@Pucc-I,
  95.     afc@Pucc-I,ag5@Pucc-K,agc@Pucc-I,agd@Pucc-I,agj@Pucc-I,
  96.     beachy@ECN,buhrt@ECN,bv@ECN,
  97.     cak@CS-Mordred,cca@Physics,crl@Physics,cvu@Pucc-K,
  98.     d4a@Pucc-H,davy@ECN,devi@Physics,droms@CS-Merlin,dwm@ECN,
  99.     gjo@Pucc-H,gml@Pucc-H,
  100.     hal@Physics,hammonds@ECN,hisao@Physics,hzn@Pucc-E,
  101.     jad@CS-Mordred,jamesl@ECN,jtk@CS-Mordred,jump@ECN,
  102.     k31@Pucc-H,kcs@CS-Mordred,kg9s@ECN,kurmas@ECN,
  103.     lewie@ECN,lq4@ECN,
  104.     mahler@ECN,mckay@ECN,mhs@Physics,miller@ECN,mj@ECN,
  105.     pam@CS-Mordred,
  106.     rgn@Pucc-D,rhs@ECN,rjs@ECN,rl0@Pucc-E,rsk@ECN,ruan@CS-Arthur,
  107.     simmons@ECN,steve@ECN,stirling@ECN,
  108.     tth@ECN,
  109.     wb9vxy@ECN,wd9get@ECN,westerm@ECN,wn9nbt@ECN
  110.  
  111. Finally, my "digest.info" file contains:
  112.  
  113. Purdue-Networking
  114. ECN
  115. Dave Curry (The Moderator) <davy@ECN>
  116. Network-People@ECN
  117. Volume  1 : Issue   1
  118. Mon,  3 Dec 84 07:31:41 EST
  119.  
  120. The digest program will automatically maintain the Issue Number (you
  121. must change the Volume Number by hand) and the date.  The date is always
  122. the date of the most recent digest created.
  123.  
  124. ----------------
  125. END OF EXAMPLE
  126. ----------------
  127.  
  128. 6. Now, compile the digest program.  This can be done with the command
  129. "cc -O -s -o digest digest.c".
  130.  
  131. 7. When people send mail to "Digest-Name@Host", it will be placed into
  132. the "/mydir/digest/inbox" file.  When you think there are enough letters
  133. to make a digest, type the following commands:
  134.  
  135.     cp inbox digest.input
  136.     cp /dev/null inbox
  137.     digest
  138.     /usr/lib/sendmail -t < digest.output
  139.     cp digest.output archivedir/issuenumber
  140.  
  141. Obviously, the last step is optional, and should only be performed if
  142. you want to maintain an archive of the digests (a nice thing to do).
  143. @//E*O*F Digest/README//
  144. chmod u=rw,g=rw,o=r Digest/README
  145.  
  146. echo x - Digest/digest.c
  147. sed 's/^@//' > "Digest/digest.c" <<'@//E*O*F Digest/digest.c//'
  148. /*
  149.  * digest - create digests of mail messages
  150.  *
  151.  * This program uses the file "digest.info" to figure out what issue
  152.  * of the digest it is making.  The format of this file is:
  153.  *
  154.  *    Name of the List        # leave out the word "digest"
  155.  *    Host                # the host where the digest lives
  156.  *    From                # who sends the digest out
  157. #ifdef OLD
  158.  *    To                # who the list is sent to
  159. #endif OLD
  160.  *    Volume                # Volume XX : Issue XXX
  161.  *    Date                # Day, dd Mon yy hh:mm:ss timezone
  162.  *
  163.  * The file "digest.input" should contain a set of mail messages.  These
  164.  * will be read into memory and a list of "Today's Topics" generated
  165.  * from the subject lines.  The messages will then be sorted so that
  166.  * all the messages on the same topic come out together.  Any message
  167.  * whose first word in the subject line is "Administrivia" will be
  168.  * guaranteed to come out at the top of the list.  The digest will be
  169.  * left in the file "<Volume>.<Issue>".
  170.  *
  171.  * PROBLEM: sorting the messages to get all the same topic seems to
  172.  *    work fairly well.  After getting them together, we sort each
  173.  *    topic back into original arrival order.  The problem arises
  174.  *    when someone changes the subject line on you.  If it is
  175.  *    alphabetically before the original subject line, then these
  176.  *    messages will come before the originals.  This shouldn't
  177.  *    occur too often though.
  178.  *
  179.  * Special thanks to Jon Solomon who sent me his TELECOM digest generating
  180.  * program.  I swiped a lot of ideas from it in writing this one.
  181.  *
  182.  * David A. Curry
  183.  * decvax!pur-ee!davy
  184.  * ecn.davy@purdue
  185.  *
  186.  * March, 1985: {ihnp4,cbosgd,seismo}plus5!hokey (Hokey)
  187.  *
  188.  * I'll take credit for any bugs.
  189.  *
  190.  * Conversational output and "progress reports" now goes to stderr.
  191.  *
  192.  * Digest output is now saved to a file named "<Volume>.<Issue>".  This
  193.  * name is echoed to stdout.  Makes it easier to archive files and send
  194.  * the digest to news and mail.
  195.  *
  196.  * The To: line has been removed, to facilitate sending the output to news
  197.  * and mail, by prepending the appropriate header info to the file.
  198.  *
  199.  * If OLD is defined, it behaves as it used to.
  200.  *
  201.  * I removed the code to munge (I like a final "e") local names to fully
  202.  * qualified names because it should be done by the mailer.  So There.
  203.  * 
  204.  * If BSD42 is not defined, the program will compile on a USG version of Unix.
  205.  */
  206. #include <sys/types.h>
  207. #ifdef BSD42
  208. #include <sys/timeb.h>
  209. #else ~BSD42
  210. #define index=strchr
  211. #endif BSD42
  212. #include <sys/time.h>
  213. #include <ctype.h>
  214. #include <stdio.h>
  215.  
  216. #define HEAD1        27        /* Field width of first third    */
  217. #define HEAD2        20        /* Field width of second third    */
  218. #define HEAD3        21        /* Field width of last third    */
  219. #define DATELEN        14        /* Amount of date to put in hdr    */
  220. #define LINELEN        70        /* Length of an average line    */
  221. #define MAXMSGS        32        /* Maximum number of msgs/digest*/
  222. #define LINESIZE    128        /* Maximum line size        */
  223. #define LISTINFO    "digest.info"    /* Information file name    */
  224. #define LISTINPUT    "digest.input"    /* Input file name        */
  225. char     ListOutput[32];            /* Output file name        */
  226.  
  227. /*
  228.  * Message structure.  We read through the input file and fill one of
  229.  * these in for each message.  The To, Cc, From, Date, and Subject
  230.  * point to the fields of the same names from the message.  The
  231.  * "sortstring" is a copy of the subject string with all whitespace
  232.  * deleted and all letters in lower case.  The messageaddr is the
  233.  * seek position in the file where the message body starts, and
  234.  * messagelength is how long the message is.
  235.  */
  236. struct message {
  237.     char *To;
  238.     char *Cc;
  239.     char *From;
  240.     char *Date;
  241.     char *Subject;
  242.     char *sortstring;
  243.     long messageaddr;
  244.     long messagelength;
  245. } messages[MAXMSGS];
  246.  
  247. /*
  248.  * List structure.  Contains the information from the LISTINFO file.
  249.  */
  250. struct listinfo {
  251.     char *Title;
  252.     char *Host;
  253.     char *From;
  254. #ifdef OLD
  255.     char *To;
  256. #endif OLD
  257.     char *Volline;
  258.     char *Dateline;
  259. } listinfo;
  260.  
  261. FILE *input;
  262. FILE *output;
  263.  
  264. int volume_number;            /* The volume number        */
  265. int issue_number;            /* The issue number        */
  266. int nmessages = 0;            /* Number of messages        */
  267. int digestsize = 0;            /* Size of digest in bytes    */
  268.  
  269. char *index(), *malloc(), *safter(), *nospace(), *getline();
  270.  
  271. main()
  272. {
  273.     /*
  274.      * Read the list information file and update the
  275.      * issue number and date strings.
  276.      */
  277.     get_list_info();
  278.     inc_volume_and_date();
  279.  
  280.     fprintf(stderr, "Assembling %s Digest %s (%.*s)\n", listinfo.Title, listinfo.Volline, DATELEN, listinfo.Dateline);
  281.     fprintf(stderr, "Scanning and sorting messages for topic lines.\n");
  282.  
  283.     /*
  284.      * Scan the message file for subject strings and
  285.      * sort the messages to get all the messages for
  286.      * each topic next to each other.
  287.      */
  288.     scan_messages();
  289.     sort_messages();
  290.  
  291.     sprintf(ListOutput, "%d.%d", volume_number, issue_number);
  292.     fprintf(stderr, "Writing %s Digest to \"%s\"\n", listinfo.Title, ListOutput);
  293.  
  294.     /*
  295.      * Print the digest header, put the messages
  296.      * in the digest.
  297.      */
  298.     do_digest_header();
  299.     read_messages();
  300.  
  301.     fprintf(stderr, "The digest is %d characters long in %d messages.\n", digestsize, nmessages);
  302.  
  303.     /*
  304.      * Put out the new list information.
  305.      */
  306.     put_list_info();
  307.     fprintf(stdout, "%s", ListOutput);
  308.     exit(0);
  309. }
  310.  
  311. /*
  312.  * get_list_info - reads in the LISTINFO file.
  313.  */
  314. get_list_info()
  315. {
  316.     FILE *fp;
  317.     int incomplete;
  318.  
  319.     if ((fp = fopen(LISTINFO, "r")) == NULL) {
  320.         fprintf(stderr, "digest: cannot open \"%s\" for reading.\n", LISTINFO);
  321.         exit(1);
  322.     }
  323.  
  324.     incomplete = 0;
  325.  
  326.     if ((listinfo.Title = getline(fp)) == NULL)
  327.         incomplete++;
  328.     if ((listinfo.Host = getline(fp)) == NULL)
  329.         incomplete++;
  330.     if ((listinfo.From = getline(fp)) == NULL)
  331.         incomplete++;
  332. #ifdef OLD
  333.     if ((listinfo.To = getline(fp)) == NULL)
  334.         incomplete++;
  335. #endif OLD
  336.     if ((listinfo.Volline = getline(fp)) == NULL)
  337.         incomplete++;
  338.     if ((listinfo.Dateline = getline(fp)) == NULL)
  339.         incomplete++;
  340.  
  341.     fclose(fp);
  342.  
  343.     /*
  344.      * Error-check.  Not too sophisicated, but then you're
  345.      * supposed to know what you're doing anyway.
  346.      */
  347.     if (incomplete) {
  348.         fprintf(stderr, "digest: incomplete or badly formatted \"%s\" file.\n", LISTINFO);
  349.         fprintf(stderr, "Proper format:\n");
  350.         fprintf(stderr, "\tTitle\n\tHost\n\tFrom\n");
  351. #ifdef OLD
  352.         fprintf(stderr, "\tTo\n");
  353. #endif OLD
  354.         fprintf(stderr, "\tVolline\n\tDateline\n");
  355.         exit(1);
  356.     }
  357. }
  358.  
  359. /*
  360.  * inc_volume_and_date - update the volume/issue string and get a new date.
  361.  */
  362. inc_volume_and_date()
  363. {
  364.     char *msgdate();
  365.     register char *volline, *colon;
  366.  
  367.     if ((volline = malloc(strlen(listinfo.Volline)+1)) == NULL) {
  368.         fprintf(stderr, "digest: out of memory.\n");
  369.         exit(1);
  370.     }
  371.  
  372.     /*
  373.      * Volume numbers get changed by hand.
  374.      */
  375.     volume_number = atoi(safter(listinfo.Volline, "Volume "));
  376.  
  377.     issue_number = atoi(safter(listinfo.Volline, " Issue ")) + 1;
  378.  
  379.     if ((colon = index(listinfo.Volline, ':')) != NULL)
  380.         *colon = NULL;
  381.  
  382.     sprintf(volline, "%s: Issue %3d", listinfo.Volline, issue_number);
  383.     strcpy(listinfo.Volline, volline);
  384.  
  385.     /*
  386.      * Get a new date.
  387.      */
  388.     listinfo.Dateline = msgdate();
  389.  
  390.     free(volline);
  391. }
  392.  
  393. /*
  394.  * msgdate - produce a new date string.  Format is
  395.  *
  396.  *        Day, dd Mon yy hh:mm:ss tzn
  397.  */
  398. char *msgdate()
  399. {
  400. #ifdef BSD42
  401.     char *timezone();
  402.     struct timeb tbuf;
  403. #else ~BSD42
  404.     long curtime;
  405. #endif BSD42
  406.     register struct tm *t;
  407.     struct tm *localtime();
  408.     static char datebuf[64];
  409.     char *days = "SunMonTueWedThuFriSat";
  410.     char *months = "JanFebMarAprMayJunJulAugSepNovDec";
  411.  
  412. #ifdef BSD42
  413.     ftime(&tbuf);
  414.     t = localtime(&(tbuf.time));
  415. #else ~BSD42
  416.     curtime = time((long *)0);
  417.     t = localtime(&curtime);
  418. #endif BSD42
  419.     t->tm_mon--;
  420.  
  421.     sprintf(datebuf, "%3.3s, %2d %3.3s %02d %02d:%02d:%02d %3.3s",
  422.             &days[3 * t->tm_wday], t->tm_mday,
  423.             &months[3 * t->tm_mon],    t->tm_year, t->tm_hour,
  424.             t->tm_min, t->tm_sec,
  425. #ifdef BSD42
  426.             timezone(tbuf.timezone, t->tm_isdst)
  427. #else ~BSD42
  428.             tzname[daylight != 0]
  429. #endif BSD42
  430.             );
  431.  
  432.     return(datebuf);
  433. }
  434.  
  435. /*
  436.  * getline - read a line into a dynamically allocated buffer.
  437.  */
  438. char *getline(fp)
  439. FILE *fp;
  440. {
  441.     register int c;
  442.     register char *str, *str_begin;
  443.  
  444.     if ((str = malloc(LINESIZE)) == NULL) {
  445.         fprintf(stderr, "digest: out of memory.\n");
  446.         exit(1);
  447.     }
  448.  
  449.     str_begin = str;
  450.  
  451.     while (((c = getc(fp)) != '\n') && (c != EOF))
  452.         *str++ = c;
  453.     *str++ = NULL;
  454.  
  455.     if (c == EOF)
  456.         return(NULL);
  457.  
  458.     return(str_begin);
  459. }
  460.  
  461. /*
  462.  * scan_messages - scans through LISTINPUT reading in header fields
  463.  *           and marking the beginning and ending of messages.
  464.  *
  465.  * NOTE: some of the code here depends on the UNIX mail header format.
  466.  *       This format simply guarantees that the first line of a message's
  467.  *     header will be "From blah-blah-blah".  Note there is no colon
  468.  *     (`:') on the "From", the real "From:" line is farther down in
  469.  *     the headers.
  470.  */
  471. scan_messages()
  472. {
  473.     register long n;
  474.     register char *s;
  475.  
  476.     if ((input = fopen(LISTINPUT, "r")) == NULL) {
  477.         fprintf(stderr, "digest: cannot open \"%s\" for reading.\n", LISTINPUT);
  478.         exit(1);
  479.     }
  480.  
  481.     /*
  482.      * We break out of this from inside.
  483.      */
  484.     for (;;) {
  485.         if (nmessages >= MAXMSGS) {
  486.             fprintf(stderr, "digest: too many messages.\n");
  487.             exit(1);
  488.         }
  489.  
  490.         /*
  491.          * Find the start of the next message.
  492.          */
  493.         do {
  494.             /*
  495.              * If we hit EOF, mark the length of the
  496.              * previous message and go back.
  497.              */
  498.             if ((s = getline(input)) == NULL) {
  499.                 n = ftell(input);
  500.                 n = n - messages[nmessages - 1].messageaddr;
  501.                 messages[nmessages - 1].messagelength = n;
  502.                 return;
  503.             }
  504.         } while (strncmp(s, "From ", 5) != 0);
  505.  
  506.         /*
  507.          * If we have found another message, mark the
  508.          * length of the previous message.
  509.          */
  510.         if (nmessages) {
  511.             n = ftell(input);
  512.             n = n - (strlen(s) + 1);
  513.             n = n - messages[nmessages - 1].messageaddr;
  514.             messages[nmessages - 1].messagelength = n;
  515.         }
  516.  
  517.         /*
  518.          * Read in the headers.
  519.          */
  520.         for (;;) {
  521.             /*
  522.              * We shouldn't hit EOF here, we should
  523.              * at least finish the headers first.
  524.              */
  525.             if ((s = getline(input)) == NULL) {
  526.                 fprintf(stderr, "digest: \"%s\": unexpected EOF.\n", LISTINPUT);
  527.                 exit(1);
  528.             }
  529.  
  530.             /*
  531.              * Blank line terminates headers.
  532.              */
  533.             if (*s == NULL)
  534.                 break;
  535.  
  536.             /*
  537.              * Save certain headers.  We strip the
  538.              * header name and leading whitespace.
  539.              */
  540.             if (strncmp(s, "To:", 3) == 0) {
  541.                 messages[nmessages].To = nospace(safter(s, "To:"));
  542.             }
  543.             else if (strncmp(s, "Cc:", 3) == 0) {
  544.                 messages[nmessages].Cc = nospace(safter(s, "Cc:"));
  545.             }
  546.             else if (strncmp(s, "From:", 5) == 0) {
  547.                 messages[nmessages].From = nospace(safter(s, "From:"));
  548.             }
  549.             else if (strncmp(s, "Date:", 5) == 0) {
  550.                 messages[nmessages].Date = nospace(safter(s, "Date:"));
  551.             }
  552.             else if (strncmp(s, "Subject:", 8) == 0) {
  553.                 s = nospace(safter(s, "Subject:"));
  554.  
  555.                 /*
  556.                  * We don't need the "Re:" stuff.
  557.                  */
  558.                 if ((strncmp(s, "re:", 3) == 0) || (strncmp(s, "Re:", 3) == 0) ||
  559.                     (strncmp(s, "RE:", 3) == 0) || (strncmp(s, "rE:", 3) == 0))
  560.                         s += 3;
  561.  
  562.                 messages[nmessages].Subject = nospace(s);
  563.             }
  564.             else {
  565.                 /*
  566.                  * If we aren't saving this line,
  567.                  * give the memory back.
  568.                  */
  569.                 free(s);
  570.             }
  571.         }
  572.  
  573.         /*
  574.          * The message starts after the header.
  575.          */
  576.         messages[nmessages].messageaddr = ftell(input);
  577.         nmessages++;
  578.     }
  579. }
  580.  
  581. /*
  582.  * sort_messages - convert each message's subject line to a string
  583.  *           all in lower case with no whitespace.  Then sort
  584.  *           the messages on this string.  This will group
  585.  *           all the messages on the same subject together.
  586.  */
  587. sort_messages()
  588. {
  589.     register int i;
  590.     extern int comp();
  591.     register char *s, *t;
  592.  
  593.     for (i=0; i < nmessages; i++) {
  594.         /*
  595.          * Skip messages with no subject.
  596.          */
  597.         if (messages[i].Subject == NULL)
  598.             continue;
  599.  
  600.         s = messages[i].Subject;
  601.  
  602.         if ((t = malloc(strlen(s)+1)) == NULL) {
  603.             fprintf(stderr, "digest: out of memory.\n");
  604.             exit(1);
  605.         }
  606.  
  607.         messages[i].sortstring = t;
  608.  
  609.         /*
  610.          * Zap leading whitespace.
  611.          */
  612.         s = nospace(s);
  613.  
  614.         /*
  615.          * Copy the subject string into sortstring
  616.          * converting upper case to lower case and
  617.          * ignoring whitespace.
  618.          */
  619.         while (*s) {
  620.             if ((*s == ' ') || (*s == '\t')) {
  621.                 s++;
  622.                 continue;
  623.             }
  624.  
  625.             if (isupper(*s))
  626.                 *t++ = tolower(*s);
  627.             else
  628.                 *t++ = *s;
  629.  
  630.             s++;
  631.         }
  632.  
  633.         *t = NULL;
  634.     }
  635.  
  636.     /*
  637.      * Sort 'em.
  638.      */
  639.     qsort(messages, nmessages, sizeof(struct message), comp);
  640. }
  641.  
  642. /*
  643.  * comp - comparison routine for qsort.  Messages with no subject go
  644.  *      at the end of the digest, messages with "administrivia" as
  645.  *      the subject go to the top of the digest.
  646.  */
  647. comp(m1, m2)
  648. register struct message *m1, *m2;
  649. {
  650.     int admin1, admin2;
  651.  
  652.     if (m1->sortstring == NULL) {
  653.         if (m2->sortstring == NULL)
  654.             return(0);
  655.         return(1);        /* no subject messages to end */
  656.     }
  657.  
  658.     if (m2->sortstring == NULL)
  659.         return(-1);        /* no subject messages to end */
  660.  
  661.     admin1 = strncmp(m1->sortstring, "administrivia", 13);
  662.     admin2 = strncmp(m2->sortstring, "administrivia", 13);
  663.  
  664.     if (admin1 == 0) {
  665.         if (admin2 == 0)
  666.             return(0);
  667.         return(-1);        /* administrivia to beginning */
  668.     }
  669.  
  670.     if (admin2 == 0)
  671.         return(1);        /* administrivia to beginning */
  672.  
  673.     return(strcmp(m1->sortstring, m2->sortstring));
  674. }
  675.  
  676. /*
  677.  * do_digest_header - prints the digest header and mailer headers.
  678.  */
  679. do_digest_header()
  680. {
  681.     char *laststr;
  682.     char buf[BUFSIZ];
  683.     char tmp[LINESIZE];
  684.     extern int comp2();
  685.     register int i, j, length;
  686.  
  687.     if ((output = fopen(ListOutput, "w")) == NULL) {
  688.         fprintf(stderr, "digest: cannot create \"%s\"\n", ListOutput);
  689.         exit(1);
  690.     }
  691.  
  692.     digestsize = 0;
  693.  
  694.     /*
  695.      * Mailer headers.
  696.      */
  697.     sprintf(buf, "Date: %s\n", listinfo.Dateline);
  698.     digestsize += strlen(buf);
  699.     fputs(buf, output);
  700.  
  701.     sprintf(buf, "From: %s\n", listinfo.From);
  702.     digestsize += strlen(buf);
  703.     fputs(buf, output);
  704.  
  705.     sprintf(buf, "Reply-To: %s@%s\n", listinfo.Title, listinfo.Host);
  706.     digestsize += strlen(buf);
  707.     fputs(buf, output);
  708.  
  709.     sprintf(buf, "Subject: %s Digest V1 #%d\n", listinfo.Title, issue_number);
  710.     digestsize += strlen(buf);
  711.     fputs(buf, output);
  712.  
  713. #ifdef OLD
  714.     sprintf(buf, "To: %s\n", listinfo.To);
  715.     digestsize += strlen(buf);
  716.     fputs(buf, output);
  717. #endif OLD
  718.  
  719.     /*
  720.      * The digest header.
  721.      */
  722.     sprintf(tmp, "%s Digest", listinfo.Title);
  723.     sprintf(buf, "\n\n%-*.*s %-*.*s %-*.*s\n\n",
  724.                 HEAD1, HEAD1, tmp,
  725.                 HEAD2, DATELEN, listinfo.Dateline,
  726.                 HEAD3, HEAD3, listinfo.Volline);
  727.     digestsize += strlen(buf);
  728.     fputs(buf, output);
  729.  
  730.     sprintf(buf, "Today's Topics:\n");
  731.     digestsize += strlen(buf);
  732.     fputs(buf, output);
  733.  
  734.     /*
  735.      * Do today's topics lines.
  736.      */
  737.     laststr = "";
  738.     for (i=0; i < nmessages; i++) {
  739.         /*
  740.          * No topic.
  741.          */
  742.         if (messages[i].Subject == NULL)
  743.             continue;
  744.  
  745.         laststr = messages[i].sortstring;
  746.  
  747.         /*
  748.          * Count the number of messages with this topic.
  749.          */
  750.         j = 1;
  751.         while (((i + j) < nmessages) && (strcmp(laststr, messages[i+j].sortstring) == 0))
  752.             j++;
  753.  
  754.         /*
  755.          * Print the topic centered on the line.
  756.          */
  757.         if (j > 1) {
  758.             sprintf(tmp, "%s (%d msgs)", messages[i].Subject, j);
  759.             length = (LINELEN / 2) + (strlen(tmp) / 2);
  760.             sprintf(buf, "%*s\n", length, tmp);
  761.  
  762.             /*
  763.              * Sort messages with same topic into their
  764.              * original arrival order.
  765.              */
  766.             qsort(&messages[i], j, sizeof(struct message), comp2);
  767.             i += (j - 1);
  768.         }
  769.         else {
  770.             length = (LINELEN / 2) + (strlen(messages[i].Subject) / 2);
  771.             sprintf(buf, "%*s\n", length, messages[i].Subject);
  772.         }
  773.  
  774.         digestsize += strlen(buf);
  775.         fputs(buf, output);
  776.     }
  777.  
  778.     /*
  779.      * Print a line of dashes.
  780.      */
  781.     for (i=0; i < LINELEN; i++) {
  782.         putc('-', output);
  783.         digestsize++;
  784.     }
  785.  
  786.     fputs("\n\n", output);
  787.     digestsize += 2;
  788. }
  789.  
  790. /*
  791.  * comp2 - comparison routine for second qsort.  This one simply compares
  792.  *       messages addresses in the input file, so that we can sort the
  793.  *       messages with the same topic back into the order they arrived.
  794.  */
  795. comp2(m1, m2)
  796. register struct message *m1, *m2;
  797. {
  798.     return(m1->messageaddr - m2->messageaddr);
  799. }
  800.  
  801. /*
  802.  * read_messages - reads in the message texts and puts them in the
  803.  *           digest with their headers.
  804.  */
  805. read_messages()
  806. {
  807.     char buf[BUFSIZ];
  808.     register char *s, *t;
  809.     register int i, length;
  810.  
  811.     for (i=0; i < nmessages; i++) {
  812.         /*
  813.          * Just in case.
  814.          */
  815.         clearerr(input);
  816.  
  817.         /*
  818.          * Put the message's headers back in.
  819.          */
  820.         sprintf(buf, "Date: %s\n", messages[i].Date);
  821.         digestsize += strlen(buf);
  822.         fputs(buf, output);
  823.  
  824.         sprintf(buf, "From: %s\n", messages[i].From);
  825.         digestsize += strlen(buf);
  826.         fputs(buf, output);
  827.  
  828.         if (messages[i].Subject != NULL) {
  829.             sprintf(buf, "Subject: %s\n", messages[i].Subject);
  830.             digestsize += strlen(buf);
  831.             fputs(buf, output);
  832.         }
  833.  
  834.         sprintf(buf, "To: %s\n\n", messages[i].To);
  835.         digestsize += strlen(buf);
  836.         fputs(buf, output);
  837.  
  838.         /*
  839.          * Read the message into memory.  This is
  840.          * so we can zap extra blank lines.
  841.          */
  842.         fseek(input, messages[i].messageaddr, 0);
  843.         length = messages[i].messagelength;
  844.  
  845.         if ((s = malloc(length+1)) == NULL) {
  846.             fprintf(stderr, "digest: out of memory.\n");
  847.             exit(1);
  848.         }
  849.  
  850.         fread(s, 1, length, input);
  851.  
  852.         /*
  853.          * Zap trailing newlines.
  854.          */
  855.         t = s + length;
  856.         while (*--t == '\n')
  857.             length--;
  858.         *++t = NULL;
  859.         
  860.         /*
  861.          * Zap leading newlines.
  862.          */
  863.         t = s;
  864.         while (*t++ == '\n')
  865.             length--;
  866.         t--;
  867.  
  868.         /*
  869.          * Write the message.
  870.          */
  871.         digestsize += length;
  872.         fwrite(t, 1, length, output);
  873.  
  874.         sprintf(buf, "\n\n------------------------------\n\n");
  875.         digestsize += strlen(buf);
  876.         fputs(buf, output);
  877.         free(s);
  878.     }
  879.  
  880.     /*
  881.      * All done.
  882.      */
  883.     sprintf(buf, "End of %s Digest\n******************************\n", listinfo.Title);
  884.     digestsize += strlen(buf);
  885.     fputs(buf, output);
  886.     fclose(output);
  887.     fclose(input);
  888. }
  889.  
  890. /*
  891.  * put_list_info - rewrite the LISTINFO file with the new data.
  892.  */
  893. put_list_info()
  894. {
  895.     FILE *fp;
  896.     char tmp[LINESIZE];
  897.  
  898.     sprintf(tmp, "%s.old", LISTINFO);
  899.  
  900. #ifdef BSD42
  901.     if (rename(LISTINFO, tmp) < 0) {
  902.         fprintf(stderr, "digest: cannot move old \"%s\" file, today's data lost.\n", LISTINFO);
  903.         return;
  904.     }
  905. #else ~BSD42
  906.     if (link(LISTINFO, tmp) < 0) {
  907.         fprintf(stderr, "digest: cannot move link \"%s\" file to \"%s\", today's data lost.\n", LISTINFO, tmp);
  908.         return;
  909.     }
  910.     if (unlink(LISTINFO) < 0) {
  911.         fprintf(stderr, "digest: cannot remove \"%s\" file, today's data lost.\n", LISTINFO);
  912.         return;
  913.     }
  914. #endif BSD42
  915.  
  916.     if ((fp = fopen(LISTINFO, "w")) == NULL) {
  917.         fprintf(stderr, "digest: cannot create \"%s\", today's data lost.\n", LISTINFO);
  918.         return;
  919.     }
  920.  
  921.     fprintf(fp, "%s\n", listinfo.Title);
  922.     fprintf(fp, "%s\n", listinfo.Host);
  923.     fprintf(fp, "%s\n", listinfo.From);
  924. #ifdef OLD
  925.     fprintf(fp, "%s\n", listinfo.To);
  926. #endif OLD
  927.     fprintf(fp, "%s\n", listinfo.Volline);
  928.     fprintf(fp, "%s\n", listinfo.Dateline);
  929.  
  930.     fclose(fp);
  931.     unlink(tmp);
  932. }
  933.  
  934. /*
  935.  * safter - return a pointer to the position in str which follows pat.
  936.  */
  937. char *safter(str, pat)
  938. register char *str, *pat;
  939. {
  940.     register int len;
  941.  
  942.     len = strlen(pat);
  943.  
  944.     while (*str) {
  945.         if (strncmp(str, pat, len) == 0) {
  946.             str += len;
  947.             return(str);
  948.         }
  949.  
  950.         str++;
  951.     }
  952.  
  953.     return(NULL);
  954. }
  955.  
  956. /*
  957.  * nospace - advance s over leading whitespace, return new value.
  958.  */
  959. char *nospace(s)
  960. register char *s;
  961. {
  962.     while ((*s != NULL) && ((*s == ' ') || (*s == '\t')))
  963.         s++;
  964.  
  965.     return(s);
  966. }
  967.  
  968. @//E*O*F Digest/digest.c//
  969. chmod u=rw,g=rw,o=r Digest/digest.c
  970.  
  971. echo x - aliases
  972. sed 's/^@//' > "aliases" <<'@//E*O*F aliases//'
  973. bowie@nimbus.dec
  974. ihnp4!sask!regina!mumps
  975. okane@tennessee.csnet
  976. ihnp4!ucbvax!ucdavis!clover:mumps
  977. @//E*O*F aliases//
  978. chmod u=rw,g=rw,o=r aliases
  979.  
  980. echo x - request
  981. sed 's/^@//' > "request" <<'@//E*O*F request//'
  982. @//E*O*F request//
  983. chmod u=rw,g=rw,o=r request
  984.  
  985. echo x - inbox
  986. sed 's/^@//' > "inbox" <<'@//E*O*F inbox//'
  987. @//E*O*F inbox//
  988. chmod u=rw,g=rw,o=rw inbox
  989.  
  990. echo x - hdr.mail
  991. sed 's/^@//' > "hdr.mail" <<'@//E*O*F hdr.mail//'
  992. To: std-mumps-People
  993. @//E*O*F hdr.mail//
  994. chmod u=rw,g=rw,o=r hdr.mail
  995.  
  996. echo x - hdr.news
  997. sed 's/^@//' > "hdr.news" <<'@//E*O*F hdr.news//'
  998. Newsgroups: mod.std.mumps
  999. Approved: hokey@plus5.uucp
  1000. @//E*O*F hdr.news//
  1001. chmod u=rw,g=rw,o=r hdr.news
  1002.  
  1003. echo x - submit
  1004. sed 's/^@//' > "submit" <<'@//E*O*F submit//'
  1005. :
  1006. Requests=requests
  1007. : 'Check to see if any new requests have come in'
  1008. if [ -s $Requests ]
  1009. then
  1010.     echo "There are mailing list requests which must be handled"
  1011.     exit 1
  1012. fi
  1013. : 'Check to see if any submissions have arrived'
  1014. if [ ! -s inbox ]
  1015. then
  1016.     echo "No new submissions"
  1017.     exit 1
  1018. fi
  1019.  
  1020. mv inbox digest.input
  1021. touch inbox
  1022. chmod 666 inbox
  1023. : 'protect against disaster'
  1024. cp digest.input inbox-
  1025. cp digest.info digest.info-
  1026. : 'This is a good place to "pre-edit" input'
  1027.  
  1028. Digest=`Digest/digest`
  1029. if [ -z "$Digest" ]
  1030. then
  1031.     echo "No digest created."
  1032.     exit 1
  1033. fi
  1034. : 'This is a good place to make sure we did OK'
  1035.  
  1036. cat hdr.mail $Digest | /usr/lib/sendmail -t
  1037. cat hdr.news $Digest | /usr/lib/news/inews -h
  1038. mv $Digest OLD
  1039. exit 0
  1040. @//E*O*F submit//
  1041. chmod u=rwx,g=rwx,o=rx submit
  1042.  
  1043. echo x - digest.info
  1044. sed 's/^@//' > "digest.info" <<'@//E*O*F digest.info//'
  1045. std-mumps
  1046. plus5.uucp
  1047. Hokey (The Moderator) <hokey@plus5.uucp>
  1048. Volume  1 : Issue  10
  1049. Sat,  9 Feb 85 19:20:44 CDT
  1050. @//E*O*F digest.info//
  1051. chmod u=rw,g=rw,o=r digest.info
  1052.  
  1053. exit 0
  1054.  
  1055. From cbosgd!ihnp4!wnuxb!netnews Wed Mar 13 03:32:44 1985
  1056. Received: by genrad.UUCP (4.12/4.7)
  1057.     id AA03315; Wed, 13 Mar 85 03:32:39 est
  1058. From: ihnp4!wnuxb!netnews
  1059. Message-Id: <8503130753.AA10972@cbosgd.ATT.UUCP>
  1060. Received: by cbosgd.ATT.UUCP (4.12/3.7boo)
  1061.     id AA10972; Wed, 13 Mar 85 02:53:59 est
  1062. Date: 12 Mar 85 22:42:29 CST (Tue)
  1063. Received: by ihnp4.ATT.UUCP; id AA20654; 12 Mar 85 22:42:29 CST (Tue)
  1064. To: ihnp4!cbosgd!moderators
  1065. Subject: Re: shar of digest software
  1066. Status: R
  1067.  
  1068. The stuff hokey posted worked out really well for me.  I was using
  1069. just the "lame" shell scripts, now the C stuff makes things MUCH
  1070. easier.  Of course, I couldn't leave well enough alone, so I made
  1071. a few changes.  On my SysV, time is not in /usr/include/sys, just
  1072. /usr/include.  Also, I didn't see any reason to include the "To:"
  1073. lines in each of the digestified messages, so that is now surrounded
  1074. by #ifdef INTO.  (Although I may have missed something so that it
  1075. may break if INTO actually gets defined.)  I was getting memory
  1076. faults on some long lines, so I bumped the max line size to 256.
  1077. And, I like GMT.  (Berkleyites should check this part.  I just do
  1078. SysV.  :->) Another thing was that I wanted the "Name" of the
  1079. digest to be different from the "address" to which submissions should
  1080. be sent, so I added a line to the digest.info file.  Here are context
  1081. diffs of digest.c.  (Hope you all have patch!)  After that, is an
  1082. example of the new digest.info file (virtually identical).  Ron.
  1083. -------------------
  1084. *** digest.old    Sun Mar 10 21:59:05 1985
  1085. --- digest.c    Mon Mar 11 22:45:27 1985
  1086. ***************
  1087. *** 62,68
  1088.   #else ~BSD42
  1089.   #define index=strchr
  1090.   #endif BSD42
  1091. ! #include <sys/time.h>
  1092.   #include <ctype.h>
  1093.   #include <stdio.h>
  1094.   
  1095.  
  1096. --- 62,68 -----
  1097.   #else ~BSD42
  1098.   #define index=strchr
  1099.   #endif BSD42
  1100. ! #include <time.h>
  1101.   #include <ctype.h>
  1102.   #include <stdio.h>
  1103.   
  1104. ***************
  1105. *** 72,78
  1106.   #define DATELEN        14        /* Amount of date to put in hdr    */
  1107.   #define LINELEN        70        /* Length of an average line    */
  1108.   #define MAXMSGS        32        /* Maximum number of msgs/digest*/
  1109. ! #define LINESIZE    128        /* Maximum line size        */
  1110.   #define LISTINFO    "digest.info"    /* Information file name    */
  1111.   #define LISTINPUT    "digest.input"    /* Input file name        */
  1112.   char     ListOutput[32];            /* Output file name        */
  1113.  
  1114. --- 72,78 -----
  1115.   #define DATELEN        14        /* Amount of date to put in hdr    */
  1116.   #define LINELEN        70        /* Length of an average line    */
  1117.   #define MAXMSGS        32        /* Maximum number of msgs/digest*/
  1118. ! #define LINESIZE    256        /* Maximum line size        */
  1119.   #define LISTINFO    "digest.info"    /* Information file name    */
  1120.   #define LISTINPUT    "digest.input"    /* Input file name        */
  1121.   char     ListOutput[32];            /* Output file name        */
  1122. ***************
  1123. *** 102,107
  1124.    */
  1125.   struct listinfo {
  1126.       char *Title;
  1127.       char *Host;
  1128.       char *From;
  1129.   #ifdef OLD
  1130.  
  1131. --- 102,108 -----
  1132.    */
  1133.   struct listinfo {
  1134.       char *Title;
  1135. +     char *Address;
  1136.       char *Host;
  1137.       char *From;
  1138.   #ifdef OLD
  1139. ***************
  1140. *** 178,183
  1141.   
  1142.       if ((listinfo.Title = getline(fp)) == NULL)
  1143.           incomplete++;
  1144.       if ((listinfo.Host = getline(fp)) == NULL)
  1145.           incomplete++;
  1146.       if ((listinfo.From = getline(fp)) == NULL)
  1147.  
  1148. --- 179,186 -----
  1149.   
  1150.       if ((listinfo.Title = getline(fp)) == NULL)
  1151.           incomplete++;
  1152. +     if ((listinfo.Address = getline(fp)) == NULL)
  1153. +         incomplete++;
  1154.       if ((listinfo.Host = getline(fp)) == NULL)
  1155.           incomplete++;
  1156.       if ((listinfo.From = getline(fp)) == NULL)
  1157. ***************
  1158. *** 257,263
  1159.       long curtime;
  1160.   #endif BSD42
  1161.       register struct tm *t;
  1162. !     struct tm *localtime();
  1163.       static char datebuf[64];
  1164.       char *days = "SunMonTueWedThuFriSat";
  1165.       char *months = "JanFebMarAprMayJunJulAugSepNovDec";
  1166.  
  1167. --- 260,266 -----
  1168.       long curtime;
  1169.   #endif BSD42
  1170.       register struct tm *t;
  1171. !     struct tm *gmtime();
  1172.       static char datebuf[64];
  1173.       char *days = "SunMonTueWedThuFriSat";
  1174.       char *months = "JanFebMarAprMayJunJulAugSepNovDec";
  1175. ***************
  1176. *** 264,270
  1177.   
  1178.   #ifdef BSD42
  1179.       ftime(&tbuf);
  1180. !     t = localtime(&(tbuf.time));
  1181.   #else ~BSD42
  1182.       curtime = time((long *)0);
  1183.       t = localtime(&curtime);
  1184.  
  1185. --- 267,273 -----
  1186.   
  1187.   #ifdef BSD42
  1188.       ftime(&tbuf);
  1189. !     t = gmtime(&(tbuf.time));
  1190.   #else ~BSD42
  1191.       curtime = time((long *)0);
  1192.       t = gmtime(&curtime);
  1193. ***************
  1194. *** 267,273
  1195.       t = localtime(&(tbuf.time));
  1196.   #else ~BSD42
  1197.       curtime = time((long *)0);
  1198. !     t = localtime(&curtime);
  1199.   #endif BSD42
  1200.       t->tm_mon--;
  1201.   
  1202.  
  1203. --- 270,276 -----
  1204.       t = gmtime(&(tbuf.time));
  1205.   #else ~BSD42
  1206.       curtime = time((long *)0);
  1207. !     t = gmtime(&curtime);
  1208.   #endif BSD42
  1209.       t->tm_mon--;
  1210.   
  1211. ***************
  1212. *** 276,282
  1213.               &months[3 * t->tm_mon],    t->tm_year, t->tm_hour,
  1214.               t->tm_min, t->tm_sec,
  1215.   #ifdef BSD42
  1216. !             timezone(tbuf.timezone, t->tm_isdst)
  1217.   #else ~BSD42
  1218.               tzname[daylight != 0]
  1219.   #endif BSD42
  1220.  
  1221. --- 279,285 -----
  1222.               &months[3 * t->tm_mon],    t->tm_year, t->tm_hour,
  1223.               t->tm_min, t->tm_sec,
  1224.   #ifdef BSD42
  1225. !             "GMT"
  1226.   #else ~BSD42
  1227.               "GMT"
  1228.   #endif BSD42
  1229. ***************
  1230. *** 278,284
  1231.   #ifdef BSD42
  1232.               timezone(tbuf.timezone, t->tm_isdst)
  1233.   #else ~BSD42
  1234. !             tzname[daylight != 0]
  1235.   #endif BSD42
  1236.               );
  1237.   
  1238.  
  1239. --- 281,287 -----
  1240.   #ifdef BSD42
  1241.               "GMT"
  1242.   #else ~BSD42
  1243. !             "GMT"
  1244.   #endif BSD42
  1245.               );
  1246.   
  1247. ***************
  1248. *** 555,561
  1249.       digestsize += strlen(buf);
  1250.       fputs(buf, output);
  1251.   
  1252. !     sprintf(buf, "Reply-To: %s@%s\n", listinfo.Title, listinfo.Host);
  1253.       digestsize += strlen(buf);
  1254.       fputs(buf, output);
  1255.   
  1256.  
  1257. --- 558,564 -----
  1258.       digestsize += strlen(buf);
  1259.       fputs(buf, output);
  1260.   
  1261. !     sprintf(buf, "Reply-To: %s@%s\n", listinfo.Address, listinfo.Host);
  1262.       digestsize += strlen(buf);
  1263.       fputs(buf, output);
  1264.   
  1265. ***************
  1266. *** 679,685
  1267.           fputs(buf, output);
  1268.   
  1269.           if (messages[i].Subject != NULL) {
  1270. !             sprintf(buf, "Subject: %s\n", messages[i].Subject);
  1271.               digestsize += strlen(buf);
  1272.               fputs(buf, output);
  1273.           }
  1274.  
  1275. --- 682,689 -----
  1276.           fputs(buf, output);
  1277.   
  1278.           if (messages[i].Subject != NULL) {
  1279. !             sprintf(buf, "Subject: %s\n\n", messages[i].Subject);
  1280. !         } else sprintf(buf, "\n");
  1281.               digestsize += strlen(buf);
  1282.               fputs(buf, output);
  1283.   
  1284. ***************
  1285. *** 682,688
  1286.               sprintf(buf, "Subject: %s\n", messages[i].Subject);
  1287.               digestsize += strlen(buf);
  1288.               fputs(buf, output);
  1289. -         }
  1290.   
  1291.           sprintf(buf, "To: %s\n\n", messages[i].To);
  1292.           digestsize += strlen(buf);
  1293.  
  1294. --- 686,691 -----
  1295.           } else sprintf(buf, "\n");
  1296.               digestsize += strlen(buf);
  1297.               fputs(buf, output);
  1298.   
  1299.   #ifdef INTO
  1300.           sprintf(buf, "To: %s\n\n", messages[i].To);
  1301. ***************
  1302. *** 684,689
  1303.               fputs(buf, output);
  1304.           }
  1305.   
  1306.           sprintf(buf, "To: %s\n\n", messages[i].To);
  1307.           digestsize += strlen(buf);
  1308.           fputs(buf, output);
  1309.  
  1310. --- 687,693 -----
  1311.               digestsize += strlen(buf);
  1312.               fputs(buf, output);
  1313.   
  1314. + #ifdef INTO
  1315.           sprintf(buf, "To: %s\n\n", messages[i].To);
  1316.           digestsize += strlen(buf);
  1317.           fputs(buf, output);
  1318. ***************
  1319. *** 687,692
  1320.           sprintf(buf, "To: %s\n\n", messages[i].To);
  1321.           digestsize += strlen(buf);
  1322.           fputs(buf, output);
  1323.   
  1324.           /*
  1325.            * Read the message into memory.  This is
  1326.  
  1327. --- 691,697 -----
  1328.           sprintf(buf, "To: %s\n\n", messages[i].To);
  1329.           digestsize += strlen(buf);
  1330.           fputs(buf, output);
  1331. + #endif INTO
  1332.   
  1333.           /*
  1334.            * Read the message into memory.  This is
  1335. ***************
  1336. *** 772,777
  1337.       }
  1338.   
  1339.       fprintf(fp, "%s\n", listinfo.Title);
  1340.       fprintf(fp, "%s\n", listinfo.Host);
  1341.       fprintf(fp, "%s\n", listinfo.From);
  1342.   #ifdef OLD
  1343.  
  1344. --- 777,783 -----
  1345.       }
  1346.   
  1347.       fprintf(fp, "%s\n", listinfo.Title);
  1348. +     fprintf(fp, "%s\n", listinfo.Address);
  1349.       fprintf(fp, "%s\n", listinfo.Host);
  1350.       fprintf(fp, "%s\n", listinfo.From);
  1351.   #ifdef OLD
  1352. -------------------------------
  1353. Unix Technical
  1354. unix
  1355. cbosgd.UUCP
  1356. Ron Heiby (The Moderator) <unix-request@cbosgd.UUCP>
  1357. Volume  1 : Issue  14
  1358. Wed, 13 Feb 85 04:13:30 GMT
  1359.  
  1360.  
  1361. From cbosgd!ihnp4!wnuxb!netnews Thu Mar 14 00:41:42 1985
  1362. Received: by genrad.UUCP (4.12/4.7)
  1363.     id AA17962; Thu, 14 Mar 85 00:41:40 est
  1364. From: ihnp4!wnuxb!netnews
  1365. Message-Id: <8503140334.AA21213@cbosgd.ATT.UUCP>
  1366. Received: by cbosgd.ATT.UUCP (4.12/3.73boo)
  1367.     id AA21213; Wed, 13 Mar 85 22:34:23 est
  1368. Date: 13 Mar 85 21:32:22 CST (Wed)
  1369. Received: by ihnp4.ATT.UUCP; id AA15294; 13 Mar 85 21:32:22 CST (Wed)
  1370. To: ihnp4!cbosgd!moderators
  1371. Subject: Re: New digest software
  1372. Status: R
  1373.  
  1374. There seems to be a bug in digest.c in the date area.  Just after we
  1375. find out what the current time is and fill in the tm struct, there is
  1376. a line that says, "t->tm_mon--;".  This puts the message one month
  1377. into the past on my System V machine.  I have removed the line.  Ron.
  1378.  
  1379.  
  1380.