home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 January / usenetsourcesnewsgroupsinfomagicjanuary1994.iso / sources / unix / volume4 / msg / part5 < prev    next >
Encoding:
Internet Message Format  |  1986-11-30  |  62.8 KB

  1. From: decvax!hplabs!hpcnou!dat (Dave Taylor)
  2. Subject: Msg Shar.part.5
  3. Newsgroups: mod.sources
  4. Approved: jpn@panda.UUCP
  5.  
  6. Mod.sources:  Volume 4, Issue 9
  7. Submitted by: decvax!hplabs!hpcnou!dat (Dave Taylor)
  8.  
  9. # Msg Shar part 5 of 7
  10.  
  11. # Shell Archive created by hpcnou!dat at Wed Feb 26 15:56:34 1986
  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. # This archive contains;
  18. #  src/notesfile.c  src/opt_utils.c     src/output_utils.c  src/pattern.c
  19. #  src/quit.c       src/read_rc.c       src/reply.c         src/return_addr.c
  20. #  src/savecopy.c   src/screen.c        src/showmsg.c       src/softkeys.c
  21.  
  22.  
  23. if [ ! -d src ]
  24. then
  25.   echo creating directory src
  26.   mkdir src
  27. fi
  28.  
  29. # ---------- file src/notesfile.c ----------
  30.  
  31.  
  32. if [ -f src/notesfile.c ]
  33. then
  34.   echo File 'src/notesfile.c' already exists\!
  35.   exit 1
  36. fi
  37.  
  38. echo extracting file src/notesfile.c...
  39. cat << 'END-OF-FILE' > src/notesfile.c
  40. /**            notesfile.c            **/
  41.  
  42. /**  Routine that reads in a file comprised of saved messages from
  43.      'notes'.  
  44.  
  45.      (C) Copyright 1986 Dave Taylor
  46. **/
  47.  
  48. #include "headers.h"
  49. #include <errno.h>
  50.  
  51. char *notes_machine();
  52.  
  53. extern int errno;
  54.  
  55. int
  56. read_notesfile()
  57. {
  58.     /** read in the current mailfile, assuming it's actually a set
  59.         of stored notes from the notes program... **/
  60.  
  61.     char buffer[LONG_STRING];
  62.     register int line = 0, count = 0;
  63.     long  bytes = 0L, line_bytes = 0L;
  64.     static int first_read = 0;
  65.     int count_x , count_y = 17;
  66.  
  67.     dprint0("read_notesfile()\n");
  68.  
  69.     if (! first_read++) {
  70.       MoveCursor(LINES-2, 0);
  71.       CleartoEOS();
  72.       PutLine(LINES-1, 0, "Reading in %s, message: 0", infile);
  73.       count_x = LINES-1;
  74.           count_y = 22 + strlen(infile);
  75.     }
  76.     else {
  77.       PutLine(LINES-2, 0, "Reading message: 0");
  78.       count_x = LINES-2;
  79.     }
  80.  
  81.     while (fgets(buffer, LONG_STRING, mailfile) != NULL) {
  82.  
  83.       if (line == 0) {
  84.     
  85.         /** Double check to make sure this is okay... if the first
  86.             word is "From " then we're actually reading a normal
  87.             file so cruise over to the read_headers() routine
  88.         instead! **/
  89.     
  90.         if (first_word(buffer, "From ")) {
  91.           notesfile = 0;   /* turn that bloody flag off! */
  92.           rewind(mailfile);  /* back up in da file... */
  93.           return( read_headers(FALSE) );
  94.         }
  95.       }
  96.     
  97.       line_bytes = (long) strlen(buffer); 
  98.       line++;
  99.  
  100.       if (first_word(buffer, "/***** ")) {
  101.         if (real_notes_header(buffer, &header_table[count])) {
  102.           header_table[count].offset = (long) bytes;
  103.           header_table[count].delete = 0;
  104.           header_table[count++].lines = line;
  105.           header_table[count].priority = 0;
  106.           PutLine(count_x, count_y, "%d", count);
  107.           if (count > 1)
  108.             header_table[count-2].lines = line -header_table[count-2].lines;
  109.         }
  110.       }
  111.       bytes += (long) line_bytes;
  112.     }
  113.  
  114.     total_lines_in_file = line;
  115.     header_table[count-1].lines = line - header_table[count-1].lines;
  116.  
  117.         rewind(mailfile);
  118.  
  119.     return(count);
  120. }
  121.  
  122. int
  123. real_notes_header(buffer, entry)
  124. char *buffer;
  125. struct header_rec *entry;
  126. {
  127.     /** confirms that we're looking at a REAL notes header,
  128.         and if so, saves it in the appropriate data entry  **/
  129.  
  130.     char subjectbuffer[SLEN], timebuffer[NLEN], lastbuffer[NLEN], 
  131.          am_pm[NLEN], the_day[NLEN], nullbuffer[NLEN];
  132.     
  133.     dprint1("real_notes_header(buffer='%s')\n", buffer);
  134.  
  135.     strcpy(nullbuffer, "NULL");
  136.     strcpy(lastbuffer, "LAST");
  137.  
  138.     sscanf(buffer, "%*s %s %*c %s %*c %s %s %s %s %s %s", 
  139.         subjectbuffer, entry->from, 
  140.         timebuffer, am_pm, entry->month, the_day,
  141.         lastbuffer, nullbuffer);
  142.  
  143.     if (strcmp(lastbuffer, "LAST") == 0) 
  144.       return(0);
  145.     
  146.     if (strcmp(nullbuffer,"NULL") != 0) 
  147.       return(0);
  148.  
  149.     if (timebuffer[1] != ':' && timebuffer[2] != ':') 
  150.       return(0);
  151.  
  152.     /* now let's play format! */
  153.  
  154.     clean_up(subjectbuffer);
  155.  
  156.     sprintf(entry->subject, "Note from group %s", subjectbuffer);
  157.     sprintf(entry->day,"%d", atoi(the_day));
  158.     sprintf(entry->year,"%d", atoi(lastbuffer) % 100);
  159.     sprintf(entry->time,"%s %s", timebuffer, am_pm);
  160.  
  161.     return(1);
  162. }
  163.  
  164. char *notes_machine()
  165. {
  166.     /** For those rare notes posted by someone on the machine that
  167.         the notesfiles are saved from, this routine will fix the
  168.         address to ensure it's valid.  The return value will be
  169.         either 'machine!' or NULL if it's from the machine we're on
  170.     **/
  171.  
  172.     static char machine_group[NLEN];
  173.     char buffer[SLEN];
  174.     register int i;
  175.  
  176.     dprint0("notes_machine()\n");
  177.     
  178.     if (fseek(mailfile, header_table[current-1].offset, 0L) != 0) {
  179.       error("error [notes_machine] trying to seek!");
  180.       dprint1("\n\tError %d trying to seek into file!\n\n", errno);
  181.       return( NULL );
  182.     }
  183.  
  184.     if (fgets(buffer, SLEN, mailfile) == NULL) {
  185.       error("error [notes_machine] trying to read!");
  186.       dprint1("\n\tError %d trying to read file!\n\n", errno);
  187.       return( NULL );
  188.     }
  189.  
  190.     sscanf(buffer,"%*s %s", machine_group);
  191.  
  192.     for (i=0; machine_group[i] != ':'; i++)
  193.        ;
  194.  
  195.     machine_group[i] = '\0';
  196.  
  197.     return( (char *) machine_group);
  198. }
  199. END-OF-FILE
  200.  
  201. size=`wc -c < src/notesfile.c`
  202.  
  203. if [ $size != 3955 ]
  204. then
  205.   echo Warning: src/notesfile.c changed - should be 3955 bytes, not $size bytes
  206. fi
  207.  
  208. chmod 644 src/notesfile.c
  209.  
  210. # ---------- file src/opt_utils.c ----------
  211.  
  212.  
  213. if [ -f src/opt_utils.c ]
  214. then
  215.   echo File 'src/opt_utils.c' already exists\!
  216.   exit 1
  217. fi
  218.  
  219. echo extracting file src/opt_utils.c...
  220. cat << 'END-OF-FILE' > src/opt_utils.c
  221. /**            opt_utils.c            **/
  222.  
  223. /** This file contains routines that might be needed for the various
  224.      machines that the mailer can run on.  Please check the Makefile
  225.      for more help and/or information. 
  226.  
  227.      (C) Copyright 1986 Dave Taylor
  228. **/
  229.  
  230. #include "headers.h"
  231.  
  232. #ifdef BSD
  233. #  include <pwd.h>
  234. #endif
  235.  
  236. #ifdef UTS
  237. #  include <sys/utsname.h>
  238.  
  239. gethostname(hostname,size) /* get name of current host */
  240. int size;
  241. char *hostname;
  242. {
  243.     /** Return the name of the current host machine.  UTS only **/
  244.  
  245.     /** This routine compliments of Scott McGregor at the HP
  246.         Corporate Computing Center **/
  247.      
  248.     int uname();
  249.     struct utsname name;
  250.  
  251.     (void) uname(&name);
  252.     (void) strncpy(hostname,name.nodename,size-1);
  253.     hostname[size] = '\0';
  254.  
  255. }
  256.  
  257. #endif /* def UTS */
  258.  
  259. #ifdef BSD
  260.  
  261. cuserid(username)
  262. char *username;
  263. {
  264.     /** Added for compatibility with Bell systems, this is the last-ditch
  265.         attempt to get the users login name, after getlogin() fails.  It
  266.         instantiates "username" to the name of the user...
  267.     **/
  268.  
  269.     struct passwd *password_entry, *getpwuid();
  270.  
  271.     password_entry = getpwuid(getuid());
  272.  
  273.     strcpy(username, password_entry->pw_name);
  274. }
  275.  
  276. /** some supplementary string functions for Berkeley Unix systems **/
  277.  
  278. strspn(source, keys)
  279. char *source, *keys;
  280. {
  281.     /** This function returns the length of the substring of
  282.         'source' (starting at zero) that consists ENTIRELY of
  283.         characters from 'keys'.  This is used to skip over a
  284.         defined set of characters with parsing, usually. 
  285.     **/
  286.  
  287.     register int loc = 0, key_index = 0;
  288.  
  289.     while (source[loc] != '\0') {
  290.       key_index = 0;
  291.       while (keys[key_index] != source[loc])
  292.         if (keys[key_index++] == '\0')
  293.           return(loc);
  294.       loc++;
  295.     }
  296.  
  297.     return(loc);
  298. }
  299.  
  300. strcspn(source, keys)
  301. char *source, *keys;
  302. {
  303.     /** This function returns the length of the substring of
  304.         'source' (starting at zero) that consists entirely of
  305.         characters NOT from 'keys'.  This is used to skip to a
  306.         defined set of characters with parsing, usually. 
  307.         NOTE that this is the opposite of strspn() above
  308.     **/
  309.  
  310.     register int loc = 0, key_index = 0;
  311.  
  312.     while (source[loc] != '\0') {
  313.       key_index = 0;
  314.       while (keys[key_index] != '\0')
  315.         if (keys[key_index++] == source[loc])
  316.           return(loc);
  317.       loc++;
  318.     }
  319.  
  320.     return(loc);
  321. }
  322.  
  323. char *strtok(source, keys)
  324. char *source, *keys;
  325. {
  326.     /** This function returns a pointer to the next word in source
  327.         with the string considered broken up at the characters 
  328.         contained in 'keys'.  Source should be a character pointer
  329.         when this routine is first called, then NULL subsequently.
  330.         When strtok has exhausted the source string, it will 
  331.         return NULL as the next word. 
  332.  
  333.         WARNING: This routine will DESTROY the string pointed to
  334.         by 'source' when first invoked.  If you want to keep the
  335.         string, make a copy before using this routine!!
  336.      **/
  337.  
  338.     register int  last_ch;
  339.     static   char *sourceptr;
  340.          char *return_value;
  341.  
  342.     if (source != NULL)
  343.       sourceptr = source;
  344.     
  345.     if (*sourceptr == '\0') 
  346.       return(NULL);        /* we hit end-of-string last time!? */
  347.  
  348.     sourceptr += strspn(sourceptr, keys);    /* skip leading crap */
  349.     
  350.     if (*sourceptr == '\0') 
  351.       return(NULL);        /* we've hit end-of-string */
  352.  
  353.     last_ch = strcspn(sourceptr, keys);    /* end of good stuff */
  354.  
  355.     return_value = sourceptr;        /* and get the ret   */
  356.  
  357.     sourceptr += last_ch;            /* ...value          */
  358.  
  359.     if (*sourceptr != '\0')        /* don't forget if we're at END! */
  360.       sourceptr++;               /* and skipping for next time */
  361.  
  362.     return_value[last_ch] = '\0';        /* ..ending right    */
  363.     
  364.     return((char *) return_value);        /* and we're outta here! */
  365. }
  366.  
  367. char *strpbrk(source, keys)
  368. char *source, *keys;
  369. {
  370.     /** Returns a pointer to the first character of source that is any
  371.         of the specified keys, or NULL if none of the keys are present
  372.         in the source string. 
  373.     **/
  374.  
  375.     register int loc = 0, key_index = 0;
  376.  
  377.     while (source[loc] != '\0') {
  378.       key_index = 0;
  379.       while (keys[key_index] != '\0')
  380.         if (keys[key_index++] == source[loc])
  381.           return((char *) (source + loc));
  382.       loc++;
  383.     }
  384.     
  385.     return(NULL);
  386. }
  387.  
  388. #endif
  389. END-OF-FILE
  390.  
  391. size=`wc -c < src/opt_utils.c`
  392.  
  393. if [ $size != 4053 ]
  394. then
  395.   echo Warning: src/opt_utils.c changed - should be 4053 bytes, not $size bytes
  396. fi
  397.  
  398. chmod 644 src/opt_utils.c
  399.  
  400. # ---------- file src/output_utils.c ----------
  401.  
  402.  
  403. if [ -f src/output_utils.c ]
  404. then
  405.   echo File 'src/output_utils.c' already exists\!
  406.   exit 1
  407. fi
  408.  
  409. echo extracting file src/output_utils.c...
  410. cat << 'END-OF-FILE' > src/output_utils.c
  411. /**            output_utils.c            **/
  412.  
  413. /** This file contains routines used for output in the MSG program.
  414.  
  415.     These routines (C) Copyright 1986 Dave Taylor
  416. **/
  417.  
  418. #include "headers.h"
  419.  
  420.  
  421. static char err_buffer[SLEN];        /* store last error message */
  422.  
  423. static char central_message_buffer[SLEN];
  424.  
  425.  
  426. show_last_error()
  427. {
  428.     /** rewrite last error message! **/
  429.  
  430.     error(err_buffer);
  431. }
  432.  
  433. clear_error()
  434. {
  435.     MoveCursor(LINES,0);
  436.     CleartoEOLN();
  437.     err_buffer[0] = '\0';
  438. }
  439.  
  440. set_error(s)
  441. char *s;
  442. {
  443.     strcpy(err_buffer, s);
  444. }
  445.  
  446. error(s)
  447. char *s;
  448. {
  449.     /** outputs error 's' to screen at line 22, centered! **/
  450.  
  451.     MoveCursor(LINES,0);
  452.     CleartoEOLN();
  453.     PutLine(LINES,(COLUMNS-strlen(s))/2,s);
  454.     if (strlen(s) > 0)
  455.       dprint1("\nError: %s\n\n", s);
  456.     fflush(stdout);
  457.     strcpy(err_buffer, s);    /* save it too! */
  458. }
  459.  
  460. error1(s, a)
  461. char *s, *a;
  462. {
  463.     /** same as error, but with a 'printf' argument **/
  464.     char buffer[SLEN];
  465.  
  466.     sprintf(buffer,s,a);
  467.     error(buffer);
  468. }
  469.  
  470. error2(s, a1, a2)
  471. char *s, *a1, *a2;
  472. {
  473.     /** same as error, but with two 'printf' arguments **/
  474.     char buffer[SLEN];
  475.  
  476.     sprintf(buffer,s, a1, a2);
  477.     error(buffer);
  478. }
  479.  
  480. prompt(s)
  481. char *s;
  482. {
  483.     /** prompt user for input on LINES-3 line, left justified **/
  484.  
  485.     PutLine(LINES-3,0,s);
  486.     CleartoEOLN();
  487. }
  488.  
  489. prompt1(s,a)
  490. char *s, *a;
  491. {
  492.     /** same as prompt, but with a 'printf' argument **/
  493.     char buffer[SLEN];
  494.  
  495.     sprintf(buffer,s,a);
  496.     prompt(buffer);
  497. }
  498.  
  499.  
  500. set_central_message(string, arg)
  501. char *string, *arg;
  502. {
  503.     /** set up the given message to be displayed in the center of
  504.         the current window **/ 
  505.  
  506.     sprintf(central_message_buffer, string, arg);
  507. }
  508.  
  509. display_central_message()
  510. {
  511.     /** display the message if set... **/
  512.  
  513.     if (central_message_buffer[0] != '\0') {
  514.       ClearLine(LINES-15);
  515.       Centerline(LINES-15, central_message_buffer);
  516.       fflush(stdout);
  517.     }
  518. }
  519.  
  520. clear_central_message()
  521. {
  522.     /** clear the central message buffer **/
  523.  
  524.     central_message_buffer[0] = '\0';
  525. }
  526. END-OF-FILE
  527.  
  528. size=`wc -c < src/output_utils.c`
  529.  
  530. if [ $size != 1861 ]
  531. then
  532.   echo Warning: src/output_utils.c changed - should be 1861 bytes, not $size bytes
  533. fi
  534.  
  535. chmod 644 src/output_utils.c
  536.  
  537. # ---------- file src/pattern.c ----------
  538.  
  539.  
  540. if [ -f src/pattern.c ]
  541. then
  542.   echo File 'src/pattern.c' already exists\!
  543.   exit 1
  544. fi
  545.  
  546. echo extracting file src/pattern.c...
  547. cat << 'END-OF-FILE' > src/pattern.c
  548. /**            pattern.c            **/
  549.  
  550. /**    General pattern matching for the MSG mailer.     
  551.  
  552.        (C) Copyright 1986 Dave Taylor
  553. **/
  554.  
  555. #include <errno.h>
  556.  
  557. #include "headers.h"
  558.  
  559. static char pattern[SLEN] = { "" };
  560. static char alt_pattern[SLEN] = { "" };
  561.  
  562. extern int errno;
  563.  
  564. int
  565. pattern_match()
  566. {
  567.     /** Get a pattern from the user and try to match it with the
  568.         from/subject lines being displayed.  If matched (ignoring
  569.         case), move current message pointer to that message, if
  570.         not, error and return ZERO **/
  571.  
  572.     register int i;
  573.  
  574.     PutLine(LINES-3,40,"/ =match anywhere in messages");
  575.     
  576.     PutLine(LINES-1,0, "Match Pattern:");
  577.  
  578.     if (pattern_enter(pattern, alt_pattern, LINES-1, 16, 
  579.         "Match Pattern (in entire mailbox):"))
  580.       if (strlen(alt_pattern) > 0)
  581.         return(match_in_message(alt_pattern));
  582.       else
  583.         return(1);
  584.       
  585.     if (strlen(pattern) == 0) 
  586.       return(0);
  587.  
  588.     for (i = current; i < message_count; i++) {
  589.       if (from_matches(i, pattern)) {
  590.         current = ++i;
  591.         return(1);
  592.       }
  593.       else if (subject_matches(i, pattern)) {
  594.         current = ++i;
  595.         return(1);
  596.       }
  597.     }
  598.  
  599.     return(0);
  600. }
  601.  
  602. int
  603. from_matches(message_number, pattern)
  604. int message_number;
  605. char *pattern;
  606. {
  607.     /** Returns true iff the pattern occurs in it's entirety
  608.         in the from line of the indicated message **/
  609.  
  610.     
  611.     return( in_string(header_table[message_number].from, pattern) );
  612. }
  613.  
  614. int
  615. subject_matches(message_number, pattern)
  616. int message_number;
  617. char *pattern;
  618. {
  619.     /** Returns true iff the pattern occurs in it's entirety
  620.         in the subject line of the indicated message **/
  621.  
  622.     
  623.     return( in_string(header_table[message_number].subject, pattern) );
  624. }
  625.  
  626. match_in_message(pattern)
  627. char *pattern;
  628. {
  629.     /** Match a string INSIDE a message...starting at the current 
  630.         message read each line and try to find the pattern.  As
  631.         soon as we do, set current and leave! 
  632.         Returns 1 if found, 0 if not
  633.     **/
  634.  
  635.     char buffer[LONG_STRING];
  636.     int  message_number;
  637.     long location;
  638.  
  639.     dprint1("match_in_message(pattern='%s')\n", pattern);
  640.  
  641.     location = header_table[current-1].offset;
  642.     message_number = current-1;
  643.  
  644.     if (fseek(mailfile, location, 0) != 0) {
  645.  
  646.       dprint2("\tfseek(mailfile, %ld, 0) failed with error %d\n",
  647.            location, errno);
  648.  
  649.       error1("msg [match] failed looking %ld bytes into file",
  650.          location);
  651.       return(1);    /* fake it out to avoid replacing error message */
  652.     }
  653.  
  654.     error("searching for pattern...");
  655.  
  656.     while (fgets(buffer, LONG_STRING, mailfile) != NULL) {
  657.     
  658.       if (in_string(buffer, pattern)) {
  659.         current = message_number; 
  660.         clear_error();
  661.         return(1);
  662.       }
  663.  
  664.       location += strlen(buffer);
  665.  
  666.       if (location > header_table[message_number].offset)
  667.         message_number++;
  668.     }
  669.  
  670.     return(0);
  671. }
  672. END-OF-FILE
  673.  
  674. size=`wc -c < src/pattern.c`
  675.  
  676. if [ $size != 2675 ]
  677. then
  678.   echo Warning: src/pattern.c changed - should be 2675 bytes, not $size bytes
  679. fi
  680.  
  681. chmod 644 src/pattern.c
  682.  
  683. # ---------- file src/quit.c ----------
  684.  
  685.  
  686. if [ -f src/quit.c ]
  687. then
  688.   echo File 'src/quit.c' already exists\!
  689.   exit 1
  690. fi
  691.  
  692. echo extracting file src/quit.c...
  693. cat << 'END-OF-FILE' > src/quit.c
  694. /**        quit.c        **/
  695.  
  696. /** quit: leave the current mailbox and quit the program.
  697.   
  698.     (C) Copyright 1985, Dave Taylor
  699. **/
  700.  
  701. #ifndef TRUE
  702. #define TRUE    1
  703. #endif
  704.  
  705. quit()
  706. {
  707.     /* a wonderfully short routine!! */
  708.  
  709.     leave_mbox();
  710.  
  711.     leave();
  712. }
  713.  
  714. resync()
  715. {
  716.     /* leave the current mailbox and read it in again.  This
  717.        is used as needed to allow editing of messages and so
  718.        on... */
  719.  
  720.     leave_mbox();
  721.  
  722.     error("reading mailfile in again...");
  723.  
  724.     newmbox(2, TRUE);
  725.     showscreen();
  726. }
  727. END-OF-FILE
  728.  
  729. size=`wc -c < src/quit.c`
  730.  
  731. if [ $size != 466 ]
  732. then
  733.   echo Warning: src/quit.c changed - should be 466 bytes, not $size bytes
  734. fi
  735.  
  736. chmod 644 src/quit.c
  737.  
  738. # ---------- file src/read_rc.c ----------
  739.  
  740.  
  741. if [ -f src/read_rc.c ]
  742. then
  743.   echo File 'src/read_rc.c' already exists\!
  744.   exit 1
  745. fi
  746.  
  747. echo extracting file src/read_rc.c...
  748. cat << 'END-OF-FILE' > src/read_rc.c
  749. /**            read_rc.c            **/
  750.  
  751. /** (C) Copyright 1985, Dave Taylor            **/
  752.  
  753. /** This file contains programs to allow the user to have a .msgrc file
  754.     in their home directory containing any of the following: 
  755.  
  756.     fullname= <username string>
  757.     maildir = <directory>
  758.     mailbox = <file>
  759.     editor  = <editor>
  760.     savemail= <savefile>
  761.     shell   = <shell>
  762.     print   = <print command>
  763.     weedout = <list of headers to weed out>
  764.     prefix  = <copied message prefix string>
  765.  
  766.     alternatives = <list of addresses that forward to us>
  767.  
  768.     and/or the logical arguments:
  769.     
  770.     autocopy [on|off]
  771.     copy     [on|off]    
  772.     resolve  [on|off]
  773.     weed     [on|off]
  774.     noheader [on|off]
  775.     titles   [on|off]
  776.     editout  [on|off]
  777.     savebyname [on|off]
  778.     movepage [on|off]
  779.  
  780.     Lines starting with '#' are considered comments and are not checked
  781.     any further!
  782.  
  783.     Modified 10/85 to know about "Environment" variables..
  784.     Modified 12/85 for the 'prefix' option
  785.     Modified  2/86 for the "movepage" flag
  786. **/
  787.  
  788. #include <stdio.h>
  789. #include <ctype.h>
  790.  
  791. #ifdef BSD
  792. #undef tolower
  793. #endif
  794.  
  795. #include "headers.h"
  796.  
  797. char *shift_lower(), *strtok(), *getenv();
  798.  
  799. #define NOTWEEDOUT    0
  800. #define WEEDOUT        1
  801. #define ALTERNATIVES    2
  802.  
  803. read_rc_file()
  804. {
  805.     /** this routine does all the actual work of reading in the
  806.         .rc file... **/
  807.  
  808.     FILE *file;
  809.     char buffer[SLEN], filename[SLEN];
  810.     char word1[SLEN], word2[SLEN];
  811.     int  errors = 0, last = NOTWEEDOUT;
  812.  
  813.     dprint0("read_rc_file()\n");
  814.     
  815.     sprintf(filename,"%s/%s", home, msgrcfile);
  816.  
  817.     default_weedlist();
  818.  
  819.     alternative_addresses = NULL;     /* none yet! */
  820.  
  821.     if ((file = fopen(filename, "r")) == NULL)
  822.       return;    /* we're done! */
  823.  
  824.     while (fgets(buffer, SLEN, file) != NULL) {
  825.       no_ret(buffer);         /* remove return */
  826.       if (buffer[0] == '#') {     /* comment       */
  827.         last = NOTWEEDOUT;
  828.         continue;
  829.       }
  830.       if (strlen(buffer) < 2) {    /* empty line    */
  831.         last = NOTWEEDOUT;
  832.         continue;
  833.       }
  834.  
  835.       breakup(buffer, word1, word2);
  836.  
  837.       strcpy(word1, shift_lower(word1));    /* to lower case */
  838.  
  839.       if (word2[0] == 0 && (last != WEEDOUT || last != ALTERNATIVES)) {
  840.         fprintf(stderr, "Malformed line from .msgrc file: %s\n", buffer);
  841.         errors++;
  842.         continue;
  843.       }
  844.     
  845.       if (equal(word1,"maildir") || equal(word1,"folders")) {
  846.         expand_env(folders, word2);
  847.         last = NOTWEEDOUT;
  848.       }
  849.       else if (equal(word1, "fullname") || equal(word1,"username") ||
  850.            equal(word1, "name")) {
  851.         strcpy(full_username, word2);
  852.         last = NOTWEEDOUT;
  853.       }
  854.       else if (equal(word1, "prefix")) {
  855.         strcpy(prefixchars, word2);
  856.         last = NOTWEEDOUT;
  857.       }
  858.       else if (equal(word1, "shell")) {
  859.         expand_env(shell, word2);
  860.         last = NOTWEEDOUT;
  861.       }
  862.       else if (equal(word1, "mailbox")) {
  863.         expand_env(mailbox, word2);
  864.         last = NOTWEEDOUT;
  865.       }
  866.       else if (equal(word1, "editor") || equal(word1,"mailedit")) {
  867.         expand_env(editor, word2);
  868.         last = NOTWEEDOUT;
  869.       }
  870.       else if (equal(word1, "savemail") || equal(word1, "saveto")) {
  871.         expand_env(savefile, word2);
  872.         last = NOTWEEDOUT;
  873.       }
  874.       else if (equal(word1, "print") || equal(word1, "printmail")) {
  875.         expand_env(printout, word2);
  876.         last = NOTWEEDOUT;
  877.       }
  878.       else if (equal(word1, "autocopy")) {
  879.         auto_copy = equal(shift_lower(word2), "on");
  880.         last = NOTWEEDOUT;
  881.       }
  882.       else if (equal(word1, "copy") || equal(word1, "auto_cc")) {
  883.         auto_cc = equal(shift_lower(word2), "on");
  884.         last = NOTWEEDOUT;
  885.       }
  886.       else if (equal(word1, "resolve")) {
  887.         resolve_mode = equal(shift_lower(word2), "on");
  888.         last = NOTWEEDOUT;
  889.       }
  890.       else if (equal(word1, "weed")) {
  891.         filter = equal(shift_lower(word2), "on");
  892.         last = NOTWEEDOUT;
  893.       }
  894.       else if (equal(word1, "noheader")) {
  895.         noheader = equal(shift_lower(word2), "on");
  896.         last = NOTWEEDOUT;
  897.       }
  898.       else if (equal(word1, "titles")) {
  899.         title_messages = equal(shift_lower(word2), "on");
  900.         last = NOTWEEDOUT;
  901.       }
  902.       else if (equal(word1, "editout")) {
  903.         edit_outbound = equal(shift_lower(word2), "on");
  904.         last = NOTWEEDOUT;
  905.       }
  906.       else if (equal(word1, "savebyname") || equal(word1, "savename")) {
  907.         save_by_name = equal(shift_lower(word2), "on");
  908.         last = NOTWEEDOUT;
  909.       }
  910.       else if (equal(word1, "movepage") || equal(word1, "page") ||
  911.            equal(word1, "movewhenpaged")) {
  912.         move_when_paged = equal(shift_lower(word2), "on");
  913.         last = NOTWEEDOUT;
  914.       }
  915.       else if (equal(word1, "weedout")) {
  916.         weedout(word2);
  917.         last = WEEDOUT;
  918.       }
  919.       else if (equal(word1, "alternatives")) {
  920.         alternatives(word2);
  921.         last = ALTERNATIVES;
  922.       }
  923.       else if (last == WEEDOUT)    /* could be multiple line weedout */
  924.         weedout(buffer);
  925.       else if (last == ALTERNATIVES)    /* multi-line addresses   */
  926.         alternatives(buffer);
  927.       else {
  928.         fprintf(stderr, "Unknown line from .rc file: %s\n", buffer);
  929.         errors++;
  930.       }
  931.     }
  932.  
  933.     if (errors) {
  934.       fprintf(stderr,"Msg quit from errors in .msgrc file\n");
  935.       exit(errors);
  936.     }
  937. }
  938.     
  939. weedout(string)
  940. char *string;
  941. {
  942.     /** This routine is called with a list of headers to weed out.   **/
  943.  
  944.     register int i;
  945.     char *strptr, *header;
  946.  
  947.     dprint1("weedout(string='%s')\n", string);
  948.  
  949.     strptr = (char *) string;
  950.  
  951.     while ((header = strtok(strptr, "\t ,\"'")) != NULL) {
  952.       if (weedcount == MAX_IN_WEEDLIST)
  953.         exit(fprintf(stderr, "Read in too many weed headers.  Max is %d\n", 
  954.            MAX_IN_WEEDLIST-1));
  955.       if (strlen(header) > 0)
  956.         if (strlen(header) > NLEN)
  957.           fprintf(stderr, "Bad weed header: %s.  Too Long - Len is < %d!\n",
  958.                  header, NLEN);
  959.         else {
  960.           for (i=0; i < strlen(header); i++)
  961.             if (header[i] == '_') header[i] = ' ';
  962.           strncpy(weedlist[weedcount++], header, NLEN);
  963.         }
  964.       strptr = (char *) NULL;
  965.     }
  966. }
  967.  
  968. alternatives(string)
  969. char *string;
  970. {
  971.     /** This routine is called with a list of alternative addresses
  972.         that you may receive mail from (forwarded) **/
  973.  
  974.     char *strptr, *address;
  975.     struct addr_rec *current_record, *previous_record;
  976.  
  977.     dprint1("alternatives(string='%s')\n", string);
  978.  
  979.     previous_record = NULL;
  980.  
  981.     strptr = (char *) string;
  982.  
  983.     while ((address = strtok(strptr, "\t ,\"'")) != NULL) {
  984.       if (previous_record == NULL) {
  985.         previous_record = (struct addr_rec *) 
  986.                    malloc(sizeof *alternative_addresses);
  987.  
  988.         strcpy(previous_record->address, address);
  989.         previous_record->next = NULL;
  990.         alternative_addresses = previous_record;
  991.       }
  992.       else {
  993.         current_record = (struct addr_rec *) 
  994.                    malloc(sizeof *alternative_addresses);
  995.       
  996.         strcpy(current_record->address, address);
  997.         current_record->next = NULL;
  998.         previous_record->next = current_record;
  999.         previous_record = current_record;
  1000.       }
  1001.       strptr = (char *) NULL;
  1002.     }
  1003. }
  1004.  
  1005. default_weedlist()
  1006. {
  1007.     /** install the default headers to weed out! **/
  1008.  
  1009.     dprint0("default_weedlist()\n");
  1010.  
  1011.     weedcount = 0;
  1012.  
  1013.     strncpy(weedlist[weedcount++], ">From", NLEN);
  1014.     strncpy(weedlist[weedcount++], "In-Reply-To", NLEN);
  1015.     strncpy(weedlist[weedcount++], "References", NLEN);
  1016.     strncpy(weedlist[weedcount++], "Newsgroups", NLEN);
  1017.     strncpy(weedlist[weedcount++], "Received", NLEN);
  1018.     strncpy(weedlist[weedcount++], "Apparently-To:", NLEN);
  1019.     strncpy(weedlist[weedcount++], "Message-Id:", NLEN);
  1020. }
  1021.  
  1022. int
  1023. matches_weedlist(buffer)
  1024. char *buffer;
  1025. {
  1026.     /** returns true iff the first 'n' characters of 'buffer' 
  1027.         match an entry of the weedlist **/
  1028.     
  1029.     register int i;
  1030.  
  1031.     dprint1("matches_weedlist(buffer='%s')\n", buffer);
  1032.  
  1033.     for (i=0;i < weedcount; i++)
  1034.       if (strncmp(buffer, weedlist[i], strlen(weedlist[i])) == 0) 
  1035.         return(1);
  1036.  
  1037.     return(0);
  1038. }
  1039.  
  1040. breakup(buffer, word1, word2)
  1041. char *buffer, *word1, *word2;
  1042. {
  1043.     /** This routine breaks buffer down into word1, word2 where 
  1044.         word1 is alpha characters only, and there is an equal
  1045.         sign delimiting the two...
  1046.         alpha = beta
  1047.         For lines with more than one 'rhs', word2 is set to the
  1048.         entire string...
  1049.     **/
  1050.  
  1051.     register int i;
  1052.     
  1053.     for (i=0;i<strlen(buffer) && isalpha(buffer[i]); i++)
  1054.       word1[i] = buffer[i];
  1055.  
  1056.     word1[i++] = '\0';    /* that's the first word! */
  1057.  
  1058.     /** spaces before equal sign? **/
  1059.  
  1060.     while (buffer[i] == ' ' || buffer[i] == '\t') i++;
  1061.  
  1062.     if (buffer[i] == '=') i++;
  1063.  
  1064.     /** spaces after equal sign? **/
  1065.  
  1066.     while (buffer[i] == ' ' || buffer[i] == '\t') i++;
  1067.  
  1068.     if (i < strlen(buffer))
  1069.       strcpy(word2, (char *) (buffer + i));
  1070.     else
  1071.       word2[0] = '\0';
  1072. }
  1073.  
  1074. expand_env(dest, buffer)
  1075. char *dest, *buffer;
  1076. {
  1077.     /** expand possible metacharacters in buffer and then copy
  1078.         to dest... 
  1079.         This routine knows about "~" being the home directory,
  1080.         and "$xxx" being an environment variable.
  1081.     **/
  1082.  
  1083.     char  *word, *string, next_word[SLEN];
  1084.     
  1085.     if (buffer[0] == '/') {
  1086.       dest[0] = '/';
  1087.       dest[1] = '\0';
  1088.     }
  1089.     else
  1090.       dest[0] = '\0';
  1091.     string = (char *) buffer;
  1092.  
  1093.     while ((word = strtok(string, "/")) != NULL) {
  1094.       if (word[0] == '$') {
  1095.         strcpy(next_word, getenv((char *) (word + 1)));
  1096.         if (strlen(next_word) == 0)
  1097.           leave(printf("\n\rCan't expand environment variable '%s'\n\r",
  1098.             word));
  1099.       }
  1100.       else if (word[0] == '~' && word[1] == '\0')
  1101.         strcpy(next_word, home);
  1102.       else
  1103.         strcpy(next_word, word);
  1104.  
  1105.       sprintf(dest, "%s%s%s", dest, (strlen(dest) > 0? "/":""),
  1106.                   next_word);
  1107.  
  1108.       string = (char *) NULL;
  1109.     }
  1110. }
  1111. END-OF-FILE
  1112.  
  1113. size=`wc -c < src/read_rc.c`
  1114.  
  1115. if [ $size != 9083 ]
  1116. then
  1117.   echo Warning: src/read_rc.c changed - should be 9083 bytes, not $size bytes
  1118. fi
  1119.  
  1120. chmod 644 src/read_rc.c
  1121.  
  1122. # ---------- file src/reply.c ----------
  1123.  
  1124.  
  1125. if [ -f src/reply.c ]
  1126. then
  1127.   echo File 'src/reply.c' already exists\!
  1128.   exit 1
  1129. fi
  1130.  
  1131. echo extracting file src/reply.c...
  1132. cat << 'END-OF-FILE' > src/reply.c
  1133. /**        reply.c        **/
  1134.  
  1135. /*** routine allows replying to the sender of the current message 
  1136.  
  1137.      (C) Copyright 1985, Dave Taylor
  1138. ***/
  1139.  
  1140. #include "headers.h"
  1141. #ifndef BSD
  1142. #  include <sys/utsname.h>
  1143. #endif
  1144.  
  1145. /** Note that this routine generates automatic header information
  1146.     for the subject and (obviously) to lines, but that these can
  1147.     be altered while in the editor composing the reply message! 
  1148. **/
  1149.  
  1150. char *strip_parens(), *get_token(), *notes_machine();
  1151.  
  1152. int
  1153. reply()
  1154. {
  1155.     /** Reply to the current message.  Returns non-zero iff
  1156.         the screen has to be rewritten. **/
  1157.  
  1158.     char return_address[LONG_SLEN], subject[SLEN];
  1159.     int  return_value;
  1160.  
  1161.     dprint0("reply()\n");
  1162.  
  1163.     get_return(return_address);
  1164.     
  1165.     if (header_table[current-1].subject[0] != '\0') {
  1166.       if ((strncmp("Re:", header_table[current-1].subject, 3) == 0) ||
  1167.           (strncmp("RE:", header_table[current-1].subject, 3) == 0) ||
  1168.           (strncmp("re:", header_table[current-1].subject, 3) == 0)) 
  1169.         strcpy(subject, header_table[current-1].subject);
  1170.       else {
  1171.         strcpy(subject,"Re: ");
  1172.         strcat(subject,header_table[current-1].subject); 
  1173.       }
  1174.       return_value = send(return_address, subject, TRUE);
  1175.     }
  1176.     else
  1177.       return_value = send(return_address, "Re: your mail", TRUE);
  1178.  
  1179.     return(return_value);
  1180. }
  1181.  
  1182. int
  1183. reply_to_everyone()
  1184. {
  1185.     /** Reply to everyone who received the current message.  
  1186.         This includes other people in the 'To:' line and people
  1187.         in the 'Cc:' line too.  Returns non-zero iff the screen 
  1188.             has to be rewritten. **/
  1189.  
  1190.     char return_address[LONG_SLEN], subject[SLEN];
  1191.     char full_address[VERY_LONG_STRING];
  1192.     int  return_value;
  1193.  
  1194.     dprint0("reply_to_everyone()\n");
  1195.  
  1196.     get_return(return_address);
  1197.  
  1198.     strcpy(full_address, return_address);    /* sender gets copy */
  1199.     
  1200.     get_and_expand_everyone(return_address, full_address);
  1201.  
  1202.     if (header_table[current-1].subject[0] != '\0') {
  1203.       if ((strncmp("Re:", header_table[current-1].subject, 3) == 0) ||
  1204.           (strncmp("RE:", header_table[current-1].subject, 3) == 0) ||
  1205.           (strncmp("re:", header_table[current-1].subject, 3) == 0)) 
  1206.         strcpy(subject, header_table[current-1].subject);
  1207.       else {
  1208.         strcpy(subject,"Re: ");
  1209.         strcat(subject,header_table[current-1].subject); 
  1210.       }
  1211.       return_value = send(full_address, subject, TRUE);
  1212.     }
  1213.     else
  1214.       return_value = send(full_address, "Re: your mail", TRUE);
  1215.  
  1216.     return(return_value);
  1217.  
  1218. }
  1219.  
  1220. int
  1221. forward()
  1222. {
  1223.     /** Forward the current message.  What this actually does is
  1224.         to set auto_copy to true, then call 'send' to get the 
  1225.         address and route the mail. 
  1226.     **/
  1227.  
  1228.     char subject[SLEN], address[VERY_LONG_STRING];
  1229.     int  original_cc, results, edit_msg;
  1230.  
  1231.     dprint0("forward()\n");
  1232.  
  1233.     original_cc = auto_copy;
  1234.     address[0] = '\0';
  1235.  
  1236.     edit_msg = (want_to("Edit outgoing message (y/n) ? ",'y',FALSE) != 'n');
  1237.     printf("%s", edit_msg? "Yes" : "No");
  1238.  
  1239.     auto_cc = TRUE;            /* we want a copy */
  1240.  
  1241.     if (strlen(header_table[current-1].subject) > 0) {
  1242.       strcpy(subject,header_table[current-1].subject); 
  1243.       results = send(address, subject, edit_msg);
  1244.     }
  1245.     else
  1246.       results = send(address, "Forwarded Mail...", edit_msg);
  1247.     
  1248.     auto_copy = original_cc;
  1249.  
  1250.     return(results);
  1251. }
  1252.  
  1253. get_and_expand_everyone(return_address, full_address)
  1254. char *return_address, *full_address;
  1255. {
  1256.     /** Read the current message, extracting addresses from the 'To:'
  1257.         and 'Cc:' lines.   As each address is taken, ensure that it
  1258.         isn't to the author of the message NOR to us.  If neither,
  1259.         prepend with current return address and append to the 
  1260.         'full_address' string.
  1261.     **/
  1262.  
  1263.     char ret_address[LONG_SLEN], buf[LONG_SLEN], new_address[LONG_SLEN];
  1264.     char *bufptr, *address;
  1265.     int  in_message = 1, first_pass = 0;
  1266.  
  1267.     dprint1("get_and_expand_everyone(return_address='%s', <buffer>)\n", 
  1268.          return_address);
  1269.  
  1270.     /** First off, get to the first line of the message desired **/
  1271.  
  1272.     if (fseek(mailfile, header_table[current-1].offset, 0) == -1) {
  1273.     error1("msg [seek] couldn't read %d bytes into file",
  1274.            header_table[current-1].offset);
  1275.     return;
  1276.     }
  1277.  
  1278.     /** okay!  Now we're there!  **/
  1279.  
  1280.     /** let's fix the ret_address to reflect the return address of this
  1281.     message with '%s' instead of the persons login name... **/
  1282.  
  1283.     translate_return(return_address, ret_address);
  1284.  
  1285.     /** now let's parse the actual message! **/
  1286.  
  1287.     while (in_message) {
  1288.       in_message = (int) (fgets(buf, LONG_SLEN, mailfile) != NULL);
  1289.       if (first_word(buf, "From ") && first_pass++ != 0) 
  1290.     in_message = FALSE;
  1291.       else if (first_word(buf, "To:") || first_word(buf, "Cc:") ||
  1292.            first_word(buf, "CC:") || first_word(buf, "cc:")) {
  1293.     do {
  1294.       no_ret(buf);
  1295.  
  1296.       bufptr = (char *) (strip_parens(buf) + 3); /* 3 = strlen of prompt */
  1297.  
  1298.       while ((address = get_token(bufptr, "\t, ", 0)) != NULL) {
  1299.         if (okay_address(address, return_address)) {
  1300.           sprintf(new_address, ret_address, address);
  1301.           optimize_and_add(new_address, full_address);
  1302.         }
  1303.         bufptr = NULL;
  1304.       }
  1305.  
  1306.           in_message = (int) (fgets(buf, LONG_SLEN, mailfile) != NULL);
  1307.     
  1308.     } while (in_message && whitespace(buf[0]));
  1309.  
  1310.       }
  1311.       else if (strlen(buf) < 2)    /* done with header */
  1312.      in_message = FALSE;
  1313.     }
  1314. }
  1315.  
  1316. int
  1317. okay_address(address, return_address)
  1318. char *address, *return_address;
  1319. {
  1320.     /** This routine checks to ensure that the address we just got
  1321.         from the "To:" or "Cc:" line isn't us AND isn't the person    
  1322.         who sent the message.  Returns true iff neither is the case **/
  1323.  
  1324.     char our_address[SLEN];
  1325.     struct addr_rec  *alternatives;
  1326.  
  1327.     if (in_string(address, return_address))
  1328.       return(FALSE);
  1329.  
  1330.     sprintf(our_address, "%s!%s", hostname, username);
  1331.  
  1332.     if (in_string(address, our_address))
  1333.       return(FALSE);
  1334.  
  1335.     sprintf(our_address, "%s@%s", username, hostname);
  1336.       
  1337.     if (in_string(address, our_address))
  1338.       return(FALSE);
  1339.  
  1340.     alternatives = alternative_addresses;
  1341.  
  1342.     while (alternatives != NULL) {
  1343.       if (in_string(address, alternatives->address))
  1344.         return(FALSE);
  1345.       alternatives = alternatives->next;
  1346.     }
  1347.  
  1348.     return(TRUE);
  1349. }
  1350.         
  1351. optimize_and_add(new_address, full_address)
  1352. char *new_address, *full_address;
  1353. {
  1354.     /** This routine will add the new address to the list of addresses
  1355.         in the full address buffer IFF it doesn't already occur.  It
  1356.         will also try to fix dumb hops if possible, specifically hops
  1357.         of the form ...a!b...!a... and hops of the form a@b@b etc 
  1358.     **/
  1359.  
  1360.     register int len, host_count = 0, i;
  1361.     char     hosts[MAX_HOPS][SLEN];    /* array of machine names */
  1362.     char     *host, *addrptr;
  1363.  
  1364.     if (in_string(full_address, new_address))
  1365.       return(1);    /* duplicate address */
  1366.  
  1367.     /** optimize **/
  1368.     /*  break down into a list of machine names, checking as we go along */
  1369.     
  1370.     addrptr = (char *) new_address;
  1371.  
  1372.     while ((host = get_token(addrptr, "!", 1)) != NULL) {
  1373.       for (i = 0; i < host_count && ! equal(hosts[i], host); i++)
  1374.           ;
  1375.  
  1376.       if (i == host_count) {
  1377.         strcpy(hosts[host_count++], host);
  1378.         if (host_count == MAX_HOPS) {
  1379.            error("Can't build return address - hit MAX_HOPS limit!");
  1380.            return(1);
  1381.         }
  1382.       }
  1383.       else 
  1384.         host_count = i + 1;
  1385.       addrptr = NULL;
  1386.     }
  1387.  
  1388.     /** fix the ARPA addresses, if needed **/
  1389.     
  1390.     if (chloc(hosts[host_count-1], '@') > -1)
  1391.       fix_arpa_address(hosts[host_count-1]);
  1392.       
  1393.     /** rebuild the address.. **/
  1394.  
  1395.     new_address[0] = '\0';
  1396.  
  1397.     for (i = 0; i < host_count; i++)
  1398.       sprintf(new_address, "%s%s%s", new_address, 
  1399.               new_address[0] == '\0'? "" : "!",
  1400.               hosts[i]);
  1401.  
  1402.     dprint1("\tgenerated address '%s'\n", new_address);
  1403.  
  1404.     if (full_address[0] == '\0')
  1405.       strcpy(full_address, new_address);
  1406.     else {
  1407.       len = strlen(full_address);
  1408.       full_address[len  ] = ',';
  1409.       full_address[len+1] = ' ';
  1410.       full_address[len+2] = '\0';
  1411.       strcat(full_address, new_address);
  1412.     }
  1413.  
  1414.     return(0);
  1415. }
  1416.  
  1417. get_return_name(address, name)
  1418. char *address, *name;
  1419. {
  1420.     /** Given the address (either a single address or a combined list 
  1421.         of addresses) extract the login name of the first person on
  1422.         the list and return it as 'name'.  Modified to stop at
  1423.         any non-alphanumeric character. **/
  1424.  
  1425.     /** An important note to remember is that it isn't vital that this
  1426.         always returns just the login name, but rather that it always
  1427.         returns the SAME name.  If the persons' login happens to be,
  1428.         for example, joe.richards, then it's arguable if the name 
  1429.         should be joe, or the full login.  It's really immaterial, as
  1430.         indicated before, so long as we ALWAYS return the same name! **/
  1431.  
  1432.     /** Another note: modified to return the argument as all lowercase
  1433.         always... **/
  1434.  
  1435.     char single_address[LONG_SLEN];
  1436.     register int i, loc, index = 0;
  1437.  
  1438.     /* first step - copy address up to a comma, space, or EOLN */
  1439.  
  1440.     for (i=0; address[i] != ',' && ! whitespace(address[i]) && 
  1441.          address[i] != '\0'; i++)
  1442.       single_address[i] = address[i];
  1443.     single_address[i] = '\0';
  1444.  
  1445.     /* Now is it an ARPA address?? */
  1446.  
  1447.     if ((loc = chloc(single_address, '@')) != -1) {      /* Yes */
  1448.  
  1449.       /* At this point the algorithm is to keep shifting our copy 
  1450.          window left until we hit a '!'.  The login name is then
  1451.              located between the '!' and the first metacharacter to 
  1452.          it's right (ie '%', ':' or '@'). */
  1453.  
  1454.       for (i=loc; single_address[i] != '!' && i > -1; i--)
  1455.           if (single_address[i] == '%' || 
  1456.               single_address[i] == ':' ||
  1457.               single_address[i] == '.' ||    /* no domains */
  1458.           single_address[i] == '@') loc = i-1;
  1459.     
  1460.       if (single_address[i] == '!') i++;
  1461.  
  1462.       for (index = 0; index < loc - i + 1; index++)
  1463.         name[index] = tolower(single_address[index+i]);
  1464.       name[index] = '\0';
  1465.     }
  1466.     else {    /* easier - standard USENET address */
  1467.  
  1468.       /* This really is easier - we just cruise left from the end of
  1469.          the string until we hit either a '!' or the beginning of the
  1470.              line.  No sweat. */
  1471.  
  1472.       loc = strlen(single_address)-1;     /* last char */
  1473.  
  1474.       for (i = loc; single_address[i] != '!' && single_address[i] != '.' 
  1475.            && i > -1; i--)
  1476.          name[index++] = tolower(single_address[i]);
  1477.       name[index] = '\0';
  1478.       reverse(name);
  1479.     }
  1480. }
  1481. END-OF-FILE
  1482.  
  1483. size=`wc -c < src/reply.c`
  1484.  
  1485. if [ $size != 9927 ]
  1486. then
  1487.   echo Warning: src/reply.c changed - should be 9927 bytes, not $size bytes
  1488. fi
  1489.  
  1490. chmod 644 src/reply.c
  1491.  
  1492. # ---------- file src/return_addr.c ----------
  1493.  
  1494.  
  1495. if [ -f src/return_addr.c ]
  1496. then
  1497.   echo File 'src/return_addr.c' already exists\!
  1498.   exit 1
  1499. fi
  1500.  
  1501. echo extracting file src/return_addr.c...
  1502. cat << 'END-OF-FILE' > src/return_addr.c
  1503. /**            return_addr.c            **/
  1504.  
  1505. /** This set of routines is used to generate real return addresses
  1506.     and also return addresses suitable for inclusion in a users
  1507.     alias files (ie optimized based on the pathalias database).
  1508.  
  1509.     These routines (C) Copyright 1986 Dave Taylor
  1510. **/
  1511.  
  1512. #include "headers.h"
  1513.  
  1514. #include <sys/types.h>
  1515. #include <sys/stat.h>
  1516.  
  1517. char *shift_lower(), *notes_machine(), *expand_address();
  1518.  
  1519. optimize_return(address)
  1520. char *address;
  1521. {
  1522.     /** This routine tries to create an optimized address, that is,
  1523.         an address that has the minimal information needed to 
  1524.         route a message to this person given the current path
  1525.         database...
  1526.     **/
  1527.  
  1528.     /** first step is to figure out what sort of address we 
  1529.         have... **/
  1530.  
  1531.     dprint1("\noptimize_return(address='%s')\n", address);
  1532.  
  1533.     if (chloc(address, '%') != -1)
  1534.       optimize_cmplx_arpa(address);
  1535.     else if (chloc(address, '@') != -1)
  1536.       optimize_arpa(address);
  1537.     else
  1538.       optimize_usenet(address);
  1539. }
  1540.  
  1541. optimize_cmplx_arpa(address)
  1542. char *address;
  1543. {
  1544.     /** Try to optimize a complex ARPA address.  A Complex address is one 
  1545.         that contains '%' (deferred '@').  For example:  
  1546.         veeger!hpcnof!hplabs!joe%sytech@syte  
  1547.         is a complex address (no kidding, right?).  The algorithm for 
  1548.         trying to resolve it is to move all the way to the right, then 
  1549.         back up left until the first '!' then from there to the SECOND 
  1550.         metacharacter on the right is the name@host address...(in this 
  1551.             example, it would be "joe%sytech").  Check this in the routing
  1552.         table.  If not present, keep backing out to the right until we
  1553.         find a host that is present, or we hit the '@' sign.  Once we
  1554.         have a 'normal' ARPA address, hand it to optimize_arpa().
  1555.     **/
  1556.  
  1557.     char name[SHORT_SLEN], buffer[SLEN], junk[SLEN];
  1558.     char host[SHORT_SLEN], old_host[SHORT_SLEN];
  1559.     register int i, loc, nloc = 0, hloc = 0, passes = 1;
  1560.  
  1561.     dprint1("optimize_cmplx_arpa(address='%s')\n", address);
  1562.  
  1563.     /** first off, get the name%host... **/
  1564.  
  1565.     for (loc = strlen(address)-1; address[loc] != '!' && loc > -1; loc--)
  1566.        ;
  1567.  
  1568.     while (address[loc] != '\0') {
  1569.  
  1570.       if (passes == 1) {
  1571.         loc++;
  1572.  
  1573.         while (address[loc] != '%' && address[loc] != '@')
  1574.           name[nloc++] = address[loc++];
  1575.       }
  1576.       else {
  1577.         for (i=0; old_host[i] != '\0'; i++)
  1578.           name[nloc++] = old_host[i];
  1579.       }
  1580.  
  1581.       loc++;
  1582.   
  1583.       while (address[loc] != '%' && address[loc] != '@')
  1584.         host[hloc++] = address[loc++];
  1585.   
  1586.       host[hloc] = name[nloc] = '\0';
  1587.  
  1588.       dprint2("\tgot name = %s and host = %s\n", name, host);
  1589.  
  1590.       strcpy(old_host, host);
  1591.       remove_domains(host);
  1592.  
  1593.       sprintf(buffer, "%s@%s", name, shift_lower(host));
  1594.  
  1595.       if (expand_site(buffer, junk) == 0) {
  1596.         strcpy(address, buffer);
  1597.         return;
  1598.       }
  1599.       else if (address[loc] == '@') {
  1600.         optimize_arpa(address);
  1601.         return;
  1602.       }
  1603.       else
  1604.         name[nloc++] = '%';    /* for next pass through */
  1605.  
  1606.     }
  1607. }
  1608.  
  1609. optimize_arpa(address)
  1610. char *address;
  1611. {
  1612.     /** Get an arpa address and simplify it to the minimal
  1613.         route needed to get mail to this person... **/
  1614.  
  1615.     char name[SHORT_SLEN], buffer[SLEN], junk[SLEN];
  1616.     char host[SHORT_SLEN];
  1617.     register int loc, nloc = 0, hloc = 0, at_sign = 0;
  1618.  
  1619.     dprint1("optimize_arpa(address='%s')\n", address);
  1620.  
  1621.     for (loc = strlen(address)-1; address[loc] != '!' && loc > -1; loc--) {
  1622.       if (address[loc] == '@')
  1623.          at_sign++;    /* remember this spot! */
  1624.       else if (at_sign)
  1625.         name[nloc++] = address[loc];
  1626.       else
  1627.         host[hloc++] = address[loc];
  1628.     }
  1629.  
  1630.     name[nloc] = host[hloc] = '\0';
  1631.  
  1632.     reverse(name);
  1633.     reverse(host);
  1634.  
  1635.     remove_domains(host);
  1636.  
  1637.     dprint2("\tname = %s and host = %s\n", name, shift_lower(host));
  1638.  
  1639.     sprintf(buffer,"%s@%s", name, shift_lower(host));
  1640.  
  1641.     if (expand_site(buffer, junk) == 0) {
  1642.       strcpy(address, buffer);
  1643.       return;
  1644.     }
  1645.  
  1646.     optimize_usenet(address);    /* that didn't work... */
  1647. }
  1648.     
  1649. optimize_usenet(address)
  1650. char *address;
  1651. {
  1652.     /** optimize the return address IFF it's a standard usenet
  1653.         address...
  1654.     **/
  1655.  
  1656.     char name[SHORT_SLEN],  new_address[SLEN], buffer[SLEN], junk[SLEN];
  1657.     register int loc, nloc = 0, aloc = 0, passes = 1;
  1658.  
  1659.     dprint1("\noptimize_usenet(address='%s')\n", address);
  1660.  
  1661.     for (loc = strlen(address)-1; address[loc] != '!' && loc > -1; loc--) 
  1662.       name[nloc++] = address[loc];
  1663.     name[nloc] = '\0';
  1664.  
  1665.     reverse(name);
  1666.  
  1667.     dprint1("\tgot name = %s\n", name);
  1668.  
  1669.     new_address[0] = '\0';    
  1670.  
  1671.     /* got name, now get machine until we can get outta here */
  1672.  
  1673.     while (loc > -1) {
  1674.  
  1675.       new_address[aloc++] = address[loc--];    /* the '!' char */
  1676.  
  1677.       while (address[loc] != '!' && loc > -1)
  1678.         new_address[aloc++] = address[loc--];
  1679.  
  1680.       new_address[aloc] = '\0';
  1681.  
  1682.       strcpy(buffer, new_address);
  1683.       reverse(buffer);
  1684.     
  1685.       if (expand_site(buffer, junk) == 0) {
  1686.         if (passes == 1 && chloc(name, '@') == -1) {
  1687.           buffer[strlen(buffer) - 1] = '\0';    /* remove '!' */
  1688.           dprint2("\tReturning address %s@%s\n", name, buffer);
  1689.           sprintf(address, "%s@%s", name, buffer);
  1690.         }
  1691.         else {
  1692.           dprint2("\tReturning address '%s%s'\n", buffer, name);
  1693.           sprintf(address, "%s%s", buffer, name);
  1694.         }
  1695.         return;        /* success! */
  1696.       }
  1697.       else
  1698.         dprint1("\taddress %s failed!\n", buffer);
  1699.  
  1700.       passes++;
  1701.     }
  1702.  
  1703.     dprint0("\tnothing to do!\n");
  1704.     return;        /* nothing to do! */
  1705. }
  1706.  
  1707. get_return(buffer)
  1708. char *buffer;
  1709. {
  1710.     /** reads 'current' message again, building up the full return 
  1711.         address including all machines that might have forwarded 
  1712.         the message.  **/
  1713.  
  1714.     char buf[LONG_SLEN], name1[SLEN], name2[SLEN], lastname[SLEN];
  1715.     char hold_return[LONG_SLEN], alt_name2[SLEN];
  1716.     int ok = 1, lines;
  1717.  
  1718.     dprint0("get_return(<buffer>)\n");
  1719.  
  1720.     /** are we reading a notesfile file??  **/
  1721.  
  1722.     if (notesfile) {
  1723.       strcpy(buf, header_table[current-1].from);
  1724.       if (chloc(buf, '!') == -1) 
  1725.         sprintf(buf, "%s!%s", notes_machine(), header_table[current-1].from);
  1726.       strcpy(buffer, expand_system(buf, 1));
  1727.       dprint1("\treturn address [notes] = %s\n", buffer);
  1728.       return;
  1729.     }
  1730.  
  1731.     /** get to the first line of the message desired **/
  1732.  
  1733.     if (fseek(mailfile, header_table[current-1].offset, 0) == -1) {
  1734.     error1("msg [seek] couldn't read %d bytes into file",
  1735.            header_table[current-1].offset);
  1736.     return;
  1737.     }
  1738.  
  1739.     /** okay!  Now we're there!  **/
  1740.  
  1741.     lines = header_table[current-1].lines;
  1742.     
  1743.     buffer[0] = '\0';
  1744.  
  1745.     while (ok && lines--) {
  1746.       ok = (int) (fgets(buf, LONG_SLEN, mailfile) != NULL);
  1747.       if (first_word(buf, "From ")) {
  1748.     sscanf(buf, "%*s %s", hold_return);
  1749.       }
  1750.       else if (first_word(buf, ">From")) {
  1751.     sscanf(buf,"%*s %s %*s %*s %*s %*s %*s %*s %*s %s %s", 
  1752.            name1, name2, alt_name2);
  1753.     if (strcmp(name2, "from") == 0)
  1754.       strcpy(name2, alt_name2);
  1755.     add_site(buffer, name2, lastname);
  1756.       }
  1757.  
  1758. #ifdef USE_EMBEDDED_ADDRESSES
  1759.  
  1760.       else if (first_word(buf, "From:")) {
  1761.     get_address_from("From:", buf, hold_return);
  1762.       }
  1763.       else if (first_word(buf, "Reply-To:")) {
  1764.     get_address_from("Reply-To:", buf, buffer);
  1765.     return;
  1766.       }
  1767.  
  1768. #endif
  1769.  
  1770.       else if (strlen(buf) < 2)    /* done with header */
  1771.          lines = 0; /* let's get outta here!  We're done!!! */
  1772.      }
  1773.  
  1774.     if (buffer[0] == '\0')
  1775.       strcpy(buffer, hold_return); /* default address! */
  1776.     else
  1777.       add_site(buffer, name1, lastname);    /* get the user name too! */
  1778.  
  1779.     dprint1("\treturn address = '%s'\n", buffer);
  1780.  
  1781. }
  1782. END-OF-FILE
  1783.  
  1784. size=`wc -c < src/return_addr.c`
  1785.  
  1786. if [ $size != 7247 ]
  1787. then
  1788.   echo Warning: src/return_addr.c changed - should be 7247 bytes, not $size bytes
  1789. fi
  1790.  
  1791. chmod 644 src/return_addr.c
  1792.  
  1793. # ---------- file src/savecopy.c ----------
  1794.  
  1795.  
  1796. if [ -f src/savecopy.c ]
  1797. then
  1798.   echo File 'src/savecopy.c' already exists\!
  1799.   exit 1
  1800. fi
  1801.  
  1802. echo extracting file src/savecopy.c...
  1803. cat << 'END-OF-FILE' > src/savecopy.c
  1804. /**             savecopy.c            **/
  1805.  
  1806. /** Save a copy of the specified message in the users savemail mailbox.
  1807.  
  1808.          (C) Copyright 1986, Dave Taylor                    
  1809. **/
  1810.  
  1811. #include "headers.h"
  1812. #ifdef BSD
  1813. #  include <sys/time.h>
  1814. #else
  1815. #  include <time.h>
  1816. #endif
  1817.  
  1818. char *format_long(), *get_arpa_date();
  1819.  
  1820. extern char reply_to[SLEN];    /* In-Reply-To: string */
  1821. extern int gotten_key;        /* for encryption      */
  1822.  
  1823. save_copy(subject, to, cc, filename, original_to)
  1824. char *subject, *to, *cc, *filename, *original_to;
  1825. {
  1826.     /** This routine appends a copy of the outgoing message to the
  1827.         file specified by the SAVEFILE environment variable.  **/
  1828.  
  1829.     FILE *save,        /* file id for file to save to */
  1830.          *message;        /* the actual message body     */
  1831.     long  thetime;        /* variable holder for time    */
  1832.     char  buffer[SLEN],    /* read buffer                */
  1833.           savename[SLEN],    /* name of file saving into    */
  1834.           newbuffer[SLEN];  /* first name in 'to' line     */
  1835.     register int i;        /* for chopping 'to' line up   */
  1836.     int   crypted=0;    /* are we encrypting?          */
  1837.  
  1838.     dprint5(
  1839. "save_copy(subject='%s', to='%s', cc='%s', filename='%s', original-to='%s')\n", 
  1840.          subject, to, cc, filename, original_to);
  1841.  
  1842.     savename[0] = '\0';
  1843.  
  1844.     if (save_by_name) {
  1845.       get_return_name(to, buffer);
  1846.       sprintf(savename, "%s%s%s", folders, 
  1847.               lastch(folders) == '/'? "" : "/", buffer);
  1848.       if (access(savename, ACCESS_EXISTS) == -1)     /* don't create new! */
  1849.         savename[0] = '\0';
  1850.     }
  1851.  
  1852.     if (strlen(savename) == 0) {
  1853.       if (strlen(savefile) == 0)
  1854.         return(error("variable 'SAVEFILE' not defined!"));
  1855.       strcpy(savename, savefile);
  1856.       if (save_by_name)
  1857.         error2("Not creating file '%s'...saving in %s instead",
  1858.              buffer, savename);
  1859.     }
  1860.  
  1861.     dprint1("\tsaving copy of outbound message to file '%s'\n", savename);
  1862.  
  1863.     if ((save = fopen(savename, "a")) == NULL)
  1864.       return(error1("couldn't append to %s", savename));
  1865.  
  1866.     if ((message = fopen(filename, "r")) == NULL) {
  1867.       fclose(save);
  1868.       return(error1("save_copy couldn't read file %s!", filename));
  1869.     }
  1870.  
  1871.     for (i=0; original_to[i] != '\0' && ! whitespace(original_to[i]); i++)
  1872.       newbuffer[i] = original_to[i];
  1873.  
  1874.     newbuffer[i] = '\0';
  1875.  
  1876.     tail_of(newbuffer, buffer, FALSE);
  1877.  
  1878.     thetime = time(0);    /* this must be here for it to work! */
  1879.  
  1880.     fprintf(save,"\nFrom To:%s %s", buffer, (char *) ctime(&thetime));
  1881.  
  1882.     fprintf(save, "Date: %s\n", get_arpa_date());
  1883.             
  1884.     fprintf(save,"To: %s\nSubject: %s\n", 
  1885.         format_long(to,strlen("To: ")), subject);
  1886.  
  1887.     if (strlen(cc) > 0)
  1888.       fprintf(save,"Cc: %s\n", 
  1889.           format_long(cc, strlen("Cc:")));
  1890.  
  1891.     if (strlen(reply_to) > 0)
  1892.       fprintf(save, "In-Reply-To: %s\n", reply_to);
  1893.  
  1894.     (void) putc('\n', save);    /* put another return, please! */
  1895.  
  1896.     /** now copy over the message... **/
  1897.  
  1898.     while (fgets(buffer, SLEN, message) != NULL) {
  1899.       if (buffer[0] == '[') {
  1900.         if (strncmp(buffer, START_ENCODE, strlen(START_ENCODE))==0)
  1901.           crypted = 1;
  1902.         else if (strncmp(buffer, END_ENCODE, strlen(END_ENCODE))==0)
  1903.           crypted = 0;
  1904.         else if (strncmp(buffer, DONT_SAVE, strlen(DONT_SAVE)) == 0) {
  1905.           fclose(message);
  1906.           fclose(save);
  1907.           chown(savename, userid, getgid());    
  1908.           return(TRUE);
  1909.         }
  1910.       }
  1911.       else if (crypted) {
  1912.         if (! gotten_key++)
  1913.           getkey(ON);
  1914.         encode(buffer);
  1915.       }
  1916.       fputs(buffer, save);
  1917.     }
  1918.  
  1919.     dprint0("\tclosing the files...\n");
  1920.  
  1921.     fclose(message);
  1922.     fclose(save);
  1923.  
  1924.     /* make sure save file isn't owned by root! */
  1925.     chown(savename, userid, getgid());    
  1926.  
  1927.     return(TRUE);
  1928. }
  1929. END-OF-FILE
  1930.  
  1931. size=`wc -c < src/savecopy.c`
  1932.  
  1933. if [ $size != 3441 ]
  1934. then
  1935.   echo Warning: src/savecopy.c changed - should be 3441 bytes, not $size bytes
  1936. fi
  1937.  
  1938. chmod 644 src/savecopy.c
  1939.  
  1940. # ---------- file src/screen.c ----------
  1941.  
  1942.  
  1943. if [ -f src/screen.c ]
  1944. then
  1945.   echo File 'src/screen.c' already exists\!
  1946.   exit 1
  1947. fi
  1948.  
  1949. echo extracting file src/screen.c...
  1950. cat << 'END-OF-FILE' > src/screen.c
  1951. /**        screen.c        **/
  1952.  
  1953. /**  screen display routines for MSG program 
  1954.  
  1955.      (C) Copyright 1985, Dave Taylor
  1956. **/
  1957.  
  1958. #include "headers.h"
  1959.  
  1960. static   int  last_current     = -1;
  1961.  
  1962. showscreen()
  1963. {
  1964.     char buffer[SLEN];
  1965.  
  1966.     dprint0("showscreen()\n");
  1967.  
  1968.     ClearScreen();
  1969.  
  1970.     if (notesfile) 
  1971.       sprintf(buffer, "Notes from '%s' (%d note%s) [Version %s]",
  1972.             infile, message_count, 
  1973.         plural(message_count), VERSION);
  1974.     else 
  1975.       sprintf(buffer, "Mailbox is '%s' with %d message%s [Version %s]",
  1976.             infile, message_count, 
  1977.         plural(message_count), VERSION);
  1978.     Centerline(1, buffer);
  1979.  
  1980.     last_header_page = -1;         /* force a redraw regardless */
  1981.     show_headers();
  1982.  
  1983.     if (mini_menu)
  1984.       show_menu();
  1985.  
  1986.     show_last_error();
  1987.     
  1988.     if (hp_terminal) 
  1989.       define_softkeys(MAIN);
  1990. }
  1991.  
  1992. show_menu()
  1993. {
  1994.     /** write main system menu... **/
  1995.  
  1996.     Centerline(LINES-7,
  1997.   "|=pipe, !=shell, ?=help, <n>=set current to n, /=search pattern");
  1998.         Centerline(LINES-6,
  1999.   "A)lias, C)hange mailbox, D)elete, F)orward, G)roup reply, M)ail,"); 
  2000.     Centerline(LINES-5,
  2001.    "N)ext, P)rint, R)eply, S)ave to file, Q)uit, U)ndelete, or eX)it");
  2002. }
  2003.  
  2004. int
  2005. show_headers()
  2006. {
  2007.     /** display page of headers (10) if present.  First check to 
  2008.         ensure that header_page is in bounds, fixing silently if not.
  2009.         If out of bounds, return zero, else return non-zero **/
  2010.  
  2011.     register int first = 0, line = 4, last = 0, last_line;
  2012.     char newfrom[SLEN], buffer[SLEN];
  2013.     
  2014.     dprint0("show_headers()\n");
  2015.  
  2016.     if (fix_header_page())
  2017.       return(FALSE);
  2018.  
  2019.     if (header_page == last_header_page)     /* nothing to do! */
  2020.       return(FALSE);
  2021.  
  2022.     /** compute last header to display **/
  2023.  
  2024.     first= header_page * headers_per_page;
  2025.  
  2026.     last = first + (headers_per_page - 1);
  2027.  
  2028.     if (last >= message_count) last = message_count-1;
  2029.  
  2030.     dprint2("\tdisplaying headers %d thru %d\n", first, last);
  2031.  
  2032.     /** okay, now let's show the header page! **/
  2033.  
  2034.     while (first <= last) {
  2035.       tail_of(header_table[first].from, newfrom, TRUE); 
  2036.       build_header_line(buffer, &header_table[first], first+1, newfrom);
  2037.       PutLine(line,COLUMNS-80,"%s", buffer);    /* avoid '%' probs */
  2038.       CleartoEOLN();
  2039.       first++;
  2040.       line++;    /* for clearing up in a sec... */
  2041.     }
  2042.     
  2043.     /* clear up the rest of the screen! */
  2044.  
  2045.     if (mini_menu)
  2046.       last_line = LINES-8;
  2047.     else
  2048.       last_line = LINES-3;
  2049.  
  2050.     while (line < last_line) {
  2051.       MoveCursor(line,0);
  2052.       CleartoEOLN();
  2053.       line++;
  2054.     }
  2055.  
  2056.     display_central_message();
  2057.  
  2058.     last_current = current;
  2059.     last_header_page = header_page;
  2060.  
  2061.     return(TRUE);
  2062. }
  2063.  
  2064. show_current()
  2065. {
  2066.     /** display page of headers (10) if present.  First check to 
  2067.         ensure that header_page is in bounds, fixing silently if not.
  2068.         Note that this will ensure that 'current' is always set to
  2069.         the top message on the screen if we go to a new screen! **/
  2070.  
  2071.     register int first = 0, last = 0, line = 4, changed;
  2072.     
  2073.     dprint0("show_current()\n");
  2074.  
  2075.     changed = fix_header_page();
  2076.  
  2077.     /** compute last header to display **/
  2078.  
  2079.     first = header_page * headers_per_page;
  2080.     last  = first + (headers_per_page - 1);
  2081.  
  2082.     if (last > message_count) 
  2083.       last = message_count;
  2084.  
  2085.     /** okay, now let's show the pointers... **/
  2086.  
  2087.     /** have we changed??? **/
  2088.  
  2089.     if (current == last_current) {
  2090.       dprint0("\tno change.  at same message!\n");
  2091.       return;
  2092.     }
  2093.  
  2094.     /** first condition - current on this page & last too */
  2095.  
  2096.     if (last_current >= first && last_current <= last+1) {
  2097.       dprint2("\tMoving arrow from %d to (current) %d\n",
  2098.                last_current, current);
  2099.       PutLine(((last_current-1) % headers_per_page) + 4, COLUMNS-76,"  ");
  2100.       PutLine(((current-1) % headers_per_page) + 4, COLUMNS-76,"<-");
  2101.     }
  2102.     
  2103.     /** second condition - current on this page **/
  2104.     else if (! changed) {
  2105.       dprint1("\tMoving arrow to (current) %d\n", current);
  2106.       PutLine(((current-1) % headers_per_page) + 4, COLUMNS-76,"<-");
  2107.     }
  2108.  
  2109.     /** third condition - page changed!        **/
  2110.     else {
  2111.           dprint2("\tdisplaying from message %d to %d\n", first, last);
  2112.  
  2113.       while (first <= last) {
  2114.         if (current-1 == first)   PutLine(line++,COLUMNS-76,"<-");
  2115.          else                PutLine(line++,COLUMNS-76,"  ");
  2116.         first++;
  2117.       }
  2118.     }
  2119.     last_current = current;
  2120. }
  2121.  
  2122. build_header_line(buffer, entry, number, from)
  2123. char *buffer;
  2124. struct header_rec *entry;
  2125. int number;
  2126. char *from;
  2127. {
  2128.     /** Build in buffer the message header ... entry is the current
  2129.         message entry, number is the numerical ID of the message,
  2130.         and 'from' is a modified (displayable) from line... **/
  2131.  
  2132.     /** Note: using 'strncpy' allows us to output as much of the
  2133.         subject line as possible given the dimensions of the screen.
  2134.         The key is that 'strncpy' returns a 'char *' to the string
  2135.         that it is handing to the dummy variable!  Neat, eh? **/
  2136.     
  2137.     char subj[LONG_SLEN];        /* to output subject */
  2138.  
  2139.     strncpy(subj, entry->subject, COLUMNS-34);
  2140.  
  2141.     subj[COLUMNS-34] = '\0';    /* insurance, eh? */
  2142.  
  2143.     sprintf(buffer, "%c%3d%s %c %3.3s %-2d %-18.18s  %s", 
  2144.             (entry->priority? 'U' : new_msg(entry)? 'N' : ' '),
  2145.         number, (number == current? "<-" : "  "),
  2146.         (entry->delete? '*' : ' '), 
  2147.             entry->month, atoi(entry->day), from, subj);
  2148. }
  2149.  
  2150. int
  2151. fix_header_page()
  2152. {
  2153.     /** this routine will check and ensure that the current header
  2154.         page being displayed contains messages!  It will silently
  2155.         fix 'header-page' if wrong.  Returns TRUE if changed.  **/
  2156.  
  2157.     int last_page, old_header;
  2158.  
  2159.     dprint1("fix_header_page() [%d messages total]\n", message_count);
  2160.  
  2161.     old_header = header_page;
  2162.  
  2163.     last_page = (int) ((message_count-1) / headers_per_page);
  2164.  
  2165.     dprint2("\tThere are 0 to %d pages in file [%d per page]\n", 
  2166.         last_page, headers_per_page);
  2167.  
  2168.     if (header_page > last_page) 
  2169.       header_page = last_page;
  2170.     else if (header_page < 0) 
  2171.           header_page = 0;
  2172.  
  2173.     return(old_header != header_page);
  2174. }
  2175. END-OF-FILE
  2176.  
  2177. size=`wc -c < src/screen.c`
  2178.  
  2179. if [ $size != 5636 ]
  2180. then
  2181.   echo Warning: src/screen.c changed - should be 5636 bytes, not $size bytes
  2182. fi
  2183.  
  2184. chmod 644 src/screen.c
  2185.  
  2186. # ---------- file src/showmsg.c ----------
  2187.  
  2188.  
  2189. if [ -f src/showmsg.c ]
  2190. then
  2191.   echo File 'src/showmsg.c' already exists\!
  2192.   exit 1
  2193. fi
  2194.  
  2195. echo extracting file src/showmsg.c...
  2196. cat << 'END-OF-FILE' > src/showmsg.c
  2197. /**         showmsg.c        **/
  2198.  
  2199. /** This file contains all the routines needed to display the specified
  2200.     message.
  2201.  
  2202.    These routines (C) Copyright 1986 Dave Taylor 
  2203. **/
  2204.  
  2205.  
  2206. #include "headers.h"
  2207. #include <ctype.h>
  2208.  
  2209. #ifdef BSD
  2210. #undef tolower
  2211. #endif
  2212.  
  2213. int
  2214. show_msg(number)
  2215. int number;
  2216. {
  2217.     /*** display number'th message.  Get starting and ending lines
  2218.          of message from headers data structure, then fly through
  2219.          the file, displaying only those lines that are between the
  2220.          two!
  2221.          Returns non-zero if message shown!
  2222.     ***/
  2223.  
  2224.     dprint1("show_msg(number=%d)\n", number);
  2225.  
  2226.     if (number > message_count) {
  2227.       error1("Only %d messages!", message_count);
  2228.       return(0);
  2229.     }
  2230.     else if (number < 1) {
  2231.       error("you can't read THAT message!");
  2232.       return(0);
  2233.     }
  2234.  
  2235.     return(show_message(header_table[number-1].lines, 
  2236.            header_table[number-1].offset,number));
  2237. }
  2238.  
  2239. int
  2240. show_message(lines, file_loc, msgnumber)
  2241. int lines, msgnumber;
  2242. long file_loc;
  2243. {
  2244.     /*** Show the indicated range of lines from mailfile
  2245.          for message 'msgnumber' by using 'display'
  2246.              Returns non-zero if it actually put something on 
  2247.          the screen.
  2248.     ***/
  2249.  
  2250.     dprint3("show_message(lines=%d, loc=%ld, msg-number=%d)\n", 
  2251.             lines, file_loc, msgnumber);
  2252.  
  2253.     if (fseek(mailfile, file_loc, 0) != 0) {
  2254.       error1("msg [seek] failed looking %d bytes into file",
  2255.           file_loc);    
  2256.       return(FALSE);
  2257.     }
  2258.  
  2259.     /* next read will get 'this' line so must be at end of previous */
  2260.  
  2261.     Raw(OFF);
  2262.     display(lines, msgnumber);
  2263.     Raw(ON);
  2264.  
  2265.     return(TRUE);    /* we did it boss! */
  2266. }
  2267.     
  2268.  
  2269. /** these two variables are used iff the variable 'title_message' is
  2270.     set, and are buffers for output of message title... **/
  2271.  
  2272. static char top_of_screen_left [LONG_STRING], 
  2273.              top_of_screen_right[LONG_STRING];
  2274.  
  2275. display(lines, msgnum)
  2276. int lines, msgnum;
  2277. {
  2278.     /** Display specified number of lines from file mailfile.
  2279.         Note: This routine MUST be placed at the first line 
  2280.         of the input file! **/
  2281.  
  2282.     char buffer[LONG_STRING], *full_month();
  2283.  
  2284.     int lines_on_screen = 0;        /* display */
  2285.     int crypted = 0, gotten_key = 0;    /* encryption */
  2286.     int weed_header, weeding_out = 0;    /* weeding */ 
  2287.  
  2288.     dprint2("display(lines=%d, msgnum=%d)\n", lines, msgnum);
  2289.  
  2290.     if (title_messages) {
  2291.       tail_of(header_table[msgnum-1].from, buffer, FALSE);
  2292.       sprintf(top_of_screen_left, "%s #%d %s %s", 
  2293.            notesfile? "Note" : "Message", msgnum, 
  2294.            (strncmp(header_table[msgnum-1].from, "To:", 3) == 0?
  2295.             "to": "from"), buffer);
  2296.       sprintf(top_of_screen_right," %s %s %s, %d at %s",
  2297.           notesfile? "Posted" : "Mailed",
  2298.                full_month(header_table[msgnum-1].month), 
  2299.           header_table[msgnum-1].day, 
  2300.               atoi(header_table[msgnum-1].year) + 1900,
  2301.               header_table[msgnum-1].time);
  2302.  
  2303.       dprint1("\ttos_left: '%s'\n", top_of_screen_left);
  2304.       dprint1("\ttos_right: '%s'\n", top_of_screen_right);
  2305.     }
  2306.  
  2307.     weed_header = filter;    /* allow us to change it after header */
  2308.  
  2309.     ClearScreen();
  2310.  
  2311.     if (cursor_control) transmit_functions(OFF);
  2312.  
  2313.     while (lines > 0) {
  2314.  
  2315.         if (fgets(buffer, LONG_STRING, mailfile) == NULL) {
  2316.           PutLine(LINES-1, 0, "Please press <space> to return: ");
  2317.           (void) ReadCh();
  2318.           if (cursor_control) transmit_functions(ON);
  2319.           return(TRUE);
  2320.         }
  2321.  
  2322.         if (strlen(buffer) > 0) 
  2323.               no_ret(buffer);
  2324.  
  2325.         if (strlen(buffer) == 0) {
  2326.           weed_header = 0;        /* past header! */
  2327.           weeding_out = 0;
  2328.         }
  2329.  
  2330.         lines--;
  2331.  
  2332.         if (notesfile) {    /* treat notes differently! */
  2333.  
  2334.           if (filter && (first_word(buffer, NOTES_HEADER) ||
  2335.               first_word(buffer, NOTES_FOOTER)) ) 
  2336.             /*** weed this line out of the display! ***/;
  2337.           else if (show_line(buffer, &lines_on_screen, &lines)) {
  2338.               if (cursor_control) transmit_functions(ON);
  2339.               return(TRUE);
  2340.           }
  2341.         }
  2342.  
  2343.         else { /* "normal" message */
  2344.  
  2345.           if (weed_header && matches_weedlist(buffer)) 
  2346.             weeding_out = 1;     /* aha!  We don't want to see this! */
  2347.           else if (buffer[0] == '[') {
  2348.             if (strcmp(buffer, START_ENCODE)==0)
  2349.           crypted++;
  2350.             else if (strcmp(buffer, END_ENCODE)==0)
  2351.               crypted--;
  2352.             else if (crypted) {
  2353.                   encode(buffer);
  2354.               if (show_line(buffer, &lines_on_screen, &lines)) {
  2355.                 if (cursor_control) transmit_functions(ON);
  2356.                 return(TRUE);
  2357.               }
  2358.             }
  2359.             else
  2360.               if (show_line(buffer, &lines_on_screen, &lines)) {
  2361.                 if (cursor_control) transmit_functions(ON);
  2362.                 return(TRUE);
  2363.               }
  2364.           }
  2365.           else if (crypted) {
  2366.             if (! gotten_key++) getkey(OFF);
  2367.             encode(buffer);
  2368.             if (show_line(buffer, &lines_on_screen, &lines)) {
  2369.               if (cursor_control) transmit_functions(ON);
  2370.               return(TRUE);
  2371.             }
  2372.           }
  2373.           else if (weeding_out) {
  2374.             weeding_out = (whitespace(buffer[0]));    /* 'n' line weed */
  2375.             if (! weeding_out)     /* just turned on! */
  2376.               if (show_line(buffer, &lines_on_screen, &lines)) {
  2377.                 if (cursor_control) transmit_functions(ON);
  2378.                 return(TRUE);
  2379.               }
  2380.           } 
  2381.           else
  2382.             if (show_line(buffer, &lines_on_screen, &lines)) {
  2383.               if (cursor_control) transmit_functions(ON);
  2384.               return(TRUE);
  2385.             }
  2386.         }
  2387.       }
  2388.     
  2389.  
  2390.     PutLine(LINES-1, 0, "Please press <space> to return: ");
  2391.     Raw(ON);
  2392.     (void) ReadCh();
  2393.         if (cursor_control) transmit_functions(ON);
  2394.     return(TRUE);
  2395. }
  2396.  
  2397. int
  2398. show_line(buffer, lines_on_screen, total)     
  2399. char *buffer;
  2400. int  *lines_on_screen, *total;
  2401. {
  2402.     /** Displays the given line if it can.  if not, it will put the
  2403.         'ole 'space to continue' prompt on the bottom of the screen
  2404.         and wait for either a 'space' or 'return'.  If 'return' is
  2405.         hit (or 'q'), then it will return non-zero, otherwise it'll
  2406.         return zero.
  2407.     **/
  2408.  
  2409.     static char overlap [LONG_SLEN];
  2410.            char mybuffer[SLEN], ch;
  2411.            int  last_line_loc;
  2412.  
  2413.     dprint3("show_line(buffer=%s, on-screen=%d, total=%d)\n", 
  2414.          buffer, *lines_on_screen, *total);
  2415.  
  2416.     last_line_loc     = *lines_on_screen;    /* one back... */
  2417.  
  2418.     *lines_on_screen += ((strlen(buffer) / COLUMNS) + 1);
  2419.  
  2420.     if (last_line_loc == 0 && title_messages) {
  2421.       display_title(*total);
  2422.       last_line_loc = 2;
  2423.       *lines_on_screen += 2;
  2424.     }
  2425.           
  2426.       
  2427.     if (*lines_on_screen > LINES-2) {
  2428.       if (*total > 0) {
  2429.         sprintf(mybuffer, "%d line%s left", *total, plural(*total));
  2430.         PutLine(LINES-1, COLUMNS-20, "%s", mybuffer);
  2431.         PutLine(LINES-1, 0, "Press <space> to continue: ");
  2432.       }
  2433.       else
  2434.         PutLine(LINES-1, 0, "Please press <space> to return: ");
  2435.       Raw(ON);
  2436.       ch = ReadCh();
  2437.       if (ch == '\n' || ch == '\r' || tolower(ch) == 'q')
  2438.         return(TRUE);
  2439.       if (ch == ' ' && *total == 0)    /* don't want '0' lines left */
  2440.         return(TRUE);
  2441.       Raw(OFF);
  2442.       ClearScreen();
  2443.       *lines_on_screen = 0;
  2444.  
  2445.       if (title_messages) {
  2446.         display_title(*total);
  2447.         *lines_on_screen = 2;
  2448.       }
  2449.           
  2450.       PutLine(*lines_on_screen, 0, "%s", overlap);
  2451.       *lines_on_screen  += ((strlen(overlap) / COLUMNS) + 1);
  2452.       last_line_loc = *lines_on_screen;
  2453.       *lines_on_screen += ((strlen(buffer) / COLUMNS) + 1);
  2454.     }
  2455.  
  2456.     PutLine(last_line_loc, 0, "%s", buffer);      
  2457.  
  2458.     if (*lines_on_screen > LINES-6)        /* in case next is too LONG */
  2459.       strcpy(overlap, buffer);
  2460.     
  2461.     return(FALSE);
  2462. }
  2463.  
  2464. display_title(lines_into_message)
  2465. int lines_into_message;
  2466. {
  2467.     /** Display top title, including "Page N" **/
  2468.     
  2469.     register int page;
  2470.  
  2471.     dprint1("displaytitle(lines-into-message=%d)\n", lines_into_message);
  2472.  
  2473.     page = (int) (lines_into_message) / (LINES - 4);
  2474.     
  2475.     PutLine(0,0,top_of_screen_left);
  2476.  
  2477.     PutLine(0, COLUMNS-strlen(top_of_screen_right), 
  2478.             top_of_screen_right, page);
  2479. }
  2480. END-OF-FILE
  2481.  
  2482. size=`wc -c < src/showmsg.c`
  2483.  
  2484. if [ $size != 7604 ]
  2485. then
  2486.   echo Warning: src/showmsg.c changed - should be 7604 bytes, not $size bytes
  2487. fi
  2488.  
  2489. chmod 644 src/showmsg.c
  2490.  
  2491. # ---------- file src/softkeys.c ----------
  2492.  
  2493.  
  2494. if [ -f src/softkeys.c ]
  2495. then
  2496.   echo File 'src/softkeys.c' already exists\!
  2497.   exit 1
  2498. fi
  2499.  
  2500. echo extracting file src/softkeys.c...
  2501. cat << 'END-OF-FILE' > src/softkeys.c
  2502. /**            softkeys.c            **/
  2503.  
  2504. /** This file and associated routines: (C) Copyright 1986, Dave Taylor **/
  2505.  
  2506. #include <stdio.h>
  2507. #include "headers.h"
  2508.  
  2509. define_softkeys(level)
  2510. int level;
  2511. {
  2512.     dprint0("define_softkeys(level=");
  2513.  
  2514.     if (! hp_softkeys) {
  2515.       dprint0("0) [error: no softkeys!]\n");
  2516.       return;
  2517.     }
  2518.  
  2519.     if (level == MAIN) {
  2520.       dprint0("MAIN)\n");
  2521.       if (notesfile) {
  2522.         define_key(f1, "  Show    Note",   "\r");
  2523.         define_key(f2, "  Reply  to Note",  "r");
  2524.         define_key(f3, " Change  Mailbox", "c");
  2525.         define_key(f4, "  Save    Note",   "s");
  2526.         define_key(f5, " Delete/Undelete", "^");
  2527.         define_key(f6, " Print    Note",   "p");
  2528.         define_key(f7, "  HELP",           "?");
  2529.         define_key(f8, "  Quit     Msg",   "q");
  2530.       }
  2531.       else {
  2532.         define_key(f1, "  Show     Msg",   "\r");
  2533.         define_key(f2, "  Mail     Msg",   "m");
  2534.         define_key(f3, "  Reply  to Msg",  "r");
  2535.         define_key(f4, " Change  Mailbox", "c");
  2536.         define_key(f5, "  Save     Msg",   "s");
  2537.         define_key(f6, " Delete/Undelete", "^");
  2538.         define_key(f7, " Print     Msg",   "p");
  2539.         define_key(f8, "  Quit     Msg",   "q");
  2540.       }
  2541.     }
  2542.     else if (level == ALIAS) {
  2543.       dprint0("ALIAS)\n");
  2544.       define_key(f1, " Alias  Current",  "a");
  2545.       define_key(f2, " Check   Alias",   "c");
  2546.       define_key(f3, " Make    Alias",   "m");
  2547.       clear_key(f4);
  2548.       clear_key(f5);
  2549.       clear_key(f6);
  2550.       clear_key(f7);
  2551.       define_key(f8, " Return  to Msg",  "r");
  2552.     }
  2553.     else if (level == YESNO) {
  2554.       dprint0("YES-NO)\n");
  2555.       define_key(f1, "  Yes",  "y");
  2556.       clear_key(f2);
  2557.       clear_key(f3);
  2558.       clear_key(f4);
  2559.       clear_key(f5);
  2560.       clear_key(f6);
  2561.       clear_key(f7);
  2562.       define_key(f8, "   No",  "n");
  2563.     }
  2564.     else if (level == READ) {
  2565.       dprint0("READ)\n");
  2566.       define_key(f1, "  Next    Page  ", " ");
  2567.       clear_key(f2);
  2568.       clear_key(f3);
  2569.       clear_key(f4);
  2570.       clear_key(f5);
  2571.       clear_key(f6);
  2572.       clear_key(f7);
  2573.       define_key(f8, " Return  to Msg", "\n");
  2574.     }
  2575.     else if (level == CHANGE) {
  2576.       dprint0("CHANGE)\n");
  2577.       define_key(f1, "  Mail  Directry", "=/");
  2578.       define_key(f2, "  Home  Directry", "~/");
  2579.       clear_key(f3);
  2580.       define_key(f4, "Incoming Mailbox", "!\n");
  2581.       clear_key(f5);
  2582.       clear_key(f6);
  2583.       clear_key(f7);
  2584.       define_key(f8, " Cancel", "\n");
  2585.     }
  2586.  
  2587.     softkeys_on();
  2588. }
  2589.  
  2590. define_key(key, display, send)
  2591. int key;
  2592. char *display, *send;
  2593. {
  2594.  
  2595.     char buffer[30];
  2596.  
  2597.     dprint3("define-key(key=%d, display='%s', send='%s'\n",
  2598.              key, display, send);
  2599.  
  2600.     sprintf(buffer,"%s%s", display, send);
  2601.  
  2602.     printf("%c&f%dk%dd%dL%s", ESCAPE, key,
  2603.         strlen(display), strlen(send), buffer);
  2604. }
  2605.  
  2606. softkeys_on()    
  2607.     /* turn on softkeys (esc&jB) and turn on MENU and USER/SYSTEM */
  2608.  
  2609.     if (hp_softkeys) 
  2610.       printf("%c&jB%c&jR", ESCAPE, ESCAPE); 
  2611. }
  2612.  
  2613. softkeys_off()    
  2614.     /* turn off softkeys (esc&j@) */
  2615.  
  2616.     if (hp_softkeys) 
  2617.       printf("%c&j@", ESCAPE); 
  2618. }
  2619.  
  2620. clear_key(key)  
  2621. {     
  2622.     /** set a key to nothing... **/
  2623.  
  2624.     if (hp_softkeys) 
  2625.        define_key(key, "                ", ""); 
  2626. }
  2627. END-OF-FILE
  2628.  
  2629. size=`wc -c < src/softkeys.c`
  2630.  
  2631. if [ $size != 2900 ]
  2632. then
  2633.   echo Warning: src/softkeys.c changed - should be 2900 bytes, not $size bytes
  2634. fi
  2635.  
  2636. chmod 644 src/softkeys.c
  2637.  
  2638. echo done
  2639.  
  2640. exit 0
  2641.  
  2642.  
  2643.  
  2644.  
  2645.