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

  1. Subject: v06i030:  Elm mail system (elm), Part05/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 30
  7. Archive-name: elm/Part05
  8.  
  9. # Continuation of Shell Archive, created by hpldat!taylor
  10.  
  11. # This is part 5
  12.  
  13. # To unpack the enclosed files, please use this file as input to the
  14. # Bourne (sh) shell.  This can be most easily done by the command;
  15. #     sh < thisfilename
  16.  
  17.  
  18. if [ ! -d src ]
  19. then
  20.   echo creating directory src
  21.   mkdir src
  22. fi
  23.  
  24. # ---------- file src/Makefile ----------
  25.  
  26. filename="src/Makefile"
  27.  
  28. if [ -f $filename ]
  29. then
  30.   echo File \"$filename\" already exists\!  Skipping...
  31.   filename=/dev/null        # throw it away
  32. else
  33.   echo extracting file src/Makefile...
  34. fi
  35.  
  36. cat << 'END-OF-FILE' > $filename
  37. #
  38. #  Makefile for the ELM mail program.
  39. #
  40. #         (C) Copyright 1986, Dave Taylor
  41. #
  42. #  Last modification: March 7th, 1986
  43.  
  44. SHELL=/bin/sh
  45.  
  46. ##############################
  47. #
  48. # if on a BSD system;
  49. #   DEFINE=-DBSD
  50. #   LIB2  = -lcurses
  51. # else if on a UTS system;
  52. #   DEFINE=-DUTS
  53. #   LIB2  = -la -lq
  54. # else if on a SUN system;
  55. #   DEFINE=-DBSD -DSUN
  56. #   LIB2  = -lcurses
  57. # else if on a Pyramid system;
  58. #   DEFINE=-DBSD -DNO_VAR_ARGS
  59. #   LIB2  = -lcurses
  60. # else
  61.  
  62.     DEFINE=
  63.     LIB2  =
  64.  
  65. # IF you're on an ACSnet system (Australia) then
  66. # you'll want to uncomment the following;
  67.  
  68. #   DEFINE= ${DEFINE} -DACSNET
  69.  
  70. ##############################
  71.  
  72. CFILES=    addr_utils.c alias.c aliasdb.c aliaslib.c args.c bounceback.c       \
  73.     calendar.c connect_to.c curses.c date.c delete.c domains.c edit.c   \
  74.     encode.c errno.c file.c file_utils.c fileio.c hdrconfg.c help.c     \
  75.     initialize.c input_utils.c leavembox.c mailmsg1.c mailmsg2.c        \
  76.     mailtime.c mkhdrs.c elm.c newmbox.c notesfile.c options.c opt_utils.c \
  77.     output_utils.c pattern.c quit.c read_rc.c remail.c reply.c         \
  78.     return_addr.c savecopy.c screen.c showmsg.c signals.c softkeys.c    \
  79.     sort.c strings.c syscall.c utils.c validname.c getopt.c string2.c
  80.  
  81. HEADERS=../hdrs/curses.h ../hdrs/defs.h ../hdrs/headers.h ../hdrs/sysdefs.h
  82.  
  83. OBJS=    addr_utils.o alias.o aliasdb.o aliaslib.o args.o bounceback.o       \
  84.     calendar.o connect_to.o curses.o date.o delete.o domains.o edit.o   \
  85.     encode.o errno.o file.o file_utils.o fileio.o hdrconfg.o help.o     \
  86.     initialize.o input_utils.o leavembox.o mailmsg1.o mailmsg2.o        \
  87.     mailtime.o mkhdrs.o elm.o newmbox.o notesfile.o options.o opt_utils.o \
  88.     output_utils.o pattern.o quit.o read_rc.o remail.o reply.o         \
  89.     return_addr.o savecopy.o screen.o showmsg.o signals.o softkeys.o    \
  90.     sort.o strings.o syscall.o utils.o validname.o getopt.o string2.o
  91.  
  92. BIN=    ../bin
  93. LIBS=   -ltermcap
  94. CFLAGS= -O -I../hdrs
  95. CC=    /bin/cc
  96. RM=    /bin/rm -f
  97.  
  98. ../bin/elm: ${OBJS} ${EXTRA} ${HEADERS} ../hdrs/elm.h
  99.     ${CC} -o ${BIN}/elm -n ${OBJS} ${LIBS} ${LIB2}
  100.  
  101. .c.o:   ${HEADERS}
  102.     ${CC} -c ${CFLAGS} ${DEFINE} $*.c 
  103.  
  104. curses.o: curses.c ../hdrs/curses.h
  105.     ${CC} -c ${CFLAGS} -DRAWMODE ${DEFINE} curses.c
  106.  
  107. # curses.c : curses.q
  108. #     @../bin/quickscreen curses.q
  109. #
  110. # curses.q :
  111. #     @cp curses.c curses.q
  112.  
  113. clean:
  114.     ${RM} ${OBJS} LINT.OUT
  115.  
  116. lint: LINT.OUT
  117.  
  118. LINT.OUT: ${CFILES}
  119.     lint -p -I../hdrs ${CFILES} > LINT.OUT
  120.  
  121. listing: LISTING
  122.  
  123. LISTING: Makefile INDEX ${HEADERS} ${CFILES}
  124.     @echo adding file 'Makefile'...
  125.     @/bin/echo \\f > LISTING
  126.     @cat Makefile >> LISTING
  127.     @echo adding file 'INDEX'...
  128.     @/bin/echo \\f >> LISTING
  129.     @cat INDEX >> LISTING
  130.     @../bin/makelisting ${HEADERS} ${CFILES}
  131.     @echo LISTING generated.
  132.  
  133. index: INDEX
  134.  
  135. INDEX: ${CFILES} ${HEADERS}
  136.     @echo Creating function definition index
  137.     @index *.c | sort > INDEX
  138.     @echo File INDEX generated
  139. END-OF-FILE
  140.  
  141. if [ "$filename" != "/dev/null" ]
  142. then
  143.   size=`wc -c < $filename`
  144.  
  145.   if [ $size != 2822 ]
  146.   then
  147.     echo $filename changed - should be 2822 bytes, not $size bytes
  148.   fi
  149.  
  150.   chmod 644 $filename
  151. fi
  152.  
  153. # ---------- file src/alias.c ----------
  154.  
  155. filename="src/alias.c"
  156.  
  157. if [ -f $filename ]
  158. then
  159.   echo File \"$filename\" already exists\!  Skipping...
  160.   filename=/dev/null        # throw it away
  161. else
  162.   echo extracting file src/alias.c...
  163. fi
  164.  
  165. cat << 'END-OF-FILE' > $filename
  166. /**            alias.c            **/
  167.  
  168. /** This file contains alias stuff
  169.  
  170.     (C) Copyright 1986 Dave Taylor
  171. **/
  172.  
  173. #include "headers.h"
  174. #include <errno.h>
  175.  
  176. char *expand_group(), *get_alias_address(), *expand_system(), *get_token();
  177. char *error_name(), *error_description();
  178.  
  179. extern int errno;
  180.  
  181. read_alias_files()
  182. {
  183.     /** read the system and user alias files, if present.
  184.         Set the flags 'systemfiles' and 'userfiles' accordingly.
  185.     **/
  186.  
  187.     char fname[SLEN];
  188.     int  hash;
  189.  
  190.     if ((hash = open(system_hash_file, O_RDONLY)) == -1) {
  191.      dprint1(1,
  192.         "Warning: Can't read system hash file %s (read_alias_files)\n",
  193.         system_hash_file);
  194.       goto user;
  195.     }
  196.  
  197.     read(hash, system_hash_table, sizeof system_hash_table);
  198.     close(hash);
  199.  
  200.     /* and data file opened.. */
  201.  
  202.     if ((system_data = open(system_data_file, O_RDONLY)) == -1) {
  203.      dprint1(1, 
  204.              "Warning: Can't read system data file %s (read_alias_files)\n",
  205.          system_data_file);
  206.       goto user;
  207.     }
  208.  
  209.     system_files++;    /* got the system files! */
  210.  
  211. user:   sprintf(fname,  "%s/.alias_hash", home); 
  212.  
  213.     if ((hash = open(fname, O_RDONLY)) == -1) {
  214.      dprint1(1,"Warning: Can't read user hash file %s (read_alias_files)\n",
  215.           fname);
  216.       return;
  217.     }
  218.  
  219.     read(hash, user_hash_table, sizeof user_hash_table);
  220.     close(hash);
  221.  
  222.     sprintf(fname,  "%s/.alias_data", home); 
  223.  
  224.     if ((user_data = open(fname, O_RDONLY)) == -1) {
  225.      dprint1(1,
  226.              "Warning: can't read user data file %s  (read_alias_files)\n",
  227.          fname);
  228.       return;
  229.     }
  230.  
  231.     user_files++;    /* got user files too! */
  232. }
  233.  
  234. int
  235. add_alias()
  236. {
  237.     /** add an alias to the user alias text file.  Return zero 
  238.         if alias not added in actuality **/
  239.  
  240.     char name[SLEN], *address, address1[LONG_STRING];
  241.     char comment[SLEN];
  242.  
  243.     PutLine0(LINES-2,0,"Enter alias name: ");
  244.     CleartoEOLN();
  245.     Raw(OFF);
  246.     gets(name, 20);
  247.     Raw(ON);
  248.     if (strlen(name) == 0) 
  249.       return(0);
  250.     if ((address = get_alias_address(name, 0, 0)) != NULL) {
  251.       dprint1(2, "Attempt to add a duplicate alias [%s] (add_alias)\n",
  252.            address); 
  253.       if (address[0] == '!') {
  254.         address[0] = ' ';
  255.         error1("already a group with that name:%s", address);
  256.       }
  257.       else
  258.         error1("already an alias for that: %s", address);
  259.       return(0);
  260.     }
  261.     PutLine1(LINES-2,0,"Full name for %s: ", name);
  262.     CleartoEOLN();
  263.     Raw(OFF);
  264.     gets(comment,SLEN);
  265.     Raw(ON);
  266.     if (strlen(comment) == 0) strcpy(comment, name);  
  267.     PutLine1(LINES-2,0,"Enter address for %s: ",name);
  268.     CleartoEOLN();
  269.     Raw(OFF);
  270.     gets(address1,LONG_SLEN);
  271.     Raw(ON);
  272.     if (strlen(address1) == 0) {
  273.       error("No address specified!");
  274.       return(0);
  275.     }
  276.     add_to_alias_text(name, comment, address1);
  277.     return(1);
  278. }
  279.  
  280. int
  281. add_current_alias()
  282. {
  283.     /** alias the current message to the specified name and
  284.         add it to the alias text file, for processing as
  285.         the user leaves the program.  Returns non-zero iff
  286.         alias actually added to file **/
  287.  
  288.     char name[SLEN], address1[LONG_STRING], *address;
  289.     char comment[SLEN];
  290.  
  291.     if (current == 0) {
  292.      dprint0(3,"Add current alias called without any current message!\n");
  293.      error("No message to alias to!");
  294.      return(0);
  295.     }
  296.     
  297.     PutLine0(LINES-2,0,"Current message address aliased to: ");
  298.     CleartoEOLN();
  299.     Raw(OFF);
  300.     gets(name, 20);
  301.     Raw(ON);
  302.     if (strlen(name) == 0)    /* cancelled... */
  303.       return(0);
  304.     if ((address = get_alias_address(name, 0, 0)) != NULL) {
  305.      dprint1(3,
  306.              "Attempt to add a duplicate alias [%s] (add_current_alias)\n",
  307.          address); 
  308.       if (address[1] == '!') {
  309.         address[0] = ' ';
  310.         error1("already a group with that name:%s", address);
  311.       }
  312.       else 
  313.         error1("already an alias for that: %s", address); 
  314.           return(0);
  315.     }
  316.     PutLine1(LINES-2,0,"Full name of %s: ", name);
  317.     CleartoEOLN();
  318.     Raw(OFF);
  319.     gets(comment, 40);
  320.     Raw(ON);
  321.     get_return(address1);    /* grab the return address of this message */
  322.     optimize_return(address1);
  323.     PutLine3(LINES-2,0,"%s (%s) = %s", comment, name, address1);
  324.     CleartoEOLN();
  325.     add_to_alias_text(name, comment, address1);
  326.     return(1);
  327. }
  328.  
  329. add_to_alias_text(name, comment, address)
  330. char *name, *comment, *address;
  331. {
  332.     /** Add the data to the user alias text file.  Return zero if we
  333.         succeeded, 1 if not **/
  334.     
  335.     FILE *file;
  336.     char fname[SLEN];
  337.     
  338.     sprintf(fname,"%s/.alias_text", home);
  339.     
  340.     if ((file = fopen(fname, "a")) == NULL) {
  341.       dprint2(2, "FILE Failure attempting to add alias to file %s (%s)",
  342.            fname, "add_to_alias_text");
  343.       dprint2(2, "** %s - %s **\n", error_name(errno), 
  344.            error_description(errno));
  345.       error1("couldn't open %s to add new alias!", fname);
  346.       return(1);
  347.     }
  348.  
  349.     fprintf(file,"%s : %s : %s\n", name, comment, address);
  350.     fclose(file);
  351.  
  352.     chown(fname, userid, groupid);
  353.  
  354.     return(0);
  355. }
  356.  
  357. show_alias_menu()
  358. {
  359.     MoveCursor(LINES-7,0); CleartoEOLN();    
  360.     MoveCursor(LINES-6,0); CleartoEOLN();    
  361.     MoveCursor(LINES-5,0); CleartoEOLN();
  362.     
  363.     PutLine0(LINES-7,COLUMNS-45, "Alias commands");
  364.     Centerline(LINES-5,
  365. "A)lias current msg, Check a P)erson or S)ystem, M)ake new alias, or R)eturn"
  366.     );
  367. }
  368.  
  369. alias()
  370. {
  371.     /** work with alias commands... **/
  372.     char name[NLEN], *address, ch, buffer[SLEN];
  373.     int  newaliases = 0;
  374.  
  375.     if (mini_menu)
  376.       show_alias_menu();
  377.  
  378.     define_softkeys(ALIAS);
  379.  
  380.     while (1) {
  381.       PutLine0(LINES-3,0,"Alias: ");
  382.       CleartoEOLN();
  383.       ch = ReadCh();
  384.       MoveCursor(LINES-1,0); CleartoEOLN();
  385.       
  386.       switch (tolower(ch)) {
  387.         case 'a': newaliases += add_current_alias();    break;
  388.         case 'm': newaliases += add_alias();         break;
  389.  
  390.         case RETURN:
  391.         case 'q':
  392.         case 'x':
  393.         case 'r': if (newaliases) install_aliases();
  394.               return;
  395.         case 'p': if (newaliases) 
  396.             error("Warning: new aliases not installed yet!");
  397.               PutLine0(LINES-2,0,"Check for person: ");
  398.               CleartoEOLN();
  399.               Raw(OFF);
  400.                   gets(name,NLEN);
  401.               Raw(ON);
  402.               if ((address = get_alias_address(name, 0, 0))!=NULL) {
  403.                     if (address[0] == '!') {
  404.                       address[0] = ' ';
  405.                       PutLine1(LINES-1,0,"Group alias:%-65.65s", address);
  406.                       CleartoEOLN();
  407.                 }
  408.             else
  409.               PutLine1(LINES-1,0,"Aliased addresss: %-65.65s", 
  410.               address);
  411.               }
  412.                   else 
  413.             error("not found");
  414.               break;
  415.  
  416.         case 's': PutLine0(LINES-2,0,"Check for system: ");
  417.               CleartoEOS();
  418.               Raw(OFF);
  419.                   gets(name,NLEN);
  420.               Raw(ON);
  421.               if (talk_to(name)) 
  422. #ifdef INTERNET_ADDRESS_FORMAT
  423.             PutLine1(LINES-1,0,
  424.         "You have a direct connection - the address is (user)@%s", 
  425.             name);
  426. #else
  427.             PutLine1(LINES-1,0,
  428.         "You have a direct connection - the address is %s!(user)", 
  429.             name);
  430. #endif
  431.               else {
  432.                 sprintf(buffer, "(user)@%s", name);
  433.                  address = expand_system(buffer, FALSE);
  434.                 if (strlen(address) > strlen(name) + 7)
  435.                   PutLine1(LINES-1,0,"Address is: %.65s", address);
  436.                 else
  437.                   error1("couldn't expand system '%s'", name);
  438.               }
  439.               break;
  440.  
  441.         case '@': PutLine0(LINES-2,0,"Fully expand alias: ");
  442.               CleartoEOS();
  443.               Raw(OFF);
  444.                   gets(name,NLEN);
  445.               Raw(ON);
  446.               if ((address = get_alias_address(name, 1, 0)) != NULL) {
  447.                     ClearScreen();
  448.             PutLine1(3,0,"Aliased address:\n\r%s", address);
  449.                     PutLine0(LINES-1,0,"Press <return> to continue: ");
  450.             (void) getchar();
  451.               }
  452.                   else 
  453.             error("not found");
  454.               break;
  455.         default : error("Invalid input!");
  456.       }
  457.     }
  458. }
  459.  
  460. install_aliases()
  461. {
  462.     /** run the 'newalias' program and install the newly
  463.         added aliases before going back to the main
  464.         program! 
  465.     **/
  466.  
  467.     error("Adding new aliases...");
  468.     sleep(2);
  469.  
  470.     if (system_call(newalias, SH) == 0) {
  471.       error("Re-reading the database in...");
  472.       sleep(2);
  473.       read_alias_files();
  474.       set_error("New aliases installed successfully");
  475.     }
  476.     else
  477.       set_error("'newalias' failed.  Please check alias_text");
  478. }
  479. END-OF-FILE
  480.  
  481. if [ "$filename" != "/dev/null" ]
  482. then
  483.   size=`wc -c < $filename`
  484.  
  485.   if [ $size != 7725 ]
  486.   then
  487.     echo $filename changed - should be 7725 bytes, not $size bytes
  488.   fi
  489.  
  490.   chmod 644 $filename
  491. fi
  492.  
  493. # ---------- file src/curses.c ----------
  494.  
  495. filename="src/curses.c"
  496.  
  497. if [ -f $filename ]
  498. then
  499.   echo File \"$filename\" already exists\!  Skipping...
  500.   filename=/dev/null        # throw it away
  501. else
  502.   echo extracting file src/curses.c...
  503. fi
  504.  
  505. cat << 'END-OF-FILE' > $filename
  506. /**             curses.c        **/
  507.  
  508. /**  This library gives programs the ability to easily access the
  509.      termcap information and write screen oriented and raw input
  510.      programs.  The routines can be called as needed, except that
  511.      to use the cursor / screen routines there must be a call to
  512.      InitScreen() first.  The 'Raw' input routine can be used
  513.      independently, however.
  514.  
  515.      Modified 2/86 to work (hopefully) on Berkeley systems.  If
  516.      there are any problems with BSD Unix, please report them to
  517.      the author at taylor@hplabs (fixed, if possible!)
  518.  
  519.      Modified 5/86 to add memory lock support, thanks to the
  520.      suggested code by Steve Wolf.
  521.  
  522.      (C) Copyright 1985 Dave Taylor, HP Colorado Networks
  523. **/
  524.  
  525. #ifdef BSD
  526. # include "/usr/include/curses.h"      /* don't ask! */
  527. #endif
  528.  
  529. #include "headers.h"
  530.  
  531. #ifdef RAWMODE
  532. # ifdef BSD
  533. #  include <sgtty.h>
  534. # else
  535. #  include <termio.h>
  536. # endif
  537. #endif
  538.  
  539. #include <ctype.h>
  540.  
  541. #ifdef BSD
  542. #undef tolower
  543. #endif
  544. #include "curses.h"
  545.  
  546. #ifdef RAWMODE
  547. # define TTYIN    0
  548. #endif
  549.  
  550. extern int debug;
  551.  
  552. #ifdef RAWMODE
  553. #  ifndef BSD
  554. struct termio _raw_tty, 
  555.               _original_tty;
  556. #  endif
  557.  
  558. static int _inraw = 0;                  /* are we IN rawmode?    */
  559. static int _memory_locked = 0;        /* are we IN memlock??   */
  560. static int _line  = -1,            /* initialize to "trash" */
  561.            _col   = -1;
  562.  
  563. #ifdef UTS
  564. static int _clear_screen = 0;        /* Next i/o clear screen? */
  565. static char _null_string[SLEN];        /* a string of nulls...   */
  566. #endif
  567.  
  568. #endif
  569.  
  570. static int _intransmit;            /* are we transmitting keys? */
  571.  
  572. static
  573. char *_clearscreen, *_moveto, *_up, *_down, *_right, *_left,
  574.      *_setbold, *_clearbold, *_setunderline, *_clearunderline, 
  575.      *_sethalfbright, *_clearhalfbright, *_setinverse, *_clearinverse,
  576.      *_cleartoeoln, *_cleartoeos, *_transmit_on, *_transmit_off,
  577.      *_set_memlock, *_clear_memlock;
  578.  
  579. static
  580. int _lines, _columns;
  581.  
  582. static char _terminal[1024];              /* Storage for terminal entry */
  583. static char _capabilities[1024];           /* String for cursor motion */
  584.  
  585. static char *ptr = _capabilities;    /* for buffering         */
  586.  
  587. int    outchar();            /* char output for tputs */
  588. char  *tgetstr(),                    /* Get termcap capability */
  589.       *tgoto();                /* and the goto stuff    */
  590.  
  591. InitScreen()
  592. {
  593.     /* Set up all this fun stuff: returns zero if all okay, or;
  594.         -1 indicating no terminal name associated with this shell,
  595.         -2..-n  No termcap for this terminal type known
  596.    */
  597.  
  598.     int  tgetent(),      /* get termcap entry */
  599.     error;
  600.     char termname[40];
  601.     
  602.     dprint0(8,"InitScreen()\n");
  603.  
  604. #ifdef SUN
  605.     if (getenv("TERM") == NULL)
  606.         return(-1);
  607. #endif
  608.  
  609. #ifdef UTS
  610.  
  611.     /* use _line for lack of a better variable, what the heck! */
  612.  
  613.     for (_line = 0; _line < SLEN; _line++)
  614.         _null_string[_line] = '\0';
  615. #endif
  616.  
  617.     if (strcpy(termname, getenv("TERM")) == NULL)
  618.         return(-1);
  619.  
  620.     if ((error = tgetent(_terminal, termname)) != 1)
  621.         return(error-2);
  622.  
  623.     _line  =  0;        /* where are we right now?? */
  624.     _col   =  0;        /* assume zero, zero...     */
  625.  
  626.     /* load in all those pesky values */
  627.     _clearscreen       = tgetstr("cl", &ptr);
  628.     _moveto            = tgetstr("cm", &ptr);
  629.     _up                = tgetstr("up", &ptr);
  630.     _down              = tgetstr("do", &ptr);
  631.     _right             = tgetstr("nd", &ptr);
  632.     _left              = tgetstr("bs", &ptr);
  633.     _setbold           = tgetstr("so", &ptr);
  634.     _clearbold         = tgetstr("se", &ptr);
  635.     _setunderline      = tgetstr("us", &ptr);
  636.     _clearunderline    = tgetstr("ue", &ptr);
  637.     _setinverse        = tgetstr("so", &ptr);
  638.     _clearinverse      = tgetstr("se", &ptr);
  639.     _sethalfbright     = tgetstr("hs", &ptr);
  640.     _clearhalfbright   = tgetstr("he", &ptr);
  641.     _cleartoeoln       = tgetstr("ce", &ptr);
  642.     _cleartoeos        = tgetstr("cd", &ptr);
  643.     _lines                 = tgetnum("li");
  644.     _columns       = tgetnum("co");
  645.     _transmit_on       = tgetstr("ks", &ptr);
  646.     _transmit_off      = tgetstr("ke", &ptr);
  647.     _set_memlock       = tgetstr("ml", &ptr);
  648.     _clear_memlock       = tgetstr("mu", &ptr);
  649.  
  650.  
  651.     if (!_left) {
  652.         _left = ptr;
  653.         *ptr++ = '\b';
  654.         *ptr++ = '\0';
  655.     }
  656.  
  657. #ifdef BSD
  658.     initscr();    /* initalize curses too! */
  659. #endif
  660.  
  661.     return(0);
  662. }
  663.  
  664. char *return_value_of(termcap_label)
  665. char *termcap_label;
  666. {
  667.     /** This will return the string kept by termcap for the 
  668.         specified capability. Modified to ensure that if 
  669.         tgetstr returns a pointer to a transient address    
  670.         that we won't bomb out with a later segmentation
  671.         fault (thanks to Dave@Infopro for this one!) **/
  672.  
  673.     static char escape_sequence[20];
  674.  
  675.     char *tgetstr();             /* Get termcap capability */
  676.  
  677.     dprint1(9,"return_value_of(%s)\n", termcap_label);
  678.  
  679.     strcpy(escape_sequence, tgetstr(termcap_label, &ptr));
  680.     return( (char *) escape_sequence);
  681. }
  682.  
  683. transmit_functions(newstate)
  684. int newstate;
  685. {
  686.     /** turn function key transmission to ON | OFF **/
  687.  
  688.     dprint1(9,"transmit_functions(%s)\n", onoff(newstate));
  689.  
  690.     if (newstate != _intransmit) {
  691.         _intransmit = ! _intransmit;
  692.         if (newstate == ON)
  693.           tputs(_transmit_on, 1, outchar);
  694.         else 
  695.           tputs(_transmit_off, 1, outchar);
  696.  
  697.         fflush(stdout);      /* clear the output buffer */
  698.     }
  699. }
  700.  
  701. /****** now into the 'meat' of the routines...the cursor stuff ******/
  702.  
  703. ScreenSize(lines, columns)
  704. int *lines, *columns;
  705. {
  706.     /** returns the number of lines and columns on the display. **/
  707.  
  708.     dprint2(9,"ScreenSize(_,_) returning %d, %d\n", _lines-1, _columns);
  709.  
  710.     *lines = _lines - 1;        /* assume index from zero */
  711.     *columns = _columns;
  712. }
  713.  
  714. ClearScreen()
  715. {
  716.     /* clear the screen: returns -1 if not capable */
  717.  
  718.     dprint0(9,"ClearScreen()\n");
  719.  
  720.     _line = 0;    /* clear leaves us at top... */
  721.     _col  = 0;
  722.  
  723. #ifdef UTS
  724.     if (isatube) {
  725.         _clear_screen++;    /* queue up for clearing... */
  726.         return(0);
  727.     }
  728. #endif
  729.  
  730.     if (!_clearscreen)
  731.         return(-1);
  732.  
  733.     tputs(_clearscreen, 1, outchar);
  734.     fflush(stdout);      /* clear the output buffer */
  735.     return(0);
  736. }
  737.  
  738. MoveCursor(row, col)
  739. int row, col;
  740. {
  741.     /** move cursor to the specified row column on the screen.
  742.             0,0 is the top left! **/
  743.  
  744.     char *stuff;
  745.  
  746.     /* we don't want to change "rows" or we'll mangle scrolling... */
  747.  
  748.     if (col > COLUMNS) col = COLUMNS;
  749.     if (col < 0)       col = 0;
  750.  
  751. #ifdef UTS
  752.     if (isatube) {
  753.         at row+1, col+1;
  754.         _line = row;
  755.         _col  = col;
  756.         return(0);
  757.     }
  758. #endif
  759.     if (!_moveto)
  760.         return(-1);
  761.  
  762.     if (row == _line) {
  763.       if (col == _col)
  764.         return(0);
  765.       else if (abs(col - _col) < 5) {
  766.         if (col > _col)
  767.           CursorRight(col - _col);
  768.         else 
  769.           CursorLeft(_col - col);
  770.           }
  771.       else {
  772.         stuff = tgoto(_moveto, col, row);
  773.         tputs(stuff, 1, outchar);
  774.         fflush(stdout);
  775.       }
  776.     }
  777.     else if (col == _col && abs(row - _line) < 5) {
  778.       if (row < _line)
  779.         CursorUp(_line - row);
  780.       else
  781.         CursorDown(row - _line);
  782.     }
  783.     else if (_line == row-1 && col == 0) {
  784.       putchar('\n');    /* that's */
  785.       putchar('\r');    /*  easy! */
  786.       fflush(stdout);
  787.     }
  788.     else {
  789.       stuff = tgoto(_moveto, col, row);
  790.       tputs(stuff, 1, outchar);
  791.       fflush(stdout);
  792.     }
  793.  
  794.     _line = row;    /* to ensure we're really there... */
  795.     _col  = col;
  796.  
  797.     return(0);
  798. }
  799.  
  800. CursorUp(n)
  801. int n;
  802. {
  803.     /** move the cursor up 'n' lines **/
  804.  
  805.     dprint1(9,"CursorUp(%d)\n", n);
  806.  
  807.     _line = (_line-n > 0? _line - n: 0);    /* up 'n' lines... */
  808.  
  809. #ifdef UTS
  810.     if (isatube) {
  811.         at _line+1, _col+1;
  812.         return(0);
  813.     }
  814. #endif
  815.     if (!_up)
  816.         return(-1);
  817.  
  818.     while (n-- > 0)
  819.         tputs(_up, 1, outchar);
  820.  
  821.     fflush(stdout);
  822.     return(0);
  823. }
  824.  
  825.  
  826. CursorDown(n)
  827. int n;
  828. {
  829.     /** move the cursor down 'n' lines **/
  830.  
  831.     dprint1(9,"CursorDown(%d)\n", n);
  832.  
  833.     _line = (_line+n < LINES? _line + n: LINES);    /* down 'n' lines... */
  834.  
  835. #ifdef UTS
  836.     if (isatube) {
  837.         at _line+1, _col+1 ;
  838.         return(0);
  839.     }
  840. #endif
  841.  
  842.     if (!_down)
  843.         return(-1);
  844.  
  845.     while (n-- > 0)
  846.         tputs(_down, 1, outchar);
  847.  
  848.     fflush(stdout);
  849.     return(0);
  850. }
  851.  
  852.  
  853. CursorLeft(n)
  854. int n;
  855. {
  856.     /** move the cursor 'n' characters to the left **/
  857.  
  858.     dprint1(9,"CursorLeft(%d)\n", n);
  859.  
  860.     _col = (_col - n> 0? _col - n: 0);    /* left 'n' chars... */
  861.  
  862. #ifdef UTS
  863.     if (isatube) {
  864.         at _line+1, _col+1;
  865.         return(0);
  866.     }
  867. #endif
  868.  
  869.     if (!_left)
  870.         return(-1);
  871.  
  872.     while (n-- > 0)
  873.         tputs(_left, 1, outchar);
  874.  
  875.     fflush(stdout);
  876.     return(0);
  877. }
  878.  
  879.  
  880. CursorRight(n)
  881. int n;
  882. {
  883.     /** move the cursor 'n' characters to the right (nondestructive) **/
  884.  
  885.     dprint1(9,"CursorRight(%d)\n", n);
  886.  
  887.     _col = (_col+n < COLUMNS? _col + n: COLUMNS);    /* right 'n' chars... */
  888.  
  889. #ifdef UTS
  890.     if (isatube) {
  891.         at _line+1, _col+1;
  892.         return(0);
  893.     }
  894. #endif
  895.  
  896.     if (!_right)
  897.         return(-1);
  898.  
  899.     while (n-- > 0)
  900.         tputs(_right, 1, outchar);
  901.  
  902.     fflush(stdout);
  903.     return(0);
  904. }
  905.  
  906.  
  907. StartBold()
  908. {
  909.     /** start boldface/standout mode **/
  910.  
  911.     if (!_setbold)
  912.         return(-1);
  913.  
  914.     tputs(_setbold, 1, outchar);
  915.     fflush(stdout);
  916.     return(0);
  917. }
  918.  
  919.  
  920. EndBold()
  921. {
  922.     /** compliment of startbold **/
  923.  
  924.     if (!_clearbold)
  925.         return(-1);
  926.  
  927.     tputs(_clearbold, 1, outchar);
  928.     fflush(stdout);
  929.     return(0);
  930. }
  931.  
  932.  
  933. StartUnderline()
  934. {
  935.     /** start underline mode **/
  936.  
  937.     if (!_setunderline)
  938.         return(-1);
  939.  
  940.     tputs(_setunderline, 1, outchar);
  941.     fflush(stdout);
  942.     return(0);
  943. }
  944.  
  945.  
  946. EndUnderline()
  947. {
  948.     /** the compliment of start underline mode **/
  949.  
  950.     if (!_clearunderline)
  951.         return(-1);
  952.  
  953.     tputs(_clearunderline, 1, outchar);
  954.     fflush(stdout);
  955.     return(0);
  956. }
  957.  
  958.  
  959. StartHalfbright()
  960. {
  961.     /** start half intensity mode **/
  962.  
  963.     if (!_sethalfbright)
  964.         return(-1);
  965.  
  966.     tputs(_sethalfbright, 1, outchar);
  967.     fflush(stdout);
  968.     return(0);
  969. }
  970.  
  971. EndHalfbright()
  972. {
  973.     /** compliment of starthalfbright **/
  974.  
  975.     if (!_clearhalfbright)
  976.         return(-1);
  977.  
  978.     tputs(_clearhalfbright, 1, outchar);
  979.     fflush(stdout);
  980.     return(0);
  981. }
  982.  
  983. StartInverse()
  984. {
  985.     /** set inverse video mode **/
  986.  
  987.     if (!_setinverse)
  988.         return(-1);
  989.  
  990.     tputs(_setinverse, 1, outchar);
  991.     fflush(stdout);
  992.     return(0);
  993. }
  994.  
  995.  
  996. EndInverse()
  997. {
  998.     /** compliment of startinverse **/
  999.  
  1000.     if (!_clearinverse)
  1001.         return(-1);
  1002.  
  1003.     tputs(_clearinverse, 1, outchar);
  1004.     fflush(stdout);
  1005.     return(0);
  1006. }
  1007.  
  1008. int
  1009. HasMemlock()
  1010. {
  1011.     /** returns TRUE iff memory locking is available (a terminal
  1012.         feature that allows a specified portion of the screen to
  1013.         be "locked" & not cleared/scrolled... **/
  1014.  
  1015.     return ( _set_memlock && _clear_memlock );
  1016. }
  1017.  
  1018. static int _old_LINES;
  1019.  
  1020. int
  1021. StartMemlock()
  1022. {
  1023.     /** mark the current line as the "last" line of the portion to 
  1024.         be memory locked (always relative to the top line of the
  1025.         screen) Note that this will alter LINES so that it knows
  1026.         the top is locked.  This means that (plus) the program 
  1027.         will scroll nicely but (minus) End memlock MUST be called
  1028.         whenever we leave the locked-memory part of the program! **/
  1029.  
  1030.     if (! _set_memlock)
  1031.       return(-1);
  1032.  
  1033.     if (! _memory_locked) {
  1034.  
  1035.       _old_LINES = LINES;
  1036.       LINES -= _line;        /* we can't use this for scrolling */
  1037.  
  1038.       tputs(_set_memlock, 1, outchar);
  1039.       fflush(stdout);
  1040.       _memory_locked = TRUE;
  1041.     }
  1042.  
  1043.     return(0);
  1044. }
  1045.  
  1046. int
  1047. EndMemlock()
  1048. {
  1049.     /** Clear the locked memory condition...  **/
  1050.  
  1051.     if (! _set_memlock)
  1052.       return(-1);
  1053.  
  1054.     if (_memory_locked) {
  1055.       LINES = _old_LINES;        /* back to old setting */
  1056.   
  1057.       tputs(_clear_memlock, 1, outchar);
  1058.       fflush(stdout);
  1059.       _memory_locked = FALSE;
  1060.     }
  1061.     return(0);
  1062. }
  1063.  
  1064.  
  1065. Writechar(ch)
  1066. char ch;
  1067. {
  1068.     /** write a character to the current screen location. **/
  1069.  
  1070. #ifdef UTS
  1071.     char buffer[2];    /* can't output characters! */
  1072. #endif
  1073.  
  1074.     dprint1(9,ch >= ' ' ? "Writechar(%c)\n" : "Writechar(^%c)\n",
  1075.           ch >= ' ' ?  ch : ch + 'A' - 1);
  1076. #ifdef UTS
  1077.  
  1078.     if (isatube) {
  1079.       buffer[0] = ch;
  1080.       buffer[1] = '\0';
  1081.  
  1082.       at _line+1, _col+1;
  1083.       panel (noerase, noinit, noread) {
  1084.         #ON, buffer, 1#
  1085.       }
  1086.      }
  1087.     else
  1088. #endif
  1089.       putchar(ch);
  1090.  
  1091.     if (ch == BACKSPACE)    /* moved BACK one! */
  1092.         _col--;
  1093.     else if (ch >= ' ')    /* moved FORWARD one! */
  1094.         _col++;
  1095. }
  1096.  
  1097. Write_to_screen(line, argcount, arg1, arg2, arg3)
  1098. char *line;
  1099. int   argcount, arg1, arg2, arg3;
  1100. {
  1101.     /** This routine writes to the screen at the current location.
  1102.           when done, it increments lines & columns accordingly by
  1103.         looking for "\n" sequences... **/
  1104.  
  1105.     dprint2(9,"Write_to_screen(%s) [%d args]\n", line, argcount);
  1106.  
  1107.     switch (argcount) {
  1108.     case 0 :
  1109.         PutLine0(_line, _col, line);
  1110.         break;
  1111.     case 1 :
  1112.         PutLine1(_line, _col, line, arg1);
  1113.         break;
  1114.     case 2 :
  1115.         PutLine2(_line, _col, line, arg1, arg2);
  1116.         break;
  1117.     case 3 :
  1118.         PutLine3(_line, _col, line, arg1, arg2, arg3);
  1119.         break;
  1120.     }
  1121. }
  1122.  
  1123. PutLine0(x, y, line)
  1124. int x,y;
  1125. char *line;
  1126. {
  1127.     /** Write a zero argument line at location x,y **/
  1128.  
  1129.     register int i;
  1130.  
  1131.     dprint3(8,"PutLine0(%d, %d, %s.30...)\n", x, y, line);
  1132.  
  1133. #ifdef UTS
  1134.     if (isatube) {
  1135.         at x+1, y+1;
  1136.         panel (init=_clear_screen, noread, erase=_clear_screen) {
  1137.           #ON, line, strlen(line)-1#
  1138.         }
  1139.         _clear_screen = 0;
  1140.         _col += printable_chars(line);
  1141.  
  1142.         /* line wrapped around?? */
  1143.         while (_col > COLUMNS) {
  1144.           _col  -= COLUMNS;
  1145.           _line += 1;
  1146.         }
  1147.  
  1148.         /* now let's figure out if we're supposed to do a "<return>" */
  1149.  
  1150.         for (i=0; i < strlen(line); i++)
  1151.             if (line[i] == '\n') {
  1152.                 _line++;
  1153.                 _col = 0;        /* on new line! */
  1154.             }
  1155.         return(0);
  1156.     }
  1157. #endif
  1158.     MoveCursor(x,y);
  1159.     printf("%s", line);    /* to avoid '%' problems */
  1160.     fflush(stdout);
  1161.     _col += printable_chars(line);
  1162.  
  1163.     while (_col > COLUMNS) {     /* line wrapped around?? */
  1164.         _col -= COLUMNS;
  1165.         _line += 1;
  1166.     }
  1167.  
  1168.     /** now let's figure out if we're supposed to do a "<return>" **/
  1169.  
  1170.     for (i=0; i < strlen(line); i++)
  1171.         if (line[i] == '\n') {
  1172.             _line++;
  1173.             _col = 0;        /* on new line! */
  1174.         }
  1175. }
  1176.  
  1177. PutLine1(x,y, line, arg1)
  1178. int x,y;
  1179. char *line;
  1180. char *arg1;
  1181. {
  1182.     /** write line at location x,y - one argument... **/
  1183.  
  1184.     char buffer[SLEN];
  1185.  
  1186.     dprint0(9, "PutLine1(...)\n");
  1187.  
  1188.     sprintf(buffer, line, arg1);
  1189.  
  1190.     PutLine0(x, y, buffer);
  1191. }
  1192.  
  1193. PutLine2(x,y, line, arg1, arg2)
  1194. int x,y;
  1195. char *line;
  1196. char *arg1, *arg2;
  1197. {
  1198.     /** write line at location x,y - one argument... **/
  1199.  
  1200.     char buffer[SLEN];
  1201.  
  1202.     dprint0(9, "PutLine2(...)\n");
  1203.  
  1204.     sprintf(buffer, line, arg1, arg2);
  1205.  
  1206.     PutLine0(x, y, buffer);
  1207. }
  1208.  
  1209. PutLine3(x,y, line, arg1, arg2, arg3)
  1210. int x,y;
  1211. char *line;
  1212. char *arg1, *arg2, *arg3;
  1213. {
  1214.     /** write line at location x,y - one argument... **/
  1215.  
  1216.     char buffer[SLEN];
  1217.  
  1218.     dprint0(9, "PutLine3(...)\n");
  1219.  
  1220.     sprintf(buffer, line, arg1, arg2, arg3);
  1221.  
  1222.     PutLine0(x, y, buffer);
  1223. }
  1224.  
  1225. CleartoEOLN()
  1226. {
  1227.     /** clear to end of line **/
  1228. #ifdef UTS
  1229.     char buffer[SLEN];
  1230.     register int cols, i = 0;
  1231.  
  1232.     if (isatube) {
  1233.  
  1234.         dprint0(9, "CleartoEOLN()\n");
  1235.  
  1236.         for (cols = _col; cols < COLUMNS; cols++)
  1237.             buffer[i++] = ' ';
  1238.  
  1239.         buffer[i] = '\0';
  1240.  
  1241.         at _line+1, _col+1;
  1242.         panel (noerase, noinit, noread) {
  1243.           #ON, buffer, strlen(buffer)-1#
  1244.         }
  1245.  
  1246.         return(0);
  1247.     }
  1248. #endif
  1249.  
  1250.     dprint0(9, "CleartoEOLN()\n");
  1251.  
  1252.     if (!_cleartoeoln)
  1253.         return(-1);
  1254.  
  1255.     tputs(_cleartoeoln, 1, outchar);
  1256.     fflush(stdout);  /* clear the output buffer */
  1257.     return(0);
  1258. }
  1259.  
  1260. CleartoEOS()
  1261. {
  1262.     /** clear to end of screen **/
  1263.  
  1264. #ifdef UTS
  1265.     register int line_at;
  1266.  
  1267.     if (isatube) {
  1268.       dprint0(9,"CleartoEOS()\n");
  1269.       for (line_at = _line; line_at < LINES-1; line_at++) {
  1270.         panel (noread, noinit, noread) {
  1271.                 #@ line_at, 1# #ON, _null_string, COLUMNS# 
  1272.         }
  1273.       }
  1274.     
  1275.         return(0);
  1276.     }
  1277.  
  1278. #endif
  1279.     dprint0(9,"CleartoEOS()\n");
  1280.  
  1281.     if (!_cleartoeos)
  1282.         return(-1);
  1283.  
  1284.     tputs(_cleartoeos, 1, outchar);
  1285.     fflush(stdout);  /* clear the output buffer */
  1286.     return(0);
  1287. }
  1288.  
  1289. #ifdef RAWMODE
  1290.  
  1291. Raw(state)
  1292. int state;
  1293. {
  1294.     /** state is either ON or OFF, as indicated by call **/
  1295.  
  1296.     dprint1(8,"Raw(%s)\n", onoff(state));
  1297.  
  1298.     if (state == OFF && _inraw) {
  1299. #ifdef BSD
  1300.         echo();
  1301.         nocrmode();
  1302. #else
  1303.         (void) ioctl(TTYIN, TCSETAW, &_original_tty);
  1304. #endif
  1305.         _inraw = 0;
  1306.     }
  1307.     else if (state == ON && ! _inraw) {
  1308. #ifdef BSD
  1309.         noecho();
  1310.         crmode();
  1311. #else
  1312.         (void) ioctl(TTYIN, TCGETA, &_original_tty);    /** current setting **/
  1313.  
  1314.         (void) ioctl(TTYIN, TCGETA, &_raw_tty);    /** again! **/
  1315.         _raw_tty.c_iflag &= ~(INLCR | ICRNL |BRKINT);
  1316.         _raw_tty.c_iflag |= IXON;
  1317.         _raw_tty.c_oflag |= OPOST;
  1318.         _raw_tty.c_oflag &= ~(OLCUC | ONLCR | OCRNL | ONOCR | ONLRET);
  1319.         _raw_tty.c_lflag &= ~(ICANON | ECHO);
  1320.         _raw_tty.c_cc[VMIN] = '\01';
  1321.         _raw_tty.c_cc[VTIME] = '\0';
  1322.         (void) ioctl(TTYIN, TCSETAW, &_raw_tty);
  1323. #endif
  1324.  
  1325.         _inraw = 1;
  1326.     }
  1327. }
  1328.  
  1329. int
  1330. ReadCh()
  1331. {
  1332.     /** read a character with Raw mode set! **/
  1333.  
  1334.     register int result;
  1335.     char ch;
  1336.  
  1337.     dprint0(9,"ReadCh()\n");
  1338.  
  1339.     result = read(0, &ch, 1);
  1340.  
  1341.     return(result == 0? EOF : ch);
  1342. }
  1343.  
  1344. #endif
  1345.  
  1346. outchar(c)
  1347. char c;
  1348. {
  1349.     /** output the given character.  From tputs... **/
  1350.     /** Note: this CANNOT be a macro!              **/
  1351.  
  1352.     putc(c, stdout);
  1353. }
  1354. END-OF-FILE
  1355.  
  1356. if [ "$filename" != "/dev/null" ]
  1357. then
  1358.   size=`wc -c < $filename`
  1359.  
  1360.   if [ $size != 15951 ]
  1361.   then
  1362.     echo $filename changed - should be 15951 bytes, not $size bytes
  1363.   fi
  1364.  
  1365.   chmod 666 $filename
  1366. fi
  1367.  
  1368. # ---------- file src/date.c ----------
  1369.  
  1370. filename="src/date.c"
  1371.  
  1372. if [ -f $filename ]
  1373. then
  1374.   echo File \"$filename\" already exists\!  Skipping...
  1375.   filename=/dev/null        # throw it away
  1376. else
  1377.   echo extracting file src/date.c...
  1378. fi
  1379.  
  1380. cat << 'END-OF-FILE' > $filename
  1381. /**        date.c        **/
  1382.  
  1383. /** return the current date and time in a readable format! **/
  1384. /** also returns an ARPA RFC-822 format date...            **/
  1385.  
  1386. /** (C) Copyright 1985, Dave Taylor **/
  1387.  
  1388. #include "headers.h"
  1389. #ifdef BSD
  1390. #  include <sys/time.h>
  1391. #else
  1392. #  include <time.h>
  1393. #endif
  1394.  
  1395. #include <ctype.h>
  1396.  
  1397. #ifdef BSD
  1398. #undef toupper
  1399. #endif
  1400.  
  1401. #define MONTHS_IN_YEAR    11    /* 0-11 equals 12 months! */
  1402. #define FEB         1    /* 0 = January           */
  1403. #define DAYS_IN_LEAP_FEB 29    /* leap year only       */
  1404.  
  1405. #define ampm(n)        (n > 12? n - 12 : n)
  1406. #define am_or_pm(n)    (n > 11? (n > 23? "am" : "pm") : "am")
  1407. #define leapyear(year)    ((year % 4 == 0) && (year % 100 != 0))
  1408.  
  1409. char *dayname[] = { "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday",
  1410.           "Friday", "Saturday", "" };
  1411.  
  1412. char *monname[] = { "January", "February", "March", "April", "May", "June",
  1413.           "July", "August", "September", "October", "November",
  1414.           "December", ""};
  1415.  
  1416. char *arpa_dayname[] = { "Sun", "Mon", "Tue", "Wed", "Thu",
  1417.           "Fri", "Sat", "" };
  1418.  
  1419. char *arpa_monname[] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun",
  1420.           "Jul", "Aug", "Sep", "Oct", "Nov", "Dec", ""};
  1421.  
  1422. int  days_in_month[] = { 31,    28,    31,    30,    31,     30, 
  1423.           31,     31,    30,   31,    30,     31,  -1};
  1424.  
  1425. #ifdef BSD
  1426.   char *timezone();
  1427. #else
  1428.   extern char *tzname[];
  1429. #endif
  1430.  
  1431. char *get_date()
  1432. {
  1433.     /** Return the date in the format exemplified by;
  1434.         Thursday, April 18th 1985 at 8:35 pm
  1435.  
  1436.         *************************************
  1437.         ** This routine is not used by ELM **
  1438.         *************************************
  1439.  
  1440.     **/
  1441.  
  1442.     static char buffer[SLEN];    /* static character buffer       */
  1443.     struct tm *the_time,        /* Time structure, see CTIME(3C) */
  1444.               *localtime();
  1445.     char      *suffix();         /* digit suffix for date     */
  1446.     long      junk;            /* time in seconds....         */
  1447.  
  1448.     junk = (long) time(0);    /* this must be here for it to work! */
  1449.     the_time = localtime(&junk);
  1450.         
  1451.     sprintf(buffer, "%s, %s %d%s %d at %d:%02d %s",
  1452.          dayname[the_time->tm_wday],    /* weekday */
  1453.          monname[the_time->tm_mon],    /* month   */
  1454.          the_time->tm_mday,        /* day     */
  1455.          suffix(the_time->tm_mday),    /* suffix  */
  1456.          the_time->tm_year + 1900,    /* year    */
  1457.          ampm(the_time->tm_hour),    /* hour    */
  1458.          the_time->tm_min,        /* minute  */
  1459.                  ((the_time->tm_hour == 12 || the_time->tm_hour == 24)
  1460.           && the_time->tm_min == 0) ? (the_time->tm_hour == 12? "noon" :
  1461.           "midnight") : am_or_pm(the_time->tm_hour));    /* am | pm */
  1462.  
  1463.     return( (char *) buffer);
  1464. }
  1465.  
  1466. char *suffix(day)
  1467. int day;
  1468. {
  1469.     /** this routine returns the suffix appropriate for the
  1470.         specified number to make it an ordinal number.  ie,
  1471.         if given '1' it would return 'st', and '2' => 'nd'
  1472.     **/
  1473.  
  1474.     static char buffer[10];
  1475.     register int digit;
  1476.  
  1477.     digit = day % 10;
  1478.  
  1479.     if (digit == 0 || digit > 3)
  1480.       strcpy(buffer,"th");
  1481.     else if (digit == 1)
  1482.       strcpy(buffer,"st");
  1483.     else if (digit == 2)
  1484.       strcpy(buffer, "nd");
  1485.     else
  1486.       strcpy(buffer, "rd");
  1487.  
  1488.     return( (char *) buffer);
  1489. }
  1490.  
  1491. char *get_arpa_date()
  1492. {
  1493.     /** returns an ARPA standard date.  The format for the date
  1494.         according to DARPA document RFC-822 is exemplified by;
  1495.  
  1496.                      Mon, 12 Aug 85 6:29:08 MST
  1497.  
  1498.     **/
  1499.  
  1500.     static char buffer[SLEN];    /* static character buffer       */
  1501.     struct tm *the_time,        /* Time structure, see CTIME(3C) */
  1502.           *localtime();
  1503.     long       junk;        /* time in seconds....         */
  1504. #ifdef BSD
  1505.     struct  timeval  time_val;        
  1506.     struct  timezone time_zone;
  1507. #endif
  1508.  
  1509. #ifdef BSD
  1510.     gettimeofday(&time_val, &time_zone);
  1511.     junk = time_val.tv_sec;
  1512. #else
  1513.     junk = (long) time(0);    /* this must be here for it to work! */
  1514. #endif
  1515.     the_time = localtime(&junk);
  1516.  
  1517.     sprintf(buffer, "%s, %d %s %d %d:%02d:%02d %s",
  1518.       arpa_dayname[the_time->tm_wday],
  1519.       the_time->tm_mday % 32,
  1520.       arpa_monname[the_time->tm_mon],
  1521.       the_time->tm_year % 100,
  1522.       the_time->tm_hour % 24,
  1523.       the_time->tm_min  % 61,
  1524.       the_time->tm_sec  % 61,
  1525. #ifdef BSD
  1526.       timezone(time_zone.tz_minuteswest, time_zone.tz_dsttime));
  1527. #else
  1528.       tzname[the_time->tm_isdst]);
  1529. #endif
  1530.     
  1531.     return( (char *) buffer);
  1532. }
  1533.  
  1534. char *full_month(month)
  1535. char *month;
  1536. {
  1537.     /** Given a three letter month abbreviation, return the 
  1538.         full name of the month.   If can't figure it out, just
  1539.         return the given argument. **/
  1540.  
  1541.     char   name[4];
  1542.     register int i;
  1543.  
  1544.     /** ensure name in correct case... **/
  1545.  
  1546.     strncpy(name, shift_lower(month), 3);
  1547.     name[0] = toupper(name[0]);
  1548.  
  1549.     /** now simply step through arpa_monname table to find a match **/
  1550.  
  1551.     for (i=0; i < 12; i++)
  1552.       if (strncmp(name, arpa_monname[i], 3) == 0)
  1553.         return((char *) monname[i]);
  1554.     
  1555.     dprint1(2, "Warning: Couldn't expand monthname %s (full_month)\n", 
  1556.             month);
  1557.  
  1558.     return( (char *) month);
  1559. }
  1560.  
  1561. days_ahead(days, buffer)
  1562. int days;
  1563. char *buffer;
  1564. {
  1565.     /** return in buffer the date (Day, Mon Day, Year) of the date
  1566.         'days' days after today. **/
  1567.  
  1568.     struct tm *the_time,        /* Time structure, see CTIME(3C) */
  1569.           *localtime();
  1570.     long       junk;        /* time in seconds....         */
  1571.  
  1572.     junk = (long) time(0);    /* this must be here for it to work! */
  1573.     the_time = localtime(&junk);
  1574.  
  1575.     /* increment the day of the week */
  1576.  
  1577.     the_time->tm_wday = (the_time->tm_wday + days) % 7;
  1578.  
  1579.     /* the day of the month... */
  1580.     the_time->tm_mday += days;
  1581.     
  1582.     if (the_time->tm_mday > days_in_month[the_time->tm_mon]) {
  1583.       if (the_time->tm_mon == FEB && leapyear(the_time->tm_year)) {
  1584.         if (the_time->tm_mday > DAYS_IN_LEAP_FEB) {
  1585.           the_time->tm_mday -= days_in_month[the_time->tm_mon];
  1586.           the_time->tm_mon += 1;
  1587.         }
  1588.       }
  1589.       else {
  1590.         the_time->tm_mday -= days_in_month[the_time->tm_mon];
  1591.         the_time->tm_mon += 1;
  1592.       }
  1593.     }
  1594.  
  1595.     /* check the month of the year */
  1596.     if (the_time->tm_mon > MONTHS_IN_YEAR) {
  1597.       the_time->tm_mon -= MONTHS_IN_YEAR;
  1598.       the_time->tm_year += 1;
  1599.     }
  1600.  
  1601.     /* now, finally, build the actual date string */
  1602.  
  1603.     sprintf(buffer, "%s, %d %s %d",
  1604.       arpa_dayname[the_time->tm_wday],
  1605.       the_time->tm_mday % 32,
  1606.       arpa_monname[the_time->tm_mon],
  1607.       the_time->tm_year % 100);
  1608. }
  1609.  
  1610. int
  1611. valid_date(day, mon, year)
  1612. char *day, *mon, *year;
  1613. {
  1614.     /** validate the given date - returns TRUE iff the date
  1615.         handed is reasonable and valid.  **/
  1616.  
  1617.     register int daynum, yearnum;
  1618.  
  1619.     daynum = atoi(day);
  1620.     yearnum = atoi(year);
  1621.     
  1622.     if (daynum < 1 || daynum > 31) {
  1623.       dprint1(3, "Error: day %d is obviously wrong! (valid_date)\n", 
  1624.               daynum);
  1625.       return(0);
  1626.     }
  1627.     
  1628.     if (yearnum < 1 || (yearnum > 100 && yearnum < 1900) ||
  1629.         yearnum > 2000) {
  1630.       dprint1(3, "Error: year %d is obviously wrong! (valid_date)\n", 
  1631.         yearnum);
  1632.       return(0);
  1633.     }
  1634.     
  1635.     return(1);
  1636. }
  1637.  
  1638. fix_date(entry)
  1639. struct header_rec *entry;
  1640. {
  1641.     /** This routine will 'fix' the date entry for the specified
  1642.         message.  This consists of 1) adjusting the year to 0-99
  1643.         and 2) altering time from HH:MM:SS to HH:MM am|pm **/ 
  1644.  
  1645.     if (atoi(entry->year) > 99)     
  1646.       sprintf(entry->year,"%d", atoi(entry->year) - 1900);
  1647.  
  1648.     fix_time(entry->time);
  1649. }
  1650.  
  1651. fix_time(timestring)
  1652. char *timestring;
  1653. {
  1654.     /** Timestring in format HH:MM:SS (24 hour time).  This routine
  1655.         will fix it to display as: HH:MM [am|pm] **/
  1656.  
  1657.     int hour, minute;
  1658.  
  1659.     sscanf(timestring, "%d:%d", &hour, &minute);
  1660.  
  1661.     if (hour < 1 || hour == 24) 
  1662.       sprintf(timestring, "12:%2d (midnight)", minute);
  1663.     else if (hour < 12)
  1664.       sprintf(timestring, "%d:%2.2d am", hour, minute);
  1665.     else if (hour == 12)
  1666.       sprintf(timestring, "%d:%2.2d (noon)", hour, minute);
  1667.     else if (hour < 24)
  1668.       sprintf(timestring, "%d:%2.2d pm", hour-12, minute);
  1669. }
  1670.  
  1671. int
  1672. compare_dates(rec1, rec2)
  1673. struct header_rec *rec1, *rec2;
  1674. {
  1675.     /** This function works similarly to the "strcmp" function, but
  1676.         has lots of knowledge about the internal date format...
  1677.         Apologies to those who "know a better way"...
  1678.     **/
  1679.  
  1680.     int month1, day1, year1, hour1, minute1,
  1681.         month2, day2, year2, hour2, minute2;
  1682.  
  1683.     year1 = atoi(rec1->year);
  1684.     year2 = atoi(rec2->year);
  1685.  
  1686.     if (year1 != year2)
  1687.       return( year1 - year2 );
  1688.  
  1689.     /* And HERE's where the performance of this sort dies... */
  1690.  
  1691.     month1 = month_number(rec1->month);    /* retch...  gag....  */
  1692.     month2 = month_number(rec2->month);    /*    puke...         */
  1693.  
  1694.     if (month1 == -1) 
  1695.       dprint1(2,"month_number failed on month '%s'\n", rec1->month);
  1696.  
  1697.     if (month2 == -1) 
  1698.       dprint1(2,"month_number failed on month '%s'\n", rec2->month);
  1699.  
  1700.     if (month1 != month2)
  1701.       return( month1 - month2 );
  1702.  
  1703.     /* back and cruisin' now, though... */
  1704.  
  1705.     day1 = atoi(rec1->day);     /* unfortunately, 2 is greater than 19  */
  1706.     day2 = atoi(rec2->day);  /* on a dump string-only compare...     */
  1707.  
  1708.     if (day1 != day2)
  1709.       return( day1 - day2 );
  1710.  
  1711.     /* we're really slowing down now... */
  1712.  
  1713.     sscanf(rec1->time, "%d:%d", &hour1, &minute1);
  1714.     sscanf(rec2->time, "%d:%d", &hour2, &minute2);
  1715.  
  1716.     if (hour1 != hour2)
  1717.       return( hour1 - hour2 );
  1718.  
  1719.     return( day1 - day2 );        /* ignore seconds... */
  1720. }
  1721.  
  1722. int
  1723. month_number(name)
  1724. char *name;
  1725. {
  1726.     /** return the month number given the month name... **/
  1727.  
  1728.     char ch;
  1729.  
  1730.     switch (tolower(name[0])) {
  1731.      case 'a' : if ((ch = tolower(name[1])) == 'p')    return(APRIL);
  1732.             else if (ch == 'u') return(AUGUST);
  1733.             else return(-1);    /* error! */
  1734.     
  1735.      case 'd' : return(DECEMBER);
  1736.      case 'f' : return(FEBRUARY);
  1737.      case 'j' : if ((ch = tolower(name[1])) == 'a') return(JANUARY);
  1738.             else if (ch == 'u') {
  1739.                   if ((ch = tolower(name[2])) == 'n') return(JUNE);
  1740.               else if (ch == 'l') return(JULY);
  1741.               else return(-1);        /* error! */
  1742.                 }
  1743.             else return(-1);        /* error */
  1744.      case 'm' : if ((ch = tolower(name[2])) == 'r') return(MARCH);
  1745.             else if (ch == 'y') return(MAY);
  1746.             else return(-1);        /* error! */
  1747.      case 'n' : return(NOVEMBER);
  1748.      case 'o' : return(OCTOBER);
  1749.      case 's' : return(SEPTEMBER);
  1750.      default  : return(-1);
  1751.     }
  1752. }
  1753. END-OF-FILE
  1754.  
  1755. if [ "$filename" != "/dev/null" ]
  1756. then
  1757.   size=`wc -c < $filename`
  1758.  
  1759.   if [ $size != 9538 ]
  1760.   then
  1761.     echo $filename changed - should be 9538 bytes, not $size bytes
  1762.   fi
  1763.  
  1764.   chmod 644 $filename
  1765. fi
  1766.  
  1767. # ---------- file src/delete.c ----------
  1768.  
  1769. filename="src/delete.c"
  1770.  
  1771. if [ -f $filename ]
  1772. then
  1773.   echo File \"$filename\" already exists\!  Skipping...
  1774.   filename=/dev/null        # throw it away
  1775. else
  1776.   echo extracting file src/delete.c...
  1777. fi
  1778.  
  1779. cat << 'END-OF-FILE' > $filename
  1780. /**        delete.c        **/
  1781.  
  1782. /**  Delete or undelete files: just set flag in header record! 
  1783.      Also tags specified message(s)...
  1784.  
  1785.      (C) Copyright 1985  Dave Taylor
  1786. **/
  1787.  
  1788. #include "headers.h"
  1789.  
  1790. delete(real_del)
  1791. int real_del;
  1792. {
  1793.     /** Delete current message.  If real-del is false, then we're
  1794.         actually requested to toggle the state of the current
  1795.         message... **/
  1796.  
  1797.     if (real_del)
  1798.       header_table[current-1].status |= DELETED;
  1799.     else if (ison(header_table[current-1].status, DELETED))
  1800.       clearit(header_table[current-1].status, DELETED);
  1801.     else
  1802.       setit(header_table[current-1].status, DELETED);
  1803.  
  1804.     show_msg_status(current-1);
  1805. }
  1806.  
  1807. undelete()
  1808. {
  1809.     /** clear the deleted message flag **/
  1810.  
  1811.     clearit(header_table[current-1].status, DELETED);
  1812.  
  1813.     show_msg_status(current-1);
  1814. }
  1815.  
  1816. show_msg_status(msg)
  1817. int msg;
  1818. {
  1819.     /** show the status of the current message only.  **/
  1820.  
  1821.     if (on_page(msg)) {
  1822.       MoveCursor((msg % headers_per_page) + 4, 3);
  1823.       Writechar( ison(header_table[msg].status, DELETED)? 'D' : ' ');
  1824.     }
  1825. }
  1826.  
  1827. tag_message()
  1828. {
  1829.     /** Tag current message.  If already tagged, untag it. **/
  1830.  
  1831.     if (ison(header_table[current-1].status, TAGGED))
  1832.       clearit(header_table[current-1].status, TAGGED);
  1833.     else
  1834.       setit(header_table[current-1].status, TAGGED);
  1835.  
  1836.     show_msg_tag(current-1);
  1837. }
  1838.  
  1839. show_msg_tag(msg)
  1840. int msg;
  1841. {
  1842.     /** show the tag status of the current message only.  **/
  1843.  
  1844.     if (on_page(msg)) {
  1845.       MoveCursor((msg % headers_per_page) + 4, 4);
  1846.       Writechar( ison(header_table[msg].status, TAGGED)? '+' : ' ');
  1847.     }    
  1848. }
  1849.  
  1850. show_new_status(msg)
  1851. int msg;
  1852. {
  1853.     /** If the specified message is on this screen, show
  1854.         the new status (could be marked for deletion now,
  1855.         and could have tag removed...)
  1856.     **/
  1857.  
  1858.     if (on_page(msg)) 
  1859.       PutLine2((msg % headers_per_page) + 4, 3, "%c%c",
  1860.            ison(header_table[msg].status, DELETED)? 'D' : ' ',
  1861.            ison(header_table[msg].status, TAGGED )? '+' : ' ');
  1862. }
  1863. END-OF-FILE
  1864.  
  1865. if [ "$filename" != "/dev/null" ]
  1866. then
  1867.   size=`wc -c < $filename`
  1868.  
  1869.   if [ $size != 1863 ]
  1870.   then
  1871.     echo $filename changed - should be 1863 bytes, not $size bytes
  1872.   fi
  1873.  
  1874.   chmod 644 $filename
  1875. fi
  1876.  
  1877. # ---------- file src/aliasdb.c ----------
  1878.  
  1879. filename="src/aliasdb.c"
  1880.  
  1881. if [ -f $filename ]
  1882. then
  1883.   echo File \"$filename\" already exists\!  Skipping...
  1884.   filename=/dev/null        # throw it away
  1885. else
  1886.   echo extracting file src/aliasdb.c...
  1887. fi
  1888.  
  1889. cat << 'END-OF-FILE' > $filename
  1890. /**            aliasdb.c            **/
  1891.  
  1892. /** Alias database files...
  1893.  
  1894.     (C) Copyright 1986 Dave Taylor
  1895. **/
  1896.  
  1897.  
  1898. #include "headers.h"
  1899.  
  1900. #include <sys/types.h>
  1901. #include <sys/stat.h>
  1902.  
  1903. char *shift_lower(), *find_path_to();
  1904.  
  1905. findnode(name, display_error)
  1906. char *name;
  1907. int   display_error;
  1908. {
  1909.     /** break 'name' into machine!user or user@machine and then
  1910.         see if you can find 'machine' in the path database..
  1911.         If so, return name as the expanded address.  If not,
  1912.         return what was given to us!   If display_error, then
  1913.         do so...
  1914.     **/
  1915.  
  1916.     char   old_name[SLEN];
  1917.     char   address[SLEN];
  1918.     
  1919.     if (strlen(name) == 0)
  1920.       return;
  1921.     
  1922.     strcpy(old_name, name);        /* save what we were given */
  1923.  
  1924.     if (expand_site(name, address) == -1) {
  1925.           if (display_error && name[0] != '!') {
  1926.         dprint2(2,"Couldn't expand host %s in address. (%s)\n",
  1927.                  name, "findnode");
  1928.         if (! check_only) {        /* be silent if just checking */
  1929.           error1("Warning: couldn't expand %s...", name);
  1930.           sleep(1);
  1931.         }
  1932.       }
  1933.       strcpy(name, old_name);    /* and restore... */
  1934.     }
  1935.     else
  1936.       strcpy(name, address);
  1937.     
  1938.     return;
  1939. }
  1940.  
  1941. int
  1942. expand_site(cryptic, expanded)
  1943. char *cryptic, *expanded;
  1944. {
  1945.  
  1946.     /** Given an address of the form 'xyz@site' or 'site!xyz'
  1947.         return an address of the form <expanded address for site>
  1948.             with 'xyz' embedded according to the path database entry.
  1949.         Note that 'xyz' can be eiher a simple address (as in "joe")
  1950.         or a complex address (as in "joe%xerox.parc@Xerox.ARPA")!
  1951.         0 = found, -1 return means unknown site code **/
  1952.  
  1953. #ifdef ACSNET
  1954.  
  1955.     strcpy(expanded, cryptic);    /* fast and simple */
  1956.     return(0);
  1957.  
  1958. #else
  1959.  
  1960.     char   name[VERY_LONG_STRING], sitename[VERY_LONG_STRING], 
  1961.                temp[VERY_LONG_STRING], old_name[VERY_LONG_STRING];
  1962.     char   *expand_domain(), *addr;
  1963.     register int i = 0, j = 0, domain_name;
  1964.  
  1965.     strcpy(old_name, cryptic);    /* remember what we were given */
  1966.  
  1967.     /** break down **/
  1968.  
  1969.     while (cryptic[i] != AT_SIGN && cryptic[i] != BANG && 
  1970.            cryptic[i] != '\0')
  1971.       sitename[j++] = cryptic[i++];
  1972.  
  1973.     sitename[j++] = '\0';
  1974.  
  1975.     j = 0;
  1976.     
  1977.     if (cryptic[i] == '\0') return(-1);    /* nothing to expand! */
  1978.  
  1979.     domain_name = (cryptic[i] == AT_SIGN);
  1980.  
  1981.     i++;
  1982.  
  1983.     while (cryptic[i] != '\0')
  1984.       name[j++] = cryptic[i++];
  1985.  
  1986.     name[j] = '\0';
  1987.  
  1988.     if (domain_name) {
  1989.       strcpy(temp, name);
  1990.       strcpy(name, sitename);
  1991.       strcpy(sitename, temp);
  1992.     }
  1993.  
  1994. #ifndef LOOK_CLOSE_AFTER_SEARCH
  1995.  
  1996.     if (talk_to(sitename)) {
  1997.       strcpy(expanded, old_name);    /* restore! */
  1998.       return(0);
  1999.     }
  2000. #endif
  2001.  
  2002.     if ((addr = find_path_to(sitename, TRUE)) == NULL) {
  2003.  
  2004. #ifdef LOOK_CLOSE_AFTER_SEARCH
  2005.  
  2006.         if (talk_to(sitename)) {
  2007.           strcpy(expanded, old_name);    /* restore! */
  2008.           return(0);
  2009.         }
  2010.         else
  2011. #endif
  2012.         if ((addr = expand_domain(cryptic)) != NULL) {
  2013.            strcpy(expanded, addr);    /* into THIS buffer */
  2014.            return(0);
  2015.         }
  2016.         else  if (size_of_pathfd == 0) {    /* no path database! */
  2017.           strcpy(expanded, old_name);    /* restore! */
  2018.           return(0);
  2019.         }
  2020.         else                 /* We just can't get there! */
  2021.           return(-1);
  2022.     }
  2023.     else {            /* search succeeded */
  2024.        sprintf(expanded, addr, name);
  2025.        return(0);
  2026.     }
  2027. #endif
  2028. }
  2029.  
  2030. int
  2031. binary_search(name, address)
  2032. char *name, *address;
  2033. {
  2034.     /* binary search file for name.  Return 0 if found, -1 if not */
  2035.  
  2036.     char machine[40];
  2037.     register long first = 0, last, middle;
  2038.     register int  compare;
  2039.  
  2040.     address[0] = '\0';
  2041.  
  2042.     last = size_of_pathfd;
  2043.  
  2044.     do {
  2045.  
  2046.       middle = (long) ((first+last) / 2);
  2047.  
  2048.       get_entry(machine, address, pathfd, middle);
  2049.  
  2050.       compare = strcmp(name, machine);
  2051.  
  2052.       if (compare < 0) 
  2053.         last = middle - 1;
  2054.       else if (compare == 0) 
  2055.         return(0);
  2056.       else  /* greater */
  2057.         first = middle + 1; 
  2058.     } while (abs(last) - abs(first) > FIND_DELTA);
  2059.  
  2060.     return(-1);
  2061. }
  2062.  
  2063. get_entry(machine, address, fileid, offset)
  2064. char *machine, *address;
  2065. FILE *fileid;
  2066. long offset;
  2067. {
  2068.     /** get entry...return machine and address immediately
  2069.         following given offset in fileid.  **/
  2070.  
  2071.     fseek(fileid, offset, 0);
  2072.  
  2073.     /* read until we hit an end-of-line */
  2074.  
  2075.     while (getc(fileid) != '\n')
  2076.        ;
  2077.  
  2078.     fscanf(fileid, "%s\t%s", machine, address);
  2079. }
  2080.  
  2081. init_findnode()
  2082. {
  2083.     /** Initialize the FILE and 'size_of_file' values for the 
  2084.         findnode procedure **/
  2085.  
  2086.     struct stat buffer;
  2087.  
  2088.     if (stat(pathfile, &buffer) == -1) {
  2089.       dprint2(1, "Warning: No pathalias file [filename %s] found! (%s)\n", 
  2090.           pathfile, "init_findnode");
  2091.       size_of_pathfd = 0;
  2092.       return;
  2093.     }
  2094.  
  2095.     size_of_pathfd = (long) buffer.st_size;
  2096.  
  2097.     if ((pathfd = fopen(pathfile,"r")) == NULL) {
  2098.       dprint2(1, "Warning: Can't read pathalias file [filename %s] (%s)\n", 
  2099.            pathfile, "init_findnode");
  2100.       size_of_pathfd = 0;
  2101.     }
  2102.     else
  2103.       dprint2(2, "\nOpened file '%s' as path alias database.  (%s)\n\n", 
  2104.           pathfile, "init_findnode");
  2105. }
  2106.  
  2107. char *find_path_to(machine, printf_format)
  2108. char *machine;
  2109. int   printf_format;
  2110. {
  2111.     /** Returns either the path to the specified machine or NULL if
  2112.         not found.  If "printf_format" is TRUE, then it leaves the
  2113.         '%s' intact, otherwise it assumes that the address is a uucp
  2114.         address for the domain expansion program and removes the
  2115.         last three characters of the expanded name ("!%s") since
  2116.         they're redundant with the expansion!
  2117.         **/
  2118.  
  2119.     static char buffer[LONG_SLEN];    /* space for path */
  2120.  
  2121.     if (size_of_pathfd > 0)
  2122.       if (binary_search(machine, buffer) != -1) {       /* found it! */
  2123.         if (! printf_format && strlen(buffer) > 3)
  2124.           buffer[strlen(buffer)-3] = '\0';
  2125.         return( (char *) buffer);
  2126.       }
  2127.  
  2128.     return(NULL);                        /* failed if it's here! */
  2129. }
  2130. END-OF-FILE
  2131.  
  2132. if [ "$filename" != "/dev/null" ]
  2133. then
  2134.   size=`wc -c < $filename`
  2135.  
  2136.   if [ $size != 5484 ]
  2137.   then
  2138.     echo $filename changed - should be 5484 bytes, not $size bytes
  2139.   fi
  2140.  
  2141.   chmod 644 $filename
  2142. fi
  2143.  
  2144. # ---------- file src/file.c ----------
  2145.  
  2146. filename="src/file.c"
  2147.  
  2148. if [ -f $filename ]
  2149. then
  2150.   echo File \"$filename\" already exists\!  Skipping...
  2151.   filename=/dev/null        # throw it away
  2152. else
  2153.   echo extracting file src/file.c...
  2154. fi
  2155.  
  2156. cat << 'END-OF-FILE' > $filename
  2157. /**        file.c        **/
  2158.  
  2159. /** File I/O routines, mostly the save to file command...
  2160.  
  2161.     (C) Copyright 1986, Dave Taylor
  2162. **/
  2163.  
  2164. #include "headers.h"
  2165. #include <ctype.h>
  2166. #include <errno.h>
  2167.  
  2168. #ifdef BSD
  2169. #undef tolower
  2170. #endif
  2171.  
  2172. extern int errno;
  2173.  
  2174. char *error_name(), *error_description();
  2175.  
  2176. int
  2177. save()
  2178. {
  2179.     /** Save all tagged messages + current in a file.  If no messages
  2180.         are tagged, save the current message instead!  This routine
  2181.         will return ZERO if the operation failed.
  2182.     **/
  2183.  
  2184.     register int tagged = 0, i, oldstat, appending = 0;
  2185.     char filename[SLEN], address[LONG_SLEN], buffer[SLEN];
  2186.     FILE *save_file;
  2187.  
  2188.     oldstat = header_table[current-1].status;    /* remember */
  2189.  
  2190.     for (i=0; i < message_count; i++)
  2191.       if (ison(header_table[i].status, TAGGED))
  2192.         tagged++;
  2193.  
  2194.     if (tagged == 0) {
  2195.       tagged = 1;
  2196.       setit(header_table[current-1].status, TAGGED);
  2197.     }
  2198.  
  2199.     dprint2(4,"%d message%s tagged for saving (save)\n", tagged,
  2200.         plural(tagged));
  2201.  
  2202.     PutLine1(LINES-2, 0, "File message%s in: ", plural(tagged));
  2203.  
  2204.     if (save_by_name) {
  2205.       /** build default filename to save to **/
  2206.       get_return(address);
  2207.       get_return_name(address, buffer, FALSE);
  2208.       sprintf(filename, "=%s", buffer);
  2209.     }
  2210.     else
  2211.       filename[0] = '\0';
  2212.  
  2213.     if (tagged > 1)
  2214.       optionally_enter(filename, LINES-2, 19, FALSE);
  2215.     else    
  2216.       optionally_enter(filename, LINES-2, 18, FALSE);
  2217.  
  2218.     MoveCursor(LINES-1,0);
  2219.  
  2220.     if (strlen(filename) == 0) {  /** <return> means 'cancel', right? **/
  2221.       header_table[current-1].status = oldstat;    /* BACK! */
  2222.       return(0);
  2223.     }
  2224.  
  2225.     if (! expand_filename(filename)) {
  2226.       dprint1(2,"Error: Failed on expansion of filename %s (save)\n", 
  2227.            filename);
  2228.       header_table[current-1].status = oldstat;    /* BACK! */
  2229.       return(0);    /* failed expanding name! */
  2230.     }
  2231.  
  2232.     if (access(filename,ACCESS_EXISTS))     /* already there!! */
  2233.       appending = 1;
  2234.       
  2235.     if ((errno = can_open(filename, "a"))) {
  2236.       error1("Wrong permissions to save message to file %s!", filename);
  2237.       dprint2(2,"Error: access permission on file %s denied (%s)! (save)\n",
  2238.           filename, error_name(errno));
  2239.       header_table[current-1].status = oldstat;    /* BACK! */
  2240.       return(0);
  2241.     }
  2242.  
  2243.     dprint1(4,"Saving mail to file '%s'...\n", filename);
  2244.  
  2245.     if ((save_file = fopen(filename,"a")) == NULL) {
  2246.       dprint1(2, "Error: couldn't append to specified file %s (save)\n", 
  2247.            filename);
  2248.       error1("Couldn't append to file %s!", filename);
  2249.       header_table[current-1].status = oldstat;    /* BACK! */
  2250.       return(0); 
  2251.     }
  2252.  
  2253.     for (i=0; i < message_count; i++)     /* save each tagged msg */
  2254.       if (header_table[i].status & TAGGED)
  2255.         save_message(i, filename, save_file, (tagged > 1), appending++);
  2256.  
  2257.     fclose(save_file);
  2258.  
  2259.     chown(filename, userid, groupid);    /* owned by user */
  2260.     if (tagged > 1)
  2261.       error1("Message%s saved", plural(tagged));
  2262.     return(1);
  2263. }
  2264.  
  2265. int
  2266. save_message(number, filename, fd, pause, appending)
  2267. int number, pause, appending;
  2268. char *filename;
  2269. FILE *fd;
  2270. {
  2271.     /** Save an actual message to a file.  This is called by 
  2272.         "save()" only!  The parameters are the message number,
  2273.         and the name and file descriptor of the file to save to.
  2274.         If 'pause' is true, a sleep(2) will be done after the
  2275.         saved message appears on the screen...
  2276.         'appending' is only true if the file already exists 
  2277.     **/
  2278.  
  2279.     register int save_current;
  2280.     
  2281.     dprint1(4, "\tSaving message %d to file...\n", number);
  2282.  
  2283.     save_current = current;
  2284.     current = number+1;
  2285.     copy_message("", fd, FALSE, FALSE);
  2286.     current = save_current;
  2287.  
  2288.     if (resolve_mode)
  2289.       setit(header_table[number].status, DELETED); /* deleted, but ...   */
  2290.     clearit(header_table[number].status, TAGGED);  /* not tagged anymore */
  2291.     clearit(header_table[number].status, NEW);     /* it's not new now!  */
  2292.  
  2293.     if (! appending)    /* don't ask */
  2294.       error2("Message %d appended to file %s", number+1, filename);
  2295.     else
  2296.       error2("Message %d saved to file %s", number+1, filename);
  2297.  
  2298.     show_new_status(number);    /* update screen, if needed */
  2299.  
  2300.     if (pause) sleep(2);
  2301. }
  2302.  
  2303. int
  2304. expand_filename(filename)
  2305. char *filename;
  2306. {
  2307.     /** Expands '~' and '=' to specified file names, also will try to 
  2308.         expand shell variables if encountered.. '+' and '%' are synonymous 
  2309.         with '=' (folder dir)... **/
  2310.  
  2311.     char buffer[SLEN], varname[SLEN], env_value[SLEN];
  2312.     register int i = 1, index = 0;
  2313.  
  2314.     /** new stuff - make sure no illegal char as last **/
  2315.  
  2316.     if (lastch(filename) == '\n' || lastch(filename) == '\r')
  2317.       lastch(filename) = '\0';
  2318.       
  2319.     if (filename[0] == '~') {
  2320.       sprintf(buffer, "%s%s%s", home, 
  2321.         (filename[1] != '/' && lastch(folders) != '/')? "/" : "",
  2322.           (char *) filename + 1);
  2323.       strcpy(filename, buffer);
  2324.     }
  2325.     else if (filename[0] == '=' || filename[0] == '+' || 
  2326.           filename[0] == '%') {
  2327.       if (strlen(folders) == 0) {
  2328.         dprint2(3,"Error: maildir not defined - can't expand '%c' (%s)\n",
  2329.              filename[0], "expand_filename");
  2330.         error1("MAILDIR not defined.  Can't expand '%c'", filename[0]);
  2331.         return(0);
  2332.       }
  2333.       sprintf(buffer, "%s%s%s", folders, 
  2334.         (filename[1] != '/' && lastch(folders) != '/')? "/" : "",
  2335.         (char *) filename + 1);
  2336.       strcpy(filename, buffer);
  2337.     }
  2338.     else if (filename[0] == '$') {    /* env variable! */
  2339.       while (isalnum(filename[i]))
  2340.         varname[index++] = filename[i++];
  2341.       varname[index] = '\0';
  2342.  
  2343. #ifdef SUN
  2344.       env_value[0] = '\0';            /* null string for strlen! */
  2345.       if (getenv(varname) != NULL)
  2346. #endif
  2347.         strcpy(env_value, getenv(varname));
  2348.  
  2349.       if (strlen(env_value) == 0) {
  2350.         dprint2(3,"Error: Can't expand environment variable $%s (%s)\n",
  2351.             varname, "expand_filename");
  2352.         error1("Don't know what the value of $%s is!", varname);
  2353.         return(0);
  2354.       }
  2355.  
  2356.       sprintf(buffer, "%s%s%s", env_value, 
  2357.           (filename[i] != '/' && lastch(env_value) != '/')? "/" : "",
  2358.           (char *) filename + i);
  2359.       strcpy(filename, buffer);
  2360.     }
  2361.       
  2362.     return(1);
  2363. }
  2364. END-OF-FILE
  2365.  
  2366. if [ "$filename" != "/dev/null" ]
  2367. then
  2368.   size=`wc -c < $filename`
  2369.  
  2370.   if [ $size != 5704 ]
  2371.   then
  2372.     echo $filename changed - should be 5704 bytes, not $size bytes
  2373.   fi
  2374.  
  2375.   chmod 644 $filename
  2376. fi
  2377.  
  2378. echo end of this archive file....
  2379. exit 0
  2380.  
  2381.