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

  1. Subject: v06i036:  Elm mail system (elm), Part11/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 36
  7. Archive-name: elm/Part11
  8.  
  9. # Continuation of Shell Archive, created by hpldat!taylor
  10.  
  11. # This is part 11
  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/options.c ----------
  25.  
  26. filename="src/options.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/options.c...
  34. fi
  35.  
  36. cat << 'END-OF-FILE' > $filename
  37. /**            options.c            **/
  38.  
  39. /** This set of routines allows the alteration of a number of paramaters
  40.     in the Elm mailer, including the following;
  41.  
  42.     printmail    <how to print messages>
  43.     default-shell    <what shell to use for "!" and "|">
  44.     full_username    <your full user name for outgoing mail>
  45.     folder-dir    <folder directory>
  46.     editor        <name of composition editor>
  47.     savefile    <file to save outbound message copies to>
  48.     calendar-file    <where to put calendar entries>
  49.     sort-by        <how to sort mailboxes>
  50.     pager        <how to page messages>
  51.  
  52.     arrow-cursor    <on or off>
  53.     
  54.     lines-on-screen    <count>
  55.     columns-on-screen <count>
  56.  
  57.     And others as they seem useful.
  58.  
  59.     (C) Copyright 1986, Dave Taylor
  60. **/
  61.  
  62. #include "headers.h"
  63.  
  64. #undef onoff
  65. #define   onoff(n)    (n == 1? "ON ":"OFF")
  66.  
  67. options()
  68. {
  69.     /** change options... **/
  70.  
  71.     char ch;
  72.  
  73.     display_options();
  74.  
  75.     do {
  76.       MoveCursor(LINES-1, strlen("Command: "));
  77.  
  78.       ch = tolower(ReadCh());
  79.  
  80.       clear_error();    /* remove possible "sorting" message etc... */ 
  81.  
  82.       switch (ch) {
  83.         case 'c' : one_liner(
  84.         "This is the file where calendar entries from messages are saved.");
  85.                optionally_enter(calendar_file, 2, 23, FALSE);    break;
  86.  
  87.         case 'd' : one_liner(
  88.         "This is the program invoked to display individual messages");
  89.                    optionally_enter(pager, 3, 23, FALSE);
  90.                break;
  91.         case 'e' : one_liner(
  92.             "This is the editor that will be used for sending messages, etc.");
  93.                optionally_enter(editor, 4, 23, FALSE);        break;
  94.  
  95.         case 'f' : one_liner(
  96.      "This is the folders directory used when '=' (etc) is used in filenames");
  97.                optionally_enter(folders, 5, 23, FALSE);        break;
  98.  
  99.         case 'm' : one_liner(
  100.               "How mailboxes are sorted;");
  101.                change_sort(6,23);                break;
  102.  
  103.         case 'o' : one_liner(
  104.         "This is where copies of outbound messages are saved automatically.");
  105.                optionally_enter(savefile, 7, 23, FALSE);    break;
  106.  
  107.         case 'p' : one_liner(
  108. "This is how printouts are generated.  \"%s\" will be replaced by the filename.");
  109.                optionally_enter(printout, 8, 23, FALSE);    break;
  110.  
  111.         case 's' : one_liner(
  112.                       "This is what shell to use for Pipe and System calls...");
  113.                optionally_enter(shell, 9, 23, FALSE);        break;
  114.  
  115.         case 'y' : one_liner(
  116.      "When mail is sent out, this is what your full name will be recorded as.");
  117.                optionally_enter(full_username, 10, 23, FALSE);    break;
  118.  
  119.         case 'a' : one_liner(
  120.        "This defines whether the ELM cursor is an arrow or a highlight bar.");
  121.                on_or_off(&arrow_cursor, 12, 23);         break;
  122.  
  123.         case 'l' : one_liner(
  124.                       "The number of lines on the screen (alter with care...)");
  125.                num_enter(&LINES, 14, 23);            break;
  126.  
  127.         case 'w' : one_liner(
  128.        "The number of characters that can go on one line (alter with care...)");
  129.                num_enter(&COLUMNS,15,23);            break;
  130.  
  131.         case 'r'      :
  132.         case ctrl('M'):
  133.         case ctrl('J'): return;
  134.  
  135.         case ctrl('L'): display_options();                break;
  136.  
  137.         default: error("Command unknown!");
  138.       }
  139.       ClearLine(LINES-3);
  140.     } while (ch != 'r');
  141. }
  142.     
  143. display_options()
  144. {
  145.     /** Display all the available options.. **/
  146.     
  147.     char *sort_name();
  148.     
  149.     ClearScreen();
  150.     Centerline(0,"-- Elm Options Editor --");
  151.  
  152. #ifdef ENABLE_CALENDAR
  153.     PutLine1(2, 0, "C)alendar file       : %s", calendar_file);
  154. #endif
  155.     PutLine1(3, 0, "D)isplay mail using  : %s", pager);
  156.     PutLine1(4, 0, "E)ditor              : %s", editor);
  157.     PutLine1(5, 0, "F)older directory    : %s", folders);
  158.     PutLine1(6, 0, "M)ailboxes sorted by : %s", sort_name(FALSE));
  159.     PutLine1(7, 0, "O)utbound mail saved : %s", savefile);
  160.     PutLine1(8, 0, "P)rint mail using    : %s", printout);
  161.     PutLine1(9, 0, "S)ystem shell        : %s", shell);
  162.     PutLine1(10,0, "Y)our full name      : %s", full_username);
  163.  
  164.     PutLine1(12,0, "A)rrow cursor        : %s", onoff(arrow_cursor));
  165.     
  166.     PutLine1(14,0, "L)ines on screen     : %d", LINES);
  167.     PutLine1(15,0, "W)idth of screen     : %d", COLUMNS);
  168.  
  169.     Centerline(LINES-5,"Select first letter of Option line or R)eturn");
  170.  
  171.     PutLine1(LINES-1,0,"Command: ");
  172. }
  173.  
  174. on_or_off(var, x, y)
  175. int *var, x,y;
  176. {
  177.     /** 'var' field at x.y toggles between on and off... **/
  178.  
  179.     char ch;
  180.  
  181.          PutLine0(x, y+6, 
  182.         "(use <space> to toggle, any other key to leave)");
  183.  
  184.     MoveCursor(x,y+3);    /* at end of value... */
  185.  
  186.     do {
  187.       ch = ReadCh();
  188.  
  189.       if (ch == SPACE) {
  190.         *var = ! *var;
  191.         PutLine0(x,y, onoff(*var));
  192.       }
  193.     } while (ch == SPACE);
  194.  
  195.     MoveCursor(x,y+4);     CleartoEOLN();    /* remove help prompt */
  196. }
  197.  
  198. num_enter(var, x, y)
  199. int *var, x, y;
  200. {
  201.     /** Enter a new value for the specified number.  For ease, we'll
  202.         use a string entry routine then convert it internally... **/
  203.  
  204.     char buffer[NLEN];
  205.  
  206.     sprintf(buffer,"%d", *var);    /* current value... */
  207.  
  208.     optionally_enter(buffer, x, y, FALSE);
  209.     
  210.     *var = atoi(buffer);
  211.  
  212.     PutLine1(x,y, "%d", *var);        CleartoEOLN();
  213. }
  214.  
  215. change_sort(x, y)
  216. int x,y;
  217. {
  218.     /** change the sorting scheme... **/
  219.     
  220.     int last_sortby,    /* so we know if it changes... */
  221.         sign = 1;        /* are we reverse sorting??    */
  222.     char ch;        /* character typed in ...      */
  223.  
  224.     last_sortby = sortby;    /* remember current ordering   */
  225.  
  226.     PutLine0(x, COLUMNS-29, "(SPACE for next, or R)everse)");
  227.     sort_one_liner(sortby);
  228.     MoveCursor(x, y);
  229.  
  230.     do {
  231.       ch = tolower(ReadCh());
  232.       switch (ch) {
  233.         case SPACE : if (sortby < 0) { 
  234.                    sign = -1; 
  235.                    sortby = - sortby; 
  236.                }
  237.              else sign = 1;        /* insurance! */
  238.                sortby = sign * ((sortby + 1) % (STATUS+1));
  239.              if (sortby == 0) sortby = sign;  /* snicker */
  240.                PutLine0(x, y, sort_name(TRUE));
  241.              sort_one_liner(sortby);
  242.                MoveCursor(x, y);
  243.              break;
  244.  
  245.         case 'r'   : sortby = - sortby;
  246.                PutLine0(x, y, sort_name(TRUE));
  247.              sort_one_liner(sortby);
  248.                MoveCursor(x, y);
  249.      }
  250.         } while (ch == SPACE || ch == 'r');
  251.  
  252.     MoveCursor(x, COLUMNS-30);    CleartoEOLN();
  253.  
  254.     if (sortby != last_sortby) {
  255.       error("resorting mailbox...");
  256.       sleep(1);
  257.       sort_mailbox(message_count);
  258.     }
  259.     ClearLine(LINES-2);        /* clear sort_one_liner()! */
  260. }
  261.  
  262. one_liner(string)
  263. char *string;
  264. {
  265.     /** A single-line description of the selected item... **/
  266.  
  267.     Centerline(LINES-3, string);
  268. }
  269.  
  270. sort_one_liner(sorting_by)
  271. int sorting_by;
  272. {
  273.     /** A one line summary of the particular sorting scheme... **/
  274.  
  275.     ClearLine(LINES-2);
  276.  
  277.     switch (sorting_by) {
  278.       
  279.       case -SENT_DATE : Centerline(LINES-2,
  280. "This sort will order most-recently-sent to least-recently-sent");    break;
  281.       case -RECEIVED_DATE : Centerline(LINES-2,
  282. "This sort will order most-recently-received to least-recently-received");
  283.                  break;
  284.       case -SENDER : Centerline(LINES-2,
  285. "This sort will order by sender name, in reverse alphabetical order");    break;
  286.       case -SIZE   : Centerline(LINES-2,
  287. "This sort will order messages by longest to shortest");        break;
  288.       case -SUBJECT : Centerline(LINES-2,
  289. "This sort will order by subject, in reverse alphabetical order");    break;
  290.       case -STATUS  : Centerline(LINES-2,
  291. "This sort will order by reverse status - Deleted through Tagged...");    break;
  292.  
  293.       case SENT_DATE : Centerline(LINES-2,
  294. "This sort will order least-recently-sent to most-recently-sent");    break;
  295.       case RECEIVED_DATE : Centerline(LINES-2,
  296. "This sort will order least-recently-received to most-recently-received");
  297.                         break;
  298.       case SENDER : Centerline(LINES-2,
  299.                 "This sort will order by sender name");    break;
  300.       case SIZE   : Centerline(LINES-2,
  301.                 "This sort will order messages by shortest to longest");
  302.             break;
  303.       case SUBJECT : Centerline(LINES-2,
  304.                     "This sort will order messages by subject");    break;
  305.       case STATUS  : Centerline(LINES-2,
  306. "This sort will order by status - Tagged through Deleted...");        break;
  307.     }
  308. }
  309. END-OF-FILE
  310.  
  311. if [ "$filename" != "/dev/null" ]
  312. then
  313.   size=`wc -c < $filename`
  314.  
  315.   if [ $size != 7702 ]
  316.   then
  317.     echo $filename changed - should be 7702 bytes, not $size bytes
  318.   fi
  319.  
  320.   chmod 666 $filename
  321. fi
  322.  
  323. # ---------- file src/showmsg.old ----------
  324.  
  325. filename="src/showmsg.old"
  326.  
  327. if [ -f $filename ]
  328. then
  329.   echo File \"$filename\" already exists\!  Skipping...
  330.   filename=/dev/null        # throw it away
  331. else
  332.   echo extracting file src/showmsg.old...
  333. fi
  334.  
  335. cat << 'END-OF-FILE' > $filename
  336. /**             showmsg.c            **/
  337.  
  338. /** This file contains all the routines needed to display the specified
  339.     message.
  340.  
  341.    These routines (C) Copyright 1986 Dave Taylor 
  342. **/
  343.  
  344.  
  345. #include "headers.h"
  346. #include <ctype.h>
  347. #include <errno.h>
  348.  
  349. #ifdef BSD
  350. #undef tolower
  351. #endif
  352.  
  353. extern int errno;
  354.  
  355. char *error_name();
  356.  
  357. int    memory_lock = FALSE;    /* is it available?? */
  358.  
  359. int
  360. show_msg(number)
  361. int number;
  362. {
  363.     /*** display number'th message.  Get starting and ending lines
  364.          of message from headers data structure, then fly through
  365.          the file, displaying only those lines that are between the
  366.          two!
  367.         Returns non-zero iff screen was changed
  368.     ***/
  369.  
  370.     dprint0(8, "show_msg called\n");
  371.  
  372.     if (number > message_count) {
  373.       error1("Only %d messages!", message_count);
  374.       return(0);
  375.     }
  376.     else if (number < 1) {
  377.       error("you can't read THAT message!");
  378.       return(0);
  379.     }
  380.  
  381.     clearit(header_table[number-1].status, NEW);   /* it's been read now! */
  382.  
  383.     memory_lock = (HasMemlock() && scrolling);
  384.  
  385.     /* some explaination for that last one - We COULD use memory locking
  386.        to speed up the paging, but the action of "ClearScreen" on a screen
  387.        with memory lock turned on seems to vary considerably (amazingly so)
  388.        so it's safer to only allow memory lock to be a viable bit of
  389.        trickery when dumping text to the screen in scroll mode.
  390.        Philosophical arguments should be forwarded to Bruce at the 
  391.        University of Walamazoo, Australia, via ACSNet  *wry chuckle* */
  392.  
  393.     return(show_message(header_table[number-1].lines, 
  394.            header_table[number-1].offset,number));
  395. }
  396.  
  397. int
  398. show_message(lines, file_loc, msgnumber)
  399. int lines, msgnumber;
  400. long file_loc;
  401. {
  402.     /*** Show the indicated range of lines from mailfile
  403.          for message 'msgnumber' by using 'display'
  404.          Returns non-zero iff screen was altered.
  405.     ***/
  406.  
  407.     dprint3(9,"show_message(%d,%ld,%d)\n", lines, file_loc, msgnumber);
  408.  
  409.     if (fseek(mailfile, file_loc, 0) != 0) {
  410.       dprint2(1,"Error: seek %d bytes into file, errno %s (show_message)\n",
  411.           file_loc, error_name(errno));
  412.       error1("ELM failed seeking %d bytes into file (%s)",
  413.           file_loc, error_name(errno));    
  414.       return(0);
  415.     }
  416.  
  417.     /* next read will get 'this' line so must be at end of previous */
  418.  
  419.     Raw(OFF);
  420.     display(lines, msgnumber);
  421.     Raw(ON);
  422.     if (memory_lock) EndMemlock();    /* turn it off!! */
  423.  
  424.     return(1);    /* we did it boss! */
  425. }
  426.     
  427.  
  428. /** these two variables are used iff the variable 'title_message' is
  429.     set, and are buffers for output of message title... **/
  430.  
  431. static char top_of_screen_left [LONG_STRING], 
  432.              top_of_screen_right[LONG_STRING],
  433.         second_line[SLEN];
  434.  
  435. int
  436. display(lines, msgnum)
  437. int lines, msgnum;
  438. {
  439.     /** Display specified number of lines from file mailfile.
  440.         Note: This routine MUST be placed at the first line 
  441.         of the input file! 
  442.         Returns the same as the routine above (namely zero or one)
  443.     **/
  444.  
  445.     char buffer[VERY_LONG_STRING], *full_month();
  446.  
  447.     int lines_displayed = 0;    
  448.     int lines_on_screen = 0;        /* display    */
  449.     int crypted = 0, gotten_key = 0;    /* encryption */
  450.     int weed_header, weeding_out = 0;    /* weeding    */ 
  451.     int mail_sent;                /* misc use   */
  452.  
  453.     dprint2(4,"displaying %d lines from message %d\n", 
  454.         lines, msgnum);
  455.  
  456.     second_line[0] = '\0';        /* must start as NULL */
  457.  
  458.     if (title_messages) {
  459.  
  460.       mail_sent = (strncmp(header_table[msgnum-1].from, "To:", 3) == 0);
  461.  
  462.       tail_of(header_table[msgnum-1].from, buffer, FALSE);
  463.       sprintf(top_of_screen_left, "%s #%d %s %s", 
  464.            notesfile? "Note" : "Message", msgnum, 
  465.            mail_sent? "to" : "from", buffer);
  466.       sprintf(top_of_screen_right," %s %s %s, %d at %s\n\r%s",
  467.           notesfile? "Posted" : "Mailed",
  468.                full_month(header_table[msgnum-1].month), 
  469.           header_table[msgnum-1].day, 
  470.               atoi(header_table[msgnum-1].year) + 1900,
  471.               header_table[msgnum-1].time,
  472.           filter? "": "\n\r\n\r");
  473.  
  474.       if (! mail_sent && matches_weedlist("To:") && filter &&
  475.           strcmp(header_table[current-1].to,username) != 0 &&
  476.           strlen(header_table[current-1].to) > 0)
  477.         sprintf(second_line, "\n\r(message addressed to %s)\n\r\n\r", 
  478.             header_table[current-1].to);
  479.     
  480.       /** The test above is: if we didn't originally send the mail
  481.           (e.g. we're not reading "mail.sent") AND the user is currently
  482.           weeding out the "To:" line (otherwise they'll get it twice!)
  483.           AND the user is actually weeding out headers AND the message 
  484.           wasn't addressed to the user AND the 'to' address is non-zero 
  485.           (consider what happens when the message doesn't HAVE a "To:" 
  486.           line...the value is NULL but it doesn't match the username 
  487.           either.  We don't want to display something ugly like 
  488.           "(message addressed to )" which will just clutter up the 
  489.           display!).
  490.  
  491.           And you thought programming was EASY!!!!
  492.       **/
  493.     }
  494.  
  495.     weed_header = filter;    /* allow us to change it after header */
  496.  
  497.     ClearScreen();
  498.  
  499.     if (cursor_control) transmit_functions(OFF);
  500.  
  501.     while (lines > 0) {
  502.  
  503.         if (fgets(buffer, VERY_LONG_STRING, mailfile) == NULL) {
  504.           if (lines_displayed == 0) {
  505.  
  506.         /* AUGH!  Why do we get this occasionally???  */
  507.  
  508.             dprint0(1,
  509.              "\n\n** Out of Sync!!  EOF with nothing read (display) **\n");
  510.         dprint0(1,"\nLeaving with all temp files intact!\n");
  511.         error("Internal error: out of sync!");
  512.         emergency_exit();
  513.  
  514.           }
  515.           if (scrolling) 
  516.         Write_to_screen("\n\r\n\r\n\r\n\r", 0);
  517.           PutLine0(LINES-1, 0, "Please press <return> to return: ");
  518.           (void) tolower(ReadCh());
  519.           if (cursor_control) transmit_functions(ON);
  520.           return(TRUE);
  521.         }
  522.  
  523.         if (strlen(buffer) > 0) 
  524.               no_ret(buffer);
  525.  
  526.         if (strlen(buffer) == 0) {
  527.           weed_header = 0;        /* past header! */
  528.           weeding_out = 0;
  529.         }
  530.  
  531.         lines--;
  532.         lines_displayed++;
  533.  
  534.         if (notesfile) {    /* treat notes differently! */
  535.  
  536.           if (filter && (first_word(buffer, NOTES_HEADER) ||
  537.               first_word(buffer, NOTES_FOOTER)) ) 
  538.  
  539.             /*** weed this line out of the display! ***/;
  540.  
  541.           else if (show_line(buffer, &lines_on_screen, &lines, 
  542.                lines_displayed)) {
  543.               if (cursor_control) transmit_functions(ON);
  544.               return(TRUE);
  545.           }
  546.         }
  547.  
  548.         else { /* "normal" message */
  549.  
  550.           if (weed_header && matches_weedlist(buffer)) 
  551.             weeding_out = 1;     /* aha!  We don't want to see this! */
  552.           else if (buffer[0] == '[') {
  553.             if (strcmp(buffer, START_ENCODE)==0)
  554.           crypted++;
  555.             else if (strcmp(buffer, END_ENCODE)==0)
  556.               crypted--;
  557.             else if (crypted) {
  558.                   encode(buffer);
  559.               if (show_line(buffer, &lines_on_screen, &lines,
  560.                   lines_displayed)) {
  561.                 if (cursor_control) transmit_functions(ON);
  562.                 return(TRUE);
  563.               }
  564.             }
  565.             else
  566.               if (show_line(buffer, &lines_on_screen, &lines,
  567.                   lines_displayed)) {
  568.                 if (cursor_control) transmit_functions(ON);
  569.                 return(TRUE);
  570.               }
  571.           }
  572.           else if (crypted) {
  573.             if (! gotten_key++) getkey(OFF);
  574.             encode(buffer);
  575.             if (show_line(buffer, &lines_on_screen, &lines,
  576.                   lines_displayed)) {
  577.               if (cursor_control) transmit_functions(ON);
  578.               return(TRUE);
  579.             }
  580.           }
  581.           else if (weeding_out) {
  582.             weeding_out = (whitespace(buffer[0]));    /* 'n' line weed */
  583.             if (! weeding_out)     /* just turned on! */
  584.               if (show_line(buffer, &lines_on_screen, &lines,
  585.                   lines_displayed)) {
  586.                 if (cursor_control) transmit_functions(ON);
  587.                 return(TRUE);
  588.               }
  589.           } 
  590.           else
  591.             if (show_line(buffer, &lines_on_screen, &lines,
  592.                   lines_displayed)) {
  593.               if (cursor_control) transmit_functions(ON);
  594.               return(TRUE);
  595.             }
  596.         }
  597.       }
  598.     
  599.  
  600.         if (scrolling) 
  601.       Write_to_screen("\n\r\n\r\n\r", 0);
  602.  
  603.     PutLine0(LINES-1, 0, "Please press <return> to return: ");
  604.     Raw(ON);
  605.     tolower(ReadCh());
  606.         if (cursor_control) transmit_functions(ON);
  607.     return(TRUE);
  608. }
  609.  
  610. int
  611. show_line(buffer, lines_on_screen, total, lines_displayed)     
  612. char *buffer;
  613. int  *lines_on_screen, *total, lines_displayed;
  614. {
  615.     /** Displays the given line if it can.  if not, it will put the
  616.         'ole 'space to continue' prompt on the bottom of the screen
  617.         and wait for either a 'space' or 'return'.  This function
  618.         returns 0 if '<space>' is hit, or the character pressed.
  619.     **/
  620.  
  621.     static char overlap [LONG_SLEN];
  622.            char ch;
  623.            int  last_line_loc;
  624.  
  625.     last_line_loc     = *lines_on_screen;    /* one back... */
  626.  
  627.     *lines_on_screen += ((strlen(buffer) / COLUMNS) + 1);
  628.  
  629.     if (last_line_loc == 0 && title_messages) {
  630.       display_title(lines_on_screen);
  631.       last_line_loc = *lines_on_screen;
  632.     }
  633.           
  634.     if (*lines_on_screen > LINES-2) {
  635.  
  636.       if (*total > 0) {
  637.  
  638.             if (scrolling) {    
  639.  
  640.           if (lines_displayed > LINES+5)  /* are we past screen 1? */
  641.             Write_to_screen("\n\r\n\r\n\r\n\r", 0);    /* don't ask */
  642.           
  643.           PutLine2(LINES, COLUMNS-20, "%d line%s left", 
  644.              *total, plural(*total));
  645.           PutLine0(LINES, 0,
  646.              "Press <space> to continue, <return> to return: ", 0);
  647.         }
  648.             else {
  649.           PutLine0(LINES-1, 0, 
  650.              "Press <space> to continue, <return> to return: ");
  651.           PutLine2(LINES-1, COLUMNS-20, "%d line%s left", 
  652.              *total, plural(*total));
  653.         }
  654.       }
  655.  
  656.       else if (scrolling)
  657.         Write_to_screen("\n\r\n\rPlease press <return> to return: ");
  658.       else
  659.         PutLine0(LINES-1, 0, "Please press <return> to return: ");
  660.  
  661.       Raw(ON);
  662.       ch = tolower(ReadCh());
  663.       if (ch != ' ' || *total == 0) 
  664.         return(ch);
  665.       Raw(OFF);
  666.       if (scrolling) {
  667.         MoveCursor(LINES-2, 0);
  668.         CleartoEOS();
  669.       }
  670.       else {
  671.         ClearScreen();
  672.       }
  673.       *lines_on_screen = 1;
  674.  
  675.       if (title_messages && ! scrolling) {
  676.         display_title(lines_on_screen);
  677.         dprint1(2,"displayed title, lines-on-screen = %d\n",
  678.            *lines_on_screen);
  679.       }
  680.           
  681.       if (! scrolling) {
  682.         PutLine1(*lines_on_screen, 0, "%s\n\r", overlap);
  683.         *lines_on_screen  += ((strlen(overlap) / COLUMNS) + 1);
  684.       }
  685.  
  686.       last_line_loc = *lines_on_screen;
  687.       *lines_on_screen += ((strlen(buffer) / COLUMNS) + 1);
  688.  
  689.       /* resync terminal from write... */
  690.       Write_to_screen("%c%c", 2, '\0', '\0');
  691.       Write_to_screen("%c%c", 2, '\0', '\0');
  692.     }
  693.  
  694.     Write_to_screen("%s\n\r", 1, buffer);
  695.  
  696.     if (*lines_on_screen > LINES-6)        /* in case next is too LONG */
  697.       strcpy(overlap, buffer);
  698.     
  699.     return(0);
  700. }
  701.  
  702. display_title(lines_on_screen)
  703. int *lines_on_screen;
  704. {
  705.     /** Display top title, including "Page N" **/
  706.     
  707.     *lines_on_screen = 2;    /* the title */
  708.     
  709.     PutLine0(0,1,top_of_screen_left);
  710.  
  711.     PutLine0(0, COLUMNS-strlen(top_of_screen_right)+(filter?1:3),
  712.               top_of_screen_right);
  713.  
  714.     if (memory_lock)
  715.       StartMemlock();    /* start up! */
  716.  
  717.     if (strlen(second_line) > 0) {
  718.       PutLine0(1, 0, second_line);
  719.       *lines_on_screen = 5;
  720.     }
  721.  
  722.     dprint1(2,"Display_title set lines-on-screen to %d\n", 
  723.            *lines_on_screen);
  724. }
  725. END-OF-FILE
  726.  
  727. if [ "$filename" != "/dev/null" ]
  728. then
  729.   size=`wc -c < $filename`
  730.  
  731.   if [ $size != 10887 ]
  732.   then
  733.     echo $filename changed - should be 10887 bytes, not $size bytes
  734.   fi
  735.  
  736.   chmod 666 $filename
  737. fi
  738.  
  739. # ---------- file src/string2.c ----------
  740.  
  741. filename="src/string2.c"
  742.  
  743. if [ -f $filename ]
  744. then
  745.   echo File \"$filename\" already exists\!  Skipping...
  746.   filename=/dev/null        # throw it away
  747. else
  748.   echo extracting file src/string2.c...
  749. fi
  750.  
  751. cat << 'END-OF-FILE' > $filename
  752. /**            string2.c        **/
  753.  
  754. /** This file contains string functions that are shared throughout the
  755.     various ELM utilities...
  756.  
  757.     (C) Copyright 1986 Dave Taylor
  758. **/
  759.  
  760. #ifndef TRUE
  761. #define TRUE        1
  762. #define FALSE        0
  763. #endif
  764.  
  765. int 
  766. in_string(buffer, pattern)
  767. char *buffer, *pattern;
  768. {
  769.     /** Returns TRUE iff pattern occurs IN IT'S ENTIRETY in buffer. **/ 
  770.  
  771.     register int i = 0, j = 0;
  772.     
  773.     while (buffer[i] != '\0') {
  774.       while (buffer[i++] == pattern[j++]) 
  775.         if (pattern[j] == '\0') 
  776.           return(TRUE);
  777.       i = i - j + 1;
  778.       j = 0;
  779.     }
  780.     return(FALSE);
  781. }
  782.  
  783. int
  784. chloc(string, ch)
  785. char *string, ch;
  786. {
  787.     /** returns the index of ch in string, or -1 if not in string **/
  788.     register int i;
  789.  
  790.     for (i=0; i<strlen(string); i++)
  791.       if (string[i] == ch) return(i);
  792.     return(-1);
  793. }
  794. END-OF-FILE
  795.  
  796. if [ "$filename" != "/dev/null" ]
  797. then
  798.   size=`wc -c < $filename`
  799.  
  800.   if [ $size != 757 ]
  801.   then
  802.     echo $filename changed - should be 757 bytes, not $size bytes
  803.   fi
  804.  
  805.   chmod 644 $filename
  806. fi
  807.  
  808. # ---------- file src/calendar.c ----------
  809.  
  810. filename="src/calendar.c"
  811.  
  812. if [ -f $filename ]
  813. then
  814.   echo File \"$filename\" already exists\!  Skipping...
  815.   filename=/dev/null        # throw it away
  816. else
  817.   echo extracting file src/calendar.c...
  818. fi
  819.  
  820. cat << 'END-OF-FILE' > $filename
  821. /**            calendar.c        **/
  822.  
  823. /** This routine implements a rather snazzy idea suggested by Warren
  824.     Carithers of the Rochester Institute of Technology that allows
  825.     mail to contain entries formatted in a manner that will allow direct
  826.     copying into a users calendar program.
  827.  
  828.     Never able to leave good-enough alone, I've extended this idea to a
  829.     further one - the knowledge of a different type of calendar program
  830.     too.  Specifically, the current message can contain either of;
  831.  
  832.     -> Mon 04/21 1:00p meet with chairman candidate
  833.  
  834.     or 
  835.  
  836.     - >April 21
  837.     -   
  838.     -     1:00 pm: Meet with Chairman Candidate
  839.     -
  840.  
  841.     The first type will have the leading '->' removed and all subsequent
  842.     white space, creating a simple one-line entry in the users calendar
  843.     file.   The second type will remove the '-' and the leading white
  844.     spaces and leave everything else intact (that is, the file in the
  845.     second example would be appended with ">April 21" followed by a
  846.     blank line, the 1:00 pm meeting info, and another blank line.
  847.     
  848.     The file to include this in is either the default as defined in the
  849.     sysdefs.h file (see CALENDAR_FILE) or a filename contained in the
  850.     users ".elmrc" file, "calendar= <filename>".
  851.  
  852.     (C) Copyright 1986 Dave Taylor
  853. **/
  854.  
  855. #include "headers.h"
  856.  
  857. #ifdef ENABLE_CALENDAR        /* if not defined, this will be an empty file */
  858.  
  859. #include <errno.h>
  860.  
  861. extern int errno;
  862.  
  863. char *error_name(), *error_number();
  864.  
  865. scan_calendar()
  866. {
  867.     FILE *calendar;
  868.     int  count;
  869.  
  870.     /* First step is to open the celendar file for appending... **/
  871.  
  872.     if ((calendar = fopen(calendar_file,"a")) == NULL) {
  873.       dprint1(2, "Error: couldn't append to calendar file %s (save)\n", 
  874.            calendar_file);
  875.       dprint2(2, "** %s - %s **\n",
  876.           error_name(errno), error_description(errno));
  877.       error1("Couldn't append to file %s!", calendar_file);
  878.       return; 
  879.     }
  880.     
  881.     count = extract_info(calendar);
  882.  
  883.     fclose(calendar);
  884.  
  885.     chown(calendar_file, userid, groupid);    /* ensure owned by user */
  886.  
  887.     if (count > 0)
  888.       error2("%d entr%s saved in calendar file", 
  889.          count, count > 1 ? "ies" : "y");
  890.     else 
  891.       error("No calendar entries found in that message");
  892.  
  893.     return;
  894. }
  895.  
  896. int
  897. extract_info(save_to_fd)
  898. FILE *save_to_fd;
  899. {
  900.     /** Save the relevant parts of the current message to the given
  901.         calendar file.  The only parameter is an opened file
  902.         descriptor, positioned at the end of the existing file **/
  903.         
  904.     register int entries = 0, ok = 1, lines, index, in_entry = FALSE;
  905.     char buffer[SLEN];
  906.  
  907.         /** get to the first line of the message desired **/
  908.  
  909.         if (fseek(mailfile, header_table[current-1].offset, 0) == -1) {
  910.              dprint2(1,"ERROR: Attempt to seek %d bytes into file failed (%s)",
  911.         header_table[current-1].offset, "extract_info");
  912.              error1("ELM [seek] failed trying to read %d bytes into file",
  913.              header_table[current-1].offset);
  914.              return(0);
  915.         }
  916.  
  917.         /* how many lines in message? */
  918.  
  919.         lines = header_table[current-1].lines;
  920.  
  921.         /* now while not EOF & still in message... scan it! */
  922.  
  923.         while (ok && lines--) {
  924.           ok = (int) (fgets(buffer, LONG_SLEN, mailfile) != NULL);
  925.       
  926.       /* now let's see if it matches the basic pattern... */
  927.  
  928.       if ((index = calendar_line(buffer)) > -1) {
  929.  
  930.         if (buffer[index] == '>') {    /* single line entry */
  931.           if (remove_through_ch(buffer, '>')) {
  932.             fprintf(save_to_fd,"%s", buffer);
  933.             entries++;
  934.           }
  935.         }
  936.         else {                /* multi-line entry  */
  937.             fprintf(save_to_fd, "%s", (char *) (buffer + index + 1));
  938.             in_entry = TRUE;    
  939.           }
  940.            }
  941.        else if (in_entry) {
  942.          in_entry = FALSE;
  943.          entries++;
  944.        }
  945.     }
  946.  
  947.     dprint2(4,"Got %d calender entr%s.\n", entries, entries > 1? "ies":"y");
  948.  
  949.     return(entries);
  950. }
  951.  
  952. int
  953. calendar_line(string)
  954. char *string;
  955. {
  956.     /** Iff the input line is of the form;
  957.  
  958.           {white space} <one or more '-'> 
  959.     
  960.         this routine will return the index of the NEXT character
  961.         after the dashed sequence...If this pattern doesn't occur, 
  962.         or if any other problems are encountered, it'll return "-1"
  963.     **/
  964.  
  965.     register int loc = 0;
  966.  
  967.     if (chloc(string,'-') == -1)       /* no dash??? */
  968.       return(-1);            /* that was easy! */
  969.  
  970.     /** skip leading white space... **/
  971.  
  972.     while (whitespace(string[loc])) loc++;       /* MUST have '-' too! */
  973.  
  974.     if (string[loc] != '-')    return(-1);       /* nice try, sleazo! */
  975.  
  976.     while (string[loc] == '-') loc++;
  977.  
  978.     if (loc >= strlen(string)) return(-1);    /* Empty line... */
  979.  
  980.     /* otherwise.... */  
  981.  
  982.     return(loc);
  983. }
  984.     
  985.  
  986. int
  987. remove_through_ch(string, ch)
  988. char *string;
  989. char  ch;
  990. {
  991.     /** removes all characters from zero to ch in the string, and 
  992.         any 'white-space' following the 'n'th char... if it hits a
  993.             NULL string, it returns FALSE, otherwise it'll return TRUE!
  994.     **/
  995.  
  996.     char buffer[SLEN];
  997.     register int index = 0, i = 0;
  998.  
  999.     while (string[index] != ch && string[index] != '\0')
  1000.       index++;
  1001.     
  1002.     if (index >= strlen(string)) 
  1003.       return(FALSE);    /* crash! burn! */
  1004.  
  1005.     index++;    /* get past the 'ch' character... */
  1006.  
  1007.     while (whitespace(string[index])) index++;
  1008.  
  1009.     while (index < strlen(string))
  1010.       buffer[i++] = string[index++];
  1011.  
  1012.     buffer[i] = '\0';
  1013.  
  1014.     strcpy(string, buffer);
  1015.     
  1016.     return(TRUE);
  1017. }
  1018.  
  1019. #endif
  1020. END-OF-FILE
  1021.  
  1022. if [ "$filename" != "/dev/null" ]
  1023. then
  1024.   size=`wc -c < $filename`
  1025.  
  1026.   if [ $size != 5189 ]
  1027.   then
  1028.     echo $filename changed - should be 5189 bytes, not $size bytes
  1029.   fi
  1030.  
  1031.   chmod 666 $filename
  1032. fi
  1033.  
  1034. # ---------- file src/elm.c ----------
  1035.  
  1036. filename="src/elm.c"
  1037.  
  1038. if [ -f $filename ]
  1039. then
  1040.   echo File \"$filename\" already exists\!  Skipping...
  1041.   filename=/dev/null        # throw it away
  1042. else
  1043.   echo extracting file src/elm.c...
  1044. fi
  1045.  
  1046. cat << 'END-OF-FILE' > $filename
  1047. /**            elm.c            **/
  1048.  
  1049. /* main program of the ELM mail system! 
  1050.  
  1051.    This file and all associated files and documentation:
  1052.     (C) Copyright 1986 Dave Taylor
  1053. */
  1054.  
  1055. #include "elm.h"
  1056.  
  1057. long bytes();
  1058.  
  1059. main(argc, argv)
  1060. int argc;
  1061. char *argv[];
  1062. {
  1063.     char ch, address[SLEN], to_whom[LONG_SLEN];
  1064.     int  redraw,         /** do we need to rewrite the entire screen? **/
  1065.          nuhead,         /** or perhaps just the headers section...   **/
  1066.          nucurr,         /** or just the current message pointer...   **/
  1067.          nufoot;         /** clear lines 16 thru bottom and new menu  **/
  1068.     int  i;              /** Random counting variable (etc)           **/
  1069.     int  pageon,         /** for when we receive new mail...          **/
  1070.          last_in_mailbox;    /** for when we receive new mail too...      **/
  1071.  
  1072.     parse_arguments(argc, argv, to_whom);
  1073.  
  1074.     if (mail_only) {
  1075.  
  1076.        initialize(FALSE);
  1077.  
  1078.        Raw(ON);
  1079.        dprint1(3,"Mail-only: mailing to\n-> \"%s\"\n", 
  1080.            format_long(to_whom));
  1081.        (void) send(to_whom, "", TRUE); 
  1082.        leave(0);
  1083.     }
  1084.  
  1085.     initialize(TRUE);
  1086.  
  1087.     ScreenSize(&LINES, &COLUMNS);
  1088.  
  1089.     showscreen();
  1090.  
  1091.     mailfile_size = bytes(infile);
  1092.  
  1093.     Raw(ON);
  1094.  
  1095.     while (1) {
  1096.       redraw = 0;
  1097.       nuhead = 0;
  1098.       nufoot = 0;
  1099.       nucurr = 0;
  1100.       if ((i = bytes(infile)) != mailfile_size) {
  1101.         dprint1(2,"Just received %d bytes more mail (elm)\n", 
  1102.             i - mailfile_size);
  1103.         error("New mail has arrived!   Hang on...");
  1104.         last_in_mailbox = message_count;
  1105.         pageon = header_page;
  1106.         newmbox(2, FALSE, TRUE);
  1107.         clear_error();
  1108.         header_page = pageon;
  1109.  
  1110.         if (on_page(current))   /* do we REALLY have to rewrite? */
  1111.           showscreen();
  1112.         else {
  1113.           update_title();
  1114.           ClearLine(LINES-1);         /* remove reading message... */
  1115.           error2("%d new message%s received", 
  1116.              message_count - last_in_mailbox,
  1117.              plural(message_count - last_in_mailbox));
  1118.         }
  1119.         mailfile_size = i;
  1120.         if (cursor_control)
  1121.           transmit_functions(ON);    /* insurance */
  1122.       }
  1123.  
  1124.       prompt("Command: ");
  1125.  
  1126.       CleartoEOLN();
  1127.       ch = tolower(GetPrompt()); 
  1128.       CleartoEOS();
  1129.       dprint1(4, "\nCommand: %c\n\n", ch);
  1130.  
  1131.       set_error("");    /* clear error buffer */
  1132.  
  1133.       MoveCursor(LINES-3,strlen("Command: "));
  1134.  
  1135.       switch (ch) {
  1136.  
  1137.         case '?'     :  if (help())
  1138.                    redraw++;
  1139.                else
  1140.                  nufoot++;
  1141.                break;
  1142.  
  1143.         case ' '    : 
  1144.         case '+'    :  header_page++; nuhead++;    
  1145.                if (move_when_paged && 
  1146.                    header_page < (message_count / headers_per_page))
  1147.                  current = header_page*headers_per_page + 1;
  1148.                break;
  1149.  
  1150.         case '-'    :  header_page--; nuhead++;    
  1151.                if (move_when_paged && header_page > 0)
  1152.                  current = header_page*headers_per_page + 1;
  1153.                break;
  1154.  
  1155.         case '='    :  if (current != 1) {
  1156.                  current = 1;
  1157.                          if (get_page(current))
  1158.                    nuhead++;    
  1159.                  else
  1160.                    nucurr++;
  1161.                }                break;
  1162.  
  1163.         case '*'    :  if (current != message_count) {
  1164.                  current = message_count;    
  1165.                          if (get_page(current))
  1166.                    nuhead++;    
  1167.                  else
  1168.                    nucurr++;
  1169.                }                break;
  1170.  
  1171.         case '|'    :  Writechar('|'); 
  1172.                    softkeys_off();
  1173.                            redraw = do_pipe();        
  1174.                        softkeys_on();         break;
  1175.  
  1176.         case '!'    :  Writechar('!'); 
  1177.                    softkeys_off();
  1178.                            redraw = subshell();        
  1179.                        softkeys_on();         break;
  1180.  
  1181.         case '%'    :  get_return(address);
  1182.                clear_error();
  1183.                PutLine1(LINES,(COLUMNS-strlen(address))/2,
  1184.                         "%.78s", address);    
  1185.                    break;
  1186.  
  1187.         case '/'    :  if (pattern_match()) {
  1188.                           if (get_page(current))
  1189.                     nuhead++;
  1190.                           else
  1191.                             nucurr++;
  1192.                        }
  1193.                else 
  1194.                   error("pattern not found!");
  1195.                break;
  1196.  
  1197.         case '<'    :  /* scan current message for calendar information */
  1198. #ifdef ENABLE_CALENDAR
  1199.                PutLine0(LINES-3, strlen("Command: "),     
  1200.                    "Scan message for calendar entries...");
  1201.                scan_calendar();
  1202. #else
  1203.                 error("Sorry - calendar function disabled");
  1204. #endif
  1205.                break;
  1206.  
  1207.         case 'a'    :  alias();     
  1208.                nufoot++;     
  1209.                define_softkeys(MAIN);     break;
  1210.             
  1211.         case 'b'    :  PutLine0(LINES-3, strlen("Command: "), 
  1212.                      "Bounce message");
  1213.                fflush(stdout);
  1214.                if (message_count < 1)
  1215.                    error("No mail to bounce!");
  1216.                else 
  1217.                  nufoot = remail();
  1218.                break;
  1219.  
  1220.         case 'c'    :  PutLine0(LINES-3, strlen("Command: "), 
  1221.                   "Change mailbox");
  1222.                define_softkeys(CHANGE);
  1223.                if ((file_changed = leave_mbox(FALSE)) != -1) {
  1224.                          redraw = newmbox(0, TRUE, TRUE);
  1225.                  mailfile_size = bytes(infile);    
  1226.                          }
  1227.                else {
  1228.                  file_changed = 0;
  1229.                  sort_mailbox(message_count, FALSE);
  1230.                }
  1231.                define_softkeys(MAIN);
  1232.                break;
  1233.  
  1234.         case '^'    :
  1235.         case 'd'    :  if (message_count < 1)
  1236.                  error("No mail to delete!");
  1237.                else {
  1238.                           delete((ch == 'd'));            
  1239.                  if (resolve_mode)     /* move after mail resolved */
  1240.                    if (current < message_count) {
  1241.                              current++;          
  1242.                      if (get_page(current))
  1243.                        nuhead++;
  1244.                      else
  1245.                        nucurr++;
  1246.                    }
  1247.                        }
  1248.                break;
  1249.  
  1250.         case ctrl('D') : if (message_count < 1)
  1251.                    error("No mail to delete!");
  1252.                  else 
  1253.                    meta_match(DELETED);
  1254.                  break;
  1255.  
  1256.         case 'e'    :  PutLine0(LINES-3, strlen("Command: "), "Edit mailbox");
  1257.                if (current > 0)
  1258.                  edit_mailbox();
  1259.                else
  1260.                  error("Mailbox is empty!");
  1261.                break;
  1262.         
  1263.         case 'f'    :  PutLine0(LINES-3, strlen("Command: "), "Forward");
  1264.                define_softkeys(YESNO);
  1265.                if (current > 0)  
  1266.                          redraw = forward();   
  1267.                else 
  1268.                          error("No mail to forward!");
  1269.                define_softkeys(MAIN);
  1270.                break;
  1271.  
  1272.         case 'g'    :  PutLine0(LINES-3, strlen("Command: "), "Group reply");
  1273.                define_softkeys(YESNO);
  1274.                    fflush(stdout);
  1275.                if (current > 0) {
  1276.                  PutLine0(LINES-3,COLUMNS-40,
  1277.                                      "building addresses...");
  1278.                          redraw = reply_to_everyone();    
  1279.                        }
  1280.                else 
  1281.                  error("No mail to reply to!"); 
  1282.                define_softkeys(MAIN);
  1283.                break;
  1284.  
  1285.         case 'h'    :  if (filter)
  1286.                          PutLine0(LINES-3, strlen("Command: "), 
  1287.                 "Message with headers...");
  1288.                        else
  1289.                  PutLine0(LINES-3, strlen("Command: "),"Read message");
  1290.                fflush(stdout);
  1291.                i = filter;
  1292.                filter = FALSE;
  1293.                redraw = show_msg(current);
  1294.                filter = i;
  1295.                break;
  1296.  
  1297.         case 'j'    :  current++;  
  1298.                if (get_page(current))
  1299.                  nuhead++;
  1300.                else
  1301.                  nucurr++;            break;
  1302.  
  1303.         case 'k'    :  current--;  
  1304.                if (get_page(current))
  1305.                  nuhead++;
  1306.                else
  1307.                  nucurr++;            break;
  1308.  
  1309.         case 'm'    :  PutLine0(LINES-3, strlen("Command: "), "Mail");
  1310.                redraw = send("", "", TRUE); 
  1311.                break;
  1312.  
  1313.         case ctrl('J'):
  1314.         case ctrl('M'):PutLine0(LINES-3, strlen("Command: "), "Read Message");    
  1315.                fflush(stdout);
  1316.                define_softkeys(READ);
  1317.                redraw = show_msg(current);
  1318.                break;
  1319.  
  1320.         case 'n'    :  PutLine0(LINES-3, strlen("Command: "), "Next Message");
  1321.                fflush(stdout);
  1322.                define_softkeys(READ);
  1323.                redraw = show_msg(current);
  1324.                current += redraw;        
  1325.                (void) get_page(current); /* rewrites ANYway */
  1326.                if (current > message_count)
  1327.                  current = message_count;
  1328.                break;
  1329.  
  1330.         case 'o'    :  PutLine0(LINES-3, strlen("Command: "), "Options");
  1331.                options();
  1332.                redraw++;    /* always fix da screen... */
  1333.                break;
  1334.  
  1335.         case 'p'    :  PutLine0(LINES-3, strlen("Command: "), "Print mail");
  1336.                fflush(stdout);
  1337.                if (message_count < 1)
  1338.                  error("No mail to print!");
  1339.                else
  1340.                  printmsg();            
  1341.                break;
  1342.  
  1343.         case 'q'    :  PutLine0(LINES-3, strlen("Command: "), "Quit");
  1344.  
  1345.                if (mbox_specified == 0) lock(OUTGOING);
  1346.  
  1347.                if (mailfile_size != bytes(infile)) {
  1348.                  error("New Mail!  Quit cancelled...");
  1349.                    if (mbox_specified == 0) unlock();
  1350.                        }
  1351.                    else
  1352.                  quit();        
  1353.  
  1354.                break;
  1355.  
  1356.         case 'r'    :  PutLine0(LINES-3, strlen("Command: "), 
  1357.                   "Reply to message");
  1358.                if (current > 0) 
  1359.                          redraw = reply();    
  1360.                else 
  1361.                  error("No mail to reply to!"); 
  1362.                softkeys_on();
  1363.                break;
  1364.  
  1365.         case '>'    : /** backwards compatibility **/
  1366.  
  1367.         case 's'    :  if  (message_count < 1)
  1368.                  error("No mail to save!");
  1369.                else {
  1370.                          PutLine0(LINES-3, strlen("Command: "),"Save Message");
  1371.                  if (save() && resolve_mode) {
  1372.                    if (current < message_count) {
  1373.                      current++;    /* move to next message */
  1374.                      if (get_page(current))
  1375.                        nuhead++;
  1376.                      else
  1377.                        nucurr++;        
  1378.                    }
  1379.                  }
  1380.                }
  1381.                ClearLine(LINES-2);        
  1382.                break;
  1383.  
  1384.             case ctrl('T') :
  1385.         case 't'       :  if (message_count < 1)
  1386.                     error("no mail to tag!");
  1387.                   else if (ch == 't')
  1388.                     tag_message(); 
  1389.                   else
  1390.                     meta_match(TAGGED);
  1391.                           break;
  1392.  
  1393.         case 'u'    :  if (message_count < 1)
  1394.                  error("no mail to mark as undeleted!");
  1395.                else {
  1396.                          undelete();                
  1397.                  if (resolve_mode)     /* move after mail resolved */
  1398.                    if (current < message_count) {
  1399.                              current++;          
  1400.                      if (get_page(current))
  1401.                        nuhead++;
  1402.                      else
  1403.                        nucurr++;
  1404.                    }
  1405.                }
  1406.                break;
  1407.  
  1408.         case ctrl('Q') :
  1409.         case ctrl('?') : 
  1410.         case 'x'    :  PutLine0(LINES-3, strlen("Command: "), "Exit");  
  1411.                            fflush(stdout);              leave();
  1412.  
  1413.         case ctrl('L') : redraw++;    break;
  1414.         
  1415.         case '@'    : debug_screen();  redraw++;    break;
  1416.     
  1417.         case '#'    : debug_message(); redraw++;    break;
  1418.  
  1419.         case NO_OP_COMMAND : break;    /* noop for timeout loop */
  1420.  
  1421.         case ESCAPE : if (cursor_control) {
  1422.                 ch = ReadCh(); 
  1423.                         if (ch == up[1]) {
  1424.                   current--;
  1425.                   if (get_page(current))
  1426.                     nuhead++;
  1427.                   else
  1428.                     nucurr++;            
  1429.                         }
  1430.                 else if (ch == down[1]) {
  1431.                   current++;
  1432.                   if (get_page(current))
  1433.                     nuhead++;
  1434.                   else
  1435.                     nucurr++;            
  1436.                 }
  1437.                 else if (hp_terminal) {    /* kludge! */
  1438.                   if (ch == 'U') {    /* <NEXT> */
  1439.                     header_page++; 
  1440.                 nuhead++;
  1441.                     if (move_when_paged)
  1442.                       current = header_page*headers_per_page + 1;
  1443.                   }
  1444.                   else if (ch == 'V') {  /* <PREV> */
  1445.                     header_page--; 
  1446.                 nuhead++;
  1447.                     if (move_when_paged)
  1448.                       current = header_page*headers_per_page + 1;
  1449.                   }
  1450.                   else if (ch == 'h' || ch == 'H') { /* <HOME UP> */
  1451.                     current = 1;
  1452.                             if (get_page(current))
  1453.                       nuhead++;
  1454.                             else
  1455.                               nucurr++;
  1456.                   }
  1457.                   else if (ch == 'F') {  /* <HOME DOWN> */
  1458.                     current = message_count;
  1459.                             if (get_page(current))
  1460.                       nuhead++;
  1461.                             else
  1462.                               nucurr++;
  1463.                   }
  1464.                   else /* what DID they hit??? */
  1465.                  PutLine2(LINES-3, strlen("Command: "), 
  1466.                           "%c%c", ESCAPE, ch);
  1467.                 }
  1468.                 else /* false hit - output */
  1469.                   PutLine2(LINES-3, strlen("Command: "), 
  1470.                           "%c%c", ESCAPE, ch);
  1471.                 break;
  1472.               }
  1473.                 /* else fall into default.. */
  1474.  
  1475.         default    : if (ch > '0' && ch <= '9') {
  1476.                 PutLine0(LINES-3, strlen("Command: "), 
  1477.                     "New Current Message");
  1478.                 current = read_number(ch, message_count);
  1479.                         if (get_page(current))
  1480.                   nuhead++;
  1481.                         else
  1482.                           nucurr++;
  1483.               }
  1484.               else
  1485.                  error("Unknown command: Use '?' for commands");
  1486.       }
  1487.  
  1488.       dprint5(4,"redraw=%s, current=%d, nuhead=%s, nufoot=%s, nucurr=%s\n",
  1489.           onoff(redraw), current, onoff(nuhead), onoff(nufoot),
  1490.           onoff(nucurr));
  1491.  
  1492.       if (redraw)
  1493.         showscreen();
  1494.  
  1495.       if (current < 1) {
  1496.         if (message_count > 0) {
  1497.           error("already at message #1!");
  1498.           current = 1;
  1499.         }
  1500.         else if (current < 0) {
  1501.           error("No messages to read!");
  1502.           current = 0;
  1503.         }
  1504.       }
  1505.       else if (current > message_count) {
  1506.         if (message_count > 0) {
  1507.           error2("only %d message%s!", message_count, 
  1508.              plural(message_count));
  1509.           current = message_count;
  1510.         }
  1511.         else {
  1512.           error("No messages to read!");
  1513.           current = 0;
  1514.         }
  1515.       }
  1516.  
  1517.       if (nuhead) 
  1518.         show_headers();
  1519.       else if (nucurr)
  1520.         show_current();
  1521.       else if (nufoot) {
  1522.         MoveCursor(LINES-7, 0);  
  1523.             CleartoEOS();
  1524.         if (mini_menu)
  1525.           show_menu();
  1526.       }
  1527.  
  1528.     } /* the BIG while loop! */
  1529. }
  1530.  
  1531. debug_screen()
  1532. {
  1533.     /**** spit out all the current variable settings and the table
  1534.           entries for the current 'n' items displayed. ****/
  1535.  
  1536.     register int i, j;
  1537.     char     buffer[SLEN];
  1538.  
  1539.     ClearScreen();
  1540.     Raw(OFF);
  1541.  
  1542.     PutLine2(0,0,"Current message number = %d\t\t%d message(s) total\n",
  1543.             current, message_count);
  1544.     PutLine2(2,0,"Header_page = %d           \t\t%d possible page(s)\n",
  1545.         header_page, (int) (message_count / headers_per_page) + 1);
  1546.  
  1547.     PutLine1(4,0,"\nCurrent mailfile is %s.\n\n", infile);
  1548.  
  1549.     i = header_page*headers_per_page;    /* starting header */
  1550.  
  1551.     if ((j = i + (headers_per_page-1)) >= message_count) 
  1552.       j = message_count-1;
  1553.  
  1554.     Write_to_screen(
  1555. "Num      From                     Subject                         Lines  Offset\n\n",0);
  1556.  
  1557.     while (i <= j) {
  1558.        sprintf(buffer, 
  1559.        "%3d  %-16.16s  %-40.40s  %4d  %d\n",
  1560.             i+1,
  1561.                 header_table[i].from, 
  1562.                 header_table[i].subject,
  1563.             header_table[i].lines,
  1564.             header_table[i].offset);
  1565.         Write_to_screen(buffer, 0);
  1566.       i++;
  1567.     }
  1568.     
  1569.     Raw(ON);
  1570.  
  1571.     PutLine0(LINES,0,"Press any key to return: ");
  1572.     (void) ReadCh();
  1573. }
  1574.  
  1575.  
  1576. debug_message()
  1577. {
  1578.     /**** Spit out the current message record.  Include EVERYTHING
  1579.           in the record structure. **/
  1580.     
  1581.     char buffer[SLEN];
  1582.  
  1583.     ClearScreen();
  1584.     Raw(OFF);
  1585.  
  1586.     Write_to_screen("\t\t\t----- Message %d -----\n\n\n\n", 1,
  1587.         current);
  1588.  
  1589.     Write_to_screen("Lines : %-5d\t\t\t\tStatus: N  E  A  P  D  T\n", 1,
  1590.         header_table[current-1].lines);
  1591.     Write_to_screen("            \t\t\t\t        e  x  c  r  e  a\n", 0);
  1592.     Write_to_screen("            \t\t\t\t        w  p  t  i  l  g\n\n", 0);
  1593.  
  1594.     sprintf(buffer, "Offset: %ld\t\t\t\t        %d  %d  %d  %d  %d  %d\n\n",
  1595.         header_table[current-1].offset,
  1596.         (header_table[current-1].status & NEW) != 0,
  1597.         (header_table[current-1].status & EXPIRED) != 0,
  1598.         (header_table[current-1].status & ACTION) != 0,
  1599.         (header_table[current-1].status & PRIORITY) != 0,
  1600.         (header_table[current-1].status & DELETED) != 0,
  1601.             (header_table[current-1].status & TAGGED) != 0);
  1602.     Write_to_screen(buffer, 0);
  1603.  
  1604.     sprintf(buffer, "Received on: %d/%d/%d at %d:%02d\n\n",
  1605.             header_table[current-1].received.month+1,
  1606.             header_table[current-1].received.day,
  1607.             header_table[current-1].received.year,
  1608.             header_table[current-1].received.hour,
  1609.             header_table[current-1].received.minute);
  1610.     Write_to_screen(buffer, 0);
  1611.  
  1612.     sprintf(buffer, "Message sent on: %s, %s %s, %s at %s\n\n",
  1613.             header_table[current-1].dayname,
  1614.             header_table[current-1].month,
  1615.             header_table[current-1].day,
  1616.             header_table[current-1].year,
  1617.             header_table[current-1].time);
  1618.     Write_to_screen(buffer, 0);
  1619.     
  1620.     Write_to_screen("\nFrom: %s\n\nSubject: %s", 2,
  1621.         header_table[current-1].from,
  1622.             header_table[current-1].subject);
  1623.  
  1624.     Write_to_screen("\nTo: %s\n\nIndex = %d\n", 2,
  1625.         header_table[current-1].to,
  1626.         header_table[current-1].index_number);
  1627.     
  1628.     Raw(ON);
  1629.  
  1630.     PutLine0(LINES,0,"Press any key to return: ");
  1631.     (void) ReadCh();
  1632. }
  1633. END-OF-FILE
  1634.  
  1635. if [ "$filename" != "/dev/null" ]
  1636. then
  1637.   size=`wc -c < $filename`
  1638.  
  1639.   if [ $size != 15852 ]
  1640.   then
  1641.     echo $filename changed - should be 15852 bytes, not $size bytes
  1642.   fi
  1643.  
  1644.   chmod 644 $filename
  1645. fi
  1646.  
  1647. # ---------- file src/replyc ----------
  1648.  
  1649. filename="src/replyc"
  1650.  
  1651. if [ -f $filename ]
  1652. then
  1653.   echo File \"$filename\" already exists\!  Skipping...
  1654.   filename=/dev/null        # throw it away
  1655. else
  1656.   echo extracting file src/replyc...
  1657. fi
  1658.  
  1659. cat << 'END-OF-FILE' > $filename
  1660.  
  1661. /**        reply.c        **/
  1662.  
  1663. /*** routine allows replying to the sender of the current message 
  1664.  
  1665.      (C) Copyright 1985, Dave Taylor
  1666. ***/
  1667.  
  1668. #include "headers.h"
  1669. #include <errno.h>
  1670.  
  1671. #ifndef BSD
  1672. #  include <sys/utsname.h>
  1673. #endif
  1674.  
  1675. /** Note that this routine generates automatic header information
  1676.     for the subject and (obviously) to lines, but that these can
  1677.     be altered while in the editor composing the reply message! 
  1678. **/
  1679.  
  1680. char *strip_parens(), *get_token(), *notes_machine();
  1681.  
  1682. extern int errno;
  1683.  
  1684. char *error_name();
  1685.  
  1686. int
  1687. reply()
  1688. {
  1689.     /** Reply to the current message.  Returns non-zero iff
  1690.         the screen has to be rewritten. **/
  1691.  
  1692.     char return_address[LONG_SLEN], subject[SLEN];
  1693.     int  return_value;
  1694.  
  1695.     get_return(return_address);
  1696.  
  1697.     if (first_word(header_table[current-1].from, "To:")) {
  1698.       strcpy(subject, header_table[current-1].subject);
  1699.       return_value = send(return_address, subject, TRUE);
  1700.     }
  1701.     else if (header_table[current-1].subject[0] != '\0') {
  1702.       if ((strncmp("Re:", header_table[current-1].subject, 3) == 0) ||
  1703.           (strncmp("RE:", header_table[current-1].subject, 3) == 0) ||
  1704.           (strncmp("re:", header_table[current-1].subject, 3) == 0)) 
  1705.         strcpy(subject, header_table[current-1].subject);
  1706.       else {
  1707.         strcpy(subject,"Re: ");
  1708.         strcat(subject,header_table[current-1].subject); 
  1709.       }
  1710.       return_value = send(return_address, subject, TRUE);
  1711.     }
  1712.     else
  1713.       return_value = send(return_address, "Re: your mail", TRUE);
  1714.  
  1715.     return(return_value);
  1716. }
  1717.  
  1718. int
  1719. reply_to_everyone()
  1720. {
  1721.     /** Reply to everyone who received the current message.  
  1722.         This includes other people in the 'To:' line and people
  1723.         in the 'Cc:' line too.  Returns non-zero iff the screen 
  1724.             has to be rewritten. **/
  1725.  
  1726.     char return_address[LONG_SLEN], subject[SLEN];
  1727.     char full_address[VERY_LONG_STRING];
  1728.     int  return_value;
  1729.  
  1730.     get_return(return_address);
  1731.  
  1732.     strcpy(full_address, return_address);    /* sender gets copy */
  1733.     
  1734.     get_and_expand_everyone(return_address, full_address);
  1735.  
  1736.     if (header_table[current-1].subject[0] != '\0') {
  1737.       if ((strncmp("Re:", header_table[current-1].subject, 3) == 0) ||
  1738.           (strncmp("RE:", header_table[current-1].subject, 3) == 0) ||
  1739.           (strncmp("re:", header_table[current-1].subject, 3) == 0)) 
  1740.         strcpy(subject, header_table[current-1].subject);
  1741.       else {
  1742.         strcpy(subject,"Re: ");
  1743.         strcat(subject,header_table[current-1].subject); 
  1744.       }
  1745.       return_value = send(full_address, subject, TRUE);
  1746.     }
  1747.     else
  1748.       return_value = send(full_address, "Re: your mail", TRUE);
  1749.  
  1750.     return(return_value);
  1751.  
  1752. }
  1753.  
  1754. int
  1755. forward()
  1756. {
  1757.     /** Forward the current message.  What this actually does is
  1758.         to set auto_copy to true, then call 'send' to get the 
  1759.         address and route the mail. 
  1760.     **/
  1761.  
  1762.     char subject[SLEN], address[VERY_LONG_STRING];
  1763.     int  original_cc, results, edit_msg;
  1764.  
  1765.     original_cc = auto_copy;
  1766.     address[0] = '\0';
  1767.  
  1768.     edit_msg = (want_to("Edit outgoing message (y/n) ? ",'y',FALSE) != 'n');
  1769.     Write_to_screen("%s", 1, edit_msg? "Yes" : "No");
  1770.  
  1771.     auto_cc = TRUE;            /* we want a copy */
  1772.  
  1773.     if (strlen(header_table[current-1].subject) > 0) {
  1774.       strcpy(subject,header_table[current-1].subject); 
  1775.       results = send(address, subject, edit_msg);
  1776.     }
  1777.     else
  1778.       results = send(address, "Forwarded Mail...", edit_msg);
  1779.     
  1780.     auto_copy = original_cc;
  1781.  
  1782.     return(results);
  1783. }
  1784.  
  1785. get_and_expand_everyone(return_address, full_address)
  1786. char *return_address, *full_address;
  1787. {
  1788.     /** Read the current message, extracting addresses from the 'To:'
  1789.         and 'Cc:' lines.   As each address is taken, ensure that it
  1790.         isn't to the author of the message NOR to us.  If neither,
  1791.         prepend with current return address and append to the 
  1792.         'full_address' string.
  1793.     **/
  1794.  
  1795.     char ret_address[LONG_SLEN], buf[LONG_SLEN], new_address[LONG_SLEN];
  1796.     char *bufptr, *address;
  1797.     int  in_message = 1, first_pass = 0;
  1798.  
  1799.     /** First off, get to the first line of the message desired **/
  1800.  
  1801.     if (fseek(mailfile, header_table[current-1].offset, 0) == -1) {
  1802.     dprint3(1,"Error: seek %ld resulted in errno %s (%s)\n", 
  1803.          header_table[current-1].offset, error_name(errno), 
  1804.          "get_and_expand_everyone");
  1805.     error2("ELM [seek] couldn't read %d bytes into file (%s)",
  1806.            header_table[current-1].offset, error_name(errno));
  1807.     return;
  1808.     }
  1809.  
  1810.     /** okay!  Now we're there!  **/
  1811.  
  1812.     /** let's fix the ret_address to reflect the return address of this
  1813.     message with '%s' instead of the persons login name... **/
  1814.  
  1815.     translate_return(return_address, ret_address);
  1816.  
  1817.     /** now let's parse the actual message! **/
  1818.  
  1819.     while (in_message) {
  1820.       in_message = (int) (fgets(buf, LONG_SLEN, mailfile) != NULL);
  1821.       if (first_word(buf, "From ") && first_pass++ != 0) 
  1822.     in_message = FALSE;
  1823.       else if (first_word(buf, "To:") || first_word(buf, "Cc:") ||
  1824.            first_word(buf, "CC:") || first_word(buf, "cc:")) {
  1825.     do {
  1826.       no_ret(buf);
  1827.  
  1828.       bufptr = (char *) (strip_parens(buf) + 3); /* 3 = strlen of prompt */
  1829.  
  1830.       while ((address = get_token(bufptr, "\t, ", 0)) != NULL) {
  1831.         if (okay_address(address, return_address)) {
  1832.           sprintf(new_address, ret_address, address);
  1833.           optimize_and_add(new_address, full_address);
  1834.         }
  1835.         bufptr = NULL;
  1836.       }
  1837.  
  1838.           in_message = (int) (fgets(buf, LONG_SLEN, mailfile) != NULL);
  1839.     
  1840.     } while (in_message && whitespace(buf[0]));
  1841.  
  1842.       }
  1843.       else if (strlen(buf) < 2)    /* done with header */
  1844.      in_message = FALSE;
  1845.     }
  1846. }
  1847.  
  1848. int
  1849. okay_address(address, return_address)
  1850. char *address, *return_address;
  1851. {
  1852.     /** This routine checks to ensure that the address we just got
  1853.         from the "To:" or "Cc:" line isn't us AND isn't the person    
  1854.         who sent the message.  Returns true iff neither is the case **/
  1855.  
  1856.     char our_address[SLEN];
  1857.     struct addr_rec  *alternatives;
  1858.  
  1859.     if (in_string(address, return_address))
  1860.       return(FALSE);
  1861.  
  1862.     sprintf(our_address, "%s!%s", hostname, username);
  1863.  
  1864.     if (in_string(address, our_address))
  1865.       return(FALSE);
  1866.  
  1867.     sprintf(our_address, "%s@%s", username, hostname);
  1868.       
  1869.     if (in_string(address, our_address))
  1870.       return(FALSE);
  1871.  
  1872.     alternatives = alternative_addresses;
  1873.  
  1874.     while (alternatives != NULL) {
  1875.       if (in_string(address, alternatives->address))
  1876.         return(FALSE);
  1877.       alternatives = alternatives->next;
  1878.     }
  1879.  
  1880.     return(TRUE);
  1881. }
  1882.         
  1883. optimize_and_add(new_address, full_address)
  1884. char *new_address, *full_address;
  1885. {
  1886.     /** This routine will add the new address to the list of addresses
  1887.         in the full address buffer IFF it doesn't already occur.  It
  1888.         will also try to fix dumb hops if possible, specifically hops
  1889.         of the form ...a!b...!a... and hops of the form a@b@b etc 
  1890.     **/
  1891.  
  1892.     register int len, host_count = 0, i;
  1893.     char     hosts[MAX_HOPS][SLEN];    /* array of machine names */
  1894.     char     *host, *addrptr;
  1895.  
  1896.     if (in_string(full_address, new_address))
  1897.       return(1);    /* duplicate address */
  1898.  
  1899.     /** optimize **/
  1900.     /*  break down into a list of machine names, checking as we go along */
  1901.     
  1902.     addrptr = (char *) new_address;
  1903.  
  1904.     while ((host = get_token(addrptr, "!", 1)) != NULL) {
  1905.       for (i = 0; i < host_count && ! equal(hosts[i], host); i++)
  1906.           ;
  1907.  
  1908.       if (i == host_count) {
  1909.         strcpy(hosts[host_count++], host);
  1910.         if (host_count == MAX_HOPS) {
  1911.            dprint1(2,
  1912.               "Error: hit max_hops limit trying to build return address (%s)\n",
  1913.               "optimize_and_add");
  1914.            error("Can't build return address - hit MAX_HOPS limit!");
  1915.            return(1);
  1916.         }
  1917.       }
  1918.       else 
  1919.         host_count = i + 1;
  1920.       addrptr = NULL;
  1921.     }
  1922.  
  1923.     /** fix the ARPA addresses, if needed **/
  1924.     
  1925.     if (chloc(hosts[host_count-1], '@') > -1)
  1926.       fix_arpa_address(hosts[host_count-1]);
  1927.       
  1928.     /** rebuild the address.. **/
  1929.  
  1930.     new_address[0] = '\0';
  1931.  
  1932.     for (i = 0; i < host_count; i++)
  1933.       sprintf(new_address, "%s%s%s", new_address, 
  1934.               new_address[0] == '\0'? "" : "!",
  1935.               hosts[i]);
  1936.  
  1937.     if (full_address[0] == '\0')
  1938.       strcpy(full_address, new_address);
  1939.     else {
  1940.       len = strlen(full_address);
  1941.       full_address[len  ] = ',';
  1942.       full_address[len+1] = ' ';
  1943.       full_address[len+2] = '\0';
  1944.       strcat(full_address, new_address);
  1945.     }
  1946.  
  1947.     return(0);
  1948. }
  1949.  
  1950. get_return_name(address, name, shift_lower)
  1951. char *address, *name;
  1952. int  shift_lower;
  1953. {
  1954.     /** Given the address (either a single address or a combined list 
  1955.         of addresses) extract the login name of the first person on
  1956.         the list and return it as 'name'.  Modified to stop at
  1957.         any non-alphanumeric character. **/
  1958.  
  1959.     /** An important note to remember is that it isn't vital that this
  1960.         always returns just the login name, but rather that it always
  1961.         returns the SAME name.  If the persons' login happens to be,
  1962.         for example, joe.richards, then it's arguable if the name 
  1963.         should be joe, or the full login.  It's really immaterial, as
  1964.         indicated before, so long as we ALWAYS return the same name! **/
  1965.  
  1966.     /** Another note: modified to return the argument as all lowercase
  1967.         always, unless "shift_lower" isn't TRUE... **/
  1968.  
  1969.     char single_address[LONG_SLEN];
  1970.     register int i, loc, index = 0;
  1971.  
  1972.     dprint2(6,"get_return_name called with (%s, %s)\n", 
  1973.            address, name);
  1974.  
  1975.     /* First step - copy address up to a comma, space, or EOLN */
  1976.  
  1977.     for (i=0; address[i] != ',' && ! whitespace(address[i]) && 
  1978.          address[i] != '\0'; i++)
  1979.       single_address[i] = address[i];
  1980.     single_address[i] = '\0';
  1981.  
  1982.     /* Now is it an ARPA address?? */
  1983.  
  1984.     if ((loc = chloc(single_address, '@')) != -1) {      /* Yes */
  1985.  
  1986.       /* At this point the algorithm is to keep shifting our copy 
  1987.          window left until we hit a '!'.  The login name is then
  1988.              located between the '!' and the first metacharacter to 
  1989.          it's right (ie '%', ':' or '@'). */
  1990.  
  1991.       dprint0(3,"Breaking down ARPA address...(get_return_name)\n");
  1992.  
  1993.       for (i=loc; single_address[i] != '!' && i > -1; i--)
  1994.           if (single_address[i] == '%' || 
  1995.               single_address[i] == ':' ||
  1996.               single_address[i] == '.' ||    /* no domains */
  1997.           single_address[i] == '@') loc = i-1;
  1998.     
  1999.       if (i < 0 || single_address[i] == '!') i++;
  2000.  
  2001.       dprint3(3,"\tgetting from %d to %d out of '%s'\n", 
  2002.           i, loc - i + 1, single_address);
  2003.  
  2004.       for (index = 0; index < loc - i + 1; index++)
  2005.         if (shift_case)
  2006.           name[index] = tolower(single_address[index+i]);
  2007.         else
  2008.           name[index] = single_address[index+i];
  2009.       name[index] = '\0';
  2010.  
  2011.       dprint1(3,"\tfor a return name of '%s'\n", name);
  2012.     }
  2013.     else {    /* easier - standard USENET address */
  2014.  
  2015.       /* This really is easier - we just cruise left from the end of
  2016.          the string until we hit either a '!' or the beginning of the
  2017.              line.  No sweat. */
  2018.  
  2019.       loc = strlen(single_address)-1;     /* last char */
  2020.  
  2021.       for (i = loc; single_address[i] != '!' && single_address[i] != '.' 
  2022.            && i > -1; i--)
  2023.          name[index++] = tolower(single_address[i]);
  2024.       name[index] = '\0';
  2025.       reverse(name);
  2026.     }
  2027.  
  2028.     dprint2(6,"get_return_name leaves with (%s, %s)\n", 
  2029.            address, name);
  2030. }
  2031. END-OF-FILE
  2032.  
  2033. if [ "$filename" != "/dev/null" ]
  2034. then
  2035.   size=`wc -c < $filename`
  2036.  
  2037.   if [ $size != 10750 ]
  2038.   then
  2039.     echo $filename changed - should be 10750 bytes, not $size bytes
  2040.   fi
  2041.  
  2042.   chmod 666 $filename
  2043. fi
  2044.  
  2045. echo end of this archive file....
  2046. exit 0
  2047.  
  2048.