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

  1. Subject: v06i033:  Elm mail system (elm), Part08/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 33
  7. Archive-name: elm/Part08
  8.  
  9. # Continuation of Shell Archive, created by hpldat!taylor
  10.  
  11. # This is part 8
  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/utils.c ----------
  25.  
  26. filename="src/utils.c"
  27.  
  28. if [ -f $filename ]
  29. then
  30.   echo File \"$filename\" already exists\!  Skipping...
  31.   filename=/dev/null        # throw it away
  32. else
  33.   echo extracting file src/utils.c...
  34. fi
  35.  
  36. cat << 'END-OF-FILE' > $filename
  37. /**        utils.c        **/
  38.  
  39. /** Utility routines for ELM 
  40.  
  41.     All routines herein: (C) Copyright 1985 Dave Taylor
  42. **/
  43.  
  44. #include "headers.h"
  45. #include <sys/types.h>
  46. #include <sys/stat.h>
  47. #include <ctype.h>
  48.  
  49. #ifdef BSD
  50. #undef tolower
  51. #endif
  52.  
  53. #include <signal.h>
  54.  
  55. emergency_exit()
  56. {
  57.     /** used in dramatic cases when we must leave without altering
  58.         ANYTHING about the system... **/
  59.  
  60.     dprint0(1,
  61.      "\nERROR: Something dreadful is happening!  Taking emergency exit!!\n\n");
  62.     dprint0(1,"  possibly leaving behind the following files;\n");
  63.     dprint2(1,"     The mailbox tempfile : %s%s\n", temp_mbox, username);
  64.     dprint2(1,"     The mailbox lock file: %s%s.lock\n", mailhome, username);
  65.     dprint2(1,"     The composition file : %s%d\n", temp_file, getpid());
  66.     dprint2(1,"     The header comp file : %s%d\n", temp_file, getpid()+1);
  67.     dprint2(1,"     The readmsg data file: %s/%s\n", home, readmsg_file);
  68.  
  69.     Raw(OFF);
  70.     if (cursor_control)  transmit_functions(OFF);
  71.     if (hp_terminal)     softkeys_off();
  72.  
  73.     if (cursor_control)
  74.       MoveCursor(LINES, 0);
  75.  
  76.     PutLine0(LINES,0, "\nEmergency Exit taken!  All temp files intact!\n\n");
  77.  
  78.     exit(1);
  79. }
  80.  
  81. leave(val)
  82. int val;    /* not used, placeholder for signal catching! */
  83. {
  84.     char buffer[SLEN];
  85.  
  86.     dprint0(2,"\nLeaving mailer normally (leave)\n");
  87.  
  88.     Raw(OFF);
  89.     if (cursor_control)  transmit_functions(OFF);
  90.     if (hp_terminal)     softkeys_off();
  91.  
  92.     sprintf(buffer,"%s%d",temp_file, getpid());  /* editor buffer */
  93.     (void) unlink(buffer);
  94.  
  95.     sprintf(buffer,"%s%d",temp_file, getpid()+1);  /* editor buffer */
  96.     (void) unlink(buffer);
  97.  
  98.     sprintf(buffer,"%s%s",temp_mbox, username);  /* temp mailbox */
  99.     (void) unlink(buffer);
  100.  
  101.     sprintf(buffer,"%s/%s", home, readmsg_file);  /* readmsg temp */
  102.     (void) unlink(buffer);
  103.  
  104.     sprintf(buffer,"%s%s.lock",mailhome, username); /* lock file */
  105.     (void) unlink(buffer);
  106.  
  107.     if (! mail_only) {
  108.       MoveCursor(LINES,0);
  109.       Writechar('\n');
  110.     }
  111.  
  112.     exit(0);
  113. }
  114.  
  115. leave_locked(val)
  116. int val;    /* not used, placeholder for signal catching! */
  117. {
  118.     /** same as leave routine, but don't disturb lock file **/
  119.  
  120.     char buffer[SLEN];
  121.  
  122.         dprint0(3,
  123.         "\nLeaving mailer due to presence of lock file (leave_locked)\n");
  124.  
  125.     Raw(OFF);
  126.     if (cursor_control)  transmit_functions(OFF);
  127.     if (hp_terminal)     softkeys_off();
  128.  
  129.     sprintf(buffer,"%s%d",temp_file, getpid());  /* editor buffer */
  130.     (void) unlink(buffer);
  131.  
  132.     sprintf(buffer,"%s%d",temp_file, getpid()+1);  /* editor buffer */
  133.     (void) unlink(buffer);
  134.  
  135.     sprintf(buffer,"%s%s",temp_mbox, username);  /* temp mailbox */
  136.     (void) unlink(buffer);
  137.  
  138.     MoveCursor(LINES,0);
  139.     Writechar('\n');
  140.  
  141.     exit(0);
  142. }
  143.  
  144. int
  145. get_page(msg_pointer)
  146. int msg_pointer;
  147. {
  148.     /** ensure that 'current' is on the displayed page,
  149.         returning non-zero iff the page changed! **/
  150.  
  151.     register int first_on_page, last_on_page;
  152.  
  153.     first_on_page = (header_page * headers_per_page) + 1;
  154.  
  155.     last_on_page = first_on_page + headers_per_page - 1;
  156.  
  157.     if (msg_pointer > last_on_page) {
  158.       header_page = (int) (msg_pointer-1) / headers_per_page;
  159.       return(1);
  160.     }
  161.     else if (msg_pointer < first_on_page) {
  162.       header_page = (int) (msg_pointer-1) / headers_per_page;
  163.       return(1);
  164.     }
  165.     else
  166.       return(0);
  167. }
  168.  
  169. int
  170. copy_to_self(buffer)
  171. char *buffer;
  172. {
  173.     /** returns true iff buffer = 'Cc: username' where username
  174.         is the account name of the person sending the message.
  175.         Used for weeding out 'Cc:' lines from the messages if
  176.         'weed' is turned on. **/
  177.  
  178.     /** note: tail_of() is located in file "strings.c"  **/
  179.  
  180.     char name[SLEN], buf[SLEN];
  181.     register int i=0, j=0;
  182.     
  183.     tail_of(header_table[current-1].from, name, FALSE);
  184.  
  185.     while (name[i] != '!' && i < strlen(name))
  186.        i++;
  187.  
  188.     if (name[i] == '!') {
  189.       for (i++; i < strlen(name); i++)
  190.         name[j++] = name[i];
  191.  
  192.       name[j] = 0;
  193.     }
  194.  
  195.     sprintf(buf, "Cc: %s\n", name);
  196.  
  197.     return( strcmp(buf, buffer) == 0 );
  198. }
  199. END-OF-FILE
  200.  
  201. if [ "$filename" != "/dev/null" ]
  202. then
  203.   size=`wc -c < $filename`
  204.  
  205.   if [ $size != 3786 ]
  206.   then
  207.     echo $filename changed - should be 3786 bytes, not $size bytes
  208.   fi
  209.  
  210.   chmod 644 $filename
  211. fi
  212.  
  213. # ---------- file src/validname.c ----------
  214.  
  215. filename="src/validname.c"
  216.  
  217. if [ -f $filename ]
  218. then
  219.   echo File \"$filename\" already exists\!  Skipping...
  220.   filename=/dev/null        # throw it away
  221. else
  222.   echo extracting file src/validname.c...
  223. fi
  224.  
  225. cat << 'END-OF-FILE' > $filename
  226. /**            validname.c            **/
  227.  
  228. /** This routine takes a single address, no machine hops or
  229.     anything, and returns 1 if it's valid and 0 if not.  The
  230.     algorithm it uses is the same one that uux uses, namely:
  231.  
  232.     1. Is there a file '/usr/mail/%s'?  
  233.     2. Is there a password entry for %s?
  234.     
  235.    (C) Copyright 1986 Dave Taylor 
  236. **/
  237.  
  238. #include <stdio.h>
  239.  
  240. #include "defs.h"
  241.  
  242. int
  243. valid_name(name)
  244. char *name;
  245. {
  246.     /** does what it says above, boss! **/
  247.  
  248. #ifdef NOCHECK_VALIDNAME
  249.  
  250.     return(1);        /* always say it's okay! */
  251.  
  252. #else
  253.     char filebuf[SLEN];
  254.  
  255.     sprintf(filebuf,"%s/%s", mailhome, name);
  256.     
  257.     if (access(filebuf, ACCESS_EXISTS) == 0)
  258.       return(1);
  259.  
  260.     if (getpwnam(name) != NULL)
  261.       return(1);
  262.  
  263.     return(0);
  264.  
  265. #endif
  266.  
  267. }
  268. END-OF-FILE
  269.  
  270. if [ "$filename" != "/dev/null" ]
  271. then
  272.   size=`wc -c < $filename`
  273.  
  274.   if [ $size != 706 ]
  275.   then
  276.     echo $filename changed - should be 706 bytes, not $size bytes
  277.   fi
  278.  
  279.   chmod 644 $filename
  280. fi
  281.  
  282. # ---------- file src/syscall.c ----------
  283.  
  284. filename="src/syscall.c"
  285.  
  286. if [ -f $filename ]
  287. then
  288.   echo File \"$filename\" already exists\!  Skipping...
  289.   filename=/dev/null        # throw it away
  290. else
  291.   echo extracting file src/syscall.c...
  292. fi
  293.  
  294. cat << 'END-OF-FILE' > $filename
  295. /**            syscall.c        **/
  296.  
  297. /** These routines are used for user-level system calls, including the
  298.     '!' command and the '|' commands...
  299.  
  300.     (C) Copyright 1986 Dave Taylor
  301. **/
  302.  
  303. #include "headers.h"
  304.  
  305. #include <signal.h>
  306.  
  307. char *argv_zero();    
  308.  
  309. int
  310. subshell()
  311. {
  312.     /** spawn a subshell with either the specified command
  313.         returns non-zero if screen rewrite needed
  314.     **/
  315.  
  316.     char command[SLEN];
  317.     int  ret;
  318.  
  319.     PutLine0(LINES-3,COLUMNS-40,"(use the shell name for a shell)");
  320.     PutLine0(LINES-2,0,"Shell Command: ");
  321.     command[0] = '\0';
  322.     (void) optionally_enter(command, LINES-2, 15, FALSE);
  323.     if (strlen(command) == 0) {
  324.       MoveCursor(LINES-2,0);    CleartoEOLN();
  325.       return(0);
  326.     }
  327.  
  328.     MoveCursor(LINES,0);     CleartoEOLN();
  329.     Raw(OFF);
  330.     if (cursor_control)  transmit_functions(OFF);
  331.     
  332.     ret = system_call(command, USER_SHELL);
  333.  
  334.     PutLine0(LINES, 0, "\n\nPress <return> to return to ELM: ");
  335.  
  336.     Raw(ON);
  337.     (void) getchar();
  338.     if (cursor_control)  transmit_functions(ON);
  339.  
  340.     if (ret != 0) error1("Return code was %d", ret);
  341.     return(1);
  342. }
  343.  
  344. system_call(string, shell_type)
  345. char *string;
  346. int   shell_type;
  347. {
  348.     /** execute 'string', setting uid to userid... **/
  349.     /** if shell-type is "SH" /bin/sh is used regardless of the 
  350.         users shell setting.  Otherwise, "USER_SHELL" is sent **/
  351.  
  352.     int status, pid, w;
  353.     register int (*istat)(), (*qstat)();
  354.     
  355.     dprint2(2,"System Call: %s\n\t%s\n", shell_type == SH? "/bin/sh" : shell,
  356.         string);
  357.  
  358. #ifdef NO_VM        /* machine without virtual memory! */
  359.     if ((pid = fork()) == 0) {
  360. #else
  361.     if ((pid = vfork()) == 0) {
  362. #endif
  363.       setuid(userid);    /* back to the normal user! */
  364.       setgid(groupid);    /* and group id            */
  365.  
  366.       if (strlen(shell) > 0 && shell_type == USER_SHELL) {
  367.         execl(shell, argv_zero(shell), "-c", string, 0);
  368.       }
  369.       else 
  370.         execl("/bin/sh", "sh", "-c", string, 0);
  371.       _exit(127);
  372.     }
  373.  
  374.     istat = signal(SIGINT, SIG_IGN);
  375.     qstat = signal(SIGQUIT, SIG_IGN);
  376.  
  377.     while ((w = wait(&status)) != pid && w != -1)
  378.         ;
  379.  
  380.     if (w == -1) status = -1;
  381.     
  382.     signal(SIGINT, istat);
  383.     signal(SIGQUIT, qstat);
  384.  
  385.     return(status);
  386. }
  387.  
  388. int
  389. do_pipe()
  390. {
  391.     /** pipe the tagged messages to the specified sequence.. **/
  392.  
  393.     char command[SLEN], buffer[LONG_SLEN], message_list[SLEN];
  394.     register int  ret, tagged = 0, oldstat, i;
  395.  
  396.     message_list[0] = '\0';    /* NULL string to start... */
  397.  
  398.     for (i=0; i < message_count; i++)
  399.       if (ison(header_table[i].status, TAGGED)) {
  400.         sprintf(message_list,"%s %d", message_list, 
  401.             header_table[i].index_number);
  402.         tagged++;
  403.       }
  404.  
  405.     if (tagged > 1)
  406.       PutLine0(LINES-2,0,"Pipe tagged msgs to: ");
  407.     else if (tagged) 
  408.       PutLine0(LINES-2,0,"Pipe tagged msg to : ");
  409.     else {
  410.       PutLine0(LINES-2,0,"Pipe current msg to: ");
  411.       sprintf(message_list,"%d", header_table[current-1].index_number);
  412.     }
  413.  
  414.     command[0] = '\0';
  415.  
  416.     (void) optionally_enter(command, LINES-2, 21, FALSE);
  417.     if (strlen(command) == 0) {
  418.       MoveCursor(LINES-2,0);    CleartoEOLN();
  419.       return(0);
  420.     }
  421.  
  422.     MoveCursor(LINES,0);     CleartoEOLN();
  423.     Raw(OFF);
  424.  
  425.     if (cursor_control)  transmit_functions(OFF);
  426.     
  427.     sprintf(buffer, "%s -f %s -h %s | %s",
  428.         readmsg,
  429.         infile,
  430.         message_list,
  431.         command);
  432.     
  433.     ret = system_call(buffer, USER_SHELL);
  434.  
  435.     PutLine0(LINES, 0, "\n\nPress <return> to return to ELM: ");
  436.     Raw(ON);
  437.     (void) getchar();
  438.     if (cursor_control)  transmit_functions(ON);
  439.  
  440.     if (ret != 0) error1("Return code was %d", ret);
  441.     return(1);
  442. }
  443.  
  444. printmsg()
  445. {
  446.     /** Print current message or tagged messages using 'printout' 
  447.         variable.  Error message iff printout not defined! **/
  448.  
  449.     char buffer[LONG_SLEN], filename[SLEN], printbuffer[LONG_SLEN];
  450.     char message_list[SLEN];
  451.     register int  retcode, tagged = 0, oldstat, i;
  452.  
  453.     if (strlen(printout) == 0) {
  454.       error("Don't know how to print - option \"printmail\" undefined!");
  455.       return;
  456.     }
  457.     
  458.     message_list[0] = '\0';    /* reset to null... */
  459.  
  460.     for (i=0; i < message_count; i++) 
  461.       if (header_table[i].status & TAGGED) {
  462.         sprintf(message_list, "%s %d", message_list, 
  463.             header_table[i].index_number);
  464.         tagged++;
  465.       }
  466.  
  467.     if (! tagged)
  468.       sprintf(message_list," %d", header_table[current-1].index_number);
  469.  
  470.     sprintf(filename,"%s%d", temp_print, getpid());
  471.  
  472.     if (in_string(printout, "%s"))
  473.       sprintf(printbuffer, printout, filename);
  474.     else
  475.       sprintf(printbuffer, "%s %s", printout, filename);
  476.  
  477.     sprintf(buffer,"(%s -p -f %s%s > %s; %s 2>&1) > /dev/null",
  478.         readmsg, infile, message_list, 
  479.         filename,
  480.         printbuffer);
  481.     
  482.     dprint0(2,"Printing system call...\n");
  483.  
  484.       Centerline(LINES, "queueing...");
  485.  
  486.     if ((retcode = system_call(buffer, SH)) == 0) {
  487.       sprintf(buffer, "Message%s queued up to print", plural(tagged));
  488.       Centerline(LINES, buffer);
  489.     }
  490.     else
  491.       error1("Printout failed with return code %d", retcode);
  492.  
  493.     unlink(filename);    /* remove da temp file! */
  494. }
  495. END-OF-FILE
  496.  
  497. if [ "$filename" != "/dev/null" ]
  498. then
  499.   size=`wc -c < $filename`
  500.  
  501.   if [ $size != 4692 ]
  502.   then
  503.     echo $filename changed - should be 4692 bytes, not $size bytes
  504.   fi
  505.  
  506.   chmod 644 $filename
  507. fi
  508.  
  509. # ---------- file src/aliaslib.c ----------
  510.  
  511. filename="src/aliaslib.c"
  512.  
  513. if [ -f $filename ]
  514. then
  515.   echo File \"$filename\" already exists\!  Skipping...
  516.   filename=/dev/null        # throw it away
  517. else
  518.   echo extracting file src/aliaslib.c...
  519. fi
  520.  
  521. cat << 'END-OF-FILE' > $filename
  522. /**            aliaslib.c            **/
  523.  
  524. /** Library of functions dealing with the alias system...
  525.  
  526.     (C) Copyright 1986 Dave Taylor
  527.  **/
  528.  
  529. #include "headers.h"
  530.  
  531. char *expand_group(), *get_alias_address(), *expand_system();
  532. char *get_token(), *strpbrk();
  533.  
  534. char *get_alias_address(name, mailing, depth)
  535. char *name;
  536. int   mailing, depth;
  537. {
  538.     /** return the line from either datafile that corresponds 
  539.         to the specified name.  If 'mailing' specified, then
  540.         fully expand group names.  Depth specifies the nesting
  541.         depth - the routine should always initially be called
  542.         with this equal 0.  Returns NULL if not found   **/
  543.  
  544.     static char buffer[VERY_LONG_STRING];
  545.     int    loc;
  546.  
  547.     if (strlen(name) == 0)
  548.       return( (char *) NULL);
  549.  
  550.     if (user_files) 
  551.       if ((loc = find(name, user_hash_table, MAX_UALIASES)) >= 0) {
  552.         lseek(user_data, user_hash_table[loc].byte, 0L);
  553.         get_line(user_data, buffer);
  554.         if (buffer[0] == '!' && mailing)
  555.           return(expand_group(buffer, depth));
  556.         else if (strpbrk(buffer,"!@:") != NULL)    /* has a hostname */
  557.           return(expand_system(buffer, TRUE));
  558.         else
  559.           return((char *) buffer);
  560.       }
  561.      
  562.     if (system_files) 
  563.       if ((loc = find(name, system_hash_table, MAX_SALIASES)) >= 0) {
  564.         lseek(system_data, system_hash_table[loc].byte, 0L);
  565.         get_line(system_data, buffer);
  566.         if (buffer[0] == '!' && mailing)
  567.           return(expand_group(buffer, depth));
  568.         else if (strpbrk(buffer,"!@:") != NULL)    /* has a hostname */
  569.           return(expand_system(buffer, TRUE));
  570.         else
  571.           return((char *) buffer);
  572.       }
  573.     
  574.     return( (char *) NULL);
  575. }
  576.  
  577. char *expand_system(buffer, show_errors)
  578. char *buffer;
  579. int   show_errors;
  580. {
  581.     /** This routine will check the first machine name in the given path 
  582.         (if any) and expand it out if it is an alias...if not, it will 
  583.         return what it was given.  If show_errors is false, it won't 
  584.         display errors encountered...
  585.     **/
  586.  
  587.     dprint2(6, "expand_system(%s, show-errors=%s)\n", buffer,
  588.         onoff(show_errors));
  589.     findnode(buffer, show_errors);
  590.  
  591.     return( (char *) buffer);
  592. }
  593.           
  594. char *expand_group(members, depth)
  595. char *members;
  596. int  depth;
  597. {
  598.     /** Given a group of names separated by commas, this routine
  599.         will return a string that is the full addresses of each
  600.         member separated by spaces. Depth is an internal counter
  601.         that keeps track of the depth of nesting that the routine
  602.         is in...it's for the get_token routine!  **/
  603.  
  604.     static char buffer[VERY_LONG_STRING];
  605.     char   buf[LONG_STRING], *word, *address, *bufptr;
  606.  
  607.     strcpy(buf, members);             /* parameter safety! */
  608.     if (depth == 0) buffer[0] = '\0';    /* nothing in yet!   */
  609.     bufptr = (char *) buf;            /* grab the address  */
  610.     depth++;                /* one deeper!       */
  611.  
  612.     while ((word = get_token(bufptr, "!, ", depth)) != NULL) {
  613.       if ((address = get_alias_address(word, 1, depth)) == NULL) {
  614.         if (! valid_name(word)) {
  615.           dprint2(3, "Encountered illegal address %s (%s)\n",
  616.             word, "expand_group");
  617.           error1("%s is an illegal address!", word);
  618.           return( (char *) NULL);
  619.         }
  620.         else if (strcmp(buffer, word) != 0)
  621.           sprintf(buffer, "%s%s%s", buffer,
  622.             (strlen(buffer) > 0)? ", ":"", word);
  623.       }
  624.       else if (strcmp(buffer, address) != 0)
  625.         sprintf(buffer,"%s%s%s", buffer, 
  626.             (strlen(buffer) > 0)? ", ":"", address);
  627.  
  628.       bufptr = NULL;
  629.     }
  630.  
  631.     return( (char *) buffer);
  632. }
  633.  
  634. int
  635. find(word, table, size)
  636. char *word;
  637. struct alias_rec table[];
  638. int size;
  639. {
  640.     /** find word and return loc, or -1 **/
  641.     register int loc;
  642.     
  643.     if (strlen(word) > 20) {
  644.       dprint2(3, "Too long alias name entered [%s] (%s)\n", word, "find");
  645.       error1("Bad alias name: %s.  Too long.\n", word);
  646.       return(-1);
  647.     }
  648.  
  649.     loc = hash_it(word, size);
  650.  
  651.     while (strcmp(word, table[loc].name) != 0) {
  652.       if (table[loc].name[0] == '\0')
  653.         return(-1);
  654.       loc = (loc + 1) % size; 
  655.     }
  656.  
  657.     return(loc);
  658. }
  659.  
  660. int
  661. hash_it(string, table_size)
  662. char *string;
  663. int   table_size;
  664. {
  665.     /** compute the hash function of the string, returning
  666.         it (mod table_size) **/
  667.  
  668.     register int i, sum = 0;
  669.     
  670.     for (i=0; string[i] != '\0'; i++)
  671.       sum += (int) string[i];
  672.  
  673.     return(sum % table_size);
  674. }
  675.  
  676. get_line(fd, buffer)
  677. int fd;
  678. char *buffer;
  679. {
  680.     /* read from file fd.  End read upon reading either 
  681.        EOF or '\n' character (this is where it differs 
  682.        from a straight 'read' command!) */
  683.  
  684.     register int i= 0;
  685.     char     ch;
  686.  
  687.     while (read(fd, &ch, 1) > 0)
  688.       if (ch == '\n' || ch == '\r') {
  689.         buffer[i] = 0;
  690.         return;
  691.       }
  692.       else
  693.         buffer[i++] = ch;
  694. }
  695. END-OF-FILE
  696.  
  697. if [ "$filename" != "/dev/null" ]
  698. then
  699.   size=`wc -c < $filename`
  700.  
  701.   if [ $size != 4476 ]
  702.   then
  703.     echo $filename changed - should be 4476 bytes, not $size bytes
  704.   fi
  705.  
  706.   chmod 644 $filename
  707. fi
  708.  
  709. # ---------- file src/domains.c ----------
  710.  
  711. filename="src/domains.c"
  712.  
  713. if [ -f $filename ]
  714. then
  715.   echo File \"$filename\" already exists\!  Skipping...
  716.   filename=/dev/null        # throw it away
  717. else
  718.   echo extracting file src/domains.c...
  719. fi
  720.  
  721. cat << 'END-OF-FILE' > $filename
  722. /**            domains.c            **/
  723.  
  724. /** This file contains all the code dealing with the expansion of 
  725.     domain based addresses in Elm.  It uses the file "domains" as
  726.     defined in the sysdefs.h file.
  727.  
  728.     (C) Copyright 1986 Dave Taylor
  729.  
  730.     From a file format and idea in "uumail" - designed by Stan Barber.
  731. **/
  732.  
  733. #include <stdio.h>
  734. #include <ctype.h>
  735.  
  736. #include "headers.h"
  737.  
  738. /** define the various characters that we can encounter after a "%" sign
  739.     in the template file...
  740. **/
  741.  
  742. #define USERNAME    'U'    /* %U = the name of the remote user */
  743. #define HOSTNAME    'N'    /* %N = the remote machine name     */
  744. #define FULLNAME    'D'    /* %D = %N + domain info given      */
  745. #define NPATH        'R'    /* %R = path to %N from pathalias   */
  746. #define PPATH        'P'    /* %P = path to 'P' from pathalias  */
  747. #define OBSOLETE    'S'    /* %S = (used to be suffix string)  */
  748.  
  749. /** and finally some characters that are allowed in user/machine names **/
  750.  
  751. #define okay_others(c)    (c == '-' || c == '^' || c == '$' || c == '_')
  752.  
  753. /** and some allowed ONLY in the username field **/
  754.  
  755. #define special_chars(c)    (c == '%' || c == ':')
  756.  
  757. char *find_path_to(), *expand_domain(), *match_and_expand_domain();
  758.           
  759. open_domain_file()
  760. {
  761.     if ((domainfd = fopen(domains, "r")) == NULL) {
  762.       dprint1(1, "Can't open file %s as domains file (open_domain_file)\n", 
  763.           domains);
  764.     }
  765.     else {
  766.       dprint1(2,
  767.             "\nOpened '%s' as the domain database. (open_domain_file)\n\n", 
  768.           domains);
  769.     }
  770.     
  771.     /* if it fails it'll instantiate domainfd to NULL which is
  772.        exactly what we want to have happen!! */
  773. }
  774.  
  775. char *expand_domain(buffer)
  776. char *buffer;
  777. {
  778.     /** Expand the address 'buffer' based on the domain information, 
  779.         if any.  Returns NULL if it can't expand it for any reason.
  780.     **/
  781.  
  782.     char name[2*NLEN], address[2*NLEN], domain[2*NLEN];
  783.     char *match_and_expand_domain();
  784.  
  785.     if (domainfd == NULL) return(NULL);    /* no file present! */
  786.  
  787.     if (explode(buffer, name, address, domain)) 
  788.       return( match_and_expand_domain(domain, name, address) );
  789.     else {    /* invalid format - not "user@host.domain" */
  790.       dprint1(3, 
  791.          "Invalid format for domain expansion: %s (expand_domain)\n", 
  792.            buffer);
  793.       return(NULL);
  794.     }
  795. }    
  796.  
  797. int
  798. explode(buffer, name, address, domain)
  799. char *buffer, *name, *address, *domain;
  800. {
  801.     /** Break buffer, if in format name@machine.domain, into the
  802.         component parts, otherwise return ZERO and don't worry
  803.         about the values of the parameters!
  804.     **/
  805.     
  806.     register int i, j = 0;
  807.  
  808.     /** First get the name... **/
  809.  
  810.     for (i=0; buffer[i] != '@'; i++) {
  811.       if (! isalnum(buffer[i]) && ! okay_others(buffer[i]) && ! 
  812.         special_chars(buffer[i]))
  813.         return(0);            /* invalid character in string! */
  814.       name[i] = buffer[i];
  815.     }
  816.  
  817.     name[i++] = '\0';
  818.  
  819.     /** now let's get the machinename **/
  820.  
  821.     while (buffer[i] != '.') {
  822.       if (! isalnum(buffer[i]) && ! okay_others(buffer[i]))
  823.          return(0);            /* invalid character in string! */
  824.       address[j++] = buffer[i++];
  825.     }
  826.     address[j] = '\0';
  827.  
  828.     j = 0;
  829.  
  830.     /** finally let's get the domain information (there better be some!) **/
  831.  
  832.     while (buffer[i] != '\0') {
  833.       if (! isalnum(buffer[i]) && ! okay_others(buffer[i]) && 
  834.             buffer[i] != '.')
  835.         return(0);              /* an you fail again, bozo! */
  836.       domain[j++] = toupper(buffer[i]);
  837.       i++;
  838.     }
  839.  
  840.     domain[j] = '\0';
  841.     
  842.     return(j);        /* if j == 0 there's no domain info! */
  843. }
  844.         
  845. char *match_and_expand_domain(domain, name, machine)
  846. char *domain, *name, *machine;
  847. {
  848.     /** Given the domain, try to find it in the domain file and
  849.            if found expand the entry and return the result as a 
  850.         character string...
  851.     **/
  852.  
  853.     static char address[SLEN];
  854.     char   buffer[SLEN], domainbuff[NLEN];
  855.     char   field1[2*NLEN], field2[2*NLEN], field3[2*NLEN];
  856.     char   *path, *template, *expanded, *mydomain;
  857.     int    matched = 0, in_percent = 0;
  858.     register int i, j = 0;
  859.  
  860.     address[j] = '\0';
  861.  
  862.     domainbuff[0] = '\0';
  863.     mydomain = (char *) domainbuff;            /* set up buffer etc */
  864.  
  865.     do { 
  866.       rewind(domainfd);                   /* back to ground zero! */
  867.  
  868.       if (strlen(mydomain) > 0) {           /* already in a domain! */
  869.         mydomain++;                       /* skip leading '.' */
  870.         while (*mydomain != '.' && *mydomain != ',') 
  871.           mydomain++;                   /* next character   */
  872.         if (*mydomain == ',')
  873.           return (NULL);                /* didn't find domain!  */
  874.       }
  875.       else
  876.         sprintf(mydomain, "%s,", domain);        /* match ENTIRELY! */
  877.  
  878.     /* whip through file looking for the entry, please... */
  879.  
  880.     while (fgets(buffer, SLEN, domainfd) != NULL) {
  881.       if (buffer[0] == '#')                  /* skip comments */
  882.         continue;
  883.       if (strncmp(buffer, mydomain, strlen(mydomain)) == 0) { /* match? */
  884.          matched++;    /* Gotcha!  Remember this momentous event! */
  885.          break;
  886.       }
  887.     }
  888.  
  889.     if (! matched) 
  890.        continue;        /* Nothing.  Not a sausage!  Step through! */
  891.  
  892.     /** We've matched the domain! **/
  893.  
  894.     no_ret(buffer);
  895.  
  896.     (void) strtok(buffer, ",");    /* skip the domain info */
  897.  
  898.     strcpy(field1, strtok(NULL, ","));    /* fun         */
  899.     strcpy(field2, strtok(NULL, ","));    /*    stuff     */
  900.     strcpy(field3, strtok(NULL, ","));    /*       eh?    */
  901.     
  902.     path = (char *) NULL;
  903.  
  904.     /* now we merely need to figure out what permutation this is! */
  905.  
  906.     if (field3 == NULL || strlen(field3) == 0)
  907.       if (field2 == NULL || strlen(field2) == 0)
  908.         template = (char *) field1;
  909.       else {
  910.         path     = (char *) field1;
  911.         template = (char *) field2;
  912.       }
  913.     else {
  914.       dprint1(2,"Domain info for %s from file broken into THREE fields!!\n",
  915.            domain);
  916.       dprint3(2, "-> %s\n-> %s\n-> %s\n", field1, field2, field3);
  917.       error1("Warning: domain %s uses a defunct field!!", domain);
  918.       sleep(2);
  919.       path     = (char *) field1;
  920.       template = (char *) field3;
  921.     }
  922.  
  923.     if (strlen(path) > 0 && path[0] == '>') 
  924.        path++;    /* skip the '>' character, okay? */
  925.  
  926.     j = 0;             /* address is zero, right now, right?? */
  927.     address[j] = '\0';          /* make sure string is too! */
  928.  
  929.     for (i=0; i < strlen(template); i++) {
  930.       if (template[i] == '%') {
  931.         if (! in_percent)               /* just hit a NEW percent! */
  932.           in_percent = 1;
  933.         else {          /* just another percent sign on the wall... */
  934.           address[j++] = '%';
  935.           address[j] = '\0';             /* ALWAYS NULL terminate */
  936.           in_percent = 0;
  937.         }
  938.       }
  939.       else if (in_percent) {           /* Hey! a real command string */
  940.         in_percent = 0;
  941.         switch (template[i]) {
  942.           case USERNAME: strcat(address, name);        break;
  943.           case HOSTNAME: strcat(address, machine);        break;
  944.           case FULLNAME: strcat(address, machine);
  945.                  strcat(address, domain);        break;
  946.           case NPATH   : 
  947.  
  948.          if ((expanded = find_path_to(machine, FALSE)) == NULL) {
  949.             dprint2(3,"\nCouldn't expand system path '%s' (%s)\n\n",
  950.                 machine, "domains");
  951.                 error1("Couldn't find a path to %s!", machine);
  952.                 sleep(2);
  953.                 return(NULL);    /* failed!! */
  954.              }
  955.              strcat(address, expanded);    /* isn't this fun??? */
  956.  
  957.              break;
  958.  
  959.           case PPATH   : 
  960.  
  961.          if ((expanded = find_path_to(path, FALSE)) == NULL) {
  962.             dprint2(3,"\nCouldn't expand system path '%s' (%s)\n\n",
  963.                 path, "domains");
  964.                 error1("I Couldn't find a path to %s!", path);
  965.                 sleep(2);
  966.                 return(NULL);    /* failed!! */
  967.              }
  968.              strcat(address, expanded);    /* isn't this fun??? */
  969.  
  970.              break;
  971.  
  972.           case OBSOLETE:    /* fall through.. */
  973.           default      : dprint2(1,
  974.          "\nError: Bad sequence in template file for domain '%s': %%%c\n\n",
  975.             domain, template[i]);
  976.         }
  977.         j = strlen(address);
  978.       }
  979.       else {
  980.         address[j++] = template[i];
  981.         address[j] = '\0';            /* null terminate */
  982.       }
  983.     }    
  984.  
  985.     address[j] = '\0';
  986.  
  987.     } while (strlen(address) < 1);
  988.  
  989.     return( (char *) address);
  990. }
  991. END-OF-FILE
  992.  
  993. if [ "$filename" != "/dev/null" ]
  994. then
  995.   size=`wc -c < $filename`
  996.  
  997.   if [ $size != 7635 ]
  998.   then
  999.     echo $filename changed - should be 7635 bytes, not $size bytes
  1000.   fi
  1001.  
  1002.   chmod 644 $filename
  1003. fi
  1004.  
  1005. # ---------- file src/fileio.c ----------
  1006.  
  1007. filename="src/fileio.c"
  1008.  
  1009. if [ -f $filename ]
  1010. then
  1011.   echo File \"$filename\" already exists\!  Skipping...
  1012.   filename=/dev/null        # throw it away
  1013. else
  1014.   echo extracting file src/fileio.c...
  1015. fi
  1016.  
  1017. cat << 'END-OF-FILE' > $filename
  1018. /**            fileio.c            **/
  1019.  
  1020. /** File I/O routines, including deletion from the mailbox! 
  1021.  
  1022.     (C) Copyright 1986 Dave Taylor
  1023. **/
  1024.  
  1025. #include "headers.h"
  1026. #include <ctype.h>
  1027.  
  1028. #ifdef BSD
  1029. #undef tolower
  1030. #endif
  1031.  
  1032. copy_message(prefix, dest_file, remove_header, remote)
  1033. char *prefix;
  1034. FILE *dest_file;
  1035. int  remove_header, remote;
  1036. {
  1037.     /** Copy current message to destination file, with optional 'prefix' 
  1038.         as the prefix for each line.  If remove_header is true, it will 
  1039.         skip lines in the message until it finds the end of header line...
  1040.             then it will start copying into the file... If remote is true
  1041.         then it will append "remote from <hostname>" at the end of the
  1042.         very first line of the file (for remailing) **/
  1043.  
  1044.     char buffer[LONG_SLEN];
  1045.     register int ok = 1, lines, in_header = 1, first_line = TRUE;
  1046.  
  1047.     /** get to the first line of the message desired **/
  1048.  
  1049.     if (fseek(mailfile, header_table[current-1].offset, 0) == -1) {
  1050.        dprint2(1,"ERROR: Attempt to seek %d bytes into file failed (%s)",
  1051.         header_table[current-1].offset, "copy_message");
  1052.        error1("ELM [seek] failed trying to read %d bytes into file",
  1053.          header_table[current-1].offset);
  1054.        return;
  1055.     }
  1056.  
  1057.     /* how many lines in message? */
  1058.  
  1059.     lines = header_table[current-1].lines;
  1060.  
  1061.     /* now while not EOF & still in message... copy it! */
  1062.  
  1063.     while (ok && lines--) {
  1064.       ok = (int) (fgets(buffer, LONG_SLEN, mailfile) != NULL);
  1065.       if (strlen(buffer) < 2) in_header = 0;
  1066.       if (ok) 
  1067.     if (! (remove_header && in_header))
  1068.       if (first_line && remote) {
  1069.         no_ret(buffer);
  1070.         fprintf(dest_file, "%s%s remote from %s\n",
  1071.             prefix, buffer, hostname);
  1072.         first_line = FALSE;
  1073.       }
  1074.       else if (! in_header && first_word(buffer, "From ")) {
  1075.         dprint0(1,"\n*** Internal Problem...Tried to add the following;\n");
  1076.         dprint1(1,"  '%s'\nto output file (copy_message) ***\n", buffer);
  1077.       }
  1078.       else
  1079.         fprintf(dest_file, "%s%s", prefix, buffer);
  1080.     }
  1081. }
  1082. END-OF-FILE
  1083.  
  1084. if [ "$filename" != "/dev/null" ]
  1085. then
  1086.   size=`wc -c < $filename`
  1087.  
  1088.   if [ $size != 1967 ]
  1089.   then
  1090.     echo $filename changed - should be 1967 bytes, not $size bytes
  1091.   fi
  1092.  
  1093.   chmod 644 $filename
  1094. fi
  1095.  
  1096. # ---------- file src/return_addr.c ----------
  1097.  
  1098. filename="src/return_addr.c"
  1099.  
  1100. if [ -f $filename ]
  1101. then
  1102.   echo File \"$filename\" already exists\!  Skipping...
  1103.   filename=/dev/null        # throw it away
  1104. else
  1105.   echo extracting file src/return_addr.c...
  1106. fi
  1107.  
  1108. cat << 'END-OF-FILE' > $filename
  1109. /**            return_addr.c            **/
  1110.  
  1111. /** This set of routines is used to generate real return addresses
  1112.     and also return addresses suitable for inclusion in a users
  1113.     alias files (ie optimized based on the pathalias database).
  1114.  
  1115.     Added: the ability to respond to messages that were originally
  1116.     sent by the user (That is, the "savemail" file format messages)
  1117.     by reading the return address, seeing the "To:" prefix and then
  1118.     calling the "get_existing_return()" routine.  Currently this does
  1119.     NOT include any "Cc" lines in the message, just the "To:" line(s).
  1120.  
  1121.     Also added the PREFER_UUCP stuff for listing reasonable addresses
  1122.     and such...*sigh*
  1123.  
  1124.     These routines (C) Copyright 1986 Dave Taylor
  1125. **/
  1126.  
  1127. #include "headers.h"
  1128.  
  1129. #include <errno.h>
  1130.  
  1131. #include <sys/types.h>
  1132. #include <sys/stat.h>
  1133.  
  1134. char *shift_lower(), *notes_machine(), *expand_address();
  1135.  
  1136. extern int errno;
  1137.  
  1138. char *error_name();
  1139.  
  1140. optimize_return(address)
  1141. char *address;
  1142. {
  1143.     /** This routine tries to create an optimized address, that is,
  1144.         an address that has the minimal information needed to 
  1145.         route a message to this person given the current path
  1146.         database...
  1147.     **/
  1148.  
  1149. #ifdef PREFER_UUCP
  1150.  
  1151.     /** first off, let's see if we need to strip off the localhost
  1152.         address crap... **/
  1153.  
  1154.     /** if we have a uucp part (e.g.a!b) AND the bogus address...**/
  1155.  
  1156.     if (chloc(address,'!') != -1 && in_string(address, BOGUS_INTERNET))
  1157.       address[strlen(address)-strlen(BOGUS_INTERNET)] = '\0';
  1158. #endif
  1159.  
  1160.     /** next step is to figure out what sort of address we have... **/
  1161.  
  1162.     if (chloc(address, '%') != -1)
  1163.       optimize_cmplx_arpa(address);
  1164.     else if (chloc(address, '@') != -1)
  1165.       optimize_arpa(address);
  1166.     else
  1167.       optimize_usenet(address);
  1168. }
  1169.  
  1170. optimize_cmplx_arpa(address)
  1171. char *address;
  1172. {
  1173.     /** Try to optimize a complex ARPA address.  A Complex address is one 
  1174.         that contains '%' (deferred '@').  For example:  
  1175.         veeger!hpcnof!hplabs!joe%sytech@syte  
  1176.         is a complex address (no kidding, right?).  The algorithm for 
  1177.         trying to resolve it is to move all the way to the right, then 
  1178.         back up left until the first '!' then from there to the SECOND 
  1179.         metacharacter on the right is the name@host address...(in this 
  1180.             example, it would be "joe%sytech").  Check this in the routing
  1181.         table.  If not present, keep backing out to the right until we
  1182.         find a host that is present, or we hit the '@' sign.  Once we
  1183.         have a 'normal' ARPA address, hand it to optimize_arpa().
  1184.     **/
  1185.  
  1186.     char name[SHORT_SLEN], buffer[SLEN], junk[SLEN];
  1187.     char host[SHORT_SLEN], old_host[SHORT_SLEN];
  1188.     register int i, loc, nloc = 0, hloc = 0, passes = 1;
  1189.  
  1190.     /** first off, get the name%host... **/
  1191.  
  1192.     for (loc = strlen(address)-1; address[loc] != '!' && loc > -1; loc--)
  1193.        ;
  1194.  
  1195.     while (address[loc] != '\0') {
  1196.  
  1197.       if (passes == 1) {
  1198.         loc++;
  1199.  
  1200.         while (address[loc] != '%' && address[loc] != '@')
  1201.           name[nloc++] = address[loc++];
  1202.       }
  1203.       else {
  1204.         for (i=0; old_host[i] != '\0'; i++)
  1205.           name[nloc++] = old_host[i];
  1206.       }
  1207.  
  1208.       loc++;
  1209.   
  1210.       while (address[loc] != '%' && address[loc] != '@')
  1211.         host[hloc++] = address[loc++];
  1212.   
  1213.       host[hloc] = name[nloc] = '\0';
  1214.  
  1215.       strcpy(old_host, host);
  1216.       remove_domains(host);
  1217.  
  1218.       sprintf(buffer, "%s@%s", name, shift_lower(host));
  1219.  
  1220.       if (expand_site(buffer, junk) == 0) {
  1221.         strcpy(address, buffer);
  1222.         return;
  1223.       }
  1224.       else if (address[loc] == '@') {
  1225.         optimize_arpa(address);
  1226.         return;
  1227.       }
  1228.       else
  1229.         name[nloc++] = '%';    /* for next pass through */
  1230.  
  1231.     }
  1232. }
  1233.  
  1234. optimize_arpa(address)
  1235. char *address;
  1236. {
  1237.     /** Get an arpa address and simplify it to the minimal
  1238.         route needed to get mail to this person... **/
  1239.  
  1240.     char name[SHORT_SLEN], buffer[SLEN], junk[SLEN];
  1241.     char host[SHORT_SLEN];
  1242.     register int loc, nloc = 0, hloc = 0, at_sign = 0;
  1243.  
  1244.     for (loc = strlen(address)-1; address[loc] != '!' && loc > -1; loc--) {
  1245.       if (address[loc] == '@')
  1246.          at_sign++;    /* remember this spot! */
  1247.       else if (at_sign)
  1248.         name[nloc++] = address[loc];
  1249.       else
  1250.         host[hloc++] = address[loc];
  1251.     }
  1252.  
  1253.     name[nloc] = host[hloc] = '\0';
  1254.  
  1255.     reverse(name);
  1256.     reverse(host);
  1257.  
  1258.     remove_domains(host);
  1259.  
  1260.     sprintf(buffer,"%s@%s", name, shift_lower(host));
  1261.  
  1262.     if (expand_site(buffer, junk) == 0) {
  1263.       strcpy(address, buffer);
  1264.       return;
  1265.     }
  1266.  
  1267.     optimize_usenet(address);    /* that didn't work... */
  1268. }
  1269.     
  1270. optimize_usenet(address)
  1271. char *address;
  1272. {
  1273.     /** optimize the return address IFF it's a standard usenet
  1274.         address...
  1275.     **/
  1276.  
  1277.     char name[SHORT_SLEN],  new_address[SLEN], buffer[SLEN], junk[SLEN];
  1278.     register int loc, nloc = 0, aloc = 0, passes = 1;
  1279.  
  1280.     for (loc = strlen(address)-1; address[loc] != '!' && loc > -1; loc--) 
  1281.       name[nloc++] = address[loc];
  1282.     name[nloc] = '\0';
  1283.  
  1284.     reverse(name);
  1285.  
  1286.     new_address[0] = '\0';    
  1287.  
  1288.     /* got name, now get machine until we can get outta here */
  1289.  
  1290.     while (loc > -1) {
  1291.  
  1292.       new_address[aloc++] = address[loc--];    /* the '!' char */
  1293.  
  1294.       while (address[loc] != '!' && loc > -1)
  1295.         new_address[aloc++] = address[loc--];
  1296.  
  1297.       new_address[aloc] = '\0';
  1298.  
  1299.       strcpy(buffer, new_address);
  1300.       reverse(buffer);
  1301.     
  1302.       if (expand_site(buffer, junk) == 0) {
  1303.         if (passes == 1 && chloc(name, '@') == -1) {
  1304.           buffer[strlen(buffer) - 1] = '\0';    /* remove '!' */
  1305.           sprintf(address, "%s@%s", name, buffer);
  1306.         }
  1307.         else 
  1308.           sprintf(address, "%s%s", buffer, name);
  1309.         return;        /* success! */
  1310.       }
  1311.       passes++;
  1312.     }
  1313.  
  1314.     return;        /* nothing to do! */
  1315. }
  1316.  
  1317. get_return(buffer)
  1318. char *buffer;
  1319. {
  1320.     /** reads 'current' message again, building up the full return 
  1321.         address including all machines that might have forwarded 
  1322.         the message.  **/
  1323.  
  1324.     char buf[LONG_SLEN], name1[SLEN], name2[SLEN], lastname[SLEN];
  1325.     char hold_return[LONG_SLEN], alt_name2[SLEN];
  1326.     int ok = 1, lines;
  1327.  
  1328.     /** are we reading a notesfile file??  **/
  1329.  
  1330.     if (notesfile) {
  1331.       strcpy(buf, header_table[current-1].from);
  1332.       if (chloc(buf, '!') == -1) 
  1333.         sprintf(buf, "%s!%s", notes_machine(), header_table[current-1].from);
  1334.       strcpy(buffer, expand_system(buf, TRUE));
  1335.       return;
  1336.     }
  1337.  
  1338.     /** get to the first line of the message desired **/
  1339.  
  1340.     if (fseek(mailfile, header_table[current-1].offset, 0) == -1) {
  1341.     dprint3(1,"Error: seek %ld bytes into file hit errno %s (%s)", 
  1342.         header_table[current-1].offset, error_name(errno), 
  1343.             "get_return");
  1344.     error2("couldn't seek %d bytes into file (%s)",
  1345.            header_table[current-1].offset, error_name(errno));
  1346.     return;
  1347.     }
  1348.  
  1349.     /** okay!  Now we're there!  **/
  1350.  
  1351.     lines = header_table[current-1].lines;
  1352.     
  1353.     buffer[0] = '\0';
  1354.  
  1355.     while (ok && lines--) {
  1356.       ok = (int) (fgets(buf, LONG_SLEN, mailfile) != NULL);
  1357.       if (first_word(buf, "From ")) {
  1358.     sscanf(buf, "%*s %s", hold_return);
  1359.       }
  1360.       else if (first_word(buf, ">From")) {
  1361.     sscanf(buf,"%*s %s %*s %*s %*s %*s %*s %*s %*s %s %s", 
  1362.            name1, name2, alt_name2);
  1363.     if (strcmp(name2, "from") == 0)
  1364.       strcpy(name2, alt_name2);
  1365.     add_site(buffer, name2, lastname);
  1366.       }
  1367.  
  1368. #ifdef USE_EMBEDDED_ADDRESSES
  1369.  
  1370.       else if (first_word(buf, "From:")) {
  1371.     get_address_from("From:", buf, hold_return);
  1372.       }
  1373.       else if (first_word(buf, "Reply-To:")) {
  1374.     get_address_from("Reply-To:", buf, buffer);
  1375.     return;
  1376.       }
  1377.  
  1378. #endif
  1379.  
  1380.       else if (strlen(buf) < 2)    /* done with header */
  1381.          lines = 0; /* let's get outta here!  We're done!!! */
  1382.      }
  1383.  
  1384.     if (buffer[0] == '\0')
  1385.       strcpy(buffer, hold_return); /* default address! */
  1386.     else
  1387.       add_site(buffer, name1, lastname);    /* get the user name too! */
  1388.  
  1389.     if (first_word(buffer, "To:"))         /* response to savecopy!  */
  1390.        get_existing_address(buffer);
  1391. }
  1392.  
  1393. get_existing_address(buffer)
  1394. char *buffer;
  1395. {
  1396.     /** This routine is called when the message being responded to has
  1397.         "To:xyz" as the return address, signifying that this message is
  1398.         an automatically saved copy of a message previously sent.  The
  1399.         correct to address can be obtained fairly simply by reading the
  1400.         To: header from the message itself and (blindly) copying it to
  1401.         the given buffer.  Note that this header can be either a normal
  1402.         "To:" line (Elm) or "Originally-To:" (previous versions e.g.Msg)
  1403.     **/
  1404.  
  1405.     char mybuf[LONG_STRING];
  1406.     register char ok = 1, in_to = 0;
  1407.  
  1408.     buffer[0] = '\0';
  1409.  
  1410.     /** first off, let's get to the beginning of the message... **/
  1411.  
  1412.         if (fseek(mailfile, header_table[current-1].offset, 0) == -1) {
  1413.         dprint3(1,"Error: seek %ld bytes into file hit errno %s (%s)", 
  1414.             header_table[current-1].offset, error_name(errno), 
  1415.             "get_existing_address");
  1416.         error2("couldn't seek %d bytes into the file (%s)",
  1417.                header_table[current-1].offset, error_name(errno));
  1418.         return;
  1419.         }
  1420.  
  1421.         /** okay!  Now we're there!  **/
  1422.  
  1423.         while (ok) {
  1424.           ok = (int) (fgets(mybuf, LONG_STRING, mailfile) != NULL);
  1425.       no_ret(mybuf);    /* remove return character */
  1426.  
  1427.           if (first_word(mybuf, "To: ")) {
  1428.         in_to = TRUE;
  1429.         strcpy(buffer, (char *) mybuf + strlen("To: "));
  1430.           }
  1431.       else if (first_word(mybuf, "Original-To:")) {
  1432.         in_to = TRUE;
  1433.         strcpy(buffer, (char *) mybuf + strlen("Original-To:"));
  1434.       }
  1435.       else if (in_to && whitespace(mybuf[0])) {
  1436.         strcat(buffer, " ");        /* tag a space in   */
  1437.         strcat(buffer, (char *) mybuf + 1);    /* skip 1 whitespace */
  1438.       }
  1439.       else if (strlen(mybuf) < 2)
  1440.         return;                /* we're done for!  */
  1441.       else
  1442.         in_to = 0;
  1443.       }
  1444. }
  1445. END-OF-FILE
  1446.  
  1447. if [ "$filename" != "/dev/null" ]
  1448. then
  1449.   size=`wc -c < $filename`
  1450.  
  1451.   if [ $size != 9321 ]
  1452.   then
  1453.     echo $filename changed - should be 9321 bytes, not $size bytes
  1454.   fi
  1455.  
  1456.   chmod 644 $filename
  1457. fi
  1458.  
  1459. # ---------- file src/addr_utils.c ----------
  1460.  
  1461. filename="src/addr_utils.c"
  1462.  
  1463. if [ -f $filename ]
  1464. then
  1465.   echo File \"$filename\" already exists\!  Skipping...
  1466.   filename=/dev/null        # throw it away
  1467. else
  1468.   echo extracting file src/addr_utils.c...
  1469. fi
  1470.  
  1471. cat << 'END-OF-FILE' > $filename
  1472. /**            addr_utils.c            **/
  1473.  
  1474. /** This file contains addressing utilities 
  1475.  
  1476.     (C) Copyright 1986 Dave Taylor 
  1477. **/
  1478.  
  1479. #include "headers.h"
  1480.  
  1481. #include <sys/types.h>
  1482. #include <sys/stat.h>
  1483. #include <ctype.h>
  1484.  
  1485. #ifdef BSD
  1486. #undef tolower
  1487. #endif
  1488.  
  1489. char *shift_lower(), *get_alias_address(), *get_token(), *strtok();
  1490.  
  1491. int
  1492. talk_to(sitename)
  1493. char *sitename;
  1494. {
  1495.     /** If we talk to the specified site, return true, else
  1496.         we're going to have to expand this baby out, so 
  1497.         return false! **/
  1498.  
  1499.     struct lsys_rec  *sysname;
  1500.  
  1501.     sysname = talk_to_sys;
  1502.  
  1503.     if (sysname == NULL) {
  1504.      dprint0(2,
  1505.         "Warning - talk_to_sys is currently set to NULL! (talk_to)\n");
  1506.      return(0);
  1507.     }
  1508.  
  1509.     while (sysname != NULL) {
  1510.       if (strcmp(sysname->name, sitename) == 0)
  1511.         return(1);
  1512.       else
  1513.         sysname = sysname->next;
  1514.     }
  1515.  
  1516.     return(0);
  1517. }
  1518.  
  1519. remove_domains(host)
  1520. char *host;
  1521. {
  1522.     /** Remove all entries following the first '.' to ensure that
  1523.         entries like "MIT.ARPA" will match "MIT" in the database
  1524.     **/
  1525.  
  1526.     register int loc = 0;
  1527.  
  1528.     while (host[loc] != '.' && host[loc] != '\0')
  1529.       loc++;
  1530.  
  1531.     if (host[loc] == '.') host[loc] = '\0';
  1532. }
  1533.  
  1534. add_site(buffer, site, lastsite)
  1535. char *buffer, *site, *lastsite;
  1536. {
  1537.     /** add site to buffer, unless site is 'uucp', current machine, or
  1538.             site is the same as lastsite.   If not, set lastsite to
  1539.             site.
  1540.     **/
  1541.  
  1542.     char local_buffer[LONG_SLEN];
  1543.  
  1544.     if (strcmp(site, "uucp") != 0)
  1545.       if (strcmp(site, lastsite) != 0) 
  1546.         if (strcmp(site, hostname) != 0) {
  1547.           if (buffer[0] == '\0')
  1548.             strcpy(buffer, strip_parens(site));         /* first in list! */
  1549.           else {
  1550.             sprintf(local_buffer,"%s!%s", buffer, strip_parens(site));
  1551.             strcpy(buffer, local_buffer);
  1552.           }
  1553.           strcpy(lastsite, strip_parens(site)); /* don't want THIS twice! */
  1554.         }
  1555. }
  1556.  
  1557. #ifdef USE_EMBEDDED_ADDRESSES
  1558.  
  1559. get_address_from(prefix, line, buffer)
  1560. char *prefix, *line, *buffer;
  1561. {
  1562.     /** This routine extracts the address from either a 'From:' line
  1563.         or a 'Reply-To:' line...the algorithm is quite simple, too:
  1564.         increment 'line' past header, then check last character of 
  1565.         line.  If it's a '>' then the address is contained within '<>'
  1566.         and if it's a ')' then the address is in the 'clear'... **/
  1567.  
  1568.     register int i, j = 0;
  1569.     
  1570.     no_ret(line);
  1571.  
  1572.     line = (char *) (line + strlen(prefix) + 1);
  1573.  
  1574.     if (line[strlen(line)-1] == '>') {
  1575.       for (i=strlen(line)-2; i > -1 && line[i] != '<'; i--)
  1576.         buffer[j++] = line[i];
  1577.       buffer[j] = 0;
  1578.       reverse(buffer);
  1579.     }
  1580.     else {    /* either ')' or address in the clear... */
  1581.       for (i=0; i < strlen(line) && line[i] != '('; i++)
  1582.         buffer[j++] = line[i];
  1583.       if (buffer[j-1] == '(') j--;
  1584.       buffer[j] = 0;
  1585.     }
  1586. }
  1587.  
  1588. #endif
  1589.  
  1590. translate_return(addr, ret_addr)
  1591. char *addr, *ret_addr;
  1592. {
  1593.     /** Return ret_addr to be the same as addr, but with the login 
  1594.             of the person sending the message replaced by '%s' for 
  1595.             future processing... 
  1596.         Fixed to make "%xx" "%%xx" (dumb 'C' system!) 
  1597.     **/
  1598.  
  1599.     register int loc, loc2, index = 0;
  1600.     
  1601.     loc2 = chloc(addr,'@');
  1602.     if ((loc = chloc(addr, '%')) < loc2)
  1603.       loc2 = loc;
  1604.  
  1605.     if (loc2 != -1) {    /* ARPA address. */
  1606.       /* algorithm is to get to '@' sign and move backwards until
  1607.          we've hit the beginning of the word or another metachar.
  1608.       */
  1609.       for (loc = loc2 - 1; loc > -1 && addr[loc] != '!'; loc--)
  1610.          ;
  1611.     }
  1612.     else {            /* usenet address */
  1613.       /* simple algorithm - find last '!' */
  1614.  
  1615.       loc2 = strlen(addr);    /* need it anyway! */
  1616.  
  1617.       for (loc = loc2; loc > -1 && addr[loc] != '!'; loc--)
  1618.           ;
  1619.     }
  1620.     
  1621.     /** now copy up to 'loc' into destination... **/
  1622.  
  1623.     while (index <= loc) {
  1624.       ret_addr[index] = addr[index];
  1625.       index++;
  1626.     }
  1627.  
  1628.     /** now append the '%s'... **/
  1629.  
  1630.     ret_addr[index++] = '%';
  1631.     ret_addr[index++] = 's';
  1632.  
  1633.     /** and, finally, if anything left, add that **/
  1634.  
  1635.     while (loc2 < strlen(addr)) {
  1636.       ret_addr[index++] = addr[loc2++];
  1637.       if (addr[loc2-1] == '%')    /* tweak for "printf" */
  1638.         ret_addr[index++] = '%';
  1639.     }
  1640.     
  1641.     ret_addr[index] = '\0';
  1642. }
  1643.  
  1644. build_address(to, full_to)
  1645. char *to, *full_to;
  1646. {
  1647.     /** loop on all words in 'to' line...append to full_to as
  1648.         we go along, until done or length > len **/
  1649.  
  1650.     register int i, changed = 0;
  1651.     char word[SLEN], *ptr, buffer[SLEN];
  1652.     char new_to_list[LONG_SLEN];
  1653.  
  1654.     new_to_list[0] = '\0';
  1655.  
  1656.     i = get_word(to, 0, word);
  1657.  
  1658.     full_to[0] = '\0';
  1659.  
  1660.     while (i > 0) {
  1661.  
  1662.       if (strpbrk(word,"!@:") != NULL)
  1663.         sprintf(full_to, "%s%s%s", full_to,
  1664.                     full_to[0] != '\0'? ", " : "", expand_system(word, 1));
  1665.       else if ((ptr = get_alias_address(word, 1, 0)) != NULL)
  1666.         sprintf(full_to, "%s%s%s", full_to, 
  1667.                     full_to[0] != '\0'? ", " : "", ptr);
  1668.       else if (strlen(word) > 0) {
  1669.         if (valid_name(word)) 
  1670.           sprintf(full_to, "%s%s%s", full_to,
  1671.                       full_to[0] != '\0'? ", " : "", word);
  1672.         else if (check_only) {
  1673.           printf("(alias \"%s\" is unknown)\n\r",
  1674.              word);
  1675.           changed++;
  1676.         }
  1677.         else if (! isatty(fileno(stdin)) ) {    /* batch mode error! */
  1678.           fprintf(stderr,"Cannot expand alias '%s'!\n\r", word);
  1679.           fprintf(stderr,"Use \"checkalias\" to find valid addresses!\n\r");
  1680.           dprint1(1,
  1681.               "Can't expand alias %s - bailing out! (build_address)\n", 
  1682.               word);
  1683.           emergency_exit();
  1684.         }
  1685.         else {
  1686.           dprint1(2,"Entered unknown address %s (build_address)\n", word);
  1687.           sprintf(buffer, "'%s' is an unknown address.  Replace with: ", 
  1688.                   word);
  1689.           word[0] = '\0';
  1690.           if (! mail_only) 
  1691.             PutLine0(LINES, 0, buffer);
  1692.         
  1693.           (void) optionally_enter(word, LINES, strlen(buffer), FALSE);
  1694.           if (strlen(word) > 0) {
  1695.             sprintf(new_to_list, "%s%s%s", new_to_list,
  1696.             strlen(new_to_list) > 0? " ":"", word);
  1697.             dprint1(3,"Replaced with %s (build_address)\n", word);
  1698.           }
  1699.           else
  1700.         dprint0(3,"Address removed from to list (build_address)\n");
  1701.           if (mail_only) printf("\n\r");
  1702.           changed++;
  1703.           clear_error();
  1704.           continue;
  1705.         }
  1706.       }
  1707.  
  1708.       i = get_word(to, i, word);
  1709.     }
  1710.  
  1711.     if (changed)
  1712.       strcpy(to, new_to_list);
  1713. }
  1714.  
  1715. int
  1716. real_from(buffer, entry)
  1717. char *buffer;
  1718. struct header_rec *entry;
  1719. {
  1720.     /***** Returns true iff 's' has the seven 'from' fields, (or
  1721.            8 - some machines include the TIME ZONE!!!)
  1722.            Initializing the date and from entries in the record 
  1723.            and also the message received date/time.  *****/
  1724.  
  1725.     char junk[STRING], timebuff[STRING], holding_from[SLEN];
  1726.     int  eight_fields = 0;
  1727.  
  1728.     entry->year[0] = '\0';
  1729.     junk[0] = '\0';
  1730.  
  1731.     /* From <user> <day> <month> <day> <hr:min:sec> <year> */
  1732.  
  1733.     sscanf(buffer, "%*s %*s %*s %*s %*s %s %*s %s", timebuff, junk);
  1734.  
  1735.     if (timebuff[1] != ':' && timebuff[2] != ':') { 
  1736.       dprint1(3,"real_from returns FAIL [bad time field] on\n-> %s\n", 
  1737.           buffer);
  1738.       return(FALSE);
  1739.     }
  1740.     if (junk[0] != '\0') {    /* try for 8 field entry */
  1741.       junk[0] = '\0';
  1742.       sscanf(buffer, "%*s %*s %*s %*s %*s %s %*s %*s %s", timebuff, junk);
  1743.       if (junk[0] != '\0') {
  1744.         dprint1(3,"real_from returns FAIL [too many fields] on\n-> %s\n", 
  1745.             buffer);
  1746.         return(FALSE);
  1747.       }
  1748.       eight_fields++;
  1749.     }
  1750.  
  1751.     /** now get the info out of the record! **/
  1752.  
  1753.     if (eight_fields) 
  1754.       sscanf(buffer, "%s %s %s %s %s %s %*s %s",
  1755.                 junk, holding_from, entry->dayname, entry->month, 
  1756.                     entry->day, entry->time, entry->year);
  1757.     else
  1758.       sscanf(buffer, "%s %s %s %s %s %s %s",
  1759.                 junk, holding_from, entry->dayname, entry->month, 
  1760.                     entry->day, entry->time, entry->year);
  1761.     
  1762.     strncpy(entry->from, holding_from, STRING);
  1763.     resolve_received(entry);
  1764.     return(entry->year[0] != '\0');
  1765. }
  1766.  
  1767. forwarded(buffer, entry)
  1768. char *buffer;
  1769. struct header_rec *entry;
  1770. {
  1771.     /** Change 'from' and date fields to reflect the ORIGINATOR of 
  1772.         the message by iteratively parsing the >From fields... 
  1773.         Modified to deal with headers that include the time zone
  1774.         of the originating machine... **/
  1775.  
  1776.     char machine[SLEN], buff[SLEN], holding_from[SLEN];
  1777.  
  1778.     machine[0] = '\0';
  1779.  
  1780.     sscanf(buffer, "%*s %s %s %s %s %s %s %*s %*s %s",
  1781.                 holding_from, entry->dayname, entry->month, 
  1782.                     entry->day, entry->time, entry->year, machine);
  1783.  
  1784.     if (isdigit(entry->month[0])) { /* try for veeger address */
  1785.       sscanf(buffer, "%*s %s %s%*c %s %s %s %s %*s %*s %s",
  1786.                 holding_from, entry->dayname, entry->day, entry->month, 
  1787.                     entry->year, entry->time, machine);
  1788.     }
  1789.     if (isalpha(entry->year[0])) { /* try for address including tz */
  1790.       sscanf(buffer, "%*s %s %s %s %s %s %*s %s %*s %*s %s",
  1791.                 holding_from, entry->dayname, entry->month, 
  1792.                     entry->day, entry->time, entry->year, machine);
  1793.     }
  1794.  
  1795.     if (machine[0] == '\0')
  1796.       sprintf(buff,"anonymous");
  1797.     else
  1798.       sprintf(buff,"%s!%s", machine, holding_from);
  1799.  
  1800.     strncpy(entry->from, buff, STRING);
  1801. }
  1802.  
  1803. parse_arpa_from(buffer, newfrom)
  1804. char *buffer, *newfrom;
  1805. {
  1806.     /** try to parse the 'From:' line given... It can be in one of
  1807.         two formats:
  1808.         From: Dave Taylor <hplabs!dat>
  1809.         or  From: hplabs!dat (Dave Taylor)
  1810.  
  1811.         Change 'newfrom' ONLY if sucessfully parsed this entry and
  1812.         the resulting name is non-null! 
  1813.         Added: removes quotes if name is quoted (12/12)
  1814.         Added: only copies STRING characters...
  1815.     **/
  1816.  
  1817.     char temp_buffer[SLEN], *temp;
  1818.     register int i, j = 0;
  1819.  
  1820.     temp = (char *) temp_buffer;
  1821.     temp[0] = '\0';
  1822.  
  1823.     no_ret(buffer);        /* blow away '\n' char! */
  1824.  
  1825.     if (lastch(buffer) == '>') {
  1826.       for (i=strlen("From: "); buffer[i] != '\0' && buffer[i] != '<' &&
  1827.            buffer[i] != '('; i++)
  1828.         temp[j++] = buffer[i];
  1829.       temp[j] = '\0';
  1830.     }
  1831.     else if (lastch(buffer) == ')') {
  1832.       for (i=strlen(buffer)-2; buffer[i] != '\0' && buffer[i] != '(' &&
  1833.            buffer[i] != '<'; i--)
  1834.         temp[j++] = buffer[i];
  1835.       temp[j] = '\0';
  1836.       reverse(temp);
  1837.     }
  1838.       
  1839.     if (strlen(temp) > 0) {        /* mess with buffer... */
  1840.  
  1841.       /* remove leading spaces and quotes... */
  1842.  
  1843.       while (whitespace(temp[0]) || quote(temp[0]))
  1844.         temp = (char *) (temp + 1);        /* increment address! */
  1845.  
  1846.       /* remove trailing spaces and quotes... */
  1847.  
  1848.       i = strlen(temp) - 1;
  1849.  
  1850.       while (whitespace(temp[i]) || quote(temp[i]))
  1851.        temp[i--] = '\0';
  1852.  
  1853.       /* if anything is left, let's change 'from' value! */
  1854.  
  1855.       if (strlen(temp) > 0)
  1856.         strncpy(newfrom, temp, STRING);
  1857.     }
  1858. }
  1859.  
  1860. parse_arpa_date(string, entry)
  1861. char *string;
  1862. struct header_rec *entry;
  1863. {
  1864.     /** Parse and figure out the given date format... return
  1865.         the entry fields changed iff it turns out we have a
  1866.         valid parse of the date!  **/
  1867.  
  1868.     char word[15][NLEN], buffer[SLEN], *bufptr;
  1869.     char *aword; 
  1870.     int  words = 0;
  1871.  
  1872.     strcpy(buffer, string);
  1873.     bufptr = (char *) buffer;
  1874.  
  1875.     /** break the line down into words... **/
  1876.  
  1877.     while ((aword = strtok(bufptr," \t '\"-/(),.")) != NULL) {
  1878.       strcpy(word[words++], aword);
  1879.       bufptr = NULL;
  1880.     }
  1881.  
  1882.     if (words < 6) {    /* strange format.  We're outta here! */
  1883.       dprint1(3,"parse_arpa_date failed [less than six fields] on\n-> %s\n",
  1884.           string);
  1885.       return;
  1886.     }
  1887.  
  1888.     /* There are now five possible combinations that we could have:
  1889.      
  1890.         Date: day_number month_name year_number time timezone
  1891.         Date: day_name day_number month_name year_number ...
  1892.         Date: day_name month_name day_number time year_number
  1893.         Date: day_name month_name day_number year_number time
  1894.         Date: day_number month_name year_number time timezone day_name
  1895.  
  1896.        Note that they are distinguishable by checking the first
  1897.        character of the second, third and fourth words... 
  1898.     */
  1899.  
  1900.     if (isdigit(word[1][0])) {            /*** type one! ***/
  1901.       if (! valid_date(word[1], word[2], word[3])) {
  1902.         dprint4(3,"parse_arpa_date failed [bad date: %s/%s/%s] on\n-> %s\n",
  1903.           word[1], word[2], word[3], string);
  1904.         return;        /* strange date! */
  1905.       }
  1906.       strncpy(entry->day, word[1], 3);
  1907.       strncpy(entry->month, word[2], 3);
  1908.       strncpy(entry->year,  word[3], 4);
  1909.       strncpy(entry->time,  word[4], 10);
  1910.     }
  1911.     else if (isdigit(word[2][0])) {                /*** type two! ***/
  1912.       if (! valid_date(word[2], word[3], word[4])) {
  1913.         dprint4(3,"parse_arpa_date failed [bad date: %s/%s/%s] on\n-> %s\n",
  1914.           word[2], word[3], word[4], string);
  1915.         return;        /* strange date! */
  1916.       }
  1917.       strncpy(entry->day, word[2], 3);
  1918.       strncpy(entry->month, word[3], 3);
  1919.       strncpy(entry->year,  word[4], 4);
  1920.       strncpy(entry->time,  word[5], 10);
  1921.     }
  1922.     else if (isdigit(word[3][0])) {        
  1923.       if (word[4][1] == ':' || 
  1924.               word[4][2] == ':') {                   /*** type three! ***/
  1925.         if (! valid_date(word[3], word[2], word[5])) {
  1926.          dprint4(3,
  1927.         "parse_arpa_date failed [bad date: %s/%s/%s] on\n-> %s\n",
  1928.             word[3], word[2], word[5], string);
  1929.           return;        /* strange date! */
  1930.         }
  1931.         strncpy(entry->year,  word[5], 4);
  1932.         strncpy(entry->time,  word[4], 10);
  1933.       }
  1934.       else {                       /*** type four!  ***/ 
  1935.         if (! valid_date(word[3], word[2], word[4])) {
  1936.          dprint4(3,"parse_arpa_date failed [bad date: %s/%s/%s] on\n-> %s\n",
  1937.             word[3], word[2], word[4], string);
  1938.           return;        /* strange date! */
  1939.         }
  1940.         strncpy(entry->year,  word[4], 4);
  1941.         strncpy(entry->time, word[5], 10);
  1942.       }
  1943.       strncpy(entry->day, word[3], 3);
  1944.       strncpy(entry->month, word[2], 3);
  1945.     }
  1946. }
  1947.  
  1948. fix_arpa_address(address)
  1949. char *address;
  1950. {
  1951.     /** Given a pure ARPA address, try to make it reasonable.
  1952.  
  1953.         This means that if you have something of the form a@b@b make 
  1954.             it a@b.  If you have something like a%b%c%b@x make it a%b@x...
  1955.     **/
  1956.  
  1957.     register int host_count = 0, i;
  1958.     char     hosts[MAX_HOPS][2*NLEN];    /* array of machine names */
  1959.     char     *host, *addrptr;
  1960.  
  1961.     /*  break down into a list of machine names, checking as we go along */
  1962.     
  1963.     addrptr = (char *) address;
  1964.  
  1965.     while ((host = get_token(addrptr, "%@", 2)) != NULL) {
  1966.       for (i = 0; i < host_count && ! equal(hosts[i], host); i++)
  1967.           ;
  1968.  
  1969.       if (i == host_count) {
  1970.         strcpy(hosts[host_count++], host);
  1971.         if (host_count == MAX_HOPS) {
  1972.            dprint0(2,
  1973.               "Can't build return address - hit MAX_HOPS (fix_arpa_address)\n");
  1974.            error("Can't build return address - hit MAX_HOPS limit!");
  1975.            return(1);
  1976.         }
  1977.       }
  1978.       else 
  1979.         host_count = i + 1;
  1980.       addrptr = NULL;
  1981.     }
  1982.  
  1983.     /** rebuild the address.. **/
  1984.  
  1985.     address[0] = '\0';
  1986.  
  1987.     for (i = 0; i < host_count; i++)
  1988.       sprintf(address, "%s%s%s", address, 
  1989.               address[0] == '\0'? "" : 
  1990.              (i == host_count - 1 ? "@" : "%"),
  1991.               hosts[i]);
  1992.  
  1993.     return(0);
  1994. }
  1995.  
  1996. figure_out_addressee(buffer, mail_to)
  1997. char *buffer;
  1998. char *mail_to;
  1999. {
  2000.     /** This routine steps through all the addresses in the "To:"
  2001.         list, initially setting it to the first entry (if mail_to
  2002.         is NULL) or, if the user is found (eg "alternatives") to
  2003.         the current "username".
  2004.  
  2005.         Modified to know how to read quoted names...
  2006.     **/
  2007.  
  2008.     char *address, *bufptr, *strchr();
  2009.     register int index = 0, index2 = 0;
  2010.     
  2011.     if (equal(mail_to, username)) return;    /* can't be better! */
  2012.  
  2013.     bufptr = (char *) buffer;    /* use the string directly   */
  2014.  
  2015.     if (strchr(buffer,'"') != NULL) {    /* we have a quoted string */
  2016.       while (buffer[index] != '"')
  2017.         index++;
  2018.       index++;    /* skip the leading quote */
  2019.       while (buffer[index] != '"' && index < strlen(buffer))
  2020.         mail_to[index2++] = buffer[index++];
  2021.       mail_to[index2] = '\0';
  2022.     }
  2023.     else while ((address = strtok(bufptr, " ,\t\n\r")) != NULL) {
  2024.       if (! okay_address(address, "don't match me!")) {
  2025.         strcpy(mail_to, username);    /* it's to YOU! */
  2026.         return;
  2027.       }
  2028.       else if (strlen(mail_to) == 0)    /* it's SOMEthing! */
  2029.         get_return_name(address, mail_to, FALSE);
  2030.  
  2031.       bufptr = (char *) NULL;    /* set to null */
  2032.     }
  2033.  
  2034.     return;
  2035. }
  2036. END-OF-FILE
  2037.  
  2038. if [ "$filename" != "/dev/null" ]
  2039. then
  2040.   size=`wc -c < $filename`
  2041.  
  2042.   if [ $size != 15408 ]
  2043.   then
  2044.     echo $filename changed - should be 15408 bytes, not $size bytes
  2045.   fi
  2046.  
  2047.   chmod 644 $filename
  2048. fi
  2049.  
  2050. # ---------- file src/input_utils.c ----------
  2051.  
  2052. filename="src/input_utils.c"
  2053.  
  2054. if [ -f $filename ]
  2055. then
  2056.   echo File \"$filename\" already exists\!  Skipping...
  2057.   filename=/dev/null        # throw it away
  2058. else
  2059.   echo extracting file src/input_utils.c...
  2060. fi
  2061.  
  2062. cat << 'END-OF-FILE' > $filename
  2063. /**            input_utils.c            **/
  2064.  
  2065. /** Mindless I/O routines for ELM 
  2066.     
  2067.     (C) Copyright 1985 Dave Taylor
  2068. **/
  2069.  
  2070. #include "headers.h"
  2071. #include <errno.h>
  2072.  
  2073. extern int errno;        /* system error number */
  2074.  
  2075. int
  2076. want_to(question, dflt, echo_answer)
  2077. char *question, dflt;
  2078. int  echo_answer;
  2079. {
  2080.     /** Ask 'question' at LINES-2, COLUMNS-40, returning the answer in 
  2081.         lower case.  If 'echo_answer', then echo answer.  'dflt' is the 
  2082.         default answer if <return> is pressed. (Note: 'dflt' is also what 
  2083.         will be returned if <return> is pressed!)
  2084.     **/
  2085.     register char ch, cols;
  2086.  
  2087.     cols = (strlen(question) < 30)? COLUMNS-40 : COLUMNS-50;
  2088.  
  2089.     PutLine3(LINES-3, cols,"%s%c%c", question, dflt, BACKSPACE);
  2090.     fflush(stdout);
  2091.     fflush(stdin);
  2092.     ch = tolower(ReadCh());
  2093.  
  2094.     if (echo_answer && ch > (char) ' ') {
  2095.       Writechar(ch);
  2096.       fflush(stdout);
  2097.     }
  2098.  
  2099.     return(ch == '\n' || ch == '\r' ? dflt : ch);
  2100. }
  2101.  
  2102. int
  2103. read_number(ch, max)
  2104. char ch;
  2105. int max;
  2106. {
  2107.     /** read a number, where 'ch' is the leading digit! 
  2108.         If max < 10 then just return 'ch' **/
  2109.     
  2110.     char buff[SHORT_SLEN];
  2111.     int  num;
  2112.  
  2113.     if (max < 10)
  2114.       return( (int) ch - '0' );
  2115.     
  2116.     buff[0] = ch;
  2117.     buff[1] = '\0';
  2118.  
  2119.     PutLine0(LINES-3, COLUMNS-40,"Set current message to :");
  2120.     if (optionally_enter(buff, LINES-3, COLUMNS-15, TRUE) == -1)
  2121.       return(current);
  2122.  
  2123.     sscanf(buff,"%d", &num);
  2124.     return(num);
  2125. }
  2126.  
  2127. int
  2128. optionally_enter(string, x, y, append_current)
  2129. char *string;
  2130. int  x,y, append_current;
  2131. {
  2132.     /** Display the string on the screen and if RETURN is pressed, return 
  2133.         it.  Otherwise, allow standard text input, including backspaces 
  2134.         and such until RETURN is hit.  
  2135.         If "append_current" is set, then leave the default string in 
  2136.         place and edit AFTER it...assume 'x,y' is placing us at the
  2137.         beginning of the string...
  2138.         This routine returns zero unless INTERRUPT hit, then it returns
  2139.         -1 and must be treated accordingly.
  2140.     **/
  2141.  
  2142.     char ch;
  2143.     register index = 0;
  2144.  
  2145.     PutLine1(x,y, "%s", string);    
  2146.     CleartoEOLN();
  2147.     if (! append_current)
  2148.       MoveCursor(x,y);
  2149.  
  2150.     if (cursor_control)
  2151.       transmit_functions(OFF);
  2152.  
  2153.     ch = getchar();
  2154.  
  2155.     if (ch == '\n' || ch == '\r') {
  2156.       if (cursor_control)
  2157.         transmit_functions(ON);
  2158.       return(0);    /* we're done.  No change needed */
  2159.     }
  2160.     
  2161.     CleartoEOLN();
  2162.  
  2163.     index = (append_current? strlen(string) : 0);
  2164.  
  2165.     if (ch == kill_line) {
  2166.       if (! mail_only)
  2167.         MoveCursor(x,y);
  2168.           CleartoEOLN();
  2169.       index = 0;
  2170.     }
  2171.     else if (ch != backspace) {
  2172.       Writechar(ch);
  2173.       string[index++] = ch;
  2174.     }
  2175.     else if (index > 0) {
  2176.       index--;
  2177.       Writechar(BACKSPACE);
  2178.       Writechar(' ');
  2179.       Writechar(BACKSPACE);
  2180.       fflush(stdout);
  2181.     }
  2182.     else {
  2183.       Writechar(' ');
  2184.       Writechar(BACKSPACE);
  2185.       fflush(stdout);
  2186.     }
  2187.  
  2188.     do {
  2189.       ch = getchar();
  2190.  
  2191.       /* the following is converted from a case statement to
  2192.          allow the variable characters (backspace, kill_line
  2193.          and break) to be processed.  Case statements in
  2194.          C require constants as labels, so it failed ...
  2195.       */
  2196.  
  2197.         if (ch == backspace) {
  2198.               if (index > 0) {
  2199.         index--;
  2200.         Writechar(BACKSPACE);
  2201.         Writechar(' ');
  2202.         Writechar(BACKSPACE);
  2203.             fflush(stdout);
  2204.           }
  2205.           else {
  2206.         Writechar(' ');
  2207.         Writechar(BACKSPACE);
  2208.             fflush(stdout);
  2209.           }
  2210.         }
  2211.         else if (ch == '\n' || ch == '\r') {
  2212.           string[index] = '\0';
  2213.           if (cursor_control)
  2214.             transmit_functions(ON);
  2215.           return(0);
  2216.         }
  2217.         else if (ch == kill_line) {
  2218.           if (mail_only)
  2219.             back_up(index+1);
  2220.           else
  2221.             MoveCursor(x,y);
  2222.               CleartoEOLN();
  2223.           index = 0;
  2224.         }
  2225.         else if (ch == NULL) {
  2226.           if (cursor_control)
  2227.             transmit_functions(ON);
  2228.           fflush(stdin);     /* remove extraneous chars, if any */
  2229.           string[0] = '\0'; /* clean up string, and... */
  2230.           return(-1);
  2231.         }
  2232.         else {  /* default case */
  2233.                 
  2234.           string[index++] = ch;
  2235.           Writechar(ch);
  2236.        }
  2237.     } while (index < SLEN);
  2238.  
  2239.     string[index] = '\0';
  2240.  
  2241.     if (cursor_control)
  2242.       transmit_functions(ON);
  2243.     return(0);
  2244. }
  2245.  
  2246.  
  2247. int
  2248. pattern_enter(string, alt_string, x, y, alternate_prompt)
  2249. char *string, *alt_string, *alternate_prompt;
  2250. int  x,y;
  2251. {
  2252.     /** This function is functionally similar to the routine
  2253.         optionally-enter, but if the first character pressed
  2254.         is a '/' character, then the alternate prompt and string
  2255.         are used rather than the normal one.  This routine 
  2256.         returns 1 if alternate was used, 0 if not
  2257.     **/
  2258.  
  2259.     char ch;
  2260.     register index = 0;
  2261.  
  2262.     PutLine1(x, y, "%s", string);    
  2263.     CleartoEOLN();
  2264.     MoveCursor(x,y);
  2265.  
  2266.     if (cursor_control)
  2267.       transmit_functions(OFF);
  2268.  
  2269.     ch = getchar();
  2270.  
  2271.     if (ch == '\n' || ch == '\r') {
  2272.       if (cursor_control)
  2273.         transmit_functions(ON);
  2274.       return(0);    /* we're done.  No change needed */
  2275.     }
  2276.     
  2277.     if (ch == '/') {
  2278.       PutLine1(x, 0, "%s", alternate_prompt);
  2279.       CleartoEOLN();
  2280.       (void) optionally_enter(alt_string, x, strlen(alternate_prompt)+1,
  2281.          FALSE);
  2282.       return(1);
  2283.     }
  2284.  
  2285.     CleartoEOLN();
  2286.  
  2287.     index = 0;
  2288.  
  2289.     if (ch == kill_line) {
  2290.       MoveCursor(x,y);
  2291.           CleartoEOLN();
  2292.       index = 0;
  2293.     }
  2294.     else if (ch != backspace) {
  2295.       Writechar(ch);
  2296.       string[index++] = ch;
  2297.     }
  2298.     else if (index > 0) {
  2299.       index--;
  2300.       Writechar(BACKSPACE);
  2301.       Writechar(' ');
  2302.       Writechar(BACKSPACE);
  2303.     }
  2304.     else {
  2305.       Writechar(' ');
  2306.       Writechar(BACKSPACE);
  2307.     }
  2308.  
  2309.     do {
  2310.       fflush(stdout);
  2311.       ch = getchar();
  2312.  
  2313.       /* the following is converted from a case statement to
  2314.          allow the variable characters (backspace, kill_line
  2315.          and break) to be processed.  Case statements in
  2316.          C require constants as labels, so it failed ...
  2317.       */
  2318.  
  2319.         if (ch == backspace) {
  2320.               if (index > 0) {
  2321.         index--;
  2322.         Writechar(BACKSPACE);
  2323.         Writechar(' ');
  2324.         Writechar(BACKSPACE);
  2325.           }
  2326.           else {
  2327.         Writechar(' ');
  2328.         Writechar(BACKSPACE);
  2329.           }
  2330.         }
  2331.         else if (ch == '\n' || ch == '\r') {
  2332.           string[index] = '\0';
  2333.           if (cursor_control)
  2334.             transmit_functions(ON);
  2335.           return(0);
  2336.         }
  2337.         else if (ch == kill_line) {
  2338.           MoveCursor(x,y);
  2339.               CleartoEOLN();
  2340.           index = 0;
  2341.         }
  2342.         else if (ch == NULL) {
  2343.           if (cursor_control)
  2344.             transmit_functions(ON);
  2345.           fflush(stdin);     /* remove extraneous chars, if any */
  2346.           string[0] = '\0'; /* clean up string, and... */
  2347.           return(-1);
  2348.         }
  2349.         else {  /* default case */
  2350.                 
  2351.           string[index++] = ch;
  2352.           Writechar(ch);
  2353.        }
  2354.     } while (index < SLEN);
  2355.  
  2356.     string[index] = '\0';
  2357.  
  2358.     if (cursor_control)
  2359.       transmit_functions(ON);
  2360.     return(0);
  2361. }
  2362.  
  2363. back_up(spaces)
  2364. int spaces;
  2365. {
  2366.     /** this routine is to replace the goto x,y call for when sending
  2367.         mail without starting the entire "elm" system up... **/
  2368.     
  2369.     while (spaces--) {
  2370.       Writechar(BACKSPACE);
  2371.       Writechar(' ');
  2372.       Writechar(BACKSPACE);
  2373.     }
  2374.  
  2375.     fflush(stdout);
  2376. }
  2377.  
  2378. int
  2379. GetPrompt()
  2380. {
  2381.     /** This routine does a read/timeout for a single character.
  2382.         The way that this is determined is that the routine to
  2383.         read a character is called, then the "errno" is checked
  2384.         against EINTR (interrupted call).  If they match, this
  2385.         returns NO_OP_COMMAND otherwise it returns the normal
  2386.         command.    
  2387.     **/
  2388.  
  2389.     int ch;
  2390.  
  2391.     if (timeout > 0) {
  2392.       alarm(timeout);
  2393.       errno = 0;    /* we actually have to do this.  *sigh*  */
  2394.       ch = ReadCh();
  2395.       if (errno == EINTR) ch = NO_OP_COMMAND;
  2396.       alarm(0);
  2397.     }
  2398.     else
  2399.       ch = ReadCh();
  2400.  
  2401.     return(ch);
  2402. }
  2403. END-OF-FILE
  2404.  
  2405. if [ "$filename" != "/dev/null" ]
  2406. then
  2407.   size=`wc -c < $filename`
  2408.  
  2409.   if [ $size != 7235 ]
  2410.   then
  2411.     echo $filename changed - should be 7235 bytes, not $size bytes
  2412.   fi
  2413.  
  2414.   chmod 644 $filename
  2415. fi
  2416.  
  2417. echo end of this archive file....
  2418. exit 0
  2419.  
  2420.