home *** CD-ROM | disk | FTP | other *** search
/ The World of Computer Software / World_Of_Computer_Software-02-385-Vol-1of3.iso / t / tel2305s.zip / ENGINE / NEW_CON.C < prev    next >
C/C++ Source or Header  |  1992-03-08  |  35KB  |  1,403 lines

  1. /*
  2. *   New_con.c
  3. *   Split from confile.c 1/91
  4. *   Reads and stores the appropriate information for the config file
  5. *       leaving out the telnet specific options (making them NOPs).
  6. *
  7. *****************************************************************************
  8. *                                                                            *
  9. *      part of:                                                                *
  10. *      Network kernel for NCSA Telnet                                        *
  11. *      by Tim Krauskopf                                                        *
  12. *                                                                            *
  13. *      National Center for Supercomputing Applications                        *
  14. *      152 Computing Applications Building                                    *
  15. *      605 E. Springfield Ave.                                                *
  16. *      Champaign, IL  61820                                                    *
  17. *                                                                            *
  18. *     This program is in the public domain.                                 *
  19. *                                                                           *
  20. *****************************************************************************
  21. *
  22. *    Revision History:
  23. *
  24. *    Initial release - 11/87 TK
  25. *    Cleanup for 2.3 release - 6/89 QK
  26. *   New for 2.3 release - 1/91 QK
  27. *
  28. */
  29.  
  30. /*
  31. *    Includes
  32. */
  33. #ifdef __TURBOC__
  34. #include "turboc.h"
  35. #endif
  36. #include <stdio.h>
  37. #include <stdlib.h>
  38. #include <string.h>
  39. #include <ctype.h>
  40. #ifdef MSC
  41. #ifdef __TURBOC__
  42. #include <alloc.h>
  43. #else
  44. #include <malloc.h>
  45. #endif
  46. #endif
  47. #include "whatami.h"
  48. #include "hostform.h"
  49. #include "externs.h"
  50. #define CONFIG_MASTER
  51. #include "confile.h"
  52.  
  53. /* STATIC function declarations */
  54. static FILE *pfopen(char *name,char *mode);    /* open file with required mode */
  55.  
  56. #ifdef NEEDIT
  57. /************************************************************************/
  58. /*  Sgetconfig
  59. *   copy the configuration information into the user's data structure
  60. *   directly.  The user can do with it what he feels like.
  61. */
  62. void Sgetconfig(struct config *cp)
  63. {
  64.     movebytes(cp,&Scon,sizeof(struct config));
  65. }
  66.  
  67. #endif /*NEEDIT*/
  68.  
  69. /************************************************************************/
  70. /*  Sreadhosts
  71. *   read in the hosts file into our in-memory data structure.
  72. *   Handle everything by keyword, see docs for specifications about file.
  73. */
  74. int Sreadhosts(void)
  75. {
  76.     FILE *fp;
  77.     int c,retval,i,j;
  78.     char *envstr, envnam[8];
  79.  
  80.     Smachlist=Smptr=NULL;
  81.     mno=0;
  82.     Sspace=malloc(256);                /* get room for gathering stuff */
  83.     if(Sspace==NULL) {
  84.         Serrline(901);
  85.         return(1);
  86.       }
  87.     position=constate=inquote=lineno=0;   /* state vars */    
  88.     if(NULL==(fp=pfopen(Smachfile,"r"))) {    /* open the configuration file */
  89.         Serrline(900);
  90.         return(1);
  91.       }    /* end if */
  92.     retval=0;
  93.     while(!retval) {
  94.         c=fgetc(fp);
  95.         if(c=='#' && !inquote)
  96.             while(c!=EOF && c!='\n' && c!='\r')        /* skip to EOL */
  97.                 c=fgetc(fp);
  98.         if(c=='\n' || c=='\r')
  99.             lineno++;
  100.          retval=Scontoken(c);        /* add character to token */
  101.       }
  102.     fclose(fp);
  103.     position=constate=inquote=0;
  104.     for(i=0;i<100;i++) {
  105.         sprintf(envnam,"NCSA%2.2d",i);
  106.         if (envstr=getenv(envnam)) {
  107.             if (*envstr=='\"')
  108.                 *(envstr+strlen(envstr++)-2) = (char)NULL;
  109.             for(j=0,retval=0;*(envstr+j)&&!retval;j++) {
  110.                 if ((*(envstr+j)=='~')||(*(envstr+j)==' '))
  111.                     *(envstr+j) = '=';
  112.                 retval = Scontoken(*(envstr+j));
  113.             }
  114.             Scontoken(';'); /* make sure last token is taken */
  115.         }
  116.     }
  117.     free(Sspace);
  118.     Smadd("default");                /* make sure name is in list */
  119.     if(retval==EOF)                /* EOF is normal end */
  120.         return(0);
  121.     else
  122.         return(retval);
  123. }
  124.  
  125. /************************************************************************/
  126. /*  ncstrcmp
  127. *   No case string compare.
  128. *   Only returns 0=match, 1=no match, does not compare greater or less
  129. *   There is a tiny bit of overlap with the | 32 trick, but shouldn't be
  130. *   a problem.  It causes some different symbols to match.
  131. */
  132. int ncstrcmp(char *sa,char *sb)
  133. {
  134.     while(*sa && *sa<33)        /* don't compare leading spaces */
  135.         sa++;
  136.     while(*sb && *sb<33)
  137.         sb++;
  138.     while(*sa && *sb) {
  139.         if((*sa!=*sb) && ((*sa | 32)!=(*sb | 32)))
  140.             return(1);
  141.         sa++;
  142.         sb++;
  143.       }    /* end while */
  144.     if(!*sa && !*sb)        /* if both at end of string */
  145.         return(0);
  146.     else
  147.         return(1);
  148. }    /* end ncstrcmp() */
  149.  
  150. /************************************************************************/
  151. /*  Serrline
  152. *   prints the line number of the host file error and posts the event
  153. *   for the line number error and posts the hosts file error.
  154. */
  155. void Serrline(int n)
  156. {
  157.     char *p;
  158.  
  159.     p=neterrstring(-1);
  160.     sprintf(p,"Config file: error at line %4d",lineno+1);
  161.     netposterr(-1);
  162.     netposterr(n);
  163. }
  164.  
  165. /************************************************************************/
  166. /* Scontoken
  167. *  tokenize the strings which get passed to Sconfile.
  168. *  Handles quotes and uses separators:  <33, ;:=
  169. */
  170. int Scontoken(int c)
  171. {
  172.     int retval;
  173.  
  174.     if(c==EOF) {
  175.         Sspace[position++]='\0';
  176.         Sconfile(Sspace);
  177.         if(!Sflags[0]) {            /* make sure last entry gets copied */
  178.             if(ncstrcmp("default",Smptr->sname))
  179.                 Scopyfrom("default");
  180.             else
  181.                 Scopyfrom("==");
  182.           }
  183.         return(-1);
  184.       }
  185.     if(!position && Sissep(c))        /* skip over junk before token */
  186.         return(0);
  187.     if(inquote || !Sissep(c)) {
  188.         if(position>200) {
  189.             Serrline(903);
  190.             return(1);
  191.           }
  192. /*
  193. *  check for quotes, a little mixed up here, could be reorganized
  194. */
  195.         if(c=='"' ) {
  196.             if(!inquote) {            /* beginning of quotes */
  197.                 inquote=1;
  198.                 return(0);
  199.               }
  200.             else
  201.                 inquote=0;        /* turn off flag and drop through */
  202.           }
  203.         else {
  204.             if(c=='\n') {            /* check for EOL inside quotes */
  205.                 Serrline(904);
  206.                 return(1);
  207.               }
  208.             Sspace[position++]=(char)c;    /* include in current string */
  209.             return(0);
  210.           }
  211.       }
  212.     Sspace[position++]='\0';
  213.     retval=Sconfile(Sspace);            /* pass the token along */
  214.     position=0;
  215.     inquote=0;
  216.     Sspace[0]='\0';
  217.     return(retval);
  218. }
  219.  
  220. /************************************************************************/
  221. /*  Sconfile
  222. *   take the characters read from the file and parse them for keywords
  223. *   which require configuration action.
  224. */
  225. int Sconfile(char *s)
  226. {
  227.     int i,a,b,c,d;
  228.  
  229.     switch(constate) {
  230.         case 0:                                /* lookup keyword */
  231.             if(!(*s))                        /* empty token */
  232.                 return(0);
  233.  
  234.             for(i=1; *Skeyw[i] && ncstrcmp(Skeyw[i],s); i++);    /* search the keyboard list for this keyword */
  235.  
  236.             if(!(*Skeyw[i])) {            /* not in list */
  237.                 Serrline(902);
  238.                 return(0);                /* don't die - helps backward compatibility */
  239.               }    /* end if */
  240.             constate=100+i;    /* change to state for keyword */
  241. /*
  242. *  check if this is a machine specific parm without a machine to
  243. *  give it to.  "name" being the only machine specific parm allowed, of course
  244. */
  245.             if(Smptr==NULL && constate>CONNAME && constate<=NUMSPECS) {
  246.                 Serrline(905);
  247.                 return(1);
  248.               }
  249.             break;
  250.  
  251.         case CONNAME:        /* session name */
  252. /*
  253. *  allocate space for upcoming parameters
  254. */
  255.             constate=0;                     /* back to new keyword */
  256.             if(Smachlist==NULL) {
  257.                 Smachlist=(struct machinfo *)malloc(sizeof(struct machinfo));
  258.                 if(Smachlist==NULL) {    /* check for bad allocate */
  259.                     Serrline(901);
  260.                     return(0);              /* don't die - helps backward compatibility */
  261.                   } /* end if */
  262.                 Smptr=Smachlist;
  263.               }
  264.             else {
  265.                 if(!Sflags[0]) {
  266.                     if(ncstrcmp("default",Smptr->sname))
  267.                         Scopyfrom("default");
  268.                     else
  269.                         Scopyfrom("==");    /* to make sure 'default' gets set */
  270.                   }
  271.                 Smptr->next=(struct machinfo *)malloc(sizeof(struct machinfo));
  272.                 if(Smptr->next==NULL) {    /* check for bad allocate */
  273.                     Serrline(901);
  274.                     return(0);              /* don't die - helps backward compatibility */
  275.                   } /* end if */
  276.                 Smptr=Smptr->next;
  277.               }
  278.             Smptr->next=NULL;
  279.             Smptr->hname=NULL;                /* guarantee to be null */
  280.             Smptr->sname=malloc(position);    /* size of name string */
  281.             if(Smptr->sname!=NULL)          /* try to avoid copying into a bad allocation */
  282.                 strcpy(Smptr->sname,s);     /* keep name field */
  283.             Smptr->ftpoptions=NULL;         /* no options */
  284.             for(i=0; i<NUMSPECS-99; i++)
  285.                 Sflags[i]=0;                /* we have no parms */
  286.             Smptr->mno=++mno;                /* new machine number */
  287.             break;
  288.  
  289.         case CONHOST:    /* also a host name */
  290.             constate=0;
  291.             Smptr->hname=malloc(position);
  292.             if(Smptr->hname==NULL) {    /* check for bad allocate */
  293.                 Serrline(901);
  294.                 return(0);              /* don't die - helps backward compatibility */
  295.               } /* end if */
  296.             strcpy(Smptr->hname,s);
  297.             Sflags[CONHOST-100]=1;    /* set the flag to indicate hostname is found */
  298.             break;
  299.  
  300.         case CONIP:        /* IP number for host */
  301.             if(4!=sscanf(s,"%d.%d.%d.%d",&a,&b,&c,&d)) {
  302.                 Serrline(906);
  303.                 return(3);
  304.               }
  305.             Smptr->hostip[0]=(char)a;     /* keep number */
  306.             Smptr->hostip[1]=(char)b;
  307.             Smptr->hostip[2]=(char)c;
  308.             Smptr->hostip[3]=(char)d;
  309.             Smptr->mstat=HFILE;
  310.             constate=0;
  311.             Sflags[CONIP-100]=1;        /* set the flag to indicate ip number found */
  312.             break;
  313.  
  314.         case CONGATE:    /* this machine is a gateway */
  315.             Smptr->gateway=(unsigned char)atoi(s);        /* gateway level */
  316.             constate=0;
  317.             Sflags[CONGATE-100]=1;        /* set the flag for this name being a gateway */
  318.             break;
  319.  
  320.         case CONCOLOR:        /* support old color format */
  321.             Smptr->nfcolor=s[1]-48;
  322.             Smptr->nbcolor=s[0]-48;
  323.             Smptr->ufcolor=s[3]-48;
  324.             Smptr->ubcolor=s[2]-48;
  325.             Smptr->bfcolor=s[5]-48;
  326.             Smptr->bbcolor=s[4]-48;
  327.             constate=0;
  328.             Sflags[CONNF-100]=1;        /* sets them all at one shot */
  329.             Sflags[CONNB-100]=1;
  330.             Sflags[CONBF-100]=1;
  331.             Sflags[CONBB-100]=1;
  332.             Sflags[CONUF-100]=1;
  333.             Sflags[CONUB-100]=1;
  334.             break;
  335.  
  336.         case CONBKSP:    /* backspace parameter */
  337.             if(!ncstrcmp(s,"backspace"))
  338.                 Smptr->bksp=8;
  339.             else
  340.                 Smptr->bksp=127;
  341.             constate=0;
  342.             Sflags[CONBKSP-100]=1;
  343.             break;
  344.  
  345.         case CONBKSC:        /* the number of line for scrollback */
  346.             Smptr->bkscroll=atoi(s);
  347.             constate=0;
  348.             Sflags[CONBKSC-100]=1;
  349.             break;
  350.  
  351.         case CONRETR:        /* how long before retransmitting */
  352.             Smptr->retrans=atoi(s);
  353.             constate=0;
  354.             Sflags[CONRETR-100]=1;
  355.             break;
  356.  
  357.         case CONWIND:        /* transmission window for this host */
  358.             Smptr->window=atoi(s);
  359.             constate=0;
  360.             Sflags[CONWIND-100]=1;
  361.             break;
  362.  
  363.         case CONSEG:        /* segment size */
  364.             Smptr->maxseg=atoi(s);
  365.             constate=0;
  366.             Sflags[CONSEG-100]=1;
  367.             break;
  368.  
  369.         case CONMTU:    /* maximum transmission unit */
  370.             Smptr->mtu=atoi(s);
  371.             constate=0;
  372.             Sflags[CONMTU-100]=1;
  373.             break;
  374.  
  375.         case CONNS:        /* nameserver level */
  376.             Smptr->nameserv=(unsigned char)atoi(s);
  377.             if(!Sns || ((Sns->nameserv)>(Smptr->nameserv))) /* keep NS */
  378.                 Sns=Smptr;
  379.             constate=0;
  380.             Sflags[CONNS-100]=1;
  381.             break;
  382.  
  383.         case CONTO:        /* time until time out */
  384.             i=atoi(s);
  385.             if(i>2) {
  386.                 Smptr->conto=i;
  387.                 Sflags[CONTO-100]=1;
  388.               }
  389.             constate=0;
  390.             break;
  391.  
  392.         case CONCRMAP:        /* carriage return mapping */
  393.             if(!ncstrcmp(s,"4.3BSDCRNUL")) 
  394.                 Smptr->crmap=0;
  395.             else
  396.                 Smptr->crmap=10;
  397.             Sflags[CONCRMAP-100]=1;
  398.             constate=0;
  399.             break;
  400.  
  401.         case CONDUP:        /* duplex */
  402.             if(!ncstrcmp(s,"half")) {
  403.                 Smptr->halfdup=1;
  404.                 Sflags[CONDUP-100]=1;
  405.               }
  406.             constate=0;
  407.             break;
  408.  
  409.         case CONWRAP:        /* whether lines wrap */
  410.             if('Y'==toupper(s[0])) 
  411.                 Smptr->vtwrap=1;
  412.             else
  413.                 Smptr->vtwrap=0;
  414.             Sflags[CONWRAP-100]=1;
  415.             constate=0;
  416.             break;
  417.  
  418.         case CONWIDE:        /* how wide the screen is */
  419.             if(132==atoi(s)) 
  420.                 Smptr->vtwidth=132;
  421.             else
  422.                 Smptr->vtwidth=80;
  423.             Sflags[CONWIDE-100]=1;
  424.             constate=0;
  425.             break;
  426.  
  427.         case CONFONT:        /* the font type */
  428.             constate=0;
  429.             Smptr->font=malloc(position);
  430.             if(Smptr->font==NULL) {    /* check for bad allocate */
  431.                 Serrline(901);
  432.                 return(0);              /* don't die - helps backward compatibility */
  433.               } /* end if */
  434.             strcpy(Smptr->font,s);
  435.             Sflags[CONFONT-100]=1;
  436.             break;
  437.  
  438.         case CONFSIZE:        /* the font point size */
  439.             Smptr->fsize=atoi(s);
  440.             Sflags[CONFSIZE-100]=1;
  441.             constate=0;
  442.             break;
  443.  
  444.         case CONNF:        /* foreground normal color */
  445. #ifdef FTPBIN
  446.             Scolorset(&Smptr->nfcolor,s);
  447. #endif
  448.             Sflags[CONNF-100]=1;
  449.             constate=0;
  450.             break;
  451.  
  452.         case CONNB:        /* background normal color */
  453. #ifdef FTPBIN
  454.             Scolorset(&Smptr->nbcolor,s);
  455. #endif
  456.             Sflags[CONNB-100]=1;
  457.             constate=0;
  458.             break;
  459.  
  460.         case CONRF:
  461.         case CONBF:        /* blink foreg color */
  462. #ifdef FTPBIN
  463.             Scolorset(&Smptr->bfcolor,s);
  464. #endif
  465.             Sflags[CONBF-100]=1;    /* in copyfrom, r's are really b's */
  466.             constate=0;
  467.             break;
  468.  
  469.         case CONRB:
  470.         case CONBB:        /* blink bg color */
  471. #ifdef FTPBIN
  472.             Scolorset(&Smptr->bbcolor,s);
  473. #endif
  474.             Sflags[CONBB-100]=1;
  475.             constate=0;
  476.             break;
  477.  
  478.         case CONUF:        /* foreground underline color */
  479. #ifdef FTPBIN
  480.             Scolorset(&Smptr->ufcolor,s);
  481. #endif
  482.             Sflags[CONUF-100]=1;
  483.             constate=0;
  484.             break;
  485.  
  486.         case CONUB:        /* bg underline color */
  487. #ifdef FTPBIN
  488.             Scolorset(&Smptr->ubcolor,s);
  489. #endif
  490.             Sflags[CONUB-100]=1;
  491.             constate=0;
  492.             break;
  493.  
  494.         case CONCLMODE:        /* save cleared lines */
  495.             if('N'==toupper(s[0])) 
  496.                 Smptr->clearsave=0;
  497.             else
  498.                 Smptr->clearsave=1;
  499.             Sflags[CONCLMODE-100]=1;
  500.             constate=0;
  501.             break;
  502.  
  503.         case CONPORT:        /* the port number */
  504.             i=atoi(s);
  505.             if(i<1)
  506.                 i=23;
  507.             Smptr->port=i;
  508.             Sflags[CONPORT-100]=1;
  509.             constate=0;
  510.             break;
  511.  
  512.         case CONFTPBAK:        /* the options for the ftp command line */
  513.             constate=0;
  514.             Smptr->ftpoptions=malloc(position);
  515.             if(Smptr->ftpoptions==NULL) {    /* check for bad allocate */
  516.                 Serrline(901);
  517.                 return(0);              /* don't die - helps backward compatibility */
  518.               } /* end if */
  519.             strcpy(Smptr->ftpoptions,s);
  520.             Sflags[CONFTPBAK-100]=1;
  521.             break;
  522.  
  523.         case CONDEBUGCONSOLE:     /* the debugging level for console output */
  524.             constate=0;
  525.             i=atoi(s);
  526.             if(i<0)
  527.                 i=0;
  528.             else if(i>3)
  529.                 i=3;
  530.             Smptr->consoledebug=i;
  531.             Sflags[CONDEBUGCONSOLE-100]=1;
  532.             break;
  533.  
  534.         case CONMAPOUTPUT:     /* the output mapping flag for each machine */
  535.             if('Y'==toupper(s[0]))
  536.                 Smptr->mapoutflag=1;
  537.             else
  538.                 Smptr->mapoutflag=0;
  539.             Sflags[CONMAPOUTPUT-100]=1;
  540.             constate=0;
  541.             break;
  542.  
  543. /*
  544. *  now the one-time entries
  545. *  Generally this information goes into the "Scon" structure for later
  546. *  retrieval by other routines.
  547. *
  548. */
  549.         case CONNDOM:                /* DOMAIN number of retries */
  550.             i=atoi(s);
  551.             if(i>1)
  552.                 Scon.ndom=i;
  553.             constate=0;
  554.             break;
  555.  
  556.         case CONMASK:        /* the subnet mask */
  557.             if(4!=sscanf(s,"%d.%d.%d.%d",&a,&b,&c,&d)) {
  558.                 Serrline(907);
  559.                 return(3);
  560.               }
  561.             Scon.netmask[0]=(char)a;
  562.             Scon.netmask[1]=(char)b;
  563.             Scon.netmask[2]=(char)c;
  564.             Scon.netmask[3]=(char)d;
  565.             Scon.havemask=1;
  566.             constate=0;
  567.             break;
  568.  
  569.         case CONMYIP:        /* what my ip number is */
  570.             constate=0;
  571.             if(!ncstrcmp(s,"rarp")) {
  572.                 movebytes(Scon.myipnum,s,4);
  573.                 netsetip("RARP");
  574.                 break;
  575.               }
  576.             if(!ncstrcmp(s,"bootp")) {
  577.                 movebytes(Scon.myipnum,s,4);
  578.                 netsetip("BOOT");
  579.                 break;
  580.               }
  581. #ifdef    NETX25
  582.             if(!ncstrcmp(s,"x25")) {
  583.                 movebytes(Scon.myipnum,s,3);
  584.                 netsetip("X25");
  585.                 break;
  586.               }
  587. #endif
  588.             if(4!=sscanf(s,"%d.%d.%d.%d",&a,&b,&c,&d)) {
  589.                 Serrline(908);
  590.                 return(3);
  591.               }
  592.             Scon.myipnum[0]=(char)a;     /* put number back in s */
  593.             Scon.myipnum[1]=(char)b;
  594.             Scon.myipnum[2]=(char)c;
  595.             Scon.myipnum[3]=(char)d;
  596.             netsetip(Scon.myipnum);        /* make permanent set */
  597.             break;
  598.  
  599.         case CONHPF:                /* File name for HP dump */
  600.             constate=0;
  601.             break;
  602.  
  603.         case CONPSF:                /* File name for PS dump */
  604.             constate=0;
  605.             break;
  606.  
  607.         case CONTEKF:                /* File name for Tek dump */
  608.             constate=0;
  609.             break;
  610.  
  611.         case CONME:                /* what my name is */
  612.             strncpy(Scon.me,s,30);
  613.             Scon.me[30]='\0';
  614.             constate=0;
  615.             break;
  616.  
  617.         case CONCCOL:        /* set all the colors */
  618.             for(i=0; i<3; i++)
  619.                 Scon.color[i]=(unsigned char) (((s[i*2]-48)<<4)+(s[i*2+1]-48));
  620.             constate=0;
  621.             break;
  622.  
  623.         case CONHW:            /* what hardware are we using? */
  624.             i=strlen(s);
  625.             if(i>9) i=9;
  626.             s[i]='\0';
  627.             i--;
  628.             while(i--)
  629.                 s[i]=(char)tolower((int)s[i]);
  630.             strcpy(Scon.hw,s);
  631.             constate=0;
  632.             break;
  633.  
  634.         case CONADDR:        /* segment address for board */
  635.             sscanf(s,"%x",&i);
  636.             Scon.address=i;
  637.             constate=0;
  638.             break;
  639.  
  640.         case CONIOA:        /* io address for board */
  641.             sscanf(s,"%x",&i);
  642.             Scon.ioaddr=i;
  643.             constate=0;
  644.             break;
  645.  
  646.         case CONDEF:                        /* default domain */
  647.             constate=0;
  648.             Scon.defdom=malloc(position);   /* space for name */
  649.             if(Scon.defdom==NULL) {    /* check for bad allocate */
  650.                 Serrline(901);
  651.                 return(0);              /* don't die - helps backward compatibility */
  652.               } /* end if */
  653.             strcpy(Scon.defdom,s);          /* copy it in */
  654.             break;
  655.  
  656.         case CONINT:            /* what IRQ to use */
  657.             sscanf(s,"%x",&i);
  658.             Scon.irqnum=(char)i;
  659.             constate=0;
  660.             break;
  661.  
  662.         case CONBIOS:        /* use BIOS screen writes */
  663.             if(toupper(*s)=='Y') {
  664.                 Scwritemode(0);
  665.                 Scon.bios=1;
  666.               }
  667.             constate=0;
  668.             break;
  669.  
  670.         case CONTEK:    /* whether to support tek graphics */
  671.             constate=0;
  672.             break;
  673.  
  674.         case CONVIDEO:        /* what type of screen we have */
  675.             i=strlen(s);
  676.             if(i>9)
  677.                 i=9;
  678.             s[i]='\0';
  679.             if(!strcmp(s,"ega43") || !strcmp(s,"vga50") ) {        /* check for special video modes */
  680.                 if(!strcmp(s,"ega43")) {
  681.                     Scon.ega43=1;
  682.                     strcpy(s,"ega");
  683.                  }    /* end if */
  684.                 else{
  685.                     Scon.ega43=2;
  686.                     strcpy(s,"vga");
  687.                 }
  688.             }
  689.             strcpy(Scon.video,s);
  690.             i--;
  691.             while(i--)
  692.                 s[i]=(char)tolower((int)s[i]);
  693.             constate=0;
  694.             break;
  695.  
  696.         case CONFTP:        /* is ftp enabled? */
  697.             if(toupper(*s)=='N') 
  698.                 Scon.ftp=0;    
  699.             constate=0;
  700.             break;
  701.  
  702.         case CONRCP:    /* is rcp enabled? */
  703.             if(toupper(*s)=='N')
  704.                 Scon.rcp=0;
  705.             constate=0;
  706.             break;
  707.  
  708.         case CONPASS:        /* do we need a password for ftp? */
  709.             constate=0;
  710.             Scon.pass=malloc(position); /* space for name */
  711.             if(Scon.pass==NULL) {    /* check for bad allocate */
  712.                 Serrline(901);
  713.                 return(0);              /* don't die - helps backward compatibility */
  714.               } /* end if */
  715.             strcpy(Scon.pass,s);            /* copy it in */
  716.             break;
  717.  
  718.         case CONCAP:    /* capture file name */
  719.             constate=0;
  720.             break;
  721.  
  722.         case CONTTYPE:        /* what terminal type to emulate */
  723.             constate=0;
  724.             Scon.termtype=malloc(position);
  725.             if(Scon.termtype==NULL) {    /* check for bad allocate */
  726.                 Serrline(901);
  727.                 return(0);              /* don't die - helps backward compatibility */
  728.               } /* end if */
  729.             strcpy(Scon.termtype,s);
  730.             break;
  731.  
  732.         case CONFROM:    /* copy the rest from another entry in the table */
  733.             Scopyfrom(s);
  734.             Sflags[0]=1;    /* indicate did copy from */
  735.             constate=0;
  736.             break;
  737.  
  738.         case CONARPTO:    /* need to lengthen arp time-out (secs) */
  739.             i=atoi(s);
  740.             if(i>0)
  741.                 netarptime(i);
  742.             constate=0;
  743.             break;
  744.  
  745.         case CONZONE:        /* the appletalk zone we are in */
  746. #ifdef KIPCARD
  747.             KIPsetzone(s);
  748. #endif
  749.             constate=0;
  750.             break;
  751.  
  752.         case CONDOMTO:                /* DOMAIN timeout value */
  753.             i=atoi(s);
  754.             if(i>1)
  755.                 Scon.domto=i;
  756.             constate=0;
  757.             break;
  758.  
  759.         case CONKBFILE:                /* File name for alternate keyboard map */
  760.             constate=0;
  761.             break;
  762.  
  763.         case CONWIRE:            /* set the wire type for 3C503 board */
  764.             if(!strcmp(s,"thick"))
  765.                 Scon.wire=0;
  766.             if(!strcmp(s,"thin"))
  767.                 Scon.wire=1;
  768.             constate=0;
  769.             break;
  770.  
  771.         case CONCURSORTOP:        /* what scan line the cursor starts on */
  772.             Scon.cursortop=atoi(s);
  773.             constate=0;
  774.             break;
  775.  
  776.         case CONCURSORBOTTOM:    /* what scan line the cursor ends on */
  777.             Scon.cursorbottom=atoi(s);
  778.             constate=0;
  779.             break;
  780.  
  781.         case CONWINDOWGOAWAY:    /* whether windows go away when they close, or whether they wait for a keypress */
  782.             if(toupper(*s)=='Y')
  783.                 Scon.wingoaway=1;
  784.             if(toupper(*s)=='N')
  785.                 Scon.wingoaway=0;
  786.             constate=0;
  787.             break;
  788.  
  789.         case CONAUTOSCROLL:        /* do we automatically scroll in scrollback */
  790.             if(!strcmp(s,"no"))
  791.                 Scon.autoscroll=0;
  792.             else
  793.                 Scon.autoscroll=1;
  794.             constate=0;
  795.             break;
  796.  
  797.         case CONCLOCK:            /* display the clock? */
  798.             if(!strcmp(s,"no") || !strcmp(s,"off"))
  799.                 Scon.clock=0;
  800.             else
  801.                 Scon.clock=1;
  802.             constate=0;
  803.             break;
  804.  
  805.         case CONBROADCAST:        /* broadcast IP number for network */
  806.             if(4!=sscanf(s,"%d.%d.%d.%d",&a,&b,&c,&d)) {
  807.                 Serrline(908);
  808.                 return(3);
  809.               }
  810.             Scon.broadip[0]=(char)a;     /* keep number */
  811.             Scon.broadip[1]=(char)b;
  812.             Scon.broadip[2]=(char)c;
  813.             Scon.broadip[3]=(char)d;
  814.             constate=0;
  815.             break;
  816.  
  817.         case CONOUTPUTMAP:           /* File name for alternate output mapping */
  818.             constate=0;
  819.             break;
  820.  
  821.         case CONBEEP:   /* turn musical note on */
  822.             constate=0;
  823.             break;
  824.  
  825.         case CONSERVICES:        /* path to services file */
  826.             constate=0;
  827.             break;
  828.  
  829.         default:
  830.             constate=0;
  831.             break;
  832.       }
  833.     return(0);
  834. }
  835.  
  836. /************************************************************************/
  837. /*  Scopyfrom
  838. *   Look at the Sflags array to determine which elements to copy from
  839. *   a previous machine's entries.  If a machine name as been given as
  840. *   "default", the state machine will fill in the fields from that
  841. *   machine's entries.
  842. *
  843. *   If the machine name to copyfrom is not present in the list, set the
  844. *   program default values for each field.
  845. */
  846. void Scopyfrom(char *s)
  847. {
  848.     struct machinfo *m;
  849.     int i;
  850.  
  851.     m=Shostlook(s);            /* search list */
  852.  
  853.     for(i=3; i<=NUMSPECS-100; i++)         /* through list of parms */
  854.         if(!Sflags[i]) {
  855.             if(m)                             /* copy old value */
  856.                 switch(100+i) {
  857.                     case CONHOST:
  858.                         Smptr->hname=m->hname;
  859.                         break;
  860.  
  861.                     case CONIP:
  862.                         movebytes(Smptr->hostip,m->hostip,4);
  863.                         Smptr->mstat=m->mstat;
  864.                         break;
  865.  
  866.                     case CONGATE:            /* gateways cannot be copied from */
  867.                         Smptr->gateway=0;
  868.                         break;
  869.  
  870.                     case CONNS:                    /* can't copy nameservers either */
  871.                         Smptr->nameserv=0;
  872.                         break;
  873.  
  874.                     case CONBKSP:
  875.                         Smptr->bksp=m->bksp;
  876.                         break;
  877.  
  878.                     case CONBKSC:
  879.                         Smptr->bkscroll=m->bkscroll;
  880.                         break;
  881.  
  882.                     case CONCLMODE:
  883.                         Smptr->clearsave=m->clearsave;
  884.                         break;
  885.  
  886.                     case CONRETR:
  887.                         Smptr->retrans=m->retrans;
  888.                         break;
  889.  
  890.                     case CONWIND:
  891.                         Smptr->window=m->window;
  892.                         break;
  893.  
  894.                     case CONSEG:
  895.                         Smptr->maxseg=m->maxseg;
  896.                         break;
  897.  
  898.                     case CONMTU:
  899.                         Smptr->mtu=m->mtu;
  900.                         break;
  901.  
  902.                     case CONTO:
  903.                         Smptr->conto=m->conto;
  904.                         break;
  905.  
  906.                     case CONCRMAP:
  907.                         Smptr->crmap=m->crmap;
  908.                         break;
  909.  
  910.                     case CONDUP:
  911.                         Smptr->halfdup=m->halfdup;
  912.                         break;
  913.  
  914.                     case CONWRAP:
  915.                         Smptr->vtwrap=m->vtwrap;
  916.                         break;
  917.  
  918.                     case CONWIDE:
  919.                         Smptr->vtwidth=m->vtwidth;
  920.                         break;
  921.  
  922.                     case CONNF:
  923.                         Smptr->nfcolor=m->nfcolor;
  924.                         break;
  925.  
  926.                     case CONNB:
  927.                         Smptr->nbcolor=m->nbcolor;
  928.                         break;
  929.  
  930.                     case CONBF:
  931.                         Smptr->bfcolor=m->bfcolor;
  932.                         break;
  933.  
  934.                     case CONBB:
  935.                         Smptr->bbcolor=m->bbcolor;
  936.                         break;
  937.  
  938.                     case CONUF:
  939.                         Smptr->ufcolor=m->ufcolor;
  940.                         break;
  941.  
  942.                     case CONUB:
  943.                         Smptr->ubcolor=m->ubcolor;
  944.                         break;
  945.  
  946.                     case CONFONT:
  947.                         Smptr->font=m->font;
  948.                         break;
  949.  
  950.                     case CONFSIZE:
  951.                         Smptr->fsize=m->fsize;
  952.                         break;
  953.  
  954.                     case CONPORT:
  955.                         Smptr->port=m->port;
  956.                         break;
  957.  
  958.                     case CONFTPBAK:
  959.                         Smptr->ftpoptions=m->ftpoptions;
  960.                         break;
  961.  
  962.                     case CONDEBUGCONSOLE:
  963.                         Smptr->consoledebug=m->consoledebug;
  964.                         break;
  965.  
  966.                     case CONMAPOUTPUT:
  967.                         Smptr->mapoutflag=m->mapoutflag;
  968.                         break;
  969.  
  970.                     default:
  971.                         break;
  972.                   }    /* end switch */
  973.             else
  974.                 switch(100+i) {        /* m=NULL, install default values */
  975.                     case CONHOST:
  976.                         Smptr->hname=NULL;
  977.                         break;
  978.  
  979.                     case CONIP:
  980.                         Smptr->mstat=NOIP;
  981.                         break;
  982.  
  983.                     case CONGATE:            /* gateways cannot be copied from */
  984.                         Smptr->gateway=0;
  985.                         break;
  986.  
  987.                     case CONBKSP:
  988.                         Smptr->bksp=127;
  989.                         break;
  990.  
  991.                     case CONBKSC:
  992.                         Smptr->bkscroll=0;
  993.                         break;
  994.  
  995.                     case CONCLMODE:
  996.                         Smptr->clearsave=1;
  997.                         break;
  998.  
  999.                     case CONRETR:
  1000.                         Smptr->retrans=SMINRTO;
  1001.                         break;
  1002.  
  1003.                     case CONWIND:
  1004.                         Smptr->window=DEFWINDOW;
  1005.                         break;
  1006.  
  1007.                     case CONSEG:
  1008.                         Smptr->maxseg=DEFSEG;
  1009.                         break;
  1010.  
  1011.                     case CONMTU:
  1012.                         Smptr->mtu=TSENDSIZE;
  1013.                         break;
  1014.  
  1015.                     case CONNS:                    /* can't copy nameservers either */
  1016.                         Smptr->nameserv=0;
  1017.                         break;
  1018.  
  1019.                     case CONTO:
  1020.                         Smptr->conto=CONNWAITTIME;
  1021.                         break;
  1022.  
  1023.                     case CONCRMAP:
  1024.                         Smptr->crmap=10;
  1025.                         break;
  1026.  
  1027.                     case CONDUP:
  1028.                         Smptr->halfdup=0;
  1029.                         break;
  1030.  
  1031.                     case CONWRAP:
  1032.                         Smptr->vtwrap=0;
  1033.                         break;
  1034.  
  1035.                     case CONWIDE:
  1036.                         Smptr->vtwidth=80;
  1037.                         break;
  1038.  
  1039.                     case CONNF:
  1040.                         Smptr->nfcolor=NFDEF;
  1041.                         break;
  1042.  
  1043.                     case CONNB:
  1044.                         Smptr->nbcolor=NBDEF;
  1045.                         break;
  1046.  
  1047.                     case CONBF:
  1048.                         Smptr->bfcolor=BFDEF;
  1049.                         break;
  1050.  
  1051.                     case CONBB:
  1052.                         Smptr->bbcolor=BBDEF;
  1053.                         break;
  1054.  
  1055.                     case CONUF:
  1056.                         Smptr->ufcolor=UFDEF;
  1057.                         break;
  1058.  
  1059.                     case CONUB:
  1060.                         Smptr->ubcolor=UBDEF;
  1061.                         break;
  1062.  
  1063.                     case CONFONT:
  1064.                         Smptr->font="Monaco";
  1065.                         break;
  1066.  
  1067.                     case CONFSIZE:
  1068.                         Smptr->fsize=9;
  1069.                         break;
  1070.  
  1071.                     case CONPORT:
  1072.                         Smptr->port=23;            /* the telnet port */
  1073.                         break;
  1074.  
  1075.                     case CONFTPBAK:
  1076.                         Smptr->ftpoptions=NULL;
  1077.                         break;
  1078.  
  1079.                     case CONDEBUGCONSOLE:
  1080.                         Smptr->consoledebug=0;
  1081.                         break;
  1082.  
  1083.                     case CONMAPOUTPUT:      /* output mapping flag */
  1084.                         Smptr->mapoutflag=0;
  1085.                         break;
  1086.  
  1087.                     default:
  1088.                         break;
  1089.                   }    /* end switch */
  1090.           }    /* end if */
  1091.     Sflags[0]=1;                    /* set that this machine was copied */
  1092. }   /* end Scopyfrom() */
  1093.  
  1094. #ifdef NEEDIT
  1095. /************************************************************************/
  1096. /*  Smadd
  1097. *   If machine is there, just returns pointer, else
  1098. *   Add a machine to the list. Increments machine number of machine.
  1099. *   Puts in parameters copied from the "default" entry.
  1100. *
  1101. */
  1102. struct machinfo *Smadd(char *mname)
  1103. {
  1104.     int i;
  1105.     struct machinfo *m;
  1106. /*
  1107. *  First, do we have the name already?
  1108. */
  1109.     m=Shostlook(mname);
  1110.     if(m)
  1111.         return(m);
  1112. /*
  1113. *   Don't have name, add another record
  1114. */
  1115.     Smptr=(struct machinfo *)malloc(sizeof(struct machinfo));
  1116.     if(Smptr==NULL)
  1117.         return(NULL);
  1118.     for(i=0; i<NUMSPECS-99; i++)
  1119.         Sflags[i]=0;                    /* we have no parms */
  1120.     Scopyfrom("default");
  1121.     Smptr->sname=NULL;
  1122.     Smptr->hname=malloc(strlen(mname)+1);
  1123.     if(Smptr->hname)
  1124.         strcpy(Smptr->hname,mname);        /* copy in name of machine */
  1125.     Smptr->mno=++mno;
  1126.     Smptr->mstat=NOIP;
  1127.     Smptr->next=Smachlist;            /* add to front of machlist */
  1128.     Smachlist=Smptr;
  1129.     return(Smptr);
  1130. }
  1131. #endif /*NEDDIT*/
  1132.  
  1133. /************************************************************************/
  1134. /* Shostfile
  1135. *   if the user wants to change the host file name from 'config.tel' to
  1136. *   something else.
  1137. */
  1138. void Shostfile(char *ptr)
  1139. {
  1140.     Smachfile=ptr;    
  1141. /*
  1142. *  note that the area with the file name must stay allocated for
  1143. *  later reference, typically it is in some argv[] parm.
  1144. */
  1145. }
  1146.  
  1147. #ifdef OLD_WAY
  1148. /************************************************************************/
  1149. /* Shostpath
  1150. *   if the user wants to change the host path name
  1151. */
  1152. void Shostpath(char *ptr)
  1153. {
  1154.     Smachpath=ptr;
  1155. /*
  1156. *  note that the area with the file name must stay allocated for
  1157. *  later reference, typically it is in some argv[] parm.
  1158. */
  1159. }
  1160. #endif
  1161.  
  1162.  
  1163. /************************************************************************/
  1164. /*  get host by name
  1165. *   Given the name of a host machine, search our database to see if we
  1166. *   have that host ip number.  Search first the name field, and then the
  1167. *   hostname field.  If the IP # is given, returns a ptr to the
  1168. *   default machine record with that IP # installed.
  1169. *   Returns the pointer to a valid record, or NULL if the IP # cannot
  1170. *   be deciphered.  
  1171. */
  1172. struct machinfo *Sgethost(char *machine)
  1173. {
  1174.     int i,j,k,l;
  1175.     unsigned char ipto[4],myipnum[4],xmask[4];
  1176.     unsigned long hnum;
  1177.     struct machinfo *m=NULL;
  1178.  
  1179. /*
  1180. *  First, check for the pound sign character which means we should use
  1181. *  the current netmask to build an IP number for the local network.
  1182. *  Take the host number, install it in the ipto[] array.  Then mask
  1183. *  in my IP number's network portion to build the final IP address.
  1184. */
  1185.     if('#'==machine[0]) {        /* on my local network */
  1186.         netgetip(myipnum);
  1187.         netgetmask(xmask);            /* mask of network portion of IP # */
  1188.         sscanf(&machine[1],"%ld",&hnum);/* host number for local network */
  1189.         for(i=3; i>=0; i--)
  1190.             ipto[i]=(unsigned char)((hnum>>(i*8)) & 255L);    /* take off a byte */
  1191.         for(i=0; i<4; i++) 
  1192.             ipto[i] |= (myipnum[i] & xmask[i]);        /* mask new one in */
  1193.       }
  1194. /*
  1195. *  next, is it an IP number?  We take it if the number is in four
  1196. *  parts, separated by periods.
  1197. */
  1198.     else 
  1199.         if(4==sscanf(machine,"%d.%d.%d.%d",&i,&j,&k,&l)) {    /* given ip num */
  1200.             ipto[0]=(unsigned char)i;
  1201.             ipto[1]=(unsigned char)j;
  1202.             ipto[2]=(unsigned char)k;
  1203.             ipto[3]=(unsigned char)l;
  1204.           }
  1205. /*
  1206. *  lastly, it must be a name, first check the local host table
  1207. *  A first number of 127 means that it doesn't have an IP number, but
  1208. *  is in the table(strange occurrence)
  1209. */
  1210.         else {                                    /* look it up */
  1211.             m=Shostlook(machine);
  1212.             if(m==NULL) {
  1213.                 netposterr(805);            /* informative */
  1214.                 return(NULL);
  1215.               } 
  1216.             if(m->mstat<HAVEIP) {
  1217.                 netposterr(806);            /* informative */
  1218.                 return(NULL);
  1219.               }
  1220.           }
  1221.     if(!m) {
  1222.         m=Shostlook("default");
  1223.         movebytes(m->hostip,ipto,4);        /* copy in newest host # */
  1224.         m->mstat=HAVEIP;                    /* we have the IP # */
  1225.       }
  1226.     return(m);
  1227. }
  1228.  
  1229. #ifdef NEEDIT
  1230. /************************************************************************/
  1231. /*  Shostlook
  1232. *   The straightforward list searcher.  Looks for either the
  1233. *   session name matching or the host name matching.  NULL if neither.
  1234. */
  1235. struct machinfo *Shostlook(char *hname)
  1236. {
  1237.     struct machinfo *m;
  1238.  
  1239.     m=Smachlist;
  1240.     while(m!=NULL) {
  1241.         if((m->sname && !ncstrcmp(hname,m->sname)) || (m->hname && !ncstrcmp(hname,m->hname)))
  1242.             return(m);
  1243.         m=m->next;
  1244.       }
  1245.     return(NULL);
  1246. }
  1247.  
  1248. /************************************************************************/
  1249. /*  Slooknum
  1250. *   get the host record by machine number, used primarily in DOMAIN name
  1251. *   lookup.
  1252. */
  1253. struct machinfo *Slooknum(int num)
  1254. {
  1255.     struct machinfo *m;
  1256.  
  1257.     m=Smachlist;
  1258.     while(m) {
  1259.         if(m->mno==num)
  1260.             return(m);
  1261.         m=m->next;
  1262.       }
  1263.     return(NULL);
  1264. }
  1265.  
  1266. /**************************************************************************/
  1267. /*  Slookip
  1268. *   For FTP to look up the transfer options to use when running
  1269. *
  1270. */
  1271. struct machinfo *Slookip(unsigned char *ipnum)
  1272. {
  1273.     struct machinfo *m;
  1274.  
  1275.     m=Smachlist;
  1276.     while(m) {
  1277.         if(comparen(m->hostip,ipnum,4))
  1278.             return(m);
  1279.         m=m->next;
  1280.       }
  1281.     return(NULL);
  1282. }
  1283.  
  1284. #endif /*NEEDIT*/
  1285. /**************************************************************************/
  1286. /*  Sissep
  1287. *   is the character a valid separator for the hosts file?
  1288. *   separators are white space, special chars and :;=
  1289. *
  1290. */
  1291. int Sissep(int c)
  1292. {
  1293.     if(c<33 || c==':' || c==';' || c=='=')
  1294.         return(1);
  1295.     return(0);
  1296. }
  1297.  
  1298. #ifdef NEEDIT
  1299. /*********************************************************************/
  1300. /*  Snewns()
  1301. *   Rotate to the next nameserver
  1302. *   Chooses the next highest number from the nameserv field
  1303. */
  1304. int Snewns(void)
  1305. {
  1306.     struct machinfo *m,*low;
  1307.     int i;
  1308.  
  1309.     if(!Sns)                    /* safety, should never happen */
  1310.         Sns=Smachlist;
  1311.     low=Sns;
  1312.     i=Sns->nameserv;            /* what is value now? */
  1313.     m=Smachlist;
  1314.     while(m) {
  1315.         if(m->nameserv==(unsigned char)i+1) {
  1316.             Sns=m;
  1317.             return(0);
  1318.           }
  1319.         if((m->nameserv>0) && (m->nameserv<low->nameserv))
  1320.             low=m;
  1321.         m=m->next;
  1322.       }
  1323.     if(Sns==low)
  1324.         return(1);                /* no alternate */
  1325.     else
  1326.         Sns=low;
  1327.     return(0);
  1328. }
  1329. #endif /*NEEDIT*/
  1330.  
  1331. /************************************************************************/
  1332. /*  Ssetgates
  1333. *   set up the gateway machines and the subnet mask after netinit()
  1334. *   and start up ftp and rcp for them.
  1335. */
  1336. void Ssetgates(void)
  1337. {
  1338.     struct machinfo *m;
  1339.     int level,again;
  1340.  
  1341.     if(Scon.havemask) {                    /* leave default unless specified */
  1342.         netsetmask(Scon.netmask);
  1343.       }    /* end if */
  1344. /*
  1345. *  Search the list of machines for gateway flags.
  1346. *  Invoke netsetgate in increasing order of gateway level #s.
  1347. *  Terminates when it gets through list without finding next higher number.
  1348. */
  1349.     level=0;
  1350.     do {
  1351.         level++;
  1352.         again=0;
  1353.         m=Smachlist;
  1354.         while(m!=NULL) {
  1355.             if(m->gateway==(unsigned char)level && m->mstat>=HAVEIP) {
  1356.                 netsetgate(m->hostip);
  1357.               }    /* end if */
  1358.             if((m->gateway)==(unsigned char)(level+1))
  1359.                 again=1;
  1360.             m=m->next;
  1361.           }
  1362.       } while(again);
  1363.     Sftpmode(Scon.ftp);
  1364.     Srcpmode(Scon.rcp);
  1365. }
  1366.  
  1367. /**********************************************************************
  1368. *  Function    :    pfopen
  1369. *  Purpose    :    open the file in the current directory, and if it is not
  1370. *                there, then search the DOS PATH variable for it
  1371. *  Parameters    :
  1372. *            name - the filename to open
  1373. *            mode - the mode to open the file in (see fopen())
  1374. *  Returns    :    a pointer to a FILE, or NULL for file not found
  1375. *  Calls    :    getenv(), fopen()
  1376. *  Called by    :    Sreadhosts()
  1377. **********************************************************************/
  1378. static FILE *pfopen(char *name,char *mode)
  1379. {
  1380.     char *path,                /* pointer to the PATH variable in the environment */
  1381.         filename[80],        /* storage for the pathes in the PATH variable */
  1382.         *fn;                /* temporary pointer to filename[] */
  1383.     FILE *fp;                /* pointer to the FILE opened */
  1384.  
  1385.     if((fp=fopen(name,mode))!=NULL)    /* check for the file being in the current directory */
  1386.         return(fp);
  1387.     path=getenv("PATH");        /* set the pointer to the PATH environment variable */
  1388.     if(path==NULL)    /* no PATH */
  1389.         return(NULL);
  1390.     while(*path) {    /* search for the file along the path */
  1391.         fn=filename;    /* reset the filename pointer */
  1392.         while(*path!=';' && *path)    /* copy the path into the array */
  1393.             *fn++=*path++;
  1394.         strcpy(fn,name);    /* append the name to the path */
  1395.         if((fp=fopen(filename,mode))!=NULL)    /* check for the file in that path */
  1396.             return(fp);
  1397.         if(*path)    /* skip the ';' */
  1398.             path++;
  1399.       }    /* end while */
  1400.     return(NULL);    /* file not on the path either */
  1401. }    /* end pfopen() */
  1402.  
  1403.