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

  1. Subject: v06i058:  Elm fixes for BSD, et. al. (elm/Patches1)
  2. Newsgroups: mod.sources
  3. Approved: rs@mirror.UUCP
  4.  
  5. Submitted by: Dave Taylor <cca!HPLABS.HP.COM!taylor@hpldat>
  6. Mod.sources: Volume 6, Issue 58
  7. Archive-name: elm/Patches1
  8.  
  9.  
  10.         Fixes to Elm version 1.1, as posted to mod.sources
  11.  
  12.                 [last update 7/14/86]
  13.  
  14.   Notationally, any lines that have an asterisk in the first column are those
  15.   that have changed in one way or another. The asterisk shouldn't be part of
  16.   what's actually typed in, needless to say!
  17.  
  18.   Secondly, when you've applied this set of patches, you should go into the
  19.   file "hdrs/defs.h" and change the VERSION number from 1.1 to 1.2, and change
  20.   the what_string line to;
  21.   ------------
  22.   #define WHAT_STRING    "@(#) Version 1.2, patch #1 release - July 1986"
  23.   -----------
  24.   Don't do it until the patches and Enhancement(s) have all been added,
  25.   though.
  26.  
  27.  
  28.   Documentation glitches;
  29.  
  30.      1. In the file "doc/elm.1" the flags listing should read;
  31.     --------------
  32. *    .TP
  33.     .B "-c"
  34.     Checkalias - expand the following aliases and return.
  35. *    .TP
  36.     .B "-d <level>"
  37.     Debug - set specified debug level - Output to "$HOME/Elm:debug.info"
  38.     --------------
  39.  
  40.     2. In the main Makefile, the configuration guide formatting should be;
  41.     --------------
  42.     doc/Config.fmtd:  doc/Config.guide
  43. *        ${TBL} doc/Config.guide | ${FORMATTER} -mm > doc/Config.fmtd
  44.     --------------
  45.  
  46.  
  47.   Makefile problems;
  48.  
  49.      1. see #2 above
  50.  
  51.      2. In the main Makefile, the multiple arguments need to be quoted
  52.     for some systems, to wit;
  53.     --------------
  54.     # else if on a Sun system:
  55. *    #   DEFINE = "-DBSD -DSUN"
  56.     #   LIB2   = -lcurses
  57.     # else if on a Pyramid system:
  58. *    #   DEFINE = "-DBSD -DNO_VAR_ARGS"
  59.     -------------
  60.     and
  61.     -------------
  62. *    #   DEFINE="${DEFINE} -DACSNET"
  63.     --------------
  64.  
  65.   Utility problems;
  66.  
  67.      1. In the Utilities makefile, the checkalias generation line to;
  68.     --------------
  69. *    @echo 'exec elm -c $$*' >> ../bin/checkalias
  70.     --------------
  71.  
  72.      2. in newmail.c and wnewmail.c move the lines;
  73.     --------------
  74.     #ifdef AUTO_BACKGROUND
  75.     # include <signal.h>    /* background jobs ignore some signals... */
  76.     #endif
  77.     --------------
  78.     to occur AFTER the include for "defs.h".  Otherwise it'll just
  79.     get hopelessly confused.
  80.  
  81.      3. In the file arepdaemon.c, change the header declarations to;
  82.     --------------
  83. *    #ifdef BSD
  84. *    # include <sys/time.h>
  85. *    #else
  86.     # include <time.h>
  87. *    #endif
  88.     --------------
  89.     and remove the definition ->in this file<- of the constant "NLEN",
  90.     which is defined in the included file "defs.h".  This will clear
  91.     up some compile-time problems on BSD systems...
  92.     
  93.      4. In the file autoreply.c, remove the macro definition for the constant
  94.     READ_ACCESS (that is, remove the line "#define READ_ACCESS 04")
  95.  
  96.   Elm system problems;
  97.  
  98.      1. In the file src/showmsg.c, change the line just before the display()
  99.     function to;
  100.     --------------
  101.     FILE   *output_pipe, 
  102. *           *popen();
  103.     --------------
  104.     This will eliminate the "illegal combination of pointer and integer"
  105.     message encountered when compiling this routine.
  106.  
  107.      2. In the file src/getopt.c, change the lines;
  108.     --------------
  109.     if (argv[_argnum] == NULL && _indx > 1) {    /* Sun compatability */
  110.       _argnum++;
  111.       _indx = 1;        /* zeroeth char is '-' */
  112.     }
  113. *    else if (argv[_argnum] != NULL)
  114.       if (_indx >= strlen(argv[_argnum]) && _indx > 1) {
  115.         _argnum++;
  116.         _indx = 1;        /* zeroeth char is '-' */
  117.       }
  118.     ---------------
  119.     This will eliminate the Bus Error encountered on the Sun systems
  120.     and some BSD systems...
  121.  
  122.     While in this file, change all compares against 'argc' from being '>'
  123.     to being '>=' (that is, change the two occurances of the line
  124.     "if (_argnum > argc) {" to "if (_argnum >= argc) {"
  125.  
  126.  
  127.      3. In the file "src/date.c" change the lines;
  128.     ---------------
  129. *    minute1 = minute2 = -1;
  130.  
  131.     sscanf(rec1->time, "%d:%d", &hour1, &minute1);
  132.     sscanf(rec2->time, "%d:%d", &hour2, &minute2);
  133.  
  134. *    if (minute1 == -1)
  135. *      sscanf(rec1->time, "%2d%2d", &hour1, &minute1);
  136.  
  137. *    if (minute2 == -1)
  138. *      sscanf(rec2->time, "%2d%2d", &hour2, &minute2);
  139.  
  140.     if (hour1 != hour2)
  141.       return( hour1 - hour2 );
  142.  
  143. *    return( minute1 - minute2 );        /* ignore seconds... */
  144.     ----------------
  145.  
  146.      4. In the file "src/hdrconfg.c" add....
  147.     ----------------
  148.       switch (c) {
  149. *        case ctrl('J'):
  150.         case ctrl('M'):
  151.         case 'Q' : goto outta_here;
  152.     ----------------
  153.  
  154.     MORE importantly - and this one causes a 'bus error' on BSD systems!!
  155.     alter the case 'I' line to read;
  156.     ----------------
  157. *        case 'I' : if (strlen(in_reply_to) > 0) {
  158.                      if (optionally_enter(in_reply_to, 11,13, FALSE) == -1)
  159.                goto outta_here;
  160.              break;        
  161.                }
  162.     ----------------
  163.     [the change is in the location of the innermost right paren on the
  164.      call to 'strlen' on the first line of this case entry...!]
  165.  
  166.      5. In the file src/initialize.c, alter the figure out lines setting to;
  167.     ----------------
  168. *    ScreenSize(&LINES, &COLUMNS);
  169.  
  170.     if ((cp = getenv("LINES")) != NULL && isdigit(*cp)) {
  171.       sscanf(cp, "%d", &LINES);
  172.       LINES -= 1;    /* kludge for HP Window system? ... */
  173.     }
  174.     ----------------
  175.     and remove the call to "ScreenSize()" from the file "src/elm.c"
  176.  
  177.      6. In the file src/elm.c, remove the call to ScreenSize() (see #5)
  178.  
  179.         Also, change the cases for '+' and '-' to read;
  180.     -----------------
  181.         case ' '    : 
  182.         case '+'    :  header_page++; nuhead++;    
  183.                if (move_when_paged && 
  184. *                   header_page <=(message_count / headers_per_page))
  185.                  current = header_page*headers_per_page + 1;
  186.                break;
  187.  
  188.         case '-'    :  header_page--; nuhead++;    
  189. *               if (move_when_paged && header_page >= 0)
  190.                  current = header_page*headers_per_page + 1;
  191.                break;
  192.     -----------------
  193.     [the change is the tests to see what page we're on have become '<='
  194.      from '<' and '>=' from '>' respectively...]
  195.  
  196.      7. In the file src/screen.c, replace sprintf with the following;
  197.     -----------------
  198.     sprintf(buffer, "%s%s%c%c%c%-3d %3.3s %-2d %-18.18s (%d) %s%s%s", 
  199. *        highlight? ((has_highlighting && !arrow_cursor) ?
  200. *                   start_highlight : "->") : "  ",
  201. *        (highlight && has_highlighting && !arrow_cursor)? "  " : "",
  202.         show_status(entry->status),
  203.         (entry->status & DELETED? 'D' : ' '), 
  204.         (entry->status & TAGGED?  '+' : ' '),
  205.             message_number,
  206.             entry->month, 
  207.         atoi(entry->day), 
  208.         from, 
  209.         entry->lines, 
  210.         (entry->lines / 1000   > 0? ""   :    /* spacing the  */
  211.           entry->lines / 100   > 0? " "  :    /* same for the */
  212.             entry->lines / 10  > 0? "  " :    /* lines in ()  */
  213.                                     "   "),    /*   [wierd]    */
  214.         subj,
  215. *        (highlight && has_highlighting && !arrow_cursor) ?
  216. *              end_highlight : "");
  217.     -----------------
  218.  
  219.      8. In the file src/delete.c change the following routines to be what's
  220.     listed here...
  221.     ------------------
  222.     show_msg_status(msg)
  223.     int msg;
  224.     {
  225.         /** show the status of the current message only.  **/
  226.  
  227.         if (on_page(msg)) {
  228.           MoveCursor((msg % headers_per_page) + 4, 3);
  229. *          if (msg == current && !arrow_cursor) {
  230. *            StartBold();
  231. *            Writechar(ison(header_table[msg].status,DELETED)?'D':' ');
  232. *            EndBold();
  233. *          }
  234. *          else
  235.             Writechar(ison(header_table[msg].status,DELETED)?'D':' ');
  236.         }
  237.     }
  238.     -----------------
  239.     show_msg_tag(msg)
  240.     int msg;
  241.     {
  242.         /** show the tag status of the current message only.  **/
  243.  
  244.         if (on_page(msg)) {
  245.           MoveCursor((msg % headers_per_page) + 4, 4);
  246. *          if (msg == current && !arrow_cursor) {
  247. *            StartBold();
  248. *            Writechar(ison(header_table[msg].status,TAGGED)? '+' : ' ');
  249. *            EndBold();
  250. *          }
  251. *          else
  252.             Writechar(ison(header_table[msg].status,TAGGED)? '+' : ' ');
  253.         }    
  254.     }
  255.  
  256.     show_new_status(msg)
  257.     int msg;
  258.     {
  259.         /** If the specified message is on this screen, show
  260.             the new status (could be marked for deletion now,
  261.             and could have tag removed...)
  262.         **/
  263.  
  264.         if (on_page(msg)) 
  265. *          if (msg == current && !arrow_cursor) {
  266. *            StartBold();
  267. *            PutLine2((msg % headers_per_page) + 4, 3, "%c%c",
  268. *               ison(header_table[msg].status, DELETED)? 'D' : ' ',
  269. *               ison(header_table[msg].status, TAGGED )? '+' : ' ');
  270. *            EndBold();
  271. *          }
  272. *          else
  273.             PutLine2((msg % headers_per_page) + 4, 3, "%c%c",
  274.                ison(header_table[msg].status, DELETED)? 'D' : ' ',
  275.                ison(header_table[msg].status, TAGGED )? '+' : ' ');
  276.     }
  277.     ------------
  278.  
  279.      9. in src/newmbox.c change;
  280.     ------------
  281.     (void) fclose(mailfile);  /* close it first, to avoid too many open */
  282.     ------------
  283.     to;
  284.     ------------
  285. *    if (mailfile != NULL)
  286.       (void) fclose(mailfile);  /* close it first, to avoid too many open */
  287.     ------------
  288.  
  289.     10. In the files src/help.c src/date.c src/initialize.c and src/domains.c
  290.     make sure both 'toupper' and 'tolower' are undefined if we're on a
  291.     BSD system;
  292.     -------------
  293. *    #ifdef BSD
  294. *    # undef tolower
  295. *    # undef toupper
  296. *    #endif
  297.     -------------
  298.  
  299.     11. In the file src/file_utils.c change the following; At the top of the 
  300.         file include the three lines;
  301.     -------------
  302. *    #ifdef BSD
  303. *    #include <sys/wait.h>
  304. *    #endif
  305.     -------------
  306.     and further in the file replace the existing "can_access()" with;    
  307.     -------------
  308.     int
  309.     can_access(file, mode)
  310.     char *file; 
  311.     int   mode;
  312.     {
  313.         /** returns ZERO iff user can access file or "errno" **/
  314.     
  315.         int stat = 0, pid, w;
  316. *    #ifdef BSD
  317. *        union wait status;
  318. *    #else
  319. *        int status;
  320. *    #endif
  321.         register int (*istat)(), (*qstat)();
  322.         
  323.     #ifdef NO_VM        /* machine without virtual memory!! */
  324.         if ((pid = fork()) == 0) {
  325.     #else
  326.         if ((pid = vfork()) == 0) {
  327.     #endif
  328.           setuid(userid);        /** back to normal userid **/
  329.           setgid(groupid);
  330.           errno = 0;
  331. *          if (access(file, mode))
  332. *            _exit(errno);
  333. *          else
  334. *            _exit(0);
  335.           _exit(127);
  336.         }
  337.  
  338.         istat = signal(SIGINT, SIG_IGN);
  339.         qstat = signal(SIGQUIT, SIG_IGN);
  340.  
  341.         while ((w = wait(&status)) != pid && w != -1)
  342.             ;
  343.  
  344. *    #ifdef BSD
  345. *        if (status.w_retcode != 0) stat = status.w_retcode;
  346. *    #else
  347. *        if (w == -1) stat = status;
  348. *    #endif
  349.         
  350.         signal(SIGINT, istat);
  351.         signal(SIGQUIT, qstat);
  352.  
  353. *        return(stat);
  354.     }
  355.     ----------------
  356.     and "can_open()" with;
  357.     ----------------
  358.     int
  359.     can_open(file, mode)
  360.     char *file; 
  361.     char *mode;
  362.     {
  363.         /** returns 0 iff user can open the file.  This is not
  364.             the same as can_access - it's used for when the file might
  365.             not exist... **/
  366.  
  367.         int stat = 0, pid, w;
  368. *    #ifdef BSD
  369. *        union wait status;
  370. *    #else
  371. *        int status;
  372. *    #endif
  373.         register int (*istat)(), (*qstat)();
  374.         
  375.     #ifdef NO_VM        /* machine without virtual memory!! */
  376.         if ((pid = fork()) == 0) {
  377.     #else
  378.         if ((pid = vfork()) == 0) {
  379.     #endif
  380.           setuid(userid);        /** back to normal userid **/
  381.           setgid(groupid);
  382.           errno = 0;
  383. *          if (fopen(file, mode) == NULL)
  384. *            _exit(errno);
  385. *          else
  386. *            _exit(0);
  387.           _exit(127);
  388.         }
  389.  
  390.         istat = signal(SIGINT, SIG_IGN);
  391.         qstat = signal(SIGQUIT, SIG_IGN);
  392.  
  393.         while ((w = wait(&status)) != pid && w != -1)
  394.             ;
  395.  
  396. *    #ifdef BSD
  397. *        if (status.w_retcode != 0) stat = status.w_retcode;
  398. *    #else
  399. *        if (w == -1) stat = status;
  400. *    #endif
  401.         
  402.         signal(SIGINT, istat);
  403.         signal(SIGQUIT, qstat);
  404.  
  405. *        return(stat);
  406.     }
  407.     --------------
  408.  
  409.     12. In the file "src/syscall.c" make the following changes;
  410.     Add the following three lines to the top of the file;
  411.     --------------
  412.     #ifdef BSD
  413.     #  include <sys/wait.h>
  414.     #endif
  415.     --------------
  416.  
  417.     system_call(string, shell_type)
  418.     char *string;
  419.     int   shell_type;
  420.     {
  421.         /** execute 'string', setting uid to userid... **/
  422.         /** if shell-type is "SH" /bin/sh is used regardless of the 
  423.             users shell setting.  Otherwise, "USER_SHELL" is sent **/
  424.  
  425.         int stat = 0, pid, w;
  426. *    #ifdef BSD
  427. *        union wait status;
  428. *    #else
  429. *        int status;
  430. *    #endif
  431.         register int (*istat)(), (*qstat)();
  432.         
  433.         dprint2(2,"System Call: %s\n\t%s\n", 
  434.             shell_type == SH? "/bin/sh" : shell, string);
  435.  
  436.         #ifdef NO_VM        /* machine without virtual memory! */
  437.             if ((pid = fork()) == 0) {
  438.         #else
  439.             if ((pid = vfork()) == 0) {
  440.         #endif
  441.               setuid(userid);    /* back to the normal user! */
  442.               setgid(groupid);    /* and group id            */
  443.  
  444.               if (strlen(shell) > 0 && shell_type == USER_SHELL) {
  445.                 execl(shell, argv_zero(shell), "-c", string, 0);
  446.               }
  447.           else 
  448.             execl("/bin/sh", "sh", "-c", string, 0);
  449.           _exit(127);
  450.         }
  451.  
  452.         istat = signal(SIGINT, SIG_IGN);
  453.         qstat = signal(SIGQUIT, SIG_IGN);
  454.  
  455.         while ((w = wait(&status)) != pid && w != -1)
  456.             ;
  457.  
  458. *        #ifdef BSD
  459. *            if (status.w_retcode != 0) stat = status.w_retcode;
  460. *        #else
  461. *            if (w == -1) stat = status;
  462. *        #endif
  463.     
  464.         signal(SIGINT, istat);
  465.         signal(SIGQUIT, qstat);
  466.  
  467. *        return(stat);
  468.     }
  469.  
  470.     
  471.     13. On BSD systems the tgetstr() function seems a tad flaky.  This can be
  472.     avoided (to some extent) by changing curses.c as follows;
  473.     --------------
  474.     char *return_value_of(termcap_label)
  475.     char *termcap_label;
  476.     {
  477.         /** This will return the string kept by termcap for the 
  478.             specified capability. Modified to ensure that if 
  479.             tgetstr returns a pointer to a transient address    
  480.             that we won't bomb out with a later segmentation
  481.             fault (thanks to Dave@Infopro for this one!) **/
  482.  
  483.         static char escape_sequence[20];
  484.  
  485.         char *tgetstr();             /* Get termcap capability */
  486.  
  487.         dprint1(9,"return_value_of(%s)\n", termcap_label);
  488.  
  489. *        if (termcap_label[0] == 's' && termcap_label[1] == 'o')
  490. *          strcpy(escape_sequence, _setinverse);
  491. *        else if (termcap_label[0] == 's' && termcap_label[1] == 'e')
  492. *          strcpy(escape_sequence, _clearinverse);
  493. *        else
  494.           strcpy(escape_sequence, tgetstr(termcap_label, &ptr));
  495.  
  496.         return( (char *) escape_sequence);
  497.     }
  498.     --------------
  499.  
  500.     14. In the file src/newmbox.c, change line 353 to read;
  501.     --------------
  502. *    header_table[count > 0? count-1:count].lines = line + 1;
  503.     --------------
  504.     [The previous version was computing the number of lines in 
  505.      the last message in the mailbox incorrectly - this will fix
  506.      that problem]
  507.  
  508.  
  509.  
  510.  
  511.                                   ENHANCEMENTS
  512.                                         
  513.                            [last added to on 7/11/86]
  514.  
  515. Enhancement One: support adding user NAMES to outbound mail and replies.
  516.  
  517.  ******************************************************************************
  518.  * NOTE: You'll need Enhancement two to be able to fully utilize this           *
  519.  *       feature - this set of changes will allow sending and replying          *
  520.  *     INDIVIDUALLY to users with their names on the outbound addresses      *
  521.  *       It will NOT be able to deal with G)roup replies until the next          *
  522.  *       BUGFIX document is issued.   Install at your own risk (as always)    *
  523.  ******************************************************************************
  524.  
  525.   1.  Replace the file "utils/newalias.c" with the following file (lots of
  526.       changes...)
  527.  
  528. [the following is 511 lines long...]
  529. ----------------------
  530. /**        newalias.c        **/
  531.  
  532. /** (C) Copyright 1986 Dave Taylor      **/
  533.  
  534. /** Install a new set of aliases for the 'Elm' mailer. 
  535.  
  536.     If invoked with a specific filename, it assumes that
  537.   it is working with an individual users alias tables, and
  538.   generates the .alias.hash and .alias.data files in their
  539.   home directory.
  540.     If, however, it is invoked with no arguments, then
  541.   it assumes that the user is updating the system alias
  542.   file and uses the defaults for everything.
  543.  
  544.   The format for the input file is;
  545.     alias1, alias2, ... : username : address
  546. or  alias1, alias2, ... : groupname: member, member, member, ...
  547.                                      member, member, member, ...
  548.  
  549.   "-q" flag added: 6/17/86
  550. **/
  551.  
  552. #ifdef BSD
  553. #  include <sys/file.h>
  554. #else
  555. #  include <fcntl.h>
  556. #endif
  557.  
  558. #include <stdio.h>
  559. #include "defs.h"        /* ELM system definitions */
  560.  
  561. static char ident[] = { WHAT_STRING };
  562.  
  563. #ifndef TAB
  564. # define TAB         '\t'    /* TAB character!         */
  565. #endif
  566.     
  567. #define alias_hash    ".alias_hash"
  568. #define alias_data    ".alias_data"
  569. #define alias_text    ".alias_text"
  570.  
  571. #define group(string)        (strpbrk(string,", ") != NULL)
  572.  
  573. struct alias_rec
  574. shash_table[MAX_SALIASES];    /* the actual hash table     */
  575.  
  576. struct alias_rec
  577. uhash_table[MAX_UALIASES];    /* the actual hash table     */
  578.  
  579. int  hash_table_loaded=0;    /* is system table actually loaded? */
  580.  
  581. int  buff_loaded;        /* for file input overlap... */
  582. int  error= 0;            /* if errors, don't save!    */
  583. int  system=0;            /* system file updating?     */
  584. int  count=0;            /* how many aliases so far?  */
  585. long offset = 0L;        /* data file line offset!    */
  586.  
  587. main(argc, argv)
  588. int argc;
  589. char *argv[];
  590. {
  591.     FILE *in, *data;
  592.     char inputname[SLEN], hashname[SLEN], dataname[SLEN];
  593.     char home[SLEN], buffer[LONG_STRING];
  594.     int  hash, count = 0, owner, quiet = 0;
  595.  
  596.     if (argc != 1)
  597.       if (strcmp(argv[1], "-q") == 0)
  598.         quiet++;
  599.       else
  600.         exit(printf("Usage: %s\n", argv[0]));
  601.  
  602.     owner = getuid();
  603.  
  604.     if (owner == 0 && ! quiet) {    /* being run by root! */
  605.       printf("Would you like to update the system aliases? (y/n)");
  606.       gets(buffer, 2);
  607.       if (buffer[0] == 'y' || buffer[0] == 'Y') {
  608.         printf("Updating the system alias file...\n");
  609.  
  610.         sprintf(inputname, "%s/%s", mailhome, alias_text);
  611.         sprintf(hashname, "%s/%s", mailhome, alias_hash);
  612.         sprintf(dataname, "%s/%s", mailhome, alias_data);
  613.         system++;
  614.         init_table(shash_table, MAX_SALIASES); 
  615.       }
  616.       else 
  617.         printf("Updating your personal alias file...\n");
  618.     }
  619.     
  620.     if (! system) {
  621.       if (strcpy(home, getenv("HOME")) == NULL)
  622.         exit(printf("Confused: No HOME variable in environment!\n"));
  623.  
  624.       sprintf(inputname, "%s/%s", home, alias_text);
  625.       sprintf(hashname,  "%s/%s", home, alias_hash); 
  626.       sprintf(dataname,  "%s/%s", home, alias_data); 
  627.  
  628.       init_table(uhash_table, MAX_UALIASES); 
  629.  
  630.       read_in_system(shash_table, sizeof shash_table);
  631.     }
  632.  
  633.     if ((in = fopen(inputname,"r")) == NULL)
  634.       exit(printf("Couldn't open %s for input!\n", inputname));
  635.  
  636.     if ((hash = open(hashname, O_WRONLY | O_CREAT, 0644)) == -1)
  637.       exit(printf("Couldn't open %s for output!\n", hashname));
  638.  
  639.     if ((data = fopen(dataname,"w")) == NULL)
  640.       exit(printf("Couldn't open %s for output!\n", dataname));
  641.  
  642.     buff_loaded = 0;     /* file buffer empty right now! */
  643.  
  644.     while (get_alias(in, buffer) != -1) {
  645.       if (system)
  646.         put_alias(data, buffer, shash_table, MAX_SALIASES);    
  647.       else
  648.         put_alias(data, buffer, uhash_table, MAX_UALIASES);    
  649.       count++;
  650.     }
  651.  
  652.     if (error) {
  653.       printf("\n** Not saving tables!  Please fix and re-run %s!\n",
  654.          argv[0]);
  655.       exit(1);
  656.     }
  657.     else {
  658.       if (system)
  659.         write(hash, shash_table, sizeof shash_table);
  660.       else
  661.         write(hash, uhash_table, sizeof uhash_table);
  662.  
  663.       close(hash);
  664.       fclose(data);
  665.       close(in);
  666.     
  667.       printf("Processed %d aliases\n", count);
  668.       exit(0);
  669.     }
  670. }
  671.  
  672. int
  673. get_alias(file, buffer)
  674. FILE *file;
  675. char *buffer;
  676. {
  677.     /* load buffer with the next complete alias from the file.
  678.        (this can include reading in multiple lines and appending
  679.        them all together!)  Returns EOF after last entry in file.
  680.     
  681.     Lines that start with '#' are assumed to be comments and are
  682.      ignored.  White space as the first field of a line is taken
  683.     to indicate that this line is a continuation of the previous. */
  684.  
  685.     static char mybuffer[SLEN];
  686.     int    done = 0, first_read = 1;
  687.  
  688.     /** get the first line of the entry... **/
  689.  
  690.     buffer[0] = '\0';            /* zero out line */
  691.  
  692.     do {
  693.       if (get_line(file, mybuffer, first_read) == -1) 
  694.         return(-1);
  695.       first_read = 0;
  696.       if (mybuffer[0] != '#')
  697.         strcpy(buffer, mybuffer);
  698.     } while (strlen(buffer) == 0);    
  699.  
  700.     /** now read in the rest (if there is any!) **/
  701.  
  702.     do {
  703.       if (get_line(file, mybuffer, first_read) == -1) {
  704.         buff_loaded = 0;    /* force a read next pass! */
  705.         return(0);    /* okay. let's just hand 'buffer' back! */
  706.       }
  707.       done = (mybuffer[0] != ' ' && mybuffer[0] != TAB);
  708.       if (mybuffer[0] != '#' && ! done)
  709.         strcat(buffer, mybuffer);
  710.       done = (done && mybuffer[0] != '#');
  711.     } while (! done);
  712.     
  713.     return(0);    /* no sweat! */
  714. }
  715.  
  716. put_alias(data, buffer, table, size)
  717. FILE *data;
  718. char *buffer;
  719. struct alias_rec table[];
  720. int  size;
  721. {
  722.     /** break buffer down into three pieces: aliases, comment, and address.
  723.         Make the appropriate entries in the table (size) 
  724.     **/
  725.  
  726.     char aliases[LONG_STRING], address[LONG_STRING];
  727.     char comment[LONG_STRING];
  728.     int  first, last, i = 0, j = 0;
  729.  
  730.     remove_all(' ', TAB, buffer);
  731.  
  732.     for (i=0; buffer[i] != ':' && i < LONG_STRING; i++)
  733.       aliases[i] = buffer[i];
  734.     aliases[i] = '\0';
  735.  
  736.     for (i=strlen(buffer)-1; buffer[i] != ':' && i > 0; i--)
  737.       address[j++] = buffer[i];
  738.     address[j] = '\0';
  739.  
  740.     comment[0] = '\0';    /* default to nothing at all... */
  741.  
  742.     if ((first=strlen(aliases)+1) < (last=(strlen(buffer) - j))) {
  743.       extract_comment(comment, buffer, first, last); 
  744.     }
  745.  
  746.     reverse(address);
  747.  
  748.     add_to_table(data, aliases, comment, address, table, size);
  749. }
  750.  
  751. int
  752. get_line(file, buffer, first_line)
  753. FILE *file;
  754. char *buffer;
  755. int  first_line;
  756. {
  757.     /** read line from file.  If first_line and buff_loaded, 
  758.         then just return! **/
  759.     int stat;
  760.  
  761.     if (first_line && buff_loaded) {
  762.       buff_loaded = 1;
  763.       return;
  764.     }
  765.  
  766.     buff_loaded = 1;    /* we're going to get SOMETHING in the buffer */
  767.  
  768.     stat = fgets(buffer, SLEN, file) == NULL ? -1 : 0;
  769.  
  770.     if (stat != -1)
  771.       no_ret(buffer);
  772.  
  773.     return(stat);
  774. }
  775.  
  776. reverse(string)
  777. char *string;
  778. {
  779.     /** reverse the order of the characters in string... 
  780.         uses a bubble-sort type of algorithm!                 **/
  781.     
  782.     register int f, l;
  783.     char     c;
  784.     
  785.     f = 0;
  786.     l = strlen(string) - 1;
  787.     
  788.     while (f < l) {
  789.       c = string[f];
  790.        string[f] = string[l];
  791.       string[l] = c;
  792.       f++;
  793.       l--;
  794.     }
  795. }
  796.  
  797. add_to_table(data, aliases, comment, address, table, size)
  798. FILE *data;
  799. char *aliases, *comment, *address;
  800. struct alias_rec table[];
  801. int  size;
  802. {
  803.     /** add address + comment to datafile, incrementing offset count 
  804.         (bytes), then for each alias in the aliases string, add to the
  805.         hash table, with the associated pointer value! **/
  806.  
  807.     static char buf[SLEN], *word;
  808.     long additive = 1L;
  809.  
  810.     word = buf;    /* use the allocated space! */
  811.  
  812.     if (group(address)) {
  813.       check_group(address, aliases);
  814.       if (error) return;    /* don't do work if we aren't to save it! */
  815.       fprintf(data, "!%s\n", address);
  816.       additive = 2L;
  817.     }
  818.     else {
  819.       if (error) return;    /* don't do work if we aren't to save it! */
  820.       if (strlen(comment) > 0) {
  821.         fprintf(data, "%s (%s)\n", address, comment);
  822.         additive = (long) (strlen(comment) + 4);
  823.       }
  824.       else
  825.         fprintf(data, "%s\n", address, comment);
  826.     }
  827.  
  828.     while ((word = (char *) strtok(aliases,", ")) != NULL) {
  829.       add_to_hash_table(word, offset, table, size);
  830.       aliases = NULL;    /* let's get ALL entries via 'strtok' */
  831.       count++;
  832.     }
  833.  
  834.     if ( system ? count > MAX_SALIASES-35 : count > MAX_UALIASES-21) {
  835.       printf("** Too many aliases in file! **\n");
  836.       error++;
  837.     }
  838.  
  839.     offset = (offset + (long) strlen(address) + additive);
  840. }    
  841.  
  842. remove_all(c1, c2, string)
  843. char c1, c2, *string;
  844. {
  845.     /* Remove all occurances of character 'c1' or 'c2' from the string.
  846.        Hacked (literally) to NOT remove ANY characters from within the
  847.        colon fields.  This will only be used if the line contains TWO
  848.        colons (and comments with colons in them are the kiss of death!)
  849.      */
  850.  
  851.     char buffer[LONG_STRING];
  852.     register int i = 0, j = 0, first_colon = -1, last_colon = -1;
  853.     
  854.     for (i = 0; string[i] != '\0' && i < LONG_STRING; i++) {
  855.       if (string[i] != c1 && string[i] != c2)
  856.         buffer[j++] = string[i];
  857.  
  858.       if (first_colon == -1 && string[i] == ':') {
  859.         first_colon = i;
  860.         for (last_colon=strlen(string);string[last_colon] != ':'; 
  861.         last_colon--) ;
  862.       }
  863.       else if (i > first_colon && i < last_colon)
  864.        if (string[i] == c1 || string[i] == c2)
  865.          buffer[j++] = string[i];
  866.     }
  867.     
  868.     buffer[j] = '\0';
  869.     strcpy(string, buffer);
  870. }
  871.  
  872. add_to_hash_table(word, offset, table, size)
  873. char *word;
  874. long  offset;
  875. struct alias_rec table[];
  876. int   size;
  877. {
  878.     /** add word and offset to current hash table. **/
  879.     register int loc;
  880.     
  881.     if (strlen(word) > 20)
  882.       exit(printf("Bad alias name: %s.  Too long.\n", word));
  883.  
  884.     loc = hash_it(word, size);
  885.  
  886.     while (table[loc].name[0] != '\0' && strcmp(table[loc].name, word) != 0)
  887.       loc = loc + 1 % size; 
  888.  
  889.     if (table[loc].name[0] == '\0') {
  890.       strcpy(table[loc].name, word);
  891.       table[loc].byte = offset;
  892.     }
  893.     else 
  894.       printf("** Duplicate alias '%s' in file.  Multiples ignored.\n",
  895.              word);
  896. }
  897.  
  898. int
  899. hash_it(string, table_size)
  900. char *string;
  901. {
  902.     /** compute the hash function of the string, returning
  903.         it (mod table_size) **/
  904.  
  905.     register int i, sum = 0;
  906.     
  907.     for (i=0; string[i] != '\0'; i++)
  908.       sum += (int) string[i];
  909.  
  910.     return(sum % table_size);
  911. }
  912.  
  913. init_table(table, size)
  914. struct alias_rec table[];
  915. int size;
  916. {
  917.     /** initialize hash table! **/
  918.  
  919.     register int i;
  920.  
  921.     for (i=0; i < size; i++)
  922.       table[i].name[0] = '\0';
  923. }
  924.  
  925. read_in_system(table, size)
  926. struct alias_rec table[];
  927. int size;
  928. {
  929.     /** read in the system hash table...to check for group aliases
  930.         from the user alias file (to ensure that there are no names
  931.         in the user group files that are not purely contained within
  932.         either alias table) **/
  933.     
  934.     int  fd;
  935.     char fname[SLEN];
  936.  
  937.     sprintf(fname, "%s/%s", mailhome, alias_hash);
  938.  
  939.     if ((fd = open(fname, O_RDONLY)) == -1)
  940.       return;    /* no sweat: flag 'hash_table_loaded' not set! */
  941.  
  942.     (void) read(fd, table, size);
  943.     close(fd);
  944.     hash_table_loaded++;
  945. }
  946.     
  947. check_group(names, groupname)
  948. char *names, *groupname;
  949. {
  950.     /** one by one make sure each name in the group is defined
  951.         in either the system alias file or the user alias file.
  952.         This search is linearly dependent, so all group aliases
  953.         in the source file should appear LAST, after all the user
  954.         aliases! **/
  955.  
  956.     char *word, *bufptr, buffer[LONG_STRING];
  957.  
  958.     strcpy(buffer, names);
  959.     bufptr = (char *) buffer;
  960.  
  961.     while ((word = (char *) strtok(bufptr,", ")) != NULL) {
  962.       if (! can_find(word)) 
  963.         if (! valid_name(word)) {
  964.           error++;
  965.           printf("** Alias %s in group %s is bad!\n", word, groupname);
  966.         }
  967.       bufptr = NULL;
  968.     }
  969. }
  970.  
  971. int
  972. can_find(name)
  973. char *name;
  974. {    
  975.     /** find name in either hash table...use 'system' variable to
  976.         determine if we should look in both or just system....    **/
  977.  
  978.     register int loc;
  979.     
  980.     if (strlen(name) > 20) {
  981.       error++;
  982.       printf("** Bad alias name: %s.  Too long.\n", name);
  983.       return(1);    /* fake out: don't want 2 error messages! */
  984.     }
  985.  
  986.     /** system alias table... **/
  987.     if (hash_table_loaded || system) {
  988.       loc = hash_it(name, MAX_SALIASES);
  989.  
  990.       while (strcmp(name, shash_table[loc].name) != 0 && 
  991.                  shash_table[loc].name[0] != '\0')
  992.         loc = (loc + 1) % MAX_SALIASES; 
  993.   
  994.       if (strcmp(name, shash_table[loc].name) == 0)
  995.         return(1);    /* found it! */
  996.     }
  997.  
  998.     if (! system) {    /* okay! Let's check the user alias file! */
  999.       loc = hash_it(name, MAX_UALIASES);
  1000.  
  1001.       while (strcmp(name, uhash_table[loc].name) != 0 && 
  1002.                  uhash_table[loc].name[0] != '\0')
  1003.         loc = (loc + 1) % MAX_UALIASES; 
  1004.  
  1005.       if (strcmp(name, uhash_table[loc].name) == 0)
  1006.         return(1);    /* found it! */
  1007.     }
  1008.  
  1009.     return(0);
  1010. }
  1011.  
  1012. extract_comment(comment, buffer, first, last)
  1013. char *comment, *buffer;
  1014. int first, last;
  1015. {
  1016.     /** Buffer contains a comment, located between the first and last
  1017.         values.  Copy that into 'comment', but remove leading and
  1018.         trailing white space.
  1019.     **/
  1020.  
  1021.     register int loc = 0; 
  1022.  
  1023.     /** first off, skip the LEADING white space... **/
  1024.  
  1025.     while (buffer[first] == ' ') first++;
  1026.     
  1027.     /** now let's backup the 'last' value until we hit a non-space **/
  1028.  
  1029.     last -= 2;    /* starts at ch AFTER colon.. */
  1030.     while (buffer[last] == ' ') last--;
  1031.  
  1032.     /** now a final check to make sure we're still talking about a 
  1033.         reasonable string (rather than a "joe :: joe@dec" type string) **/
  1034.  
  1035.     if (first < last) {
  1036.       while (first <= last)
  1037.         comment[loc++] = buffer[first++];
  1038.       comment[loc] = '\0';
  1039.     }
  1040. }
  1041. ----------------------
  1042. [end of utils/newalias.c]
  1043.  
  1044.      2. The next step is to go into the file "src/mailmsg2.c" and change the
  1045.         file to reflect;
  1046.  
  1047.     [approx. at line 180]
  1048.         -------------
  1049.     sprintf(very_long_buffer, "( (%s -s \"%s\" %s ; %s %s) & ) < %s",
  1050. *               mailx, subject, strip_parens(strip_commas(expanded_to)), 
  1051.         remove, filename, filename);
  1052.  
  1053.         -------------
  1054.         sprintf(very_long_buffer,"( (%s %s %s ; %s %s) & ) < %s",
  1055. *                 sendmail, smflags, strip_parens(strip_commas(expanded_to)), 
  1056.           remove, filename2, filename2);
  1057.       else                    /* oh well, use default mailer... */
  1058.             sprintf(very_long_buffer,"( (%s %s ; %s %s) & ) < %s", 
  1059. *                 mailer, strip_parens(strip_commas(expanded_to)), 
  1060.           remove, filename2, filename2);
  1061.     -------------
  1062.     [the change is the nested call to "strip_parens()" when cleaning up the
  1063.      'to' address list...]
  1064.  
  1065.      3. Finally, in src/return_addr.c, change the last few lines of the
  1066.     routine "get_return" to;
  1067.     ------------
  1068.           if (buffer[0] == '\0')
  1069.             strcpy(buffer, hold_return); /* default address! */
  1070.           else
  1071.             add_site(buffer, name1, lastname);    /* get the user name too! */
  1072.  
  1073.           if (first_word(buffer, "To:"))     /* response to savecopy!  */
  1074.              get_existing_address(buffer);
  1075. *         else {
  1076. *            if (chloc(' ', header_table[current-1].from) > -1 ||
  1077. *               (chloc('!', header_table[current-1].from) < 0 &&
  1078. *                chloc('@', header_table[current-1].from) < 0))
  1079. *                  sprintf(name2, " (%s)", header_table[current-1].from);
  1080. *                  strcat(buffer, name2);
  1081. *         }
  1082.         }
  1083.     -------------
  1084.  
  1085. --- end of attachment
  1086.  
  1087.