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

  1. Subject: v06i034:  Elm mail system (elm), Part09/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 34
  7. Archive-name: elm/Part09
  8.  
  9. # Continuation of Shell Archive, created by hpldat!taylor
  10.  
  11. # This is part 9
  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/output_utils.c ----------
  25.  
  26. filename="src/output_utils.c"
  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/output_utils.c...
  34. fi
  35.  
  36. cat << 'END-OF-FILE' > $filename
  37. /**            output_utils.c            **/
  38.  
  39. /** This file contains routines used for output in the ELM program.
  40.  
  41.     These routines (C) Copyright 1986 Dave Taylor
  42. **/
  43.  
  44. #include "headers.h"
  45.  
  46.  
  47. static char err_buffer[SLEN];        /* store last error message */
  48.  
  49. static char central_message_buffer[SLEN];
  50.  
  51.  
  52. show_last_error()
  53. {
  54.     /** rewrite last error message! **/
  55.  
  56.     error(err_buffer);
  57. }
  58.  
  59. clear_error()
  60. {
  61.     MoveCursor(LINES,0);
  62.     CleartoEOLN();
  63.     err_buffer[0] = '\0';
  64. }
  65.  
  66. set_error(s)
  67. char *s;
  68. {
  69.     strcpy(err_buffer, s);
  70. }
  71.  
  72. error(s)
  73. char *s;
  74. {
  75.     /** outputs error 's' to screen at line 22, centered! **/
  76.  
  77.     MoveCursor(LINES,0);
  78.     CleartoEOLN();
  79.     PutLine0(LINES,(COLUMNS-strlen(s))/2,s);
  80.     fflush(stdout);
  81.     strcpy(err_buffer, s);    /* save it too! */
  82. }
  83.  
  84. error1(s, a)
  85. char *s, *a;
  86. {
  87.     /** same as error, but with a 'printf' argument **/
  88.     char buffer[SLEN];
  89.  
  90.     sprintf(buffer,s,a);
  91.     error(buffer);
  92. }
  93.  
  94. error2(s, a1, a2)
  95. char *s, *a1, *a2;
  96. {
  97.     /** same as error, but with two 'printf' arguments **/
  98.     char buffer[SLEN];
  99.  
  100.     sprintf(buffer,s, a1, a2);
  101.     error(buffer);
  102. }
  103.  
  104. error3(s, a1, a2, a3)
  105. char *s, *a1, *a2, *a3;
  106. {
  107.     /** same as error, but with three 'printf' arguments **/
  108.     char buffer[SLEN];
  109.  
  110.     sprintf(buffer,s, a1, a2, a3);
  111.     error(buffer);
  112. }
  113.  
  114. prompt(s)
  115. char *s;
  116. {
  117.     /** prompt user for input on LINES-3 line, left justified **/
  118.  
  119.     PutLine0(LINES-3,0,s);
  120.     CleartoEOLN();
  121. }
  122.  
  123. prompt1(s,a)
  124. char *s, *a;
  125. {
  126.     /** same as prompt, but with a 'printf' argument **/
  127.     char buffer[SLEN];
  128.  
  129.     sprintf(buffer,s,a);
  130.     prompt(buffer);
  131. }
  132.  
  133.  
  134. set_central_message(string, arg)
  135. char *string, *arg;
  136. {
  137.     /** set up the given message to be displayed in the center of
  138.         the current window **/ 
  139.  
  140.     sprintf(central_message_buffer, string, arg);
  141. }
  142.  
  143. display_central_message()
  144. {
  145.     /** display the message if set... **/
  146.  
  147.     if (central_message_buffer[0] != '\0') {
  148.       ClearLine(LINES-15);
  149.       Centerline(LINES-15, central_message_buffer);
  150.       fflush(stdout);
  151.     }
  152. }
  153.  
  154. clear_central_message()
  155. {
  156.     /** clear the central message buffer **/
  157.  
  158.     central_message_buffer[0] = '\0';
  159. }
  160. END-OF-FILE
  161.  
  162. if [ "$filename" != "/dev/null" ]
  163. then
  164.   size=`wc -c < $filename`
  165.  
  166.   if [ $size != 1987 ]
  167.   then
  168.     echo $filename changed - should be 1987 bytes, not $size bytes
  169.   fi
  170.  
  171.   chmod 644 $filename
  172. fi
  173.  
  174. # ---------- file src/mailtime.c ----------
  175.  
  176. filename="src/mailtime.c"
  177.  
  178. if [ -f $filename ]
  179. then
  180.   echo File \"$filename\" already exists\!  Skipping...
  181.   filename=/dev/null        # throw it away
  182. else
  183.   echo extracting file src/mailtime.c...
  184. fi
  185.  
  186. cat << 'END-OF-FILE' > $filename
  187. /**            mailtime.c            **/
  188.  
  189. /** This set of routines is used to figure out when the user last read
  190.     their mail and to also figure out if a given message is new or not.
  191.  
  192.     (C) Copyright 1986 Dave Taylor
  193. **/
  194.  
  195. #include "headers.h"
  196.  
  197. #include <sys/types.h>
  198. #include <sys/stat.h>
  199. #ifdef BSD
  200. #  include <sys/time.h>
  201. #else
  202. #  include <time.h>
  203. #endif
  204.  
  205. resolve_received(entry)
  206. struct header_rec *entry;
  207. {
  208.     /** Entry has the data for computing the time and date the 
  209.         message was received.  Fix it and return **/
  210.  
  211.     switch (tolower(entry->month[0])) {
  212.       case 'j' : if (tolower(entry->month[1]) == 'a')
  213.                entry->received.month = JANUARY;
  214.              else if (tolower(entry->month[2]) == 'n')
  215.                    entry->received.month = JUNE;
  216.              else
  217.                    entry->received.month = JULY;
  218.                  break;
  219.       case 'f' : entry->received.month = FEBRUARY;
  220.               break;
  221.       case 'm' : if (tolower(entry->month[2]) == 'r')
  222.                    entry->received.month = MARCH;
  223.              else
  224.                entry->received.month = MAY;
  225.                  break;
  226.       case 'a' : if (tolower(entry->month[1]) == 'p')
  227.                    entry->received.month = APRIL;
  228.                  else
  229.                    entry->received.month = AUGUST;
  230.              break;
  231.       case 's' : entry->received.month = SEPTEMBER;
  232.              break;
  233.       case 'o' : entry->received.month = OCTOBER;
  234.              break;
  235.       case 'n' : entry->received.month = NOVEMBER;
  236.                break;
  237.       case 'd' : entry->received.month = DECEMBER;
  238.              break;
  239.     }
  240.  
  241.     sscanf(entry->day, "%d", &(entry->received.day));
  242.  
  243.     sscanf(entry->year, "%d", &(entry->received.year));
  244.     if (entry->received.year > 100) entry->received.year -= 1900;
  245.  
  246.     sscanf(entry->time, "%d:%d", &(entry->received.hour),
  247.            &(entry->received.minute));
  248. }
  249.  
  250. get_mailtime()
  251. {
  252.     /** Instantiate the values of the last_read_mail stat
  253.         variable based on the file access time/date of the
  254.         file mailtime_file.  IF the file doesn't exist,
  255.         then assume all mail is new. **/
  256.  
  257.     struct stat buffer;
  258.     struct tm   *timebuf;
  259.     char   filename[SLEN];
  260.  
  261.     sprintf(filename, "%s/%s", home, mailtime_file);
  262.  
  263.     if (stat(filename, &buffer) == -1) {
  264.       last_read_mail.month = 0;
  265.       last_read_mail.day = 0;
  266.       last_read_mail.year = 0;
  267.       last_read_mail.hour = 0;
  268.       last_read_mail.minute = 0;
  269.     }
  270.     else {    /* stat okay... */
  271.       timebuf = (struct tm *) localtime(&(buffer.st_mtime));
  272.       
  273.       last_read_mail.month = timebuf->tm_mon;
  274.       last_read_mail.day = timebuf->tm_mday;
  275.       last_read_mail.year = timebuf->tm_year;
  276.       last_read_mail.hour = timebuf->tm_hour;
  277.       last_read_mail.minute = timebuf->tm_min;
  278.     }
  279. }
  280.  
  281. update_mailtime()
  282. {
  283.     /** This routine updates the last modified time of the 
  284.         .last_read_mail file in the users home directory.
  285.         If the file doesn't exist, it creates it!! **/
  286.  
  287.     char filename[SLEN];
  288.  
  289. #ifdef BSD
  290.     struct timeval    tval[2];
  291.     struct timezone tzone;
  292. #endif
  293.     
  294.     sprintf(filename, "%s/%s", home, mailtime_file);
  295.  
  296. #ifdef BSD
  297.     gettimeofday(&tval[0], &tzone);
  298.     gettimeofday(&tval[1], &tzone);
  299.  
  300.     if (utime(filename, &tval) == -1)
  301. #else
  302.     if (utime(filename, NULL) == -1)
  303. #endif
  304.       (void) creat(filename, 0777);
  305. }
  306.  
  307. new_msg(entry)
  308. struct header_rec entry;
  309. {
  310.     /** Return true if the current message is NEW.  This can be
  311.         easily tested by seeing 1) if we're reading the incoming
  312.         mailbox and then, if so, 2) if the received_on_machine
  313.         date is more recent than the last_read_mail date.
  314.     **/
  315.  
  316.     if (mbox_specified != 0) return(FALSE);        /* not incoming */
  317.     
  318.     /** Two tests - if received is OLDER than last read mail, then
  319.         immediately return FALSE.  If received is NEWER than last
  320.         read mail then immediately return TRUE **/
  321.  
  322.     if (entry.received.year < last_read_mail.year) 
  323.       return(FALSE);                
  324.     
  325.     if (entry.received.year > last_read_mail.year) 
  326.       return(TRUE);                
  327.     
  328.     if (entry.received.month < last_read_mail.month)
  329.       return(FALSE);            
  330.  
  331.     if (entry.received.month > last_read_mail.month)
  332.       return(TRUE);            
  333.  
  334.     if (entry.received.day < last_read_mail.day)
  335.       return(FALSE);
  336.  
  337.     if (entry.received.day > last_read_mail.day)
  338.       return(TRUE);
  339.  
  340.     if (entry.received.hour < last_read_mail.hour)        
  341.       return(FALSE);        
  342.     
  343.     if (entry.received.hour > last_read_mail.hour)        
  344.       return(TRUE);        
  345.     
  346.     if (entry.received.minute < last_read_mail.minute)
  347.       return(FALSE);    
  348.  
  349.     return(TRUE);
  350. }
  351. END-OF-FILE
  352.  
  353. if [ "$filename" != "/dev/null" ]
  354. then
  355.   size=`wc -c < $filename`
  356.  
  357.   if [ $size != 4271 ]
  358.   then
  359.     echo $filename changed - should be 4271 bytes, not $size bytes
  360.   fi
  361.  
  362.   chmod 644 $filename
  363. fi
  364.  
  365. # ---------- file src/encode.c ----------
  366.  
  367. filename="src/encode.c"
  368.  
  369. if [ -f $filename ]
  370. then
  371.   echo File \"$filename\" already exists\!  Skipping...
  372.   filename=/dev/null        # throw it away
  373. else
  374.   echo extracting file src/encode.c...
  375. fi
  376.  
  377. cat << 'END-OF-FILE' > $filename
  378. /**        encode.c        **/
  379.  
  380. /** This is a heavily mangled version of the 'cypher' program written by
  381.     person or persons unknown.  
  382.  
  383.     (C) Copyright 1986, Dave Taylor
  384. **/
  385.  
  386. #include <stdio.h>
  387. #include "curses.h"
  388. #include "headers.h"
  389.  
  390. #define RS    94
  391. #define RN    4
  392. #define RMASK    0x7fff    /* use only 15 bits */
  393.  
  394. static char r[RS][RN];        /* rotors */
  395. static char ir[RS][RN];        /* inverse rotors */
  396. static char h[RS];        /* half rotor */
  397. static char s[RS];        /* shuffle vector */
  398. static int  p[RN];        /* rotor indices */
  399.  
  400. static char the_key[SLEN];    /* unencrypted key */
  401. static char *encrypted_key;    /* encrypted key   */
  402.  
  403. getkey(send)
  404. int send;
  405. {
  406.     /** this routine prompts for and returns an encode/decode
  407.         key for use in the rest of the program.  If send == 1
  408.         then need to mess with rawmode. **/
  409.  
  410.     char buffer[NLEN];
  411.     int gotkey = 0;
  412.  
  413.     ClearLine(21);
  414.  
  415.     if (send) Raw(OFF);
  416.  
  417.     while ( !gotkey ) {
  418.       MoveCursor(LINES-1,0);
  419.       ClearLine(LINES-1);
  420.       if (send)
  421.         strcpy( buffer, getpass( "Enter encryption key: "));
  422.       else
  423.         strcpy( buffer, getpass( "Enter decryption key: "));
  424.       MoveCursor(LINES-1,0);
  425.       if ( strcmp( buffer, getpass( "Please enter it again: "))) {
  426.         error("Your keys were not the same!");
  427.         sleep(1);
  428.         clear_error();
  429.         continue;
  430.       }
  431.       strcpy(the_key, buffer);    /* save unencrypted key */
  432.       makekey( buffer );
  433.       gotkey = 1;
  434.     }
  435.  
  436.     if (send) Raw(ON);
  437.  
  438.     setup();        /** initialize the rotors etc. **/
  439.  
  440.     ClearLine(LINES-1);        
  441.     clear_error();
  442. }
  443.  
  444. get_key_no_prompt()
  445. {
  446.     /** This performs the same action as get_key, but assumes that
  447.         the current value of 'the_key' is acceptable.  This is used
  448.         when a message is encrypted twice... **/
  449.  
  450.     char buffer[SLEN];
  451.  
  452.     strcpy(buffer, the_key);
  453.  
  454.     makekey( buffer );
  455.  
  456.     setup();
  457. }
  458.  
  459. encode(line)
  460. char *line;
  461. {
  462.     /** encrypt or decrypt the specified line.  Uses the previously
  463.         entered key... **/
  464.  
  465.     register int i, index, j, ph = 0;
  466.  
  467.     for (index=0; index < strlen(line); index++) {
  468.       i = (int) line[index];
  469.  
  470.       if ( (i >= ' ') && (i < '~') ) {
  471.         i -= ' ';
  472.  
  473.         for ( j = 0; j < RN; j++ )        /* rotor forwards */
  474.           i = r[(i+p[j])%RS][j];
  475.  
  476.         i = ((h[(i+ph)%RS])-ph+RS)%RS;    /* half rotor */
  477.  
  478.         for ( j--  ; j >= 0; j-- )        /* rotor backwards */
  479.           i = (ir[i][j]+RS-p[j])%RS;
  480.  
  481.         j = 0;                /* rotate rotors */
  482.         p[0]++;
  483.         while ( p[j] == RS ) {
  484.           p[j] = 0;
  485.           j++;
  486.           if ( j == RN ) break;
  487.           p[j]++;
  488.             }
  489.   
  490.         if ( ++ph == RS )
  491.           ph = 0;
  492.  
  493.         i += ' ';
  494.       }
  495.       
  496.       line[index] = (char) i;    /* replace with altered one */
  497.     }
  498. }
  499.  
  500.  
  501. makekey( rkey)
  502. char *rkey;
  503. {
  504.     /** encrypt the key using the system routine 'crypt' **/
  505.  
  506.     char key[8], salt[2], *crypt();
  507.  
  508.     strncpy( key, rkey, 8);
  509.     salt[0] = key[0];
  510.     salt[1] = key[1];
  511.     encrypted_key = crypt( key, salt);
  512. }
  513.  
  514. /*
  515.  * shuffle rotors.
  516.  * shuffle each of the rotors indiscriminately.  shuffle the half-rotor
  517.  * using a special obvious and not very tricky algorithm which is not as
  518.  * sophisticated as the one in crypt(1) and Oh God, I'm so depressed.
  519.  * After all this is done build the inverses of the rotors.
  520.  */
  521.  
  522. setup()
  523. {
  524.     register long i, j, k, temp;
  525.     long seed;
  526.  
  527.     for ( j = 0; j < RN; j++ ) {
  528.         p[j] = 0;
  529.         for ( i = 0; i < RS; i++ )
  530.             r[i][j] = i;
  531.     }
  532.  
  533.     seed = 123;
  534.     for ( i = 0; i < 13; i++)        /* now personalize the seed */
  535.       seed = (seed*encrypted_key[i] + i) & RMASK;
  536.  
  537.     for ( i = 0; i < RS; i++ )        /* initialize shuffle vector */
  538.       h[i] = s[i] = i;
  539.  
  540.     for ( i = 0; i < RS; i++) {        /* shuffle the vector */
  541.       seed = (5 * seed + encrypted_key[i%13]) & RMASK;;
  542.       k = ((seed % 65521) & RMASK) % RS;
  543.       temp = s[k];
  544.       s[k] = s[i];
  545.       s[i] = temp;
  546.     }
  547.  
  548.     for ( i = 0; i < RS; i += 2 ) {    /* scramble the half-rotor */
  549.       temp = h[s[i]];            /* swap rotor elements ONCE */
  550.       h[s[i]] = h[s[i+1]];
  551.       h[s[i+1]] = temp;
  552.     }
  553.  
  554.     for ( j = 0; j < RN; j++) {            /* select a rotor */
  555.  
  556.       for ( i = 0; i < RS; i++) {        /* shuffle the vector */
  557.         seed = (5 * seed + encrypted_key[i%13]) & RMASK;;
  558.         k = ((seed % 65521) & RMASK) % RS;
  559.         temp = r[i][j];
  560.         r[i][j] = r[k][j];
  561.         r[k][j] = temp;
  562.       }
  563.  
  564.       for ( i = 0; i < RS; i++)         /* create inverse rotors */
  565.         ir[r[i][j]][j] = i;
  566.        }
  567. }
  568. END-OF-FILE
  569.  
  570. if [ "$filename" != "/dev/null" ]
  571. then
  572.   size=`wc -c < $filename`
  573.  
  574.   if [ $size != 4156 ]
  575.   then
  576.     echo $filename changed - should be 4156 bytes, not $size bytes
  577.   fi
  578.  
  579.   chmod 644 $filename
  580. fi
  581.  
  582. # ---------- file src/leavembox.c ----------
  583.  
  584. filename="src/leavembox.c"
  585.  
  586. if [ -f $filename ]
  587. then
  588.   echo File \"$filename\" already exists\!  Skipping...
  589.   filename=/dev/null        # throw it away
  590. else
  591.   echo extracting file src/leavembox.c...
  592. fi
  593.  
  594. cat << 'END-OF-FILE' > $filename
  595. /**            leavembox.c            **/
  596.  
  597. /** leave current mailbox, updating etc. as needed...
  598.   
  599.     (C) Copyright 1985, Dave Taylor
  600. **/
  601.  
  602. #include "headers.h"
  603. #include <sys/types.h>
  604. #include <sys/stat.h>
  605. #include <errno.h>
  606.  
  607. #define  ECHOIT     1    /* echo on for prompting! */
  608.  
  609. /** added due to a bug in the 2.1 OS **/
  610.  
  611. struct utimbuf {
  612.     time_t    actime;        /** access time **/
  613.     time_t  modtime;    /** modification */
  614.        };
  615.  
  616. extern int errno;
  617.  
  618. char *error_name(), *error_description();
  619.  
  620. int
  621. leave_mbox(quitting)
  622. int quitting;
  623. {
  624.     /** Exit, saving files into mbox and deleting specified, or simply 
  625.         delete specified mail... If "quitting" is true, then output status 
  626.             regardless of what happens.  Returns 1 iff mailfile was
  627.         changed (ie messages deleted from file), 0 if not, and -1 if new
  628.         mail has arrived in the meantime...
  629.     **/
  630.  
  631.     FILE *temp;
  632.     char outfile[SLEN], buffer[SLEN];
  633.     struct stat buf;        /* stat command  */
  634.     struct utimbuf times;        /* utime command */
  635.     register int to_delete = 0, to_save = 0, i, mode = 00644,
  636.              pending = 0, number_saved = 0, last_sortby;
  637.     char dflt;
  638.     long bytes();
  639.  
  640.     dprint0(1,"\n\n-- leaving_mailbox --\n\n");
  641.  
  642.     if (message_count == 0) 
  643.       return(FALSE);    /* nothing changed */
  644.  
  645.     for (i = 0; i < message_count; i++)
  646.       if (ison(header_table[i].status, DELETED)) to_delete++;
  647.       else                                       to_save++;
  648.  
  649.     dprint2(2,"Count: %d to delete and %d to save\n", to_delete, to_save);
  650.  
  651.     if (mbox_specified == 0) 
  652.       update_mailtime();
  653.  
  654.     if (hp_softkeys) {
  655.       define_softkeys(YESNO);        /* YES or NO on softkeys */
  656.       softkeys_on();
  657.     }
  658.  
  659.     if (always_del)     /* set up the default answer... */
  660.       dflt = 'y';
  661.     else 
  662.       dflt = 'n';
  663.  
  664.     if (to_delete)
  665.       if (to_save) {
  666.         sprintf(buffer, "Delete message%s? (y/n) ", plural(to_delete));
  667.         if (want_to(buffer, dflt, ECHOIT) != 'y') {
  668.           if (mbox_specified == 0) unlock();    /* remove lock! */
  669.           dprint1(3,"\tDelete message%s? - answer was NO\n", 
  670.             plural(to_delete));
  671.           error("Nothing deleted");
  672.           return(FALSE);    /* nothing was deleted! */
  673.         }
  674.       }
  675.       else if (! to_save) {        /* nothing to save!! */
  676.         if (want_to("Delete all mail? (y/n) ", dflt, ECHOIT)!='y') {
  677.           if (mbox_specified == 0) unlock();    /* remove lock! */
  678.           dprint0(3,"Delete all mail? - answer was NO\n");
  679.           error("Nothing deleted");
  680.           return(FALSE);   /* nothing was deleted */
  681.         }
  682.       }
  683.  
  684.     if (always_leave) 
  685.       dflt = 'y';
  686.     else
  687.       dflt = 'n';
  688.       
  689.     /** we have to check to see what the sorting order was...so that
  690.         the order of saved messages is the same as the order of the
  691.         messages originally (a subtle point...) **/
  692.  
  693.     if (sortby != RECEIVED_DATE) {    /* what we want anyway! */
  694.       last_sortby = sortby;
  695.       sortby = RECEIVED_DATE;
  696.       sort_mailbox(message_count, FALSE);
  697.       sortby = last_sortby;
  698.     }
  699.  
  700.     if (to_save && mbox_specified == 0) 
  701.       if (want_to("Keep mail in incoming mailbox? (y/n) ",dflt, ECHOIT)
  702.           == 'y') 
  703.           if (to_delete)        /* okay - keep undeleted as pending!    */
  704.             pending++;
  705.           else {               /* gag! nothing to delete, don't save!  */    
  706.             unlock();        /* remove mailfile lock!               */
  707.             dprint0(3,"Keep mail in incoming mailbox? -- answer was YES\n");
  708.             error("Mailbox unchanged");
  709.             return(FALSE);    /* nothing changed! */
  710.           }
  711.  
  712.     /** okay...now lets do it! **/
  713.  
  714.     if (to_save > 0) {
  715.       if (to_delete > 0)
  716.         sprintf(buffer ,"[%s %d message%s, and deleting %d]", 
  717.               pending? "keeping" : "storing", 
  718.           to_save, plural(to_save), to_delete);
  719.       else if (quitting)
  720.         sprintf(buffer,"[%s %s]",
  721.               pending? "keeping" : "storing",
  722.           to_save > 1? "all messages" : "message");
  723.       else
  724.         buffer[0] = '\0';    /* no string! */
  725.     }
  726.     else {
  727.       if (to_delete > 0)
  728.         sprintf(buffer, "[deleting all messages]");
  729.       else if (quitting)
  730.         sprintf(buffer, "[no messages to %s, and none to delete]",
  731.                 pending? "keep" : "save");
  732.       else
  733.         buffer[0] = '\0';
  734.     }
  735.  
  736.     dprint1(2,"Action: %s\n", buffer);
  737.  
  738.     error(buffer);
  739.  
  740.     if (! mbox_specified) {
  741.       if (pending) {                /* keep some messages pending! */
  742.         sprintf(outfile,"%s%d", temp_mbox, getpid());
  743.         unlink(outfile);
  744.       }
  745.       else if (mailbox_defined)    /* save to specified mailbox */
  746.         strcpy(outfile, mailbox);
  747.       else                /* save to $home/mbox */
  748.         sprintf(outfile,"%s/mbox", home);
  749.     }
  750.     else {
  751.       if (! to_delete) return(FALSE);    /* no work to do! */
  752.           sprintf(outfile, "%s%d", temp_file, getpid());
  753.       unlink(outfile); /* ensure it's empty! */
  754.     }
  755.  
  756.     if (to_save) {
  757.       if ((errno = can_open(outfile, "a"))) {
  758.         error1(
  759.              "Permission to append to %s denied!  Leaving mailbox intact\n",
  760.          outfile);
  761.         dprint2(1,
  762.          "Error: Permission to append to outfile %s denied!! (%s)\n",
  763.          outfile, "leavembox");
  764.         dprint2(1,"** %s - %s **\n", error_name(errno),
  765.          error_description(errno));
  766.         unlock();
  767.         return(0);
  768.       }
  769.       if ((temp = fopen(outfile,"a")) == NULL) {
  770.         if (mbox_specified == 0)
  771.           unlock();        /* remove mailfile lock! */
  772.         dprint1(1,"Error: could not append to file %s\n", 
  773.             outfile);
  774.         dprint2(1,"** %s - %s **\n", error_name(errno),
  775.          error_description(errno));
  776.         sprintf(buffer, "           Could not append to file %s!          ",
  777.             outfile);
  778.         emergency_exit(Centerline(LINES-1, buffer));
  779.       }
  780.   
  781.       for (i = 0; i < message_count; i++)
  782.         if (! (header_table[i].status & DELETED)) {
  783.           current = i+1;
  784.           if (! number_saved++) {
  785.             dprint2(2,"Saving message%s #%d, ", plural(to_save), current);
  786.           }
  787.           else {
  788.         dprint1(2,"#%d, ", current);
  789.           }
  790.           copy_message("", temp, FALSE, FALSE);
  791.         }
  792.       fclose(temp);
  793.       dprint0(2,"\n\n");
  794.     }
  795.  
  796.     /* remove source file...either default mailbox or original copy of 
  797.            specified one! */
  798.  
  799.     if (mbox_specified == 0) {
  800.       /** let's grab the original mode and date/time of the mailfile 
  801.           before removing it **/
  802.  
  803.           if (stat(infile, &buf) == 0)
  804.         mode = buf.st_mode & 00777;
  805.       else {
  806.         dprint2(1,"Error: errno %s attempting to stat file %s\n", 
  807.              error_name(errno), infile);
  808.             error2("Error %s (%s) on stat(%s)", error_name(errno), 
  809.         error_description(errno), infile);
  810.       }
  811.     }
  812.  
  813.     fclose(mailfile);    /* close the baby... */
  814.     
  815.     if (mailfile_size != bytes(infile)) {
  816.       sort_mailbox(message_count, FALSE);    /* display sorting order! */
  817.       unlock();
  818.       error("New mail has just arrived - resyncing...");
  819.       return(-1);
  820.     }
  821.     unlink(infile);     /* and BLAMO!        */
  822.  
  823.     if (to_save && (mbox_specified || pending)) {
  824.       if (link(outfile, infile) != 0) 
  825.         if (errno == EXDEV) { /** different file devices!  Use copy! **/
  826.           if (copy(outfile, infile) != 0) {
  827.             dprint2(1,"leavembox: copy(%s, %s) failed;",
  828.             outfile, infile);
  829.             dprint2(1,"** %s - %s **\n", error_name(errno),
  830.              error_description(errno));
  831.             error("couldn't modify mail file!");
  832.             sleep(1);
  833.             sprintf(infile,"%s/%s", home, unedited_mail);
  834.         if (copy(outfile, infile) != 0) {
  835.               dprint1(1,"leavembox: couldn't copy to %s either!!  Help;", 
  836.               infile);
  837.               dprint2(1,"** %s - %s **\n", error_name(errno),
  838.                   error_description(errno));
  839.               error("something godawful is happening to me!!!");
  840.           emergency_exit();
  841.             }
  842.         else {
  843.               dprint1(1,"\nWoah! Confused - Saved mail in %s (leavembox)\n", 
  844.               infile);
  845.               error1("saved mail in %s", infile);
  846.             }
  847.           }    
  848.         }
  849.         else {
  850.           dprint2(1,"link(%s, %s) failed (leavembox)\n", outfile, infile);
  851.           dprint2(1,"** %s - %s **\n", error_name(errno),
  852.             error_description(errno));
  853.           error2("link failed! %s - %s", error_name(errno),
  854.         error_description(errno));
  855.           emergency_exit();
  856.         }
  857.       unlink(outfile);
  858.     }
  859.  
  860.     if (mbox_specified == 0) {
  861.       if (mode != 00644) { /* if not the default mail access mode... */
  862.         if (! pending) { /* if none still being saved */
  863.           temp = fopen(infile, "w");
  864.           fclose(temp);
  865.         }
  866.         chmod(infile,mode);
  867.  
  868.         /* let's set the access times of the new mail file to be
  869.            the same as the OLD one (still sitting in 'buf') ! */
  870.  
  871.         times.actime = buf.st_atime;
  872.         times.modtime= buf.st_mtime;
  873.  
  874.         if (utime(infile, ×) != 0) {
  875.           dprint0(1,"Error: encountered error doing utime (leavmbox)\n");
  876.           dprint2(1,"** %s - %s **\n", error_name(errno), 
  877.              error_description(errno));
  878.           error2("Error %s trying to change file %s access time", 
  879.              error_name(errno), infile);
  880.         }
  881.       }
  882.       unlock();    /* remove the lock on the file ASAP! */
  883.  
  884.       /** finally, let's change the ownership of the default
  885.           outgoing mailbox, if needed **/
  886.  
  887.       if (to_save) 
  888.         chown(outfile, userid, groupid);
  889.     }
  890.  
  891. #ifdef SAVE_GROUP_MAILBOX_ID
  892.     chown(infile, userid, getegid());    /** see the Config Guide **/
  893. #else
  894.     chown(infile, userid, groupid);        /**  file owned by user  **/
  895. #endif
  896.  
  897.     return(to_delete);    
  898. }
  899.  
  900. char lock_name[SLEN];
  901.  
  902. lock(direction)
  903. int direction;
  904. {
  905.     /** Create lock file to ensure that we don't get any mail 
  906.         while altering the mailbox contents!
  907.         If it already exists sit and spin until 
  908.                either the lock file is removed...indicating new mail
  909.         or
  910.            we have iterated MAX_ATTEMPTS times, in which case we
  911.            either fail or remove it and make our own (determined
  912.            by if REMOVE_AT_LAST is defined in header file
  913.  
  914.         If direction == INCOMING then DON'T remove the lock file
  915.         on the way out!  (It'd mess up whatever created it!).
  916.     **/
  917.  
  918.     register int iteration = 0, access_val;
  919.  
  920.     sprintf(lock_name,"%s%s.lock", mailhome, username);
  921.  
  922.     access_val = access(lock_name, ACCESS_EXISTS);
  923.  
  924.     while (access_val != -1 && iteration++ < MAX_ATTEMPTS) {
  925.       dprint1(2,"File '%s' currently exists!  Waiting...(lock)\n", 
  926.           lock_name);
  927.       if (direction == INCOMING)
  928.         PutLine0(LINES, 0, "\nMail being received!\twaiting...");
  929.       else
  930.         error1("Attempt %d: Mail being received...waiting", 
  931.                    iteration);
  932.       sleep(5);
  933.       access_val = access(lock_name, ACCESS_EXISTS);
  934.     }
  935.     
  936.     if (access_val != -1) {
  937.  
  938. #ifdef REMOVE_AT_LAST
  939.  
  940.       /** time to waste the lock file!  Must be there in error! **/
  941.  
  942.       dprint0(2,
  943.          "Warning: I'm giving up waiting - removing lock file(lock)\n");
  944.       if (direction == INCOMING)
  945.         PutLine0(LINES, 0,"\nTimed out - removing current lock file...");
  946.       else
  947.         error("Throwing away the current lock file!");
  948.  
  949.       if (unlink(lock_name) != 0) {
  950.         dprint3(1,"Error %s (%s)\n\ttrying to unlink file %s (%s)\n", 
  951.              error_name(errno), error_description(errno), lock_name);
  952.         PutLine1(LINES, 0, 
  953.            "\n\rI couldn't remove the current lock file %s\n\r", 
  954.            lock_name);
  955.         PutLine2(LINES, 0, "** %s - %s **\n\r", error_name(errno),
  956.            error_description(errno));
  957.         if (direction == INCOMING)
  958.           leave();
  959.         else
  960.           emergency_exit();
  961.       }
  962.       
  963.       /* everything is okay, so lets act as if nothing had happened... */
  964.  
  965. #else
  966.  
  967.       /* okay...we die and leave, not updating the mailfile mbox or
  968.          any of those! */
  969.       if (direction == INCOMING) {
  970.         PutLine1(LINES, 0, "\nGiving up after %d iterations...", iteration);
  971.         PutLine0(LINES, 0, 
  972.         "Please try to read your mail again in a few minutes.\n");
  973.         dprint1(2,"Warning:bailing out after %d iterations...(lock)\n", 
  974.             iteration);
  975.         leave_locked();
  976.       }
  977.       else {
  978.         dprint1(2,"Warning: after %d iterations, timed out! (lock)\n", 
  979.             iteration);
  980.         leave(error("Timed out on lock file reads.  Leaving program"));
  981.       }
  982.  
  983. #endif
  984.     }
  985.  
  986.     /* if we get here we can create the lock file, so lets do it! */
  987.  
  988.     if (creat(lock_name, 0) == -1) {
  989.       dprint2(1,"Can't create lock file: creat(%s) raises error %s (lock)\n", 
  990.           lock_name, error_name(errno));
  991.       if (errno == EACCES)
  992.         leave(error1(
  993.                  "Can't create lock file!  I need write permission in %s!\n\r",
  994.           mailhome));
  995.       else {
  996.         dprint1(1,"Error encountered attempting to create lock %s\n", 
  997.           lock_name);
  998.         dprint2(1,"** %s - %s **\n", error_name(errno),
  999.           error_description(errno));
  1000.         PutLine1(LINES, 0,
  1001.          "\n\rError encountered while attempting to create lock file %s;\n\r", 
  1002.           lock_name);
  1003.         PutLine2(LINES, 0, "** %s - %s **\n\r", error_name(errno),
  1004.           error_description(errno));
  1005.         leave();
  1006.       }
  1007.     }
  1008. }
  1009.  
  1010. unlock()
  1011. {
  1012.     /** Remove the lock file!    This must be part of the interrupt
  1013.         processing routine to ensure that the lock file is NEVER
  1014.         left sitting in the mailhome directory! **/
  1015.  
  1016.     (void) unlink(lock_name);
  1017. }
  1018. END-OF-FILE
  1019.  
  1020. if [ "$filename" != "/dev/null" ]
  1021. then
  1022.   size=`wc -c < $filename`
  1023.  
  1024.   if [ $size != 12538 ]
  1025.   then
  1026.     echo $filename changed - should be 12538 bytes, not $size bytes
  1027.   fi
  1028.  
  1029.   chmod 644 $filename
  1030. fi
  1031.  
  1032. # ---------- file src/bounceback.c ----------
  1033.  
  1034. filename="src/bounceback.c"
  1035.  
  1036. if [ -f $filename ]
  1037. then
  1038.   echo File \"$filename\" already exists\!  Skipping...
  1039.   filename=/dev/null        # throw it away
  1040. else
  1041.   echo extracting file src/bounceback.c...
  1042. fi
  1043.  
  1044. cat << 'END-OF-FILE' > $filename
  1045. /**            bounceback.c            **/
  1046.  
  1047. /** This set of routines implement the bounceback feature of the mailer.
  1048.     This feature allows mail greater than 'n' hops away (n specified by
  1049.     the user) to have a 'cc' to the user through the remote machine.  
  1050.  
  1051.     Due to the vagaries of the Internet addressing (uucp -> internet -> uucp)
  1052.     this will NOT generate bounceback copies with mail to an internet host!
  1053.  
  1054.     (C) Copyright 1986 by Dave Taylor
  1055. **/
  1056.  
  1057. #include "headers.h"
  1058.  
  1059. char *bounce_off_remote();        /* forward declaration */
  1060.  
  1061. int
  1062. uucp_hops(to)
  1063. char *to;
  1064. {    
  1065.     /** Given the entire "To:" list, return the number of hops in the
  1066.         first address (a hop = a '!') or ZERO iff the address is to a
  1067.           non uucp address.
  1068.     **/
  1069.  
  1070.     register int hopcount = 0, index;
  1071.  
  1072.     for (index = 0; ! whitespace(to[index]) && to[index] != '\0'; index++) {
  1073.       if (to[index] == '!')
  1074.         hopcount++;
  1075.       else if (to[index] == '@' || to[index] == '%' || to[index] == ':')
  1076.         return(0);    /* don't continue! */
  1077.     }
  1078.  
  1079.     return(hopcount);
  1080. }
  1081.     
  1082. char *bounce_off_remote(to)
  1083. char *to;
  1084. {
  1085.     /** Return an address suitable for framing (no, that's not it...)
  1086.         Er, suitable for including in a 'cc' line so that it ends up
  1087.         with the bounceback address.  The method is to take the first 
  1088.         address in the To: entry and break it into machines, then 
  1089.         build a message up from that.  For example, consider the
  1090.         following address:
  1091.             a!b!c!d!e!joe
  1092.         the bounceback address would be;
  1093.             a!b!c!d!e!d!c!b!a!ourmachine!ourname
  1094.         simple, eh?
  1095.     **/
  1096.  
  1097.     static char address[LONG_STRING];    /* BEEG address buffer! */
  1098.  
  1099.     char   host[MAX_HOPS][SHORT_SLEN];    /* for breaking up addr */
  1100.     register int hostcount = 0, hindex = 0, 
  1101.            index;
  1102.  
  1103.     for (index = 0; !whitespace(to[index]) && to[index] != '\0'; index++) {
  1104.       if (to[index] == '!') {
  1105.         host[hostcount][hindex] = '\0';
  1106.         hostcount++;
  1107.         hindex = 0;
  1108.       }
  1109.       else 
  1110.         host[hostcount][hindex++] = to[index];
  1111.     }
  1112.  
  1113.     /* we have hostcount hosts... */
  1114.  
  1115.     strcpy(address, host[0]);    /* initialize it! */
  1116.  
  1117.     for (index=1; index < hostcount; index++) {
  1118.       strcat(address, "!");
  1119.       strcat(address, host[index]);
  1120.     }
  1121.     
  1122.     /* and now the same thing backwards... */
  1123.  
  1124.     for (index = hostcount -2; index > -1; index--) {
  1125.       strcat(address, "!");
  1126.       strcat(address, host[index]);
  1127.     }
  1128.  
  1129.     /* and finally, let's tack on our machine and login name */
  1130.  
  1131.     strcat(address, "!");
  1132.     strcat(address, hostname);
  1133.     strcat(address, "!");
  1134.     strcat(address, username);
  1135.  
  1136.     /* and we're done!! */
  1137.  
  1138.     return( (char *) address );
  1139. }
  1140. END-OF-FILE
  1141.  
  1142. if [ "$filename" != "/dev/null" ]
  1143. then
  1144.   size=`wc -c < $filename`
  1145.  
  1146.   if [ $size != 2498 ]
  1147.   then
  1148.     echo $filename changed - should be 2498 bytes, not $size bytes
  1149.   fi
  1150.  
  1151.   chmod 644 $filename
  1152. fi
  1153.  
  1154. # ---------- file src/opt_utils.c ----------
  1155.  
  1156. filename="src/opt_utils.c"
  1157.  
  1158. if [ -f $filename ]
  1159. then
  1160.   echo File \"$filename\" already exists\!  Skipping...
  1161.   filename=/dev/null        # throw it away
  1162. else
  1163.   echo extracting file src/opt_utils.c...
  1164. fi
  1165.  
  1166. cat << 'END-OF-FILE' > $filename
  1167. /**            opt_utils.c            **/
  1168.  
  1169. /** This file contains routines that might be needed for the various
  1170.      machines that the mailer can run on.  Please check the Makefile
  1171.      for more help and/or information. 
  1172.  
  1173.      (C) Copyright 1986 Dave Taylor
  1174. **/
  1175.  
  1176. #include <stdio.h>
  1177.  
  1178. #ifdef BSD
  1179. #  include <pwd.h>
  1180. #endif
  1181.  
  1182. #ifdef UTS
  1183. #  include <sys/utsname.h>
  1184. #  include <sys/tubio.h>
  1185.  
  1186. #  define  TTYIN        0        /* standard input */
  1187.  
  1188. gethostname(hostname,size) /* get name of current host */
  1189. int size;
  1190. char *hostname;
  1191. {
  1192.     /** Return the name of the current host machine.  UTS only **/
  1193.  
  1194.     /** This routine compliments of Scott McGregor at the HP
  1195.         Corporate Computing Center **/
  1196.      
  1197.     int uname();
  1198.     struct utsname name;
  1199.  
  1200.     (void) uname(&name);
  1201.     (void) strncpy(hostname,name.nodename,size-1);
  1202.     hostname[size] = '\0';
  1203.  
  1204. }
  1205.  
  1206. int
  1207. isa3270()
  1208. {
  1209.     /** Returns TRUE and sets LINES and COLUMNS to the correct values
  1210.         for an Amdahl (IBM) tube screen, or returns FALSE if on a normal
  1211.         terminal (of course, next to a 3270, ANYTHING is normal!!) **/
  1212.  
  1213.     struct tubiocb tubecb;
  1214.  
  1215.     dprint0(3,"Seeing if we're a 3270...");
  1216.  
  1217.     if (ioctl(TTYIN, TUBGETMOD, &tubecb) == -1) {
  1218.       dprint0(3,"We're not!\n");
  1219.       return(FALSE);    /* not a tube! */
  1220.     }
  1221.     
  1222.     LINES   = tubecb->line_cnt - 1;
  1223.     COLUMNS = tubecb->col_cnt;
  1224.     
  1225.     dprint2(3,"We are!  %d lines and %d columns!\n",
  1226.         LINES, COLUMNS);
  1227.     return(TRUE);
  1228. }
  1229.  
  1230. #endif /* def UTS */
  1231.  
  1232. #ifdef BSD
  1233.  
  1234. cuserid(uname)
  1235. char *uname;
  1236. {
  1237.     /** Added for compatibility with Bell systems, this is the last-ditch
  1238.         attempt to get the users login name, after getlogin() fails.  It
  1239.         instantiates "uname" to the name of the user...
  1240.     **/
  1241.  
  1242.     struct passwd *password_entry, *getpwuid();
  1243.  
  1244.     password_entry = getpwuid(getuid());
  1245.  
  1246.     strcpy(uname, password_entry->pw_name);
  1247. }
  1248.  
  1249. /** some supplementary string functions for Berkeley Unix systems **/
  1250.  
  1251. strspn(source, keys)
  1252. char *source, *keys;
  1253. {
  1254.     /** This function returns the length of the substring of
  1255.         'source' (starting at zero) that consists ENTIRELY of
  1256.         characters from 'keys'.  This is used to skip over a
  1257.         defined set of characters with parsing, usually. 
  1258.     **/
  1259.  
  1260.     register int loc = 0, key_index = 0;
  1261.  
  1262.     while (source[loc] != '\0') {
  1263.       key_index = 0;
  1264.       while (keys[key_index] != source[loc])
  1265.         if (keys[key_index++] == '\0')
  1266.           return(loc);
  1267.       loc++;
  1268.     }
  1269.  
  1270.     return(loc);
  1271. }
  1272.  
  1273. strcspn(source, keys)
  1274. char *source, *keys;
  1275. {
  1276.     /** This function returns the length of the substring of
  1277.         'source' (starting at zero) that consists entirely of
  1278.         characters NOT from 'keys'.  This is used to skip to a
  1279.         defined set of characters with parsing, usually. 
  1280.         NOTE that this is the opposite of strspn() above
  1281.     **/
  1282.  
  1283.     register int loc = 0, key_index = 0;
  1284.  
  1285.     while (source[loc] != '\0') {
  1286.       key_index = 0;
  1287.       while (keys[key_index] != '\0')
  1288.         if (keys[key_index++] == source[loc])
  1289.           return(loc);
  1290.       loc++;
  1291.     }
  1292.  
  1293.     return(loc);
  1294. }
  1295.  
  1296. char *strtok(source, keys)
  1297. char *source, *keys;
  1298. {
  1299.     /** This function returns a pointer to the next word in source
  1300.         with the string considered broken up at the characters 
  1301.         contained in 'keys'.  Source should be a character pointer
  1302.         when this routine is first called, then NULL subsequently.
  1303.         When strtok has exhausted the source string, it will 
  1304.         return NULL as the next word. 
  1305.  
  1306.         WARNING: This routine will DESTROY the string pointed to
  1307.         by 'source' when first invoked.  If you want to keep the
  1308.         string, make a copy before using this routine!!
  1309.      **/
  1310.  
  1311.     register int  last_ch;
  1312.     static   char *sourceptr;
  1313.          char *return_value;
  1314.  
  1315.     if (source != NULL)
  1316.       sourceptr = source;
  1317.     
  1318.     if (*sourceptr == '\0') 
  1319.       return(NULL);        /* we hit end-of-string last time!? */
  1320.  
  1321.     sourceptr += strspn(sourceptr, keys);    /* skip leading crap */
  1322.     
  1323.     if (*sourceptr == '\0') 
  1324.       return(NULL);        /* we've hit end-of-string */
  1325.  
  1326.     last_ch = strcspn(sourceptr, keys);    /* end of good stuff */
  1327.  
  1328.     return_value = sourceptr;        /* and get the ret   */
  1329.  
  1330.     sourceptr += last_ch;            /* ...value          */
  1331.  
  1332.     if (*sourceptr != '\0')        /* don't forget if we're at END! */
  1333.       sourceptr++;               /* and skipping for next time */
  1334.  
  1335.     return_value[last_ch] = '\0';        /* ..ending right    */
  1336.     
  1337.     return((char *) return_value);        /* and we're outta here! */
  1338. }
  1339.  
  1340. char *strpbrk(source, keys)
  1341. char *source, *keys;
  1342. {
  1343.     /** Returns a pointer to the first character of source that is any
  1344.         of the specified keys, or NULL if none of the keys are present
  1345.         in the source string. 
  1346.     **/
  1347.  
  1348.     register int loc = 0, key_index = 0;
  1349.  
  1350.     while (source[loc] != '\0') {
  1351.       key_index = 0;
  1352.       while (keys[key_index] != '\0')
  1353.         if (keys[key_index++] == source[loc])
  1354.           return((char *) (source + loc));
  1355.       loc++;
  1356.     }
  1357.     
  1358.     return(NULL);
  1359. }
  1360.  
  1361. char *strchr(buffer, ch)
  1362. char *buffer, ch;
  1363. {
  1364.     /** Returns a pointer to the first occurance of the character
  1365.         'ch' in the specified string or NULL if it doesn't occur **/
  1366.  
  1367.     char *address;
  1368.  
  1369.     address = buffer;
  1370.  
  1371.     while (*address != ch) {
  1372.       if (*address == '\0')
  1373.         return (NULL);
  1374.       address++;
  1375.     }
  1376.  
  1377.     return ( (char *) address);
  1378. }
  1379.  
  1380. #endif
  1381. END-OF-FILE
  1382.  
  1383. if [ "$filename" != "/dev/null" ]
  1384. then
  1385.   size=`wc -c < $filename`
  1386.  
  1387.   if [ $size != 4997 ]
  1388.   then
  1389.     echo $filename changed - should be 4997 bytes, not $size bytes
  1390.   fi
  1391.  
  1392.   chmod 644 $filename
  1393. fi
  1394.  
  1395. # ---------- file src/softkeys.c ----------
  1396.  
  1397. filename="src/softkeys.c"
  1398.  
  1399. if [ -f $filename ]
  1400. then
  1401.   echo File \"$filename\" already exists\!  Skipping...
  1402.   filename=/dev/null        # throw it away
  1403. else
  1404.   echo extracting file src/softkeys.c...
  1405. fi
  1406.  
  1407. cat << 'END-OF-FILE' > $filename
  1408. /**            softkeys.c            **/
  1409.  
  1410. /** This file and associated routines: (C) Copyright 1986, Dave Taylor **/
  1411.  
  1412. #include <stdio.h>
  1413. #include "headers.h"
  1414.  
  1415. define_softkeys(level)
  1416. int level;
  1417. {
  1418.     if (! hp_softkeys) return;
  1419.  
  1420.     if (level == MAIN) {
  1421.       if (notesfile) {
  1422.         define_key(f1, "  Show    Note",   "\r");
  1423.         define_key(f2, "  Reply  to Note",  "r");
  1424.         define_key(f3, " Change  Mailbox", "c");
  1425.         define_key(f4, "  Save    Note",   "s");
  1426.         define_key(f5, " Delete/Undelete", "^");
  1427.         define_key(f6, " Print    Note",   "p");
  1428.         define_key(f7, "  HELP",           "?");
  1429.         define_key(f8, "  Quit     ELM",   "q");
  1430.       }
  1431.       else {
  1432.         define_key(f1, "  Show     Msg",   "\r");
  1433.         define_key(f2, "  Mail     Msg",   "m");
  1434.         define_key(f3, "  Reply  to Msg",  "r");
  1435.         define_key(f4, " Change  Mailbox", "c");
  1436.         define_key(f5, "  Save     Msg",   "s");
  1437.         define_key(f6, " Delete/Undelete", "^");
  1438.         define_key(f7, " Print     Msg",   "p");
  1439.         define_key(f8, "  Quit     ELM",   "q");
  1440.       }
  1441.     }
  1442.     else if (level == ALIAS) {
  1443.       define_key(f1, " Alias  Current",  "a");
  1444.       define_key(f2, " Check   Alias",   "c");
  1445.       define_key(f3, " Make    Alias",   "m");
  1446.       clear_key(f4);
  1447.       clear_key(f5);
  1448.       clear_key(f6);
  1449.       clear_key(f7);
  1450.       define_key(f8, " Return  to ELM",  "r");
  1451.     }
  1452.     else if (level == YESNO) {
  1453.       define_key(f1, "  Yes",  "y");
  1454.       clear_key(f2);
  1455.       clear_key(f3);
  1456.       clear_key(f4);
  1457.       clear_key(f5);
  1458.       clear_key(f6);
  1459.       clear_key(f7);
  1460.       define_key(f8, "   No",  "n");
  1461.     }
  1462.     else if (level == READ) {
  1463.       define_key(f1, "  Next    Page  ", " ");
  1464.       clear_key(f2);
  1465.       clear_key(f3);
  1466.       clear_key(f4);
  1467.       clear_key(f5);
  1468.       clear_key(f6);
  1469.       clear_key(f7);
  1470.       define_key(f8, " Return  to ELM", "\n");
  1471.     }
  1472.     else if (level == CHANGE) {
  1473.       define_key(f1, "  Mail  Directry", "=/");
  1474.       define_key(f2, "  Home  Directry", "~/");
  1475.       clear_key(f3);
  1476.       define_key(f4, "Incoming Mailbox", "!\n");
  1477.       clear_key(f5);
  1478.       clear_key(f6);
  1479.       clear_key(f7);
  1480.       define_key(f8, " Cancel", "\n");
  1481.     }
  1482.  
  1483.     softkeys_on();
  1484. }
  1485.  
  1486. define_key(key, display, send)
  1487. int key;
  1488. char *display, *send;
  1489. {
  1490.  
  1491.     char buffer[30];
  1492.  
  1493.     sprintf(buffer,"%s%s", display, send);
  1494.  
  1495.     fprintf(stderr, "%c&f%dk%dd%dL%s", ESCAPE, key,
  1496.         strlen(display), strlen(send), buffer);
  1497.     fflush(stdout);
  1498. }
  1499.  
  1500. softkeys_on()    
  1501.     /* turn on softkeys (esc&jB) and turn on MENU and USER/SYSTEM */
  1502.  
  1503.     if (hp_softkeys) {
  1504.       fprintf(stderr, "%c&jB%c&jR", ESCAPE, ESCAPE); 
  1505.       fflush(stdout);
  1506.     }
  1507.     
  1508. }
  1509.  
  1510. softkeys_off()    
  1511.     /* turn off softkeys (esc&j@) */
  1512.  
  1513.     if (hp_softkeys) {
  1514.       fprintf(stderr, "%c&j@", ESCAPE); 
  1515.       fflush(stdout);
  1516.     }
  1517. }
  1518.  
  1519. clear_key(key)  
  1520. {     
  1521.     /** set a key to nothing... **/
  1522.  
  1523.     if (hp_softkeys) 
  1524.        define_key(key, "                ", ""); 
  1525. }
  1526. END-OF-FILE
  1527.  
  1528. if [ "$filename" != "/dev/null" ]
  1529. then
  1530.   size=`wc -c < $filename`
  1531.  
  1532.   if [ $size != 2696 ]
  1533.   then
  1534.     echo $filename changed - should be 2696 bytes, not $size bytes
  1535.   fi
  1536.  
  1537.   chmod 644 $filename
  1538. fi
  1539.  
  1540. # ---------- file src/mailmsg2.c ----------
  1541.  
  1542. filename="src/mailmsg2.c"
  1543.  
  1544. if [ -f $filename ]
  1545. then
  1546.   echo File \"$filename\" already exists\!  Skipping...
  1547.   filename=/dev/null        # throw it away
  1548. else
  1549.   echo extracting file src/mailmsg2.c...
  1550. fi
  1551.  
  1552. cat << 'END-OF-FILE' > $filename
  1553. /**             mailmsg2.c            **/
  1554.  
  1555. /** Interface to allow mail to be sent to users.  Part of ELM  **/
  1556.  
  1557. /** (C) Copyright 1986, Dave Taylor                    **/
  1558.  
  1559. #include "headers.h"
  1560. #include <errno.h>
  1561.  
  1562. extern int errno;
  1563.  
  1564. char *error_name(), *error_description();
  1565.  
  1566. char *format_long(), *strip_commas(), *tail_of_string();
  1567. FILE *write_header_info();
  1568.  
  1569. extern char subject[SLEN], action[SLEN], reply_to[SLEN], expires[SLEN], 
  1570.        priority[SLEN], to[VERY_LONG_STRING], cc[VERY_LONG_STRING],
  1571.        in_reply_to[SLEN];
  1572.  
  1573. int gotten_key = 0;
  1574.  
  1575. char *bounce_off_remote();
  1576.  
  1577. mail(expanded_to, expanded_cc, copy_msg, edit_message, batch)
  1578. char *expanded_to, *expanded_cc;
  1579. int  copy_msg, edit_message, batch;
  1580. {
  1581.     /** Given the addresses and various other miscellany (specifically, 
  1582.         'copy-msg' indicates whether a copy of the current message should 
  1583.         be included, 'edit_message' indicates whether the message should 
  1584.         be edited and 'batch' indicates that the message should be read 
  1585.         from stdin) this routine will invoke an editor for the user and 
  1586.         then actually mail off the message.
  1587.     **/
  1588.  
  1589.     FILE *reply, *real_reply; /* second is post-input buffer */
  1590.     char filename[SLEN], filename2[SLEN],
  1591.              very_long_buffer[VERY_LONG_STRING];
  1592.     char ret_ch, ch;
  1593.     register int retransmit = FALSE;
  1594.  
  1595.     static int cancelled_msg = 0;
  1596.  
  1597.     dprint2(4,"\nMailing to '%s' (with%s editing)\n",
  1598.           expanded_to, edit_message? "" : "out");
  1599.     
  1600.     /** first generate the temporary filename **/
  1601.  
  1602.     sprintf(filename,"%s%d",temp_file, getpid());
  1603.  
  1604.     /** if possible, let's try to recall the last message? **/
  1605.  
  1606.     if (! batch)
  1607.       retransmit = recall_last_msg(filename, copy_msg, &cancelled_msg);
  1608.  
  1609.     /** if we're not retransmitting, create the file.. **/
  1610.  
  1611.     if (! retransmit)
  1612.       if ((reply = fopen(filename,"w")) == NULL) {
  1613.         dprint2(1,
  1614.                "Attempt to write to temp file %s failed with error %s (mail)\n",
  1615.          filename, error_name(errno));
  1616.         error2("Could not create file %s (%s)",filename,
  1617.          error_name(errno));
  1618.         return(1);
  1619.       }
  1620.  
  1621.     if (batch) {
  1622.       Raw(OFF);
  1623.       ret_ch = '\n';
  1624.       if (isatty(fileno(stdin))) {
  1625.         printf("To: %s\nSubject: %s\n", expanded_to, subject);
  1626.         printf("\nPlease enter your message, ending with a ^D:\n\n");
  1627.         ret_ch = '\0';
  1628.       }
  1629.       while (gets(very_long_buffer, VERY_LONG_STRING) != NULL) 
  1630.         fprintf(reply, "%s%c", very_long_buffer, ret_ch);
  1631.  
  1632.       if (isatty(fileno(stdin))) 
  1633.         printf("<end-of-message>\n");
  1634.     }
  1635.  
  1636.     if (copy_msg && ! retransmit)     /* if retransmit we ALREADY have it! */
  1637.       if (edit_message) 
  1638.         copy_message(prefixchars, reply, noheader, FALSE);
  1639.       else
  1640.         copy_message("", reply, noheader, FALSE);
  1641.  
  1642.     if (!batch && ! retransmit && signature) {
  1643.       sprintf(filename2, "%s/%s", home, signature_file);
  1644.       (void) append(reply, filename2);
  1645.     }
  1646.  
  1647.     if (! retransmit)
  1648.       (void) fclose(reply);    /* on replies, it won't be open! */
  1649.  
  1650.     /** Edit the message **/
  1651.  
  1652.     if (edit_message)
  1653.       create_readmsg_file();    /* for "readmsg" routine */
  1654.  
  1655.     ch = edit_message? 'e' : 'e';    /* drop through if needed... */
  1656.  
  1657.     if (! batch) {
  1658.       do {
  1659.         switch (ch) {
  1660.           case 'e' : if (edit_message) edit_the_message(filename);
  1661.  
  1662.                    /** now let's try reading it again... **/
  1663.  
  1664.                (void) fclose(reply);    /* make sure it's closed */
  1665.                    if ((reply = fopen(filename,"r")) == NULL) {
  1666.                      dprint2(1,
  1667.         "Attempt to open file %s for reading failed with error %s (mail)\n",
  1668.                                 filename, error_name(errno));
  1669.                      error1("Could not open reply file (%s)", 
  1670.                 error_name(errno));
  1671.                      return(1);
  1672.                    }
  1673.                break;
  1674.  
  1675.            case 'h' : edit_headers();        
  1676.             break;
  1677.         }
  1678.  
  1679.         /** ask that silly question again... **/
  1680.   
  1681.         if ((ch = verify_transmission()) == 'f') {    /* cancelled it! */
  1682.           cancelled_msg = TRUE;
  1683.           return(1);
  1684.         }
  1685.       } while (ch != 's');
  1686.     }
  1687.     else if ((reply = fopen(filename,"r")) == NULL) {
  1688.         dprint2(1,
  1689.         "Attempt to open file %s for reading failed with error %s (mail)\n",
  1690.              filename, error_name(errno));
  1691.         error1("Could not open reply file (%s)", error_name(errno));
  1692.         return(1);
  1693.     }
  1694.  
  1695.     cancelled_msg = FALSE;    /* it ain't cancelled, is it? */
  1696.  
  1697.     /** ask about bounceback if the user wants us to.... **/
  1698.  
  1699.     if (uucp_hops(to) > bounceback && bounceback > 0) 
  1700.       if (verify_bounceback() == TRUE) {
  1701.         if (strlen(cc) > 0) strcat(cc, ", ");
  1702.         strcat(cc, bounce_off_remote(to));
  1703.       }
  1704.  
  1705.     /** grab a copy if the user so desires... **/
  1706.  
  1707.     if (auto_cc && ! batch) 
  1708.       save_copy(subject, expanded_to, expanded_cc, filename, to);
  1709.  
  1710.     /** write all header information into real_reply **/
  1711.  
  1712.     sprintf(filename2,"%s%d",temp_file, getpid()+1);
  1713.     
  1714.     /** try to write headers to new temp file **/
  1715.  
  1716.     dprint2(5, "Composition file='%s' and mail buffer='%s'\n", 
  1717.             filename, filename2);
  1718.  
  1719.     if ((real_reply=write_header_info(filename2, expanded_to, expanded_cc))
  1720.          == NULL) {    
  1721.  
  1722.       /** IT FAILED!!  MEIN GOTT!  Use a dumb mailer instead! **/
  1723.  
  1724.       dprint1(3,"** write_header failed: %s\n", error_name(errno));
  1725.  
  1726.       if (cc[0] != '\0')          /* copies! */
  1727.         sprintf(expanded_to,"%s %s", expanded_to, expanded_cc);
  1728.  
  1729.       sprintf(very_long_buffer, "( (%s -s \"%s\" %s ; %s %s) & ) < %s",
  1730.                   mailx, subject, strip_commas(expanded_to), 
  1731.           remove, filename, filename);
  1732.  
  1733.       error1("Message sent using dumb mailer - %s", mailx);
  1734.       sleep(2);    /* ensure time to see this prompt! */
  1735.  
  1736.     }
  1737.     else {
  1738.       copy_message_across(reply, real_reply);
  1739.  
  1740.       fclose(real_reply);
  1741.  
  1742.       if (cc[0] != '\0')                           /* copies! */
  1743.         sprintf(expanded_to,"%s %s", expanded_to, expanded_cc);
  1744.  
  1745.       if (access(sendmail, EXECUTE_ACCESS) == 0)    /* Yeah!  Sendmail! */
  1746.         sprintf(very_long_buffer,"( (%s %s %s ; %s %s) & ) < %s",
  1747.                   sendmail, smflags, strip_commas(expanded_to), 
  1748.           remove, filename2, filename2);
  1749.       else                    /* oh well, use default mailer... */
  1750.             sprintf(very_long_buffer,"( (%s %s ; %s %s) & ) < %s", 
  1751.                   mailer, strip_commas(expanded_to), 
  1752.           remove, filename2, filename2);
  1753.     }
  1754.     
  1755.     fclose(reply);
  1756.  
  1757.     if (mail_only) {
  1758.       printf("sending mail...");
  1759.       fflush(stdout);
  1760.     }
  1761.     else {    
  1762.       PutLine0(LINES,0,"sending mail...");
  1763.       CleartoEOLN();
  1764.     }
  1765.  
  1766.     system_call(very_long_buffer, SH);
  1767.  
  1768.     if (mail_only) 
  1769.       printf("\rmail sent!      \n\r");
  1770.     else 
  1771.       set_error("Mail sent!");
  1772.  
  1773.     return(TRUE);
  1774. }
  1775.  
  1776. int
  1777. recall_last_msg(filename, copy_msg, cancelled_msg)
  1778. char *filename;
  1779. int  copy_msg, *cancelled_msg;
  1780. {
  1781.     /** If filename exists and we've recently cancelled a message,
  1782.         the ask if the user wants to use that message instead!  This
  1783.         routine returns TRUE if the user wants to retransmit the last
  1784.         message, FALSE otherwise...
  1785.     **/
  1786.  
  1787.     register int retransmit = FALSE;
  1788.  
  1789.     if (access(filename, EDIT_ACCESS) == 0 && *cancelled_msg) {
  1790.       Raw(ON);
  1791.       CleartoEOLN();
  1792.       if (copy_msg)
  1793.         PutLine1(LINES-1,0,"Recall last kept message instead? (y/n) y%c",
  1794.              BACKSPACE);
  1795.       else
  1796.         PutLine1(LINES-1,0,"Recall last kept message? (y/n) y%c", 
  1797.              BACKSPACE);
  1798.       fflush(stdout);
  1799.       if (tolower(ReadCh()) != 'n') {
  1800.         Write_to_screen("Yes",0);    
  1801.             retransmit++;
  1802.       }
  1803.       else 
  1804.         Write_to_screen("No",0);    
  1805.  
  1806.       fflush(stdout);
  1807.  
  1808.       *cancelled_msg = 0;
  1809.     }
  1810.  
  1811.     return(retransmit);
  1812. }
  1813.  
  1814. edit_the_message(filename)
  1815. char *filename;
  1816. {
  1817.     /** Invoke the users editor on the filename.  Return when done. **/
  1818.  
  1819.     char buffer[SLEN];
  1820.     register int stat;
  1821.  
  1822.     PutLine0(LINES, 0, "invoking editor...");  fflush(stdout);
  1823.  
  1824.     sprintf(buffer,"%s %s", editor, filename);
  1825.  
  1826.     Raw(OFF);
  1827.  
  1828.     chown(filename, userid, groupid);    /* file was owned by root! */
  1829.  
  1830.     if (cursor_control)
  1831.       transmit_functions(OFF);        /* function keys are local */
  1832.  
  1833.     if ((stat = system_call(buffer, SH)) != 0) { 
  1834.       dprint1(1,"System call failed with stat %d (edit_the_message)\n", 
  1835.           stat);
  1836.       error1("Can't invoke editor '%s' for composition", editor);
  1837.       dprint2(1,"** %s - %s **\n", error_name(errno), 
  1838.         error_description(errno));
  1839.       ClearLine(LINES-1);
  1840.       sleep(2);
  1841.     }
  1842.  
  1843.     if (cursor_control)
  1844.       transmit_functions(ON);        /* function keys are local */
  1845.     
  1846.     Raw(ON);
  1847. }
  1848.  
  1849. int
  1850. verify_transmission()
  1851. {
  1852.     /** Ensure the user wants to send this.  This routine returns
  1853.         TRUE if everything is okay, FALSE if cancelled. **/
  1854.  
  1855.     char ch;
  1856.  
  1857.     if (mail_only) {
  1858.       if (isatty(fileno(stdin))) {
  1859.         printf("\n\rAre you sure you want to send this? (y/n) ");
  1860.         CleartoEOLN();
  1861.         printf("y%c", BACKSPACE);
  1862.         fflush(stdin);                /* wait for answer! */
  1863.         fflush(stdout);
  1864.         if (tolower(ReadCh()) == 'n') {             /* >SIGH< */
  1865.           printf("No\n\r\n\r\n\rMail not sent!!\n\r");
  1866.           return('f');    /* forget it! */
  1867.         }
  1868.         else
  1869.           printf("Yes\n\r\n\r");
  1870.         return('s');       /* send this baby! */
  1871.       }
  1872.       else
  1873.         return('s');    /*    ditto       */
  1874.     }
  1875.     else if (check_first) {    /* used to check strlen(infile) > 0 too? */
  1876. reprompt:
  1877.       MoveCursor(LINES,0);
  1878.       CleartoEOLN();
  1879.       ClearLine(LINES-1);
  1880.  
  1881.       PutLine1(LINES-1, 0, 
  1882.        "Please choose: E)dit msg, edit H)eaders, S)end, or F)orget : s%c", 
  1883.        BACKSPACE);
  1884.  
  1885.       fflush(stdin);    /* wait for answer! */
  1886.       fflush(stdout);
  1887.       ch = tolower(ReadCh());
  1888.  
  1889.       switch (ch) {
  1890.          case 'f': Write_to_screen("Forget",0);
  1891.                    set_error(
  1892.           "Message kept - Can be restored at next F)orward, M)ail or R)eply ");
  1893.                break;
  1894.  
  1895.          case '\n' :
  1896.          case '\r' :
  1897.          case 's'  : Write_to_screen("Send",0);
  1898.              ch = 's';        /* make sure! */
  1899.              break;
  1900.  
  1901.          case 'e'  : Write_to_screen("Edit",0);
  1902.              break;
  1903.          case 'h'  : Write_to_screen("Headers",0);
  1904.              break;
  1905.  
  1906.          default   : Write_to_screen("%c??", 1, 07);    /* BEEP */
  1907.              sleep(1);
  1908.                  goto reprompt;        /* yech */
  1909.        }
  1910.  
  1911.        return(ch);
  1912.     }
  1913. }
  1914.  
  1915. FILE *
  1916. write_header_info(filename, long_to, long_cc)
  1917. char *filename, *long_to, *long_cc;
  1918. {
  1919.     /** Try to open filedesc as the specified filename.  If we can,
  1920.         then write all the headers into the file.  The routine returns
  1921.         'filedesc' if it succeeded, NULL otherwise **/
  1922.  
  1923.     static FILE *filedesc;        /* our friendly file descriptor  */
  1924.  
  1925.     FILE *headerfdesc;           /* file descriptor for .elmheaders */
  1926.     char  fnamebuffer[SLEN];       /* buffer for filename creation    */
  1927.     char  buffer[LONG_SLEN];       /* .elmheader file reading buffer  */
  1928.  
  1929.     char  *get_arpa_date();
  1930.  
  1931.     if ((filedesc = fopen(filename, "w")) == NULL) {
  1932.       dprint1(1,
  1933.         "Attempt to open file %s for writing failed! (write_header_info)\n",
  1934.          filename);
  1935.       dprint2(1,"** %s - %s **\n\n", error_name(errno),
  1936.          error_description(errno));
  1937.       error2("Error %s encountered trying to write to %s", 
  1938.         error_name(errno), filename);
  1939.       sleep(2);
  1940.       return(NULL);        /* couldn't open it!! */
  1941.     }
  1942.  
  1943.     fprintf(filedesc, "To: %s\n", format_long(long_to, strlen("To:")));
  1944.  
  1945.     fprintf(filedesc,"Date: %s\n", get_arpa_date());
  1946.  
  1947. #ifndef DONT_ADD_FROM
  1948. # ifdef  INTERNET_ADDRESS_FORMAT
  1949. #  ifdef  USE_DOMAIN
  1950.     fprintf(filedesc,"From: %s@%s%s (%s)\n", username, hostname, 
  1951.         DOMAIN, full_username);
  1952. #  else
  1953.     fprintf(filedesc,"From: %s@%s (%s)\n", username, hostname, 
  1954.         full_username);
  1955. #  endif
  1956. # else
  1957.     fprintf(filedesc,"From: %s!%s (%s)\n", hostname, username,
  1958.         full_username);
  1959. # endif
  1960. #endif
  1961.  
  1962.     fprintf(filedesc, "Subject: %s\n", subject);
  1963.  
  1964.     if (cc[0] != '\0')
  1965.       fprintf(filedesc, "Cc: %s\n", format_long(long_cc, strlen("Cc: ")));
  1966.  
  1967.     if (strlen(action) > 0)
  1968.         fprintf(filedesc, "Action: %s\n", action);
  1969.     
  1970.     if (strlen(priority) > 0)
  1971.         fprintf(filedesc, "Priority: %s\n", priority);
  1972.     
  1973.     if (strlen(expires) > 0)
  1974.         fprintf(filedesc, "Expiration-Date: %s\n", expires);
  1975.     
  1976.     if (strlen(reply_to) > 0)
  1977.         fprintf(filedesc, "Reply-To: %s\n", reply_to);
  1978.  
  1979.     if (strlen(in_reply_to) > 0)
  1980.         fprintf(filedesc, "In-Reply-To: %s\n", in_reply_to);
  1981.     
  1982.     /*** add the users .mailheaders file if available ***/
  1983.  
  1984.     sprintf(fnamebuffer, "%s/%s", home, mailheaders);
  1985.  
  1986.     if ((headerfdesc = fopen(fnamebuffer, "r")) != NULL) {
  1987.       while (fgets(buffer, LONG_SLEN, headerfdesc) != NULL)
  1988.         if (strlen(buffer) < 2) {
  1989.           dprint0(2,
  1990.              "Strlen of line from .elmheaders is < 2 (write_header_info)");
  1991.           error1("Warning: blank line in %s ignored!", fnamebuffer);
  1992.           sleep(2);
  1993.         }
  1994.         else 
  1995.           fprintf(filedesc, "%s", buffer);
  1996.  
  1997.         fclose(headerfdesc);
  1998.     }
  1999.  
  2000.     fprintf(filedesc, "X-Mailer: ELM [version %s]\n\n", VERSION);
  2001.  
  2002.     return((FILE *) filedesc);
  2003. }
  2004.  
  2005. copy_message_across(source, dest)
  2006. FILE *source, *dest;
  2007. {
  2008.     /** copy the message in the file pointed to by source to the
  2009.         file pointed to by dest.  **/
  2010.  
  2011.     int  crypted = FALSE;            /* are we encrypting?  */
  2012.     int  encoded_lines = 0;            /* # lines encoded     */
  2013.     char buffer[LONG_SLEN];            /* file reading buffer */
  2014.  
  2015.     while (fgets(buffer, LONG_SLEN, source) != NULL) {
  2016.       if (buffer[0] == '[') {
  2017.         if (strncmp(buffer, START_ENCODE, strlen(START_ENCODE))==0)
  2018.           crypted = TRUE;
  2019.          else if (strncmp(buffer, END_ENCODE, strlen(END_ENCODE))==0)
  2020.           crypted = FALSE;
  2021.          else if (strncmp(buffer, DONT_SAVE, strlen(DONT_SAVE)) == 0)
  2022.           continue;    /* next line? */
  2023.         }
  2024.         else if (crypted) {
  2025.           if (! gotten_key++)
  2026.             getkey(ON);
  2027.           else if (! encoded_lines++)
  2028.             get_key_no_prompt();        /* reinitialize.. */
  2029.          
  2030.           encode(buffer);
  2031.         }
  2032.         fputs(buffer, dest);
  2033.       }
  2034. }
  2035.  
  2036. int
  2037. verify_bounceback()
  2038. {
  2039.     /** Ensure the user wants to have a bounceback copy too.  (This is
  2040.         only called on messages that are greater than the specified 
  2041.         threshold hops and NEVER for non-uucp addresses.... Returns
  2042.         TRUE iff the user wants to bounce a copy back.... 
  2043.      **/
  2044.  
  2045.     if (mail_only) {
  2046.       printf("Would you like a copy \"bounced\" off the remote? (y/n) ");
  2047.       CleartoEOLN();
  2048.       printf("n%c", BACKSPACE);
  2049.       fflush(stdin);                /* wait for answer! */
  2050.       fflush(stdout);
  2051.       if (tolower(ReadCh()) != 'y') {
  2052.         printf("No\n\r");
  2053.         return(FALSE);
  2054.       }
  2055.       else
  2056.         printf("Yes - Bounceback included\n\r");
  2057.     }
  2058.     else {
  2059.       MoveCursor(LINES,0);
  2060.       CleartoEOLN();
  2061.       PutLine1(LINES,0, 
  2062.         "\"Bounce\" a copy off the remote machine? (y/n) y%c",
  2063.         BACKSPACE);
  2064.       fflush(stdin);    /* wait for answer! */
  2065.       fflush(stdout);
  2066.       if (tolower(ReadCh()) != 'y') { 
  2067.         Write_to_screen("No", 0);
  2068.         fflush(stdout);
  2069.         return(FALSE);
  2070.       }
  2071.       Write_to_screen("Yes!", 0);
  2072.       fflush(stdout);
  2073.     }
  2074.  
  2075.     return(TRUE);
  2076. }
  2077. END-OF-FILE
  2078.  
  2079. if [ "$filename" != "/dev/null" ]
  2080. then
  2081.   size=`wc -c < $filename`
  2082.  
  2083.   if [ $size != 14200 ]
  2084.   then
  2085.     echo $filename changed - should be 14200 bytes, not $size bytes
  2086.   fi
  2087.  
  2088.   chmod 644 $filename
  2089. fi
  2090.  
  2091. # ---------- file src/savecopy.c ----------
  2092.  
  2093. filename="src/savecopy.c"
  2094.  
  2095. if [ -f $filename ]
  2096. then
  2097.   echo File \"$filename\" already exists\!  Skipping...
  2098.   filename=/dev/null        # throw it away
  2099. else
  2100.   echo extracting file src/savecopy.c...
  2101. fi
  2102.  
  2103. cat << 'END-OF-FILE' > $filename
  2104. /**             savecopy.c            **/
  2105.  
  2106. /** Save a copy of the specified message in the users savemail mailbox.
  2107.  
  2108.          (C) Copyright 1986, Dave Taylor                    
  2109. **/
  2110.  
  2111. #include "headers.h"
  2112. #ifdef BSD
  2113. #  include <sys/time.h>
  2114. #else
  2115. #  include <time.h>
  2116. #endif
  2117.  
  2118. #include <errno.h>
  2119.  
  2120. char *format_long(), *get_arpa_date();
  2121. char *error_name(), *error_description();
  2122. char *ctime();
  2123.  
  2124. extern char in_reply_to[SLEN];    /* In-Reply-To: string */
  2125. extern int gotten_key;        /* for encryption      */
  2126. extern int errno;
  2127.  
  2128. save_copy(subject, to, cc, filename, original_to)
  2129. char *subject, *to, *cc, *filename, *original_to;
  2130. {
  2131.     /** This routine appends a copy of the outgoing message to the
  2132.         file specified by the SAVEFILE environment variable.  **/
  2133.  
  2134.     FILE *save,        /* file id for file to save to */
  2135.          *message;        /* the actual message body     */
  2136.     long  thetime;        /* variable holder for time    */
  2137.     char  buffer[SLEN],    /* read buffer                */
  2138.           savename[SLEN],    /* name of file saving into    */
  2139.           newbuffer[SLEN];  /* first name in 'to' line     */
  2140.     register int i;        /* for chopping 'to' line up   */
  2141.     int   crypted=0;    /* are we encrypting?          */
  2142.  
  2143.     savename[0] = '\0';
  2144.  
  2145.     if (save_by_name) {
  2146.       get_return_name(to, buffer, FALSE);
  2147.       if (strlen(buffer) == 0) {
  2148.         dprint1(3,"Warning: get_return_name couldn't break down %s\n", to);
  2149.         savename[0] = '\0';
  2150.       }
  2151.       else {
  2152.         sprintf(savename, "%s%s%s", folders, 
  2153.                 lastch(folders) == '/'? "" : "/", buffer);
  2154.  
  2155.         if ((errno = can_access(savename, READ_ACCESS)))
  2156.           savename[0] = '\0';
  2157.       }
  2158.     }
  2159.  
  2160.     if (strlen(savename) == 0) {
  2161.       if (strlen(savefile) == 0)
  2162.         return(error("variable 'SAVEFILE' not defined!"));
  2163.       strcpy(savename, savefile);
  2164.     }
  2165.  
  2166.     if ((errno = can_access(savename, WRITE_ACCESS))) {
  2167.       dprint0(2,"Error: attempt to autosave to a file that can't...\n");
  2168.       dprint1(2,"\tbe appended to: %s (save_copy)\n", savename);
  2169.       dprint2(2,"** %s - %s **\n", error_name(errno),
  2170.           error_description(errno));
  2171.       error1("permission to append to %s denied!", savename);
  2172.       sleep(2);
  2173.       return(FALSE);
  2174.     }
  2175.  
  2176.     if ((save = fopen(savename, "a")) == NULL) {
  2177.       dprint2(1,"Error: Couldn't append message to file %s (%s)\n",
  2178.           savename, "save_copy");
  2179.       dprint2(1,"** %s - %s **\n", error_name(errno),
  2180.           error_description(errno));
  2181.       error1("couldn't append to %s", savename);
  2182.       sleep(2);
  2183.       return(FALSE);
  2184.     }
  2185.  
  2186.     if ((message = fopen(filename, "r")) == NULL) {
  2187.       fclose(save);
  2188.       dprint1(1,"Error: Couldn't read file %s (save_copy)\n", filename);
  2189.       dprint2(1,"** %s - %s **\n", error_name(errno),
  2190.           error_description(errno));
  2191.       error1("couldn't read file %s!", filename);
  2192.       sleep(2);
  2193.       return(FALSE);
  2194.     }
  2195.  
  2196.     for (i=0; original_to[i] != '\0' && ! whitespace(original_to[i]); i++)
  2197.       newbuffer[i] = original_to[i];
  2198.  
  2199.     newbuffer[i] = '\0';
  2200.  
  2201.     tail_of(newbuffer, buffer, FALSE);
  2202.  
  2203.     thetime = (long) time(0);    /* this must be here for it to work! */
  2204.  
  2205.     fprintf(save,"\nFrom To:%s %s", buffer, ctime(&thetime));
  2206.  
  2207.     fprintf(save, "Date: %s\n", get_arpa_date());
  2208.             
  2209.     fprintf(save,"To: %s\nSubject: %s\n", 
  2210.         format_long(to,strlen("To: ")), subject);
  2211.  
  2212.     if (strlen(cc) > 0)
  2213.       fprintf(save,"Cc: %s\n", 
  2214.           format_long(cc, strlen("Cc:")));
  2215.  
  2216.     if (strlen(in_reply_to) > 0)
  2217.       fprintf(save, "In-Reply-To: %s\n", in_reply_to);
  2218.  
  2219.     (void) putc('\n', save);    /* put another return, please! */
  2220.  
  2221.     /** now copy over the message... **/
  2222.  
  2223.     while (fgets(buffer, SLEN, message) != NULL) {
  2224.       if (buffer[0] == '[') {
  2225.         if (strncmp(buffer, START_ENCODE, strlen(START_ENCODE))==0)
  2226.           crypted = 1;
  2227.         else if (strncmp(buffer, END_ENCODE, strlen(END_ENCODE))==0)
  2228.           crypted = 0;
  2229.         else if (strncmp(buffer, DONT_SAVE, strlen(DONT_SAVE)) == 0) {
  2230.           fclose(message);
  2231.           fclose(save);
  2232.           chown(savename, userid, groupid);    
  2233.           return(TRUE);
  2234.         }
  2235.       }
  2236.       else if (crypted) {
  2237.         if (! gotten_key++)
  2238.           getkey(ON);
  2239.         encode(buffer);
  2240.       }
  2241.       fputs(buffer, save);
  2242.     }
  2243.  
  2244.     fclose(message);
  2245.     fclose(save);
  2246.  
  2247.     /* make sure save file isn't owned by root! */
  2248.     chown(savename, userid, groupid);    
  2249.  
  2250.     return(TRUE);
  2251. }
  2252. END-OF-FILE
  2253.  
  2254. if [ "$filename" != "/dev/null" ]
  2255. then
  2256.   size=`wc -c < $filename`
  2257.  
  2258.   if [ $size != 4059 ]
  2259.   then
  2260.     echo $filename changed - should be 4059 bytes, not $size bytes
  2261.   fi
  2262.  
  2263.   chmod 644 $filename
  2264. fi
  2265.  
  2266. echo end of this archive file....
  2267. exit 0
  2268.  
  2269.