home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 October / usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso / unix / volume6 / elm / part14 < prev    next >
Text File  |  1986-11-30  |  39KB  |  1,626 lines

  1. Subject: v06i039:  Elm mail system (elm) Part14/14
  2. Newsgroups: mod.sources
  3. Approved: rs@mirror.UUCP
  4.  
  5. Submitted by: Dave Taylor <pyramid!hplabs!hpldat!taylor>
  6. Mod.sources: Volume 6, Issue 39
  7. Archive-name: elm/Part14
  8.  
  9. [  Last time, when MSG was posted, the moderator posted copies of the
  10.    documentation.  With Dave's cooperation, this time we are making
  11.    available laser-printer hardcopy.  People in the Northeast corner of
  12.    North America can get copies by mailing me their name and postal
  13.    address; I will send out a copy, and forward their name on to Dave
  14.    so he can maintain a list of users.  People in other parts of the
  15.    world should send Dave their address; he will add other "regional
  16.    distributors" as necessary.  --r$  ]
  17.  
  18. # Continuation of Shell Archive, created by hpldat!taylor
  19.  
  20. # This is part 14
  21.  
  22. # To unpack the enclosed files, please use this file as input to the
  23. # Bourne (sh) shell.  This can be most easily done by the command;
  24. #     sh < thisfilename
  25.  
  26.  
  27. if [ ! -d utils ]
  28. then
  29.   echo creating directory utils
  30.   mkdir utils
  31. fi
  32.  
  33. # ---------- file utils/readmsg.c ----------
  34.  
  35. filename="utils/readmsg.c"
  36.  
  37. if [ -f $filename ]
  38. then
  39.   echo File \"$filename\" already exists\!  Skipping...
  40.   filename=/dev/null        # throw it away
  41. else
  42.   echo extracting file utils/readmsg.c...
  43. fi
  44.  
  45. cat << 'END-OF-FILE' > $filename
  46. /**            readmsg.c            **/
  47.  
  48. /** This routine adds the functionality of the "~r" command to the Elm mail 
  49.     system while still allowing the user to use the editor of their choice.
  50.  
  51.     The program, without any arguments, tries to read a file in the users home 
  52.     directory called ".readmsg" (actually defined in the sysdefs.h system 
  53.     defines file) and if it finds it reads the current message.  If it doesn't 
  54.     find it, it will return a usage error.
  55.  
  56.     The program can also be called with an explicit message number, list of 
  57.     message numbers, or a string to match in the message (including the header).
  58.     NOTE that when you use the string matching option it will match the first 
  59.     message containing that EXACT (case sensitive) string and then exit.
  60.  
  61.     Changed 5/86 to SORT the input list of message numbers to ensure that
  62.     they're in first-to-last order...
  63.  
  64.     Added the "weed" option as the default.  This is inspired by the mail
  65.     system used at NASA RIACS.  If THEY can do it, so can we!!
  66.  
  67.     (C) Copyright 1985, Dave Taylor
  68.  
  69. **/
  70.  
  71. #include <stdio.h>
  72. #include <ctype.h>
  73.  
  74. #include "defs.h"
  75.  
  76. /** three defines for what level of headers to display **/
  77.  
  78. #define ALL        1
  79. #define WEED        2
  80. #define NONE        3
  81.  
  82. static char ident[] = { WHAT_STRING };
  83.  
  84. #define  MAX_LIST    25        /* largest single list of arguments */
  85.  
  86. #define  LAST_MESSAGE    9999        /* last message in list ('$' char)  */
  87. #define  LAST_CHAR    '$'        /* char to delimit last message..   */
  88.  
  89. int read_message[MAX_LIST];         /* list of messages to read        */
  90. int messages = 0;            /* index into list of messages      */
  91.  
  92. int numcmp();                /* strcmp, but for numbers          */
  93. char *words();                /* function defined below...        */
  94.  
  95. #define DONE    0            /* for use with the getopt        */
  96. #define ERROR   -1            /*   library call...            */
  97.  
  98. extern char *optional_arg;        /* for parsing the ...             */
  99. extern int   opt_index;            /*  .. starting arguments           */
  100.  
  101. main(argc, argv)
  102. int argc;
  103. char *argv[];
  104. {
  105.     FILE *file;                    /* generic file descriptor! */
  106.     char filename[SLEN],             /* filename buffer          */
  107.          infile[SLEN],            /* input filename        */
  108.          buffer[SLEN],             /* file reading buffer      */
  109.          string[SLEN];            /* string match buffer      */
  110.  
  111.     int current_in_queue = 0,         /* these are used for...     */
  112.         current = 0,            /* ...going through msgs     */
  113.         num,                 /* for argument parsing      */
  114.         page_breaks = 0,            /* use "^L" breaks??         */
  115.             total,                /* number of msgs current    */
  116.         include_headers = WEED,         /* flag: include msg header? */
  117.         last_message = 0,             /* flag: read last message?  */
  118.         not_in_header = 0,            /* flag: in msg header?      */
  119.         string_match = 0;            /* flag: using string match? */
  120.  
  121.     /**** start of the actual program ****/
  122.  
  123.     while ((num = get_options(argc, argv, "nhf:p")) > 0) {
  124.       switch (num) {
  125.         case 'n' : include_headers = NONE;        break;
  126.         case 'h' : include_headers = ALL;        break;
  127.         case 'f' : strcpy(infile, optional_arg);    break;
  128.         case 'p' : page_breaks++;            break;
  129.       }
  130.     }
  131.     
  132.     if (num == ERROR) {
  133.       printf("Usage: %s [-n|-h] [-f filename] [-p] <message list>\n",
  134.           argv[0]);
  135.       exit(1);
  136.     }
  137.  
  138.     /** whip past the starting arguments so that we're pointing
  139.         to the right stuff... **/
  140.  
  141.     *argv++;    /* past the program name... */
  142.  
  143.     while (opt_index-- > 1) {
  144.       *argv++;
  145.       argc--;
  146.     }
  147.  
  148.     /** now let's figure out the parameters to the program... **/
  149.  
  150.     if (argc == 1) {    /* no arguments... called from 'Elm'? */
  151.       sprintf(filename, "%s/%s", getenv("HOME"), readmsg_file);
  152.       if ((file = fopen(filename, "r")) != NULL) {
  153.         fscanf(file, "%d", &(read_message[messages++]));
  154.         fclose(file);
  155.       }
  156.       else {    /* no arguments AND no .readmsg file!! */
  157.         fprintf(stderr,
  158.             "Usage: readmsg [-n|-h] [-f filename] [-p] <message list>\n");
  159.         exit(1);
  160.       }
  161.     }
  162.     else if (! isdigit(*argv[0]) && *argv[0] != LAST_CHAR) {  
  163.       string_match++;
  164.      
  165.       while (*argv)
  166.         sprintf(string, "%s%s%s", string, string[0] == '\0'? "" : " ",
  167.             *argv++);
  168.     }
  169.     else {                         /* list of nums   */
  170.  
  171.       while (--argc > 0) {
  172.         num = -1;
  173.  
  174.         sscanf(*argv,"%d", &num);
  175.  
  176.         if (num < 0) {
  177.           if (*argv[0] == LAST_CHAR) {
  178.             last_message++;
  179.         num = LAST_MESSAGE;
  180.           }
  181.           else {
  182.             fprintf(stderr,"I don't understand what '%s' means...\n",
  183.             *argv); 
  184.                exit(1); 
  185.           }
  186.         }
  187.         else if (num == 0) {    /* another way to say "last" */
  188.           last_message++;
  189.           num = LAST_MESSAGE;
  190.         }
  191.  
  192.         *argv++; 
  193.  
  194.         read_message[messages++] = num;
  195.       }
  196.  
  197.       /** and now sort 'em to ensure they're in a reasonable order... **/
  198.  
  199.       qsort(read_message, messages, sizeof(int), numcmp);
  200.     }
  201.  
  202.     /** Now let's get to the mail file... **/
  203.  
  204.     if (strlen(infile) == 0) 
  205.       sprintf(infile, "%s/%s", mailhome, getenv("LOGNAME"));
  206.  
  207.     if ((file = fopen(infile, "r")) == NULL) {
  208.       printf("But you have no mail!\n");
  209.       exit(0);
  210.     }
  211.  
  212.     /** Now it's open, let's display some 'ole messages!! **/
  213.  
  214.     if (string_match || last_message) {   /* pass through it once */
  215.  
  216.       if (last_message) {
  217.         total = count_messages(file);    /* instantiate count */
  218.         for (num=0; num < messages; num++)
  219.           if (read_message[num] == LAST_MESSAGE)
  220.         read_message[num] = total;
  221.       }
  222.       else if (string_match)
  223.         match_string(file, string);        /* stick msg# in list */
  224.  
  225.       if (total == 0 && ! string_match) {
  226.         printf("There aren't any messages to read!\n");
  227.         exit(0);
  228.       }
  229.     }
  230.  
  231.      /** now let's have some fun! **/
  232.     
  233.     while (fgets(buffer, SLEN, file) != NULL) {
  234.       if (strncmp(buffer, "From ", 5) == 0) {
  235.         if (current == read_message[current_in_queue])
  236.           current_in_queue++;
  237.         if (current_in_queue >= messages) 
  238.           exit(0);
  239.         current++;
  240.         if (current == read_message[current_in_queue] && page_breaks
  241.            && current_in_queue > 0) 
  242.           putchar(FORMFEED);
  243.         not_in_header = 0;    /* we're in the header! */
  244.       }
  245.       if ((current == read_message[current_in_queue]))
  246.         if (include_headers==ALL || not_in_header)
  247.           printf("%s", buffer);
  248.         else if (strlen(buffer) < 2) {
  249.           not_in_header++;
  250.           if (include_headers==WEED) 
  251.         list_saved_headers();
  252.         }
  253.         else if (include_headers==WEED)
  254.           possibly_save(buffer);     /* check to see if we want this */ 
  255.     }
  256.     
  257.     exit(0);
  258. }
  259.  
  260. int
  261. count_messages(file)
  262. FILE *file;
  263. {
  264.     /** Returns the number of messages in the file **/
  265.  
  266.     char buffer[SLEN];
  267.     int  count = 0;
  268.  
  269.     while (fgets(buffer, SLEN, file) != NULL)
  270.       if (strncmp(buffer, "From ", 5) == 0)
  271.         count++;
  272.  
  273.     rewind( file );
  274.     return( count );
  275. }
  276.  
  277. match_string(mailfile, string)
  278. FILE *mailfile;
  279. char *string;
  280. {
  281.     /** Increment "messages" and put the number of the message
  282.         in the message_count[] buffer until we match the specified 
  283.         string... **/
  284.  
  285.     char buffer[SLEN];
  286.     int  message_count;
  287.  
  288.     while (fgets(buffer, SLEN, mailfile) != NULL) {
  289.       if (strncmp(buffer, "From ", 5) == 0)
  290.         message_count++;
  291.  
  292.       if (in_string(buffer, string)) {
  293.         read_message[messages++] = message_count;
  294.         rewind(mailfile);    
  295.         return;
  296.       }
  297.     }
  298.  
  299.     fprintf(stderr,"Couldn't find message containing '%s'\n", string);
  300.     exit(1);
  301. }
  302.  
  303. int 
  304. in_string(buffer, pattern)
  305. char *buffer, *pattern;
  306. {
  307.     /** Returns TRUE iff pattern occurs IN IT'S ENTIRETY in buffer. **/ 
  308.  
  309.     register int i = 0, j = 0;
  310.     
  311.     while (buffer[i] != '\0') {
  312.       while (buffer[i++] == pattern[j++]) 
  313.         if (pattern[j] == '\0') 
  314.           return(TRUE);
  315.       i = i - j + 1;
  316.       j = 0;
  317.     }
  318.     return(FALSE);
  319. }
  320.  
  321. int 
  322. numcmp(a, b)
  323. int *a, *b;
  324. {
  325.     /** compare 'a' to 'b' returning less than, equal, or greater
  326.         than, accordingly.
  327.      **/
  328.  
  329.     return(*a - *b);
  330. }
  331.  
  332. static char from[SLEN], subject[SLEN], date[SLEN];
  333.  
  334. possibly_save(buffer)
  335. char *buffer;
  336. {
  337.     /** Check to see what "buffer" is...save it if it looks 
  338.         interesting... We'll always try to get SOMETHING
  339.         by tearing apart the "From " line...  **/
  340.  
  341.     if (strncmp(buffer, "Date:", 5) == 0)
  342.       strcpy(date, buffer);
  343.     else if (strncmp(buffer, "Subject:", 8) == 0)
  344.       strcpy(subject,buffer);
  345.     else if (strncmp(buffer,"From:", 5) == 0)
  346.       strcpy(from, buffer);
  347.     else if (strncmp(buffer,"From ", 5) == 0) {
  348.       sprintf(from, "From: %s\n", words(2,1, buffer));    
  349.       sprintf(date,"Date: %s",    words(3,7, buffer));
  350.     }
  351. }
  352.  
  353. list_saved_headers()
  354. {
  355.     /** This routine will display the information saved from the
  356.         message being listed...If it displays anything it'll end
  357.         with a blank line... **/
  358.  
  359.     register int displayed_line = FALSE;
  360.  
  361.     if (strlen(from)    > 0) { printf("%s", from);    displayed_line++;}
  362.     if (strlen(subject) > 0) { printf("%s", subject); displayed_line++;}
  363.     if (strlen(date)    > 0) { printf("%s", date);    displayed_line++;}
  364.     
  365.     if (displayed_line)
  366.        putchar('\n');
  367. }
  368.  
  369. char *words(word, num_words, buffer)
  370. int word, num_words;
  371. char *buffer;
  372. {
  373.     /** Return a buffer starting at 'word' and containing 'num_words'
  374.         words from buffer.  Assume white space will delimit each word.
  375.     **/
  376.  
  377.     static char internal_buffer[SLEN];
  378.     char   *wordptr, *bufptr, mybuffer[SLEN], *strtok();
  379.     int    wordnumber = 0, copying_words = 0;
  380.  
  381.     internal_buffer[0] = '\0';    /* initialize */
  382.  
  383.     strcpy(mybuffer, buffer);
  384.     bufptr = (char *) mybuffer;    /* and setup */
  385.  
  386.     while ((wordptr = strtok(bufptr, " \t")) != NULL) {
  387.       if (++wordnumber == word) {
  388.         strcpy(internal_buffer, wordptr);
  389.         copying_words++;
  390.         num_words--;
  391.       }
  392.       else if (copying_words) {
  393.         strcat(internal_buffer, " ");
  394.         strcat(internal_buffer, wordptr);
  395.         num_words--;
  396.       }
  397.  
  398.       if (num_words < 1) 
  399.         return((char *) internal_buffer);
  400.  
  401.       bufptr = NULL;
  402.     }
  403.  
  404.     return( (char *) internal_buffer);
  405. }
  406.  
  407.  
  408.     
  409. END-OF-FILE
  410.  
  411. if [ "$filename" != "/dev/null" ]
  412. then
  413.   size=`wc -c < $filename`
  414.  
  415.   if [ $size != 9564 ]
  416.   then
  417.     echo $filename changed - should be 9564 bytes, not $size bytes
  418.   fi
  419.  
  420.   chmod 666 $filename
  421. fi
  422.  
  423. # ---------- file utils/Makefile ----------
  424.  
  425. filename="utils/Makefile"
  426.  
  427. if [ -f $filename ]
  428. then
  429.   echo File \"$filename\" already exists\!  Skipping...
  430.   filename=/dev/null        # throw it away
  431. else
  432.   echo extracting file utils/Makefile...
  433. fi
  434.  
  435. cat << 'END-OF-FILE' > $filename
  436. #
  437. #  Makefile for the MSG system utilities
  438. #
  439. #         (C) Copyright 1986, Dave Taylor
  440. #
  441. #  Last modification: March 5th, 1986
  442.  
  443. SHELL=/bin/sh
  444.  
  445. ##############################
  446. #
  447. # if on a BSD system;
  448. #   DEFINE=-DBSD
  449. #   LIB2  = -lcurses
  450. # else if on a UTS system;
  451. #   DEFINE=-DUTS
  452. #   LIB2  = -la
  453. # else if on a SUN system;
  454. #   DEFINE=-DBSD -DSUN
  455. #   LIB2  = -lcurses
  456. # else if on a Pyramid system;
  457. #   DEFINE=-DBSD -DNO_VAR_ARGS
  458. #   LIB2  = -lcurses
  459. # else
  460.  
  461.     DEFINE=
  462.     LIB2  =
  463.  
  464. ##############################
  465.  
  466. CFLAGS= -O -I../hdrs
  467. CC=    /bin/cc
  468. RM=     /bin/rm
  469. ECHO=  /bin/echo
  470.  
  471. OBJS=    ../bin/newalias ../bin/from ../bin/newmail ../bin/answer       \
  472.     ../bin/printmail ../bin/fastmail ../bin/readmsg                \
  473.     ../bin/checkalias ../bin/arepdaemon ../bin/autoreply ../bin/wnewmail
  474.  
  475. all: ${OBJS}
  476.  
  477. ../bin/newalias:  ../hdrs/defs.h newalias.c ../src/validname.o \
  478.     ../src/opt_utils.o
  479.     ${CC} ${CFLAGS} ${DEFINE} newalias.c ../src/validname.o \
  480.     ../src/opt_utils.o -o ../bin/newalias 
  481.  
  482. ../bin/from: from.c ../src/opt_utils.o ../src/string2.o
  483.     ${CC} ${CFLAGS} ${DEFINE} from.c ../src/opt_utils.o \
  484.     ../src/string2.o -o ../bin/from
  485.  
  486. ../bin/newmail: ../src/opt_utils.c newmail.c ../src/string2.o
  487.     ${CC} ${CFLAGS} ${DEFINE} newmail.c \
  488.     ../src/string2.o -o ../bin/newmail
  489.  
  490. ../bin/wnewmail: ../src/opt_utils.c wnewmail.c ../src/string2.o
  491.     ${CC} ${CFLAGS} ${DEFINE} ../src/opt_utils.o \
  492.     ../src/string2.o wnewmail.c -o ../bin/wnewmail
  493.  
  494. ../bin/answer: answer.c ../src/opt_utils.o
  495.     ${CC} ${CFLAGS} ${DEFINE} answer.c ../src/opt_utils.o -o ../bin/answer
  496.  
  497. ../bin/printmail: printmail.c ../src/opt_utils.o
  498.     ${CC} ${CFLAGS} ${DEFINE} printmail.c ../src/opt_utils.o \
  499.     -o ../bin/printmail
  500.  
  501. ../bin/fastmail: fastmail.c 
  502.     ${CC} ${CFLAGS} ${DEFINE} fastmail.c ../src/opt_utils.o \
  503.     -o ../bin/fastmail
  504.  
  505. ../bin/readmsg: readmsg.c ../src/getopt.o ../src/opt_utils.o
  506.     ${CC} ${CFLAGS} ${DEFINE} readmsg.c ../src/getopt.o \
  507.     ../src/opt_utils.o -o ../bin/readmsg
  508.  
  509. ../bin/arepdaemon: arepdaemon.c
  510.     ${CC} ${CFLAGS} ${DEFINE} arepdaemon.c -o ../bin/arepdaemon
  511.  
  512. ../bin/autoreply: autoreply.c ../src/opt_utils.o
  513.     ${CC} ${CFLAGS} ${DEFINE} autoreply.c ../src/opt_utils.o \
  514.     -o ../bin/autoreply
  515.  
  516. ../bin/checkalias: 
  517.     @echo '#!/bin/sh' > ../bin/checkalias
  518.     @echo 'if [ -z "$$*" ]; then' >> ../bin/checkalias
  519.     @echo '  echo Usage: checkalias alias \[or aliases\]' >>  \
  520.           ../bin/checkalias
  521.     @echo '  exit 1' >> ../bin/checkalias
  522.     @echo 'fi' >> ../bin/checkalias
  523.     @echo ' '  >> ../bin/checkalias
  524.     @echo 'exec elm -c $*' >> ../bin/checkalias
  525.     @chmod +x ../bin/checkalias
  526.  
  527. ../src/validname.o: ../src/validname.c
  528.     @(cd ../src; ${CC} -c ${CFLAGS} ${DEFINE} validname.c; cd ../utils)
  529.  
  530. ../src/opt_utils.o: ../src/opt_utils.c
  531.     @(cd ../src; ${CC} -c ${CFLAGS} ${DEFINE} opt_utils.c; cd ../utils)
  532.  
  533. ../src/getopt.o: ../src/getopt.c
  534.     @(cd ../src; ${CC} -c ${CFLAGS} ${DEFINE} getopt.c; cd ../utils)
  535.  
  536. ../src/string2.o: ../src/string2.c
  537.     @(cd ../src; ${CC} -c ${CFLAGS} ${DEFINE} string2.c; cd ../utils)
  538.  
  539. clean:
  540.     ${RM} *.o ${OBJS}
  541.  
  542. lint:
  543.     lint -p -I../hdrs *.c > LINT.OUT
  544. END-OF-FILE
  545.  
  546. if [ "$filename" != "/dev/null" ]
  547. then
  548.   size=`wc -c < $filename`
  549.  
  550.   if [ $size != 3031 ]
  551.   then
  552.     echo $filename changed - should be 3031 bytes, not $size bytes
  553.   fi
  554.  
  555.   chmod 666 $filename
  556. fi
  557.  
  558. # ---------- file utils/breakup.c ----------
  559.  
  560. filename="utils/breakup.c"
  561.  
  562. if [ -f $filename ]
  563. then
  564.   echo File \"$filename\" already exists\!  Skipping...
  565.   filename=/dev/null        # throw it away
  566. else
  567.   echo extracting file utils/breakup.c...
  568. fi
  569.  
  570. cat << 'END-OF-FILE' > $filename
  571. /**            breakup.c            **/
  572.  
  573. /** This program reads in a rather LARGE number of mail files (folders)
  574.     from a directory OTHER THAN THE CURRENT ONE and breaks each into
  575.     a file per message (each message being put into the directory
  576.     MESSAGES) and adds entries for each message in a mailbox with the
  577.     same name as the source mailbox.  The format of each new mailbox
  578.     is;
  579.  
  580.     FILE: <filename>
  581.     SUBJECT: <subject>
  582.     FROM: <from>
  583.     TO: <to>
  584.     SENT: <sent date>
  585.     RECEIVED: <received date>
  586.     
  587.     (enough information so that indexes can be generated without actually
  588.      having to reference the files in question...)
  589.  
  590.     filename is "YY-MM-DD.number" where YY-MM-DD is the date the
  591.              message was received (in this order for sorting)
  592.     from is the persons name or machine!user address ONLY
  593.     dates are MM-DD-YY, HH:MM ONLY.
  594.  
  595.     (C) Copyright 1986, Dave Taylor
  596. **/
  597.  
  598. #include <stdio.h>
  599. #include <errno.h>
  600.  
  601. #include "defs.h"
  602.  
  603. static int ident[] = { WHAT_STRING };
  604.  
  605. extern int errno;
  606.  
  607. #define  first_word(s,w)    strncmp(s, w, strlen(w))
  608.  
  609. #define  MESSAGES        "MESSAGES"
  610. #define  seqfile        "MESSAGES/.msg_sequence"
  611. #define  SLEN            80
  612.  
  613. char *monthnames[] = { "month-zero",
  614.     "January", "February", "March", "April", "May", "June",
  615.     "July", "August", "September", "October", "November", "December",
  616.     "month-thirteen" };
  617.  
  618. FILE *boxfd;
  619. int  messagenum = 1;
  620.  
  621. char *strtok();
  622.  
  623. main(argc, argv)
  624. int argc;
  625. char *argv[];
  626. {
  627.     FILE *fd, *outfd;
  628.     char filename[SLEN], *basename(), *box_name;
  629.     int  start;
  630.  
  631.     if (argc == 1)
  632.       exit(printf("Usage: breakup <list of files>\n"));
  633.  
  634.     if (access(MESSAGES, 00) == -1)
  635.       exit(printf("Need 'MESSAGES' directory in this directory!\n"));
  636.  
  637.     if ((fd = fopen(seqfile, "r")) == NULL)
  638.       printf("Warning: No sequence file.  Starting with sequence #1\n");
  639.     else {
  640.       fscanf(fd,"%d", &messagenum);
  641.       printf("Starting sequencing with #%d\n", messagenum);
  642.       fclose(fd);
  643.     }
  644.  
  645.     *argv++;
  646.  
  647.     start = messagenum;
  648.  
  649.     while (--argc) {
  650.       if ((fd = fopen(*argv, "r")) == NULL) 
  651.         leave(printf("\nCouldn't open file '%s' for reading!\n", *argv));
  652.       
  653.       box_name = basename(*argv);
  654.     
  655.       if ((boxfd = fopen(box_name, "w")) == NULL)
  656.         leave(printf("\nCouldn't open box '%s' for writing!\n", box_name));
  657.  
  658.       printf("%s...", *argv);  fflush(stdout);
  659.  
  660.       break_up(fd, &messagenum);
  661.  
  662.       *argv++;
  663.       fclose(boxfd);
  664.       fclose(fd);
  665.     }
  666.  
  667.     printf("\nSuccessfully broke into %d messages!\n", messagenum - start);
  668.  
  669.     leave();
  670. }
  671.  
  672. leave()
  673. {
  674.     /** leave, updating messagenum **/
  675.  
  676.     FILE *fd;
  677.  
  678.     if ((fd = fopen(seqfile, "w")) == NULL) 
  679.       printf("Warning: couldn't update sequence file '%s'\n", seqfile);
  680.     else {
  681.       fprintf(fd, "%d", messagenum);
  682.       fclose(fd);
  683.     }
  684.  
  685.     exit(0);
  686. }
  687.  
  688. break_up(msgfd, messagenum)
  689. FILE *msgfd;
  690. int  *messagenum;
  691. {
  692.     /** break up the mailbox into it's component messages,
  693.         writing each one to a file as we go along **/
  694.  
  695.     FILE *outfd;
  696.     char filename[SLEN], buffer[SLEN], save_buffer[SLEN];
  697.     char *get_fdate(), *get_sdate(), *get_rdate();
  698.     char *extract_from(), *extract_date();
  699.     int  in_header = 0, file_open = 0, from_obtained=0;
  700.     int  date_obtained = 0;
  701.  
  702.     while (fgets(buffer, SLEN, msgfd) != NULL) {
  703.       if (first_word(buffer, "From ") == 0) {
  704.         sprintf(filename, "%s/%s.%d", MESSAGES, get_fdate(buffer, '/'), 
  705.            (*messagenum)++);
  706.         if (file_open) fclose(outfd);
  707.         check_for_dirs(filename);
  708.         if ((outfd = fopen(filename, "w")) == NULL)
  709.           leave(printf("Could not open file '%s' as message file!\n",
  710.             filename));
  711.  
  712.         fprintf(outfd, "%s", buffer);
  713.          fprintf(boxfd, "\nFile: %s\nReceived: %s\n", 
  714.             filename, get_rdate(buffer));
  715.         file_open++;
  716.         in_header++;
  717.         date_obtained = 0;
  718.         from_obtained = 0;
  719.         strcpy(save_buffer, buffer);
  720.       }
  721.       else if (file_open) {
  722.           if (in_header) {
  723.             if (first_word(buffer, "Subject:") == 0) 
  724.               fprintf(boxfd, "%s", buffer);
  725.         else if (first_word(buffer, "Date:") == 0) {
  726.           date_obtained++;
  727.               fprintf(boxfd, "Sent: %s\n", get_sdate());
  728.         }
  729.         else if (first_word(buffer, "From:") == 0) {
  730.               from_obtained++;
  731.           fprintf(boxfd, "%s", buffer);
  732.             }
  733.           else if (first_word(buffer,">From") == 0)
  734.               strcpy(save_buffer, buffer);
  735.         else if (strlen(buffer) < 2) {
  736.           in_header = 0;
  737.           if (! from_obtained) 
  738.             fprintf(boxfd, "%s\n", extract_from(save_buffer));
  739.           if (! date_obtained)
  740.             fprintf(boxfd, "Sent: %s\n", extract_date(save_buffer));
  741.         }
  742.           }
  743.           fprintf(outfd, "%s", buffer);
  744.        }
  745.     }
  746.  
  747.     if (file_open) {
  748.       if (! from_obtained) 
  749.         fprintf(boxfd, "From: %s", extract_from(save_buffer));
  750.       if (! date_obtained)
  751.         fprintf(boxfd, "Date: %s", extract_date(save_buffer));
  752.       fclose(msgfd);
  753.     }
  754. }
  755.  
  756. char *get_fdate(buffer, separator)
  757. char *buffer, separator;
  758. {
  759.     /** given a "From xyz" buffer, return the date in the format
  760.         YY?MM?DD for filenaming, where ? = the separator char. **/
  761.  
  762.     static char mybuf[SLEN];
  763.     char   monthname[SLEN];
  764.     int    month=0, day=0, year=0;
  765.  
  766.     sscanf(buffer, "%*s %*s %*s %s %d %*s %d", monthname, &day, &year);
  767.  
  768.     year = year % 1900;
  769.  
  770.     switch (tolower(monthname[0])) {
  771.       case 'j' : if (tolower(monthname[1]) == 'a')
  772.             month = 1;
  773.              else if (tolower(monthname[2]) == 'n')
  774.                     month = 6;
  775.              else
  776.                     month = 7;
  777.              break;
  778.       case 'f' : month = 2;        break;
  779.       case 'm' : if (tolower(monthname[2]) == 'r')
  780.                    month = 3;
  781.              else
  782.                month = 5;
  783.              break;
  784.       case 'a' : if (tolower(monthname[1]) == 'p')
  785.                    month = 4;
  786.              else
  787.                month = 8;
  788.              break;
  789.       case 's' : month = 9;        break;
  790.       case 'o' : month = 10;    break;
  791.       case 'n' : month = 11;    break;
  792.       case 'd' : month = 12;    break;
  793.     }
  794.  
  795.     sprintf(mybuf, "%d%c%s%c%d", year+1900, separator, 
  796.         monthnames[month], separator, day);
  797.  
  798.     return( (char *) mybuf);
  799. }
  800.  
  801. char *get_rdate(buffer)
  802. char *buffer;
  803. {
  804.     /** return buffer "From xyz <date>" in the format:
  805.         MM-DD-YY, HH:MM **/
  806.  
  807.     static char mybuf[SLEN];
  808.     char   monthname[20];
  809.     int    month=0, day=0, year=0, hour, minute;
  810.  
  811.     sscanf(buffer, "%*s %*s %*s %s %d %d:%d:%*d %d", 
  812.            monthname, &day, &hour, &minute, &year);
  813.  
  814.     year = year % 1900;
  815.  
  816.     switch (tolower(monthname[0])) {
  817.       case 'j' : if (tolower(monthname[1]) == 'a')
  818.             month = 1;
  819.              else if (tolower(monthname[2]) == 'n')
  820.                     month = 6;
  821.              else
  822.                     month = 7;
  823.              break;
  824.       case 'f' : month = 2;        break;
  825.       case 'm' : if (tolower(monthname[2]) == 'r')
  826.                    month = 3;
  827.              else
  828.                month = 5;
  829.              break;
  830.       case 'a' : if (tolower(monthname[1]) == 'p')
  831.                    month = 4;
  832.              else
  833.                month = 8;
  834.              break;
  835.       case 's' : month = 9;        break;
  836.       case 'o' : month = 10;    break;
  837.       case 'n' : month = 11;    break;
  838.       case 'd' : month = 12;    break;
  839.     }
  840.  
  841.     sprintf(mybuf, "%d-%d-%d, %d:%d", month, day, year, hour, minute);
  842.  
  843.     return( (char *) mybuf);
  844. }
  845.  
  846. char *get_sdate()
  847. {
  848.     return( NULL );
  849. }
  850.  
  851. char *extract_from(buffer)
  852. char *buffer;
  853. {
  854.     /** extract machine!userid from ">From buffer.. and return From: x!z **/
  855.     /** if userid = To: <someone>, then return that field instead **/
  856.  
  857.     static char mybuf[SLEN];
  858.     char   name[SLEN], machine[SLEN];
  859.  
  860.     sscanf(buffer,"%*s %s %*s %*s %*s %*s %*s %*s %*s %s", name, machine);
  861.  
  862.     if (strncmp(name, "To:", 3) == 0)
  863.       strcpy(mybuf, name);
  864.     else if (strlen(machine) > 0)
  865.       sprintf(mybuf, "From: %s!%s", machine, name);
  866.     else
  867.       sprintf(mybuf, "From: ", name);
  868.  
  869.     return( (char *) mybuf);
  870. }
  871.  
  872. char *extract_date(buffer)
  873. char *buffer;
  874. {
  875.     /** extract the date, mm/dd/yy, hh:mm from the '>From' buffer **/
  876.  
  877.     static char mybuf[SLEN];
  878.     char   month[10], time[10];
  879.     int    day, year;
  880.  
  881.     sscanf(buffer, "%*s %*s %*s %s %d %s %d", month, &day, time, &year);
  882.  
  883.     year = year % 1900;
  884.  
  885.     sprintf(mybuf,"%s %d %d, %s", month, day, year, time);
  886.  
  887.     return( (char *) mybuf);
  888. }
  889.  
  890. check_for_dirs(fname)
  891. char *fname;
  892. {
  893.     /** Given a filename of the form x/y/z check for the existence of
  894.         the directories 'x' and 'y', and create them if they're not
  895.         currently there!  **/
  896.  
  897.     char buffer[SLEN], *dirname, dirbuf[SLEN], *bufptr;
  898.     int  loc, i;
  899.  
  900.     strcpy(buffer, fname);
  901.  
  902.     for (loc = strlen(fname)-1; buffer[loc] != '/'; loc--)
  903.         ;
  904.  
  905.     buffer[loc] = '\0';    /* broken into directories only! */
  906.  
  907.     bufptr = (char *) buffer;
  908.     dirbuf[0]= '\0';
  909.  
  910.     while ((dirname = strtok(bufptr,"/")) != NULL) {
  911.       if (strlen(dirbuf) > 0)
  912.         strcat(dirbuf, "/");
  913.       strcat(dirbuf, dirname);
  914.       if (access(dirbuf, 00) == -1) 
  915.         mkdir(dirbuf, 0700);
  916.       bufptr = NULL;
  917.     }
  918. }
  919.  
  920. char *basename(filename)
  921. char *filename;
  922. {
  923.     /** returns a string that is the BASENAME of the filename! **/
  924.  
  925.     static char mybuffer[SLEN];
  926.     register int loc, firstch = 0;
  927.  
  928.     for (loc = 0; filename[loc] != '\0'; loc++)    
  929.       if (filename[loc] == '/')
  930.         firstch = loc+1;
  931.  
  932.     loc = 0;
  933.  
  934.     while (filename[firstch] != '\0')
  935.       mybuffer[loc++] = filename[firstch++];
  936.     mybuffer[loc] = '\0';
  937.  
  938.     return ( (char *) mybuffer);
  939. }
  940. END-OF-FILE
  941.  
  942. if [ "$filename" != "/dev/null" ]
  943. then
  944.   size=`wc -c < $filename`
  945.  
  946.   if [ $size != 8868 ]
  947.   then
  948.     echo $filename changed - should be 8868 bytes, not $size bytes
  949.   fi
  950.  
  951.   chmod 666 $filename
  952. fi
  953.  
  954. # ---------- file utils/mailrc.awk ----------
  955.  
  956. filename="utils/mailrc.awk"
  957.  
  958. if [ -f $filename ]
  959. then
  960.   echo File \"$filename\" already exists\!  Skipping...
  961.   filename=/dev/null        # throw it away
  962. else
  963.   echo extracting file utils/mailrc.awk...
  964. fi
  965.  
  966. cat << 'END-OF-FILE' > $filename
  967. BEGIN { 
  968.     print "# MSG alias_text file, from a .mailrc file..." 
  969.     print ""
  970.       }
  971.  
  972. next_line == 1 { 
  973.  
  974.     next_line = 0;
  975.         group = ""
  976.     for (i = 1; i <= NF; i++) {
  977.       if (i == NF && $i == "\\") sep = ""
  978.       else                       sep = ", "
  979.     
  980.       if ($i == "\\") {
  981.         group = sprintf("%s,", group)
  982.         next_line = 1;
  983.       }
  984.       else if (length(group) > 0)
  985.         group = sprintf("%s%s%s", group, sep, $i);
  986.       else
  987.         group = $i;
  988.       }
  989.       print "\t" group
  990.  
  991.     }
  992.  
  993. $1 ~ /[Aa]lias|[Gg]roup/ { 
  994.  
  995.     if ( NF == 3)
  996.       print $2 " : user alias : " $3;
  997.     else {
  998.       group = ""
  999.       for (i = 3; i <= NF; i++) {
  1000.         if (i == NF && $i == "\\") sep = ""
  1001.         else        sep = ", "
  1002.     
  1003.         if ($i == "\\") {
  1004.            group = sprintf("%s,", group)
  1005.            next_line = 1;
  1006.         }
  1007.         else if (length(group) > 0) 
  1008.            group = sprintf("%s%s%s", group, sep, $i);
  1009.         else
  1010.            group = $i;
  1011.         }
  1012.         print $2 " : group alias : " group;
  1013.       }
  1014.      }
  1015. END-OF-FILE
  1016.  
  1017. if [ "$filename" != "/dev/null" ]
  1018. then
  1019.   size=`wc -c < $filename`
  1020.  
  1021.   if [ $size != 930 ]
  1022.   then
  1023.     echo $filename changed - should be 930 bytes, not $size bytes
  1024.   fi
  1025.  
  1026.   chmod 666 $filename
  1027. fi
  1028.  
  1029. # ---------- file utils/wnewmail.c ----------
  1030.  
  1031. filename="utils/wnewmail.c"
  1032.  
  1033. if [ -f $filename ]
  1034. then
  1035.   echo File \"$filename\" already exists\!  Skipping...
  1036.   filename=/dev/null        # throw it away
  1037. else
  1038.   echo extracting file utils/wnewmail.c...
  1039. fi
  1040.  
  1041. cat << 'END-OF-FILE' > $filename
  1042. /**            wnewmail.c            **/
  1043.  
  1044. /** Same as newmail.c but for a windowing system...
  1045.     
  1046.     (C) Copyright 1986, Dave Taylor
  1047. **/
  1048.  
  1049. #ifdef AUTO_BACKGROUND
  1050. #include <signal.h>    /* background jobs ignore some signals... */
  1051. #endif
  1052.  
  1053. #include <stdio.h>
  1054. #include <sys/types.h>
  1055. #include <sys/stat.h>
  1056.  
  1057. #include "defs.h"
  1058.  
  1059. static char ident[] = { WHAT_STRING };
  1060.  
  1061. #define LINEFEED    (char) 10
  1062. #define BEGINNING    0            /* seek fseek(3S) */
  1063. #define SLEEP_TIME    10        
  1064.  
  1065. #define NO_SUBJECT    "(No Subject Specified)"
  1066.  
  1067. FILE *mailfile;
  1068.  
  1069. long  bytes();
  1070. char  *getusername();
  1071.  
  1072. main(argc, argv)
  1073. int argc;
  1074. char *argv[];
  1075. {
  1076.     char filename[LONG_SLEN];
  1077.     long size, newsize;
  1078.  
  1079.     if (argc > 2) 
  1080.       fprintf(stderr, "Usage: %s [filename] &\n", argv[0]);
  1081.     else if (argc == 2) {
  1082.       strcpy(filename, argv[1]);
  1083.       if (access(filename, ACCESS_EXISTS) == -1) {
  1084.         fprintf(stderr,"%s: Can't open file %s to keep track of!\n",
  1085.             argv[0], filename);
  1086.         exit(1);
  1087.       }
  1088.     }
  1089.     else
  1090.       sprintf(filename,"%s%s",mailhome, getusername());
  1091.  
  1092. #ifdef AUTO_BACKGROUND
  1093.     if (fork())        /* automatically puts this task in background! */
  1094.       exit(0);
  1095.  
  1096.     signal(SIGINT, SIG_IGN);
  1097.     signal(SIGQUIT, SIG_IGN);
  1098.     signal(SIGHUP,  SIG_DFL);    /* so we exit when logged out */
  1099. #endif
  1100.  
  1101.     size = bytes(filename);
  1102.  
  1103.     mailfile = (FILE *) NULL;
  1104.  
  1105.     printf("Incoming Mail;\n");
  1106.  
  1107.     while (1) {
  1108.     
  1109. #ifndef AUTO_BACKGROUND        /* won't work if we're nested this deep! */
  1110.       if (getppid() == 1)     /* we've lost our shell! */
  1111.         exit();
  1112. #endif
  1113.     
  1114.     /** Note the lack of error checking on the fopen() (Philip Peake
  1115.         did!) - this is okay since if it fails we don't have any 
  1116.         mail and we can sleep(60) and try again later... 
  1117.     **/
  1118.  
  1119.       if (mailfile == (FILE *) NULL) 
  1120.         mailfile = fopen(filename,"r");
  1121.  
  1122.       if ((newsize = bytes(filename)) > size) {    /* new mail */
  1123.         fseek(mailfile, size, BEGINNING); /* skip all current mail */
  1124.         size = newsize;
  1125.         printf("%c", 007);    /* beep for new mail! */
  1126.         read_headers();
  1127.       }
  1128.       else if (newsize != size) {
  1129.         size = newsize;         /* mail's been removed... */
  1130.         (void) fclose(mailfile);    /* close it and ...       */
  1131.         mailfile = (FILE *) NULL;    /* let's reopen the file  */
  1132.       }
  1133.  
  1134.       sleep(SLEEP_TIME);
  1135.     }
  1136. }
  1137.  
  1138. int
  1139. read_headers()
  1140. {
  1141.     /** read the headers, output as found **/
  1142.  
  1143.     char buffer[LONG_SLEN], from_whom[SLEN], subject[SLEN];
  1144.     register int subj = 0, in_header = 1, count = 0;
  1145.  
  1146.     while (fgets(buffer, LONG_SLEN, mailfile) != NULL) {
  1147.       if (first_word(buffer,"From ")) {
  1148.         if (real_from(buffer, from_whom)) {
  1149.           subj = 0;
  1150.           in_header = 1;
  1151.         }
  1152.       }
  1153.       else if (in_header) {
  1154.         if (first_word(buffer,">From")) 
  1155.           forwarded(buffer, from_whom); /* return address */
  1156.         else if (first_word(buffer,"Subject:") ||
  1157.              first_word(buffer,"Re:")) {
  1158.           if (! subj++) {
  1159.             remove_first_word(buffer);
  1160.         strcpy(subject, buffer);
  1161.           }
  1162.         }
  1163.         else if (first_word(buffer,"From:")) 
  1164.           parse_arpa_from(buffer, from_whom);
  1165.         else if (buffer[0] == LINEFEED) {
  1166.           in_header = 0;    /* in body of message! */
  1167.           show_header(from_whom, subject);
  1168.           from_whom[0] = 0;
  1169.           subject[0] = 0;
  1170.           count++;
  1171.         }
  1172.       }
  1173.     }
  1174.     return(count);
  1175. }
  1176.  
  1177. int
  1178. real_from(buffer, who)
  1179. char *buffer, *who;
  1180. {
  1181.     /***** returns true iff 's' has the seven 'from' fields,
  1182.            initializing the who to the sender *****/
  1183.  
  1184.     char junk[80];
  1185.  
  1186.     junk[0] = '\0';
  1187.     sscanf(buffer, "%*s %s %*s %*s %*s %*s %s",
  1188.                 who, junk);
  1189.     return(junk[0] != '\0');
  1190. }
  1191.  
  1192. forwarded(buffer, who)
  1193. char *buffer, *who;
  1194. {
  1195.     /** change 'from' and date fields to reflect the ORIGINATOR of 
  1196.         the message by iteratively parsing the >From fields... **/
  1197.  
  1198.     char machine[80], buff[80];
  1199.  
  1200.     machine[0] = '\0';
  1201.     sscanf(buffer, "%*s %s %*s %*s %*s %*s %*s %*s %*s %s",
  1202.                 who, machine);
  1203.  
  1204.     if (machine[0] == '\0') /* try for srm address */
  1205.       sscanf(buffer, "%*s %s %*s %*s %*s %*s %*s %*s %s",
  1206.                 who, machine);
  1207.  
  1208.     if (machine[0] == '\0')
  1209.       sprintf(buff,"anonymous");
  1210.     else
  1211.       sprintf(buff,"%s!%s", machine, who);
  1212.  
  1213.     strncpy(who, buff, 80);
  1214. }
  1215.  
  1216.  
  1217. remove_first_word(string)
  1218. char *string;
  1219. {    /** removes first word of string, ie up to first non-white space
  1220.         following a white space! **/
  1221.  
  1222.     register int loc;
  1223.  
  1224.     for (loc = 0; string[loc] != ' ' && string[loc] != '\0'; loc++) 
  1225.         ;
  1226.  
  1227.     while (string[loc] == ' ' || string[loc] == '\t')
  1228.       loc++;
  1229.     
  1230.     move_left(string, loc);
  1231. }
  1232.  
  1233. move_left(string, chars)
  1234. char string[];
  1235. int  chars;
  1236. {
  1237.     /** moves string chars characters to the left DESTRUCTIVELY **/
  1238.  
  1239.     register int i;
  1240.  
  1241.     chars--; /* index starting at zero! */
  1242.  
  1243.     for (i=chars; string[i] != '\0' && string[i] != '\n'; i++)
  1244.       string[i-chars] = string[i];
  1245.  
  1246.     string[i-chars] = '\0';
  1247. }
  1248.  
  1249. show_header(from, subject)
  1250. char *from, *subject;
  1251. {
  1252.     /** Output header in clean format, including abbreviation
  1253.         of return address if more than one machine name is
  1254.         contained within it! **/
  1255.  
  1256.     char buffer[SLEN];
  1257.     int  loc, i=0, exc=0;
  1258.  
  1259. #ifdef PREFER_UUCP
  1260.     
  1261.     if (chloc(from,'!') != -1 && in_string(from, BOGUS_INTERNET))
  1262.       from[strlen(from) - strlen(BOGUS_INTERNET)] = '\0';
  1263.  
  1264. #endif
  1265.  
  1266.     loc = strlen(from);
  1267.  
  1268.     while (exc < 2 && loc > 0)
  1269.       if (from[--loc] == '!')
  1270.         exc++;
  1271.  
  1272.     if (exc == 2) { /* lots of machine names!  Get last one */
  1273.       loc++;
  1274.       while (loc < strlen(from) && loc < SLEN)
  1275.         buffer[i++] = from[loc++];
  1276.       buffer[i] = '\0';
  1277.       strcpy(from, buffer);
  1278.     }
  1279.  
  1280.     if (strlen(subject) < 2)
  1281.       strcpy(subject, NO_SUBJECT);
  1282.     
  1283.       if (strlen(from) > 0)    /* last final check... */
  1284.         printf("Mail from %s -- %s\n", from, subject);
  1285. }    
  1286.  
  1287. parse_arpa_from(buffer, newfrom)
  1288. char *buffer, *newfrom;
  1289. {
  1290.     /** try to parse the 'From:' line given... It can be in one of
  1291.         two formats:
  1292.         From: Dave Taylor <hpcnou!dat>
  1293.         or  From: hpcnou!dat (Dave Taylor)
  1294.         Change 'newfrom' ONLY if sucessfully parsed this entry and
  1295.         the resulting name is non-null! 
  1296.     **/
  1297.  
  1298.     char temp_buffer[SLEN], *temp;
  1299.     register int i, j = 0;
  1300.  
  1301.     temp = (char *) temp_buffer;
  1302.     temp[0] = '\0';
  1303.  
  1304.     no_ret(buffer);        /* blow away '\n' char! */
  1305.  
  1306.     if (lastch(buffer) == '>') {
  1307.       for (i=strlen("From: "); buffer[i] != '\0' && buffer[i] != '<' &&
  1308.            buffer[i] != '('; i++)
  1309.         temp[j++] = buffer[i];
  1310.       temp[j] = '\0';
  1311.     }
  1312.     else if (lastch(buffer) == ')') {
  1313.       for (i=strlen(buffer)-2; buffer[i] != '\0' && buffer[i] != '(' &&
  1314.            buffer[i] != '<'; i--)
  1315.         temp[j++] = buffer[i];
  1316.       temp[j] = '\0';
  1317.       reverse(temp);
  1318.     }
  1319.       
  1320.     if (strlen(temp) > 0) {        /* mess with buffer... */
  1321.  
  1322.       /* remove leading spaces... */
  1323.  
  1324.       while (whitespace(temp[0]))
  1325.         temp = (char *) (temp + 1);        /* increment address! */
  1326.  
  1327.       /* remove trailing spaces... */
  1328.  
  1329.       i = strlen(temp) - 1;
  1330.  
  1331.       while (whitespace(temp[i]))
  1332.        temp[i--] = '\0';
  1333.  
  1334.       /* if anything is left, let's change 'from' value! */
  1335.  
  1336.       if (strlen(temp) > 0)
  1337.         strcpy(newfrom, temp);
  1338.     }
  1339. }
  1340.  
  1341. reverse(string)
  1342. char *string;
  1343. {
  1344.     /** reverse string... pretty trivial routine, actually! **/
  1345.  
  1346.     char buffer[SLEN];
  1347.     register int i, j = 0;
  1348.  
  1349.     for (i = strlen(string)-1; i >= 0; i--)
  1350.       buffer[j++] = string[i];
  1351.  
  1352.     buffer[j] = '\0';
  1353.  
  1354.     strcpy(string, buffer);
  1355. }
  1356.  
  1357. long
  1358. bytes(name)
  1359. char *name;
  1360. {
  1361.     /** return the number of bytes in the specified file.  This
  1362.         is to check to see if new mail has arrived....  **/
  1363.  
  1364.     int ok = 1;
  1365.     extern int errno;    /* system error number! */
  1366.     struct stat buffer;
  1367.  
  1368.     if (stat(name, &buffer) != 0)
  1369.       if (errno != 2)
  1370.        exit(fprintf(stderr,"Error %d attempting fstat on %s", errno, name));
  1371.       else
  1372.         ok = 0;
  1373.     
  1374.     return(ok ? (long) buffer.st_size : 0L);
  1375. }
  1376.  
  1377. char  *getusername()
  1378. {
  1379.     /** Getting the username on some systems is a real pain, so...
  1380.        This routine is guaranteed to return a usable username **/
  1381.  
  1382.     char *return_value, *cuserid(), *getlogin();
  1383.  
  1384.     if ((return_value = cuserid(NULL)) == NULL)
  1385.       if ((return_value = getlogin()) == NULL)
  1386.         exit(printf("Newmail: I can't get username!\n"));
  1387.  
  1388.     return( (char *) return_value);
  1389. }
  1390. END-OF-FILE
  1391.  
  1392. if [ "$filename" != "/dev/null" ]
  1393. then
  1394.   size=`wc -c < $filename`
  1395.  
  1396.   if [ $size != 7804 ]
  1397.   then
  1398.     echo $filename changed - should be 7804 bytes, not $size bytes
  1399.   fi
  1400.  
  1401.   chmod 666 $filename
  1402. fi
  1403.  
  1404. # ---------- file utils/page.c ----------
  1405.  
  1406. filename="utils/page.c"
  1407.  
  1408. if [ -f $filename ]
  1409. then
  1410.   echo File \"$filename\" already exists\!  Skipping...
  1411.   filename=/dev/null        # throw it away
  1412. else
  1413.   echo extracting file utils/page.c...
  1414. fi
  1415.  
  1416. cat << 'END-OF-FILE' > $filename
  1417. /**            page.c            **/
  1418.  
  1419. /** This is an alternative method of wandering through a file
  1420.     and is essentially a "read-only" editor.
  1421.  
  1422.     This is part of the Elm mail system, although it can be
  1423.     used by itself...
  1424.  
  1425.     The functions available are;
  1426.  
  1427.     h    help
  1428.  
  1429.     -,b    back a page
  1430.     u    back 1/2 a page
  1431.  
  1432.     ^M,+,f  forward a page
  1433.     d    forward 1/2 a page
  1434.  
  1435.     r    reread file (start over)
  1436.  
  1437.     /    skip forward to pattern
  1438.     ?    skip backwards to pattern (with no arg, same as "h")
  1439.  
  1440.     q    quit
  1441.  
  1442.    The starting flags are:
  1443.     
  1444.     -s    Use scrolling rather than paging
  1445.     
  1446.    Page is also smart enough to know that if it's reading stdin
  1447.    that it needs to open a temp file to stream the input into
  1448.    to allow paging AND also knows that it then needs to read 
  1449.    /dev/tty rather than stdin (think about it).
  1450.  
  1451.    (C) Copyright 1986 Dave Taylor
  1452. **/
  1453.  
  1454. #include <stdio.h>
  1455.  
  1456. #define SLEN        100
  1457.  
  1458. #define TOP_OF_PAGE    0
  1459. #define MIDDLE_OF_PAGE    1
  1460. #define MAX_PAGES    200    /* indicates how far back we'll remember  */
  1461.  
  1462. #define MIDDLE        0
  1463. #define END        1
  1464.  
  1465. #define TEMPFILENAME    "/tmp/page."
  1466.  
  1467. FILE *keyboard;            /* always read keyboard with this...       */
  1468. FILE *infile;            /* the file we're reading...           */
  1469. FILE *tempfile;            /* temp file for streaming input        */
  1470.  
  1471. int scrolling = 0,        /* Flag: should we scroll instead of page? */
  1472.     streaming = 0;        /* Flag: are we reading stdin for file?    */
  1473.  
  1474. long offsets[2][MAX_PAGES];    /* offsets into file as we go along        */
  1475.  
  1476. long current_offset;        /* offset into file currently           */
  1477. int  current_page,        /* what page we're on...           */
  1478.      loc_on_page,        /* where are we (HALF ON, or FULLY ON)       */
  1479.      line_on_page,        /* what line on the page (Screen)       */
  1480.      lines_per_page = 24;    /* lines per page on terminal           */
  1481.  
  1482. main(argc, argv)
  1483. int argc;
  1484. char *argv[];
  1485. {
  1486.     char filename[SLEN], buffer[SLEN];
  1487.  
  1488.     if (argc > 1) {
  1489.       strcpy(filename, argv[1]);
  1490.       keyboard = stdin;
  1491.     }
  1492.     else if (isatty(fileno(stdin))) 
  1493.       exit(printf("Nothing to page through!\n"));
  1494.     else {
  1495.       sprintf(filename, "%s.%d", TEMPFILENAME, getpid());
  1496.       streaming++;
  1497.       keyboard = fopen("/dev/tty", "r");
  1498.     }
  1499.  
  1500.     /** now let's open the file accordingly... **/
  1501.  
  1502.     if (streaming) {
  1503.       infile = stdin;
  1504.       if ((tempfile = fopen(filename, "w")) == NULL) 
  1505.         exit(printf("Can't open tempfile %s for paging!\n", filename));
  1506.     }
  1507.     else {
  1508.       if ((infile = fopen(filename, "r")) == NULL)
  1509.         exit(printf("Can't open file %s for reading!\n", filename));
  1510.     }
  1511.  
  1512.     /** initialize our variables... **/
  1513.  
  1514.     current_page = 0;
  1515.     current_offset = 0L;
  1516.     line_on_page = 0;
  1517.     loc_on_page  = TOP_OF_PAGE;
  1518.  
  1519.      if (getenv("LINES") != NULL) 
  1520.        lines_per_page = atoi(getenv("LINES")) - 2;
  1521.  
  1522.      offsets[TOP_OF_PAGE][current_page] = current_offset;    /* init */
  1523.  
  1524.      while (gets(buffer, SLEN, infile) != NULL) {
  1525.        line_on_page++;
  1526.        if (line_on_page == (int) (lines_per_page / 2)) 
  1527.          offsets[MIDDLE_OF_PAGE][current_page] = current_offset;
  1528.        else if (line_on_page == lines_per_page) {
  1529.          offsets[TOP_OF_PAGE][++current_page] = current_offset;
  1530.          next_page(MIDDLE);    /* could do a "seek" remember! */
  1531.        }
  1532.      }
  1533.      
  1534.      next_page(END);
  1535.  
  1536.      exit(0);
  1537.  }
  1538.      
  1539.  next_page(where)
  1540.  int where;
  1541.  {
  1542.      /** End of page processing..where is either "MIDDLE", indicating
  1543.          that we're in the middle of a file, or "END", indicating that
  1544.          we've already hit the EOF mark **/
  1545.  
  1546.      char buffer[3];
  1547.  
  1548. top:    printf("\n%s Command? ", where == MIDDLE? "More..." : 
  1549.            "End of Message -");
  1550.  
  1551.     fgets(buffer,2, keyboard);
  1552.  
  1553.     line_on_page = 0;
  1554.  
  1555.     switch (buffer[0]) {
  1556.       case '+'  :
  1557.       case 'f'  : 
  1558.       case '\n' : return;        /* scroll to next page */
  1559.       
  1560.       case 'd'  : line_on_page = (int) (lines_per_page / 2);
  1561.               return;        /* scroll 1/2 next page */
  1562.  
  1563.       case 'u'  : getto(offsets[MIDDLE_OF_PAGE][current_page-1]);
  1564.               return;
  1565.  
  1566.       case 'b'  :
  1567.       case '-'  : getto(offsets[TOP_OF_PAGE][current_page-1]);
  1568.                return;
  1569.  
  1570.       case 'q'  : exit(0);    /* we're outta here!! */
  1571.  
  1572.       case 'h'  : help();    goto top;    /* this again? */
  1573.  
  1574.       default   : printf("Unknown command.  Please use \"h\" for help\n");
  1575.               goto top;
  1576.     }
  1577. }
  1578.  
  1579. getto(offset)
  1580. long offset;
  1581. {
  1582.     /** This routine seeks to the specified point in the file and
  1583.         sets current page accordingly...     **/
  1584.  
  1585.     if (fseek(infile, offset, 0) != -1) 
  1586.       current_offset = offset;    /* whee! */
  1587. }
  1588.  
  1589. help()
  1590. {
  1591.     printf("\nThe following options are available;\n\n");
  1592.  
  1593.     printf("   h             help\n\n");
  1594.  
  1595.     printf("   -,b             back a page\n");
  1596.     printf("   u             back 1/2 a page\n\n");
  1597.  
  1598.     printf("   <return>,+,f  forward a page\n");
  1599.     printf("   d             forward 1/2 a page\n\n");
  1600.  
  1601.     printf("   r             reread file (start over)\n\n");
  1602.  
  1603.     printf("   /             skip forward to pattern\n");
  1604.     printf("   ?             skip backwards to pattern (with no arg, same as \"h\")\n\n");
  1605.  
  1606.     printf("   q             quit\n\n");
  1607. }
  1608. END-OF-FILE
  1609.  
  1610. if [ "$filename" != "/dev/null" ]
  1611. then
  1612.   size=`wc -c < $filename`
  1613.  
  1614.   if [ $size != 4759 ]
  1615.   then
  1616.     echo $filename changed - should be 4759 bytes, not $size bytes
  1617.   fi
  1618.  
  1619.   chmod 666 $filename
  1620. fi
  1621.  
  1622. echo done
  1623.  
  1624. exit 0
  1625.  
  1626.