home *** CD-ROM | disk | FTP | other *** search
/ ProfitPress Mega CDROM2 …eeware (MSDOS)(1992)(Eng) / ProfitPress-MegaCDROM2.B6I / MISC / NETWORK / TEL23SRC.ZIP / ENGINE / UTIL.C < prev   
Encoding:
C/C++ Source or Header  |  1991-07-22  |  18.3 KB  |  846 lines

  1. /*
  2. *    UTIL.C
  3. *
  4. *    Session interface routines ( use these in user interface )
  5. *
  6. *****************************************************************************
  7. *                                                                            *
  8. *      part of:                                                                *
  9. *     TCP/IP kernel for NCSA Telnet                                            *
  10. *      by Tim Krauskopf                                                        *
  11. *                                                                            *
  12. *      National Center for Supercomputing Applications                        *
  13. *      152 Computing Applications Building                                    *
  14. *      605 E. Springfield Ave.                                                *
  15. *      Champaign, IL  61820                                                    *
  16. *                                                                            *
  17. *    Copyright (c) 1987, Board of Trustees of the University of Illinois     *
  18. *                                                                            *
  19. *****************************************************************************
  20. *
  21. *    Revision history:
  22. *
  23. *    10/87  Initial source release, Tim Krauskopf
  24. *    5/88    clean up for 2.3 release, JKM    
  25. *
  26. */
  27.  
  28. /*
  29. *    Includes
  30. */
  31. /* #define DEBUG /* define for debug printfs */
  32. #include "debug.h"
  33.  
  34. #include <stdio.h>
  35. #include <string.h>
  36. #include <stdlib.h>
  37. #if defined(MSC)
  38. #include <malloc.h>
  39. #endif
  40. #if defined(MSC) || defined(__TURBOC__)
  41. #include <conio.h>
  42. #include <io.h>
  43. #endif
  44. #ifdef MEMORY_DEBUG
  45. #include "memdebug.h"
  46. #endif
  47. #include "whatami.h"
  48. #include "hostform.h"
  49. #include "protocol.h"
  50. #include "data.h"
  51. #include "externs.h"
  52. #include "confile.h"            /* include the configuration variables and definitions, but we are not CONFIG_MASTER */
  53.  
  54. /*
  55. *#define    NETX25    0
  56. */
  57.  
  58. static unsigned char *Ssstemps[]={    /* standard output files */
  59.     "capfile",
  60.     "hp.out",
  61.     "ps.out",
  62.     "tek.out"
  63. };
  64.  
  65. char Sptypes[NPORTS];                    /* port types assigned for session use */
  66. extern struct config Scon;                /* hardware configuration */
  67. extern int ftpdata;                        /* current ftp data port */
  68. #define NTIMES 30                        /* size of timer queue */
  69.  
  70. /*
  71. *  timer queue of events which will be placed into the event queue
  72. *  when the time is up.
  73. */
  74. static struct {
  75.     unsigned char eclass,                /* event queue data */
  76.         event;
  77.     int next,                            /* next item in list */
  78.         idata;
  79.     int32 when;                            /* when timer is to go off */
  80. } Stq[NTIMES];
  81.  
  82. static int Stfirst,
  83.         Stfree;                            /* pointers for timer queue */
  84.  
  85. #define PFTP 1
  86. #define PRCP 2
  87. #define PDATA 3
  88. #define PDOMAIN 4
  89.  
  90. /************************************************************************/
  91. /*
  92. *    Snetinit ()
  93. *
  94. *    Handle all the network initialization, including reading up the config
  95. * file.  This also starts up the hardware and gets arps on their merry way.
  96. *
  97. */
  98. int Snetinit(void )
  99. {
  100.     int i;
  101. BUG("Snetinit");
  102. /*
  103. *  set up the file names
  104. */
  105.     Scon.capture=Ssstemps[0];
  106.     Scon.hpfile=Ssstemps[1];
  107.     Scon.psfile=Ssstemps[2];
  108.     Scon.tekfile=Ssstemps[3];
  109.  
  110.     neteventinit();                    /* initializes for error messages to count */
  111. BUG("After neteventinit");
  112.     for(i=0; i<NPORTS; i++)
  113.         Sptypes[i]=-1;                /* clear port type flags */
  114.  
  115.     for(i=0; i<NTIMES; i++)
  116.         Stq[i].next=i+1;            /* load linked list */
  117.     Stq[NTIMES-1].next=-1;            /* anchor end */
  118.     Stfirst=-1;
  119.     Stfree=0;
  120.     BUG("About to read config file");
  121.     if(!Sreadhosts()) {             /* parses config file */
  122.         BUG("after Sreadhosts - successful");
  123. #ifdef PC
  124.         netparms(Scon.irqnum,Scon.address,Scon.ioaddr);
  125. #endif
  126. #ifdef DEBUG
  127.         printf("irqnum = %X\n",Scon.irqnum);
  128.         printf("address = %X\n",Scon.address);
  129.         printf("ioaddr = %X\n",Scon.ioaddr);
  130. #endif
  131.  
  132.         netconfig(Scon.hw);
  133.         netsetbroad(Scon.broadip);        /* set up IP broadcast address */
  134.         BUG("Before netinit");
  135.         if((i=netinit())==0) {          /* starts up hardware */
  136.             BUG("After netinit - successful");
  137. /*
  138. *  Check for the need to RARP and do it
  139. */
  140.             netgetip(Scon.myipnum);    /* get stored ip num */
  141.             BUG("have ip");
  142.             if(comparen(Scon.myipnum,"RARP",4)) {    /* need RARP */
  143.                 if(netgetrarp())    /* stores in nnipnum at lower layer */
  144.                     return(-2);            /* failure return */
  145.                 netgetip(Scon.myipnum);
  146.                 netsetip(Scon.myipnum);    
  147.             }
  148. /*
  149.  *    Check for bootp
  150.  */
  151.             if(comparen(Scon.myipnum,"BOOT",4)) {/* need BOOTP */
  152.                 BUG("BOOTP");
  153.                 if(bootp())
  154.                     return(-3);
  155.             }
  156. /*          BUG("After BOOTP");
  157.  *    Check for x25 boot
  158.  */
  159. #ifdef    NETX25
  160.             if(comparen(Scon.myipnum,"X25",3))        /* need server and buds */
  161.                 if(X25Boot())
  162.                     return(-4);
  163. #endif
  164. /*
  165. *  Give the lower layers a chance to check to see if anyone else
  166. *  is using the same ip number.  Usually generates an ARP packet.
  167. */
  168.             BUG("about to ARP");
  169.             netarpme(Scon.myipnum);
  170. #define DEBUG
  171.             BUG("arped-about to crash");
  172.             Ssetgates();            /* finishes IP inits */
  173.             BUG("about to Stask()");
  174. #undef DEBUG
  175.             Stask();
  176.             BUG("returning");
  177.             return(0);
  178.           }
  179.           BUG("After netinit - failed");
  180.         return(-1);        /* netinit() failed */
  181.       }
  182.     BUG("after Sreadhosts - failed");
  183.     return(-5);            /* Sreadhosts() failed */
  184. }
  185.  
  186. /************************************************************************/
  187. /*  Sgetconfig
  188. *   copy the configuration information into the user's data structure
  189. *   directly.  The user can do with it what he feels like.
  190. */
  191. void Sgetconfig(cp)
  192. struct config *cp;
  193. {
  194.     movebytes(cp,&Scon,sizeof(struct config));
  195. }
  196.  
  197. /************************************************************************/
  198. /*  Smadd
  199. *   If machine is there, just returns pointer, else
  200. *   Add a machine to the list. Increments machine number of machine.
  201. *   Puts in parameters copied from the "default" entry.
  202. *
  203. */
  204. struct machinfo *Smadd(mname)
  205. char *mname;
  206. {
  207.     int i;
  208.     struct machinfo *m;
  209. /*
  210. *  First, do we have the name already?
  211. */
  212.     m=Shostlook(mname);
  213.     if(m)
  214.         return(m);
  215. /*
  216. *   Don't have name, add another record
  217. */
  218.     Smptr=(struct machinfo *)malloc(sizeof(struct machinfo));
  219.     if(Smptr==NULL)
  220.         return(NULL);
  221.     for(i=0; i<NUMSPECS-99; i++)
  222.         Sflags[i]=0;                    /* we have no parms */
  223.     Scopyfrom("default");
  224.     Smptr->sname=NULL;
  225.     Smptr->hname=malloc(strlen(mname)+1);
  226.     if(Smptr->hname)
  227.         strcpy(Smptr->hname,mname);        /* copy in name of machine */
  228.     Smptr->mno=++mno;
  229.     Smptr->mstat=NOIP;
  230.     Smptr->next=Smachlist;            /* add to front of machlist */
  231.     Smachlist=Smptr;
  232.     return(Smptr);
  233. }
  234.  
  235. /*********************************************************************/
  236. /*  Snewns()
  237. *   Rotate to the next nameserver
  238. *   Chooses the next highest number from the nameserv field
  239. */
  240. int Snewns(void)
  241. {
  242.     struct machinfo *m,*low;
  243.     int i;
  244.  
  245.     if(!Sns)                    /* safety, should never happen */
  246.         Sns=Smachlist;
  247.     low=Sns;
  248.     i=Sns->nameserv;            /* what is value now? */
  249.     m=Smachlist;
  250.     while(m) {
  251.         if((m->nameserv)==(unsigned char)(i+1)) {
  252.             Sns=m;
  253.             return(0);
  254.           }
  255.         if((m->nameserv>0) && (m->nameserv<low->nameserv))
  256.             low=m;
  257.         m=m->next;
  258.       }
  259.     if(Sns==low)
  260.         return(1);                /* no alternate */
  261.     else
  262.         Sns=low;
  263.     return(0);
  264. }
  265.  
  266. /**************************************************************************/
  267. /*  Slookip
  268. *   For FTP to look up the transfer options to use when running
  269. *
  270. */
  271. struct machinfo *Slookip(ipnum)
  272. unsigned char *ipnum;
  273. {
  274.     struct machinfo *m;
  275.  
  276.     m=Smachlist;
  277.     while(m) {
  278.         if(comparen(m->hostip,ipnum,4))
  279.             return(m);
  280.         m=m->next;
  281.       }
  282.     return(NULL);
  283. }
  284.  
  285. /************************************************************************/
  286. /*  Shostlook
  287. *   The straightforward list searcher.  Looks for either the
  288. *   session name matching or the host name matching.  NULL if neither.
  289. */
  290. struct machinfo *Shostlook(hname)
  291. char *hname;
  292. {
  293.     struct machinfo *m;
  294.  
  295.     m=Smachlist;
  296.     while(m!=NULL) {
  297.         if((m->sname && !ncstrcmp(hname,m->sname)) || (m->hname && !ncstrcmp(hname,m->hname)))
  298.             return(m);
  299.         m=m->next;
  300.       }
  301.     return(NULL);
  302. }
  303.  
  304. /************************************************************************/
  305. /*  Slooknum
  306. *   get the host record by machine number, used primarily in DOMAIN name
  307. *   lookup.
  308. */
  309. struct machinfo *Slooknum(num)
  310. int num;
  311. {
  312.     struct machinfo *m;
  313.  
  314.     m=Smachlist;
  315.     while(m) {
  316.         if(m->mno==num)
  317.             return(m);
  318.         m=m->next;
  319.       }
  320.     return(NULL);
  321. }
  322.  
  323. /**************************************************************************/
  324. /*
  325. *    Snetopen ( m, tport )
  326. *
  327. *    Takes a pointer to a machine record (already looked up with Sgethost) and
  328. * sends a TCP open call.  Uses port *tport*.  
  329. *
  330. */
  331. int Snetopen(m,tport)
  332. struct machinfo *m;
  333. int tport;
  334. {
  335.     int j;
  336.  
  337.  
  338.     if(!m || m->mstat<HAVEIP)
  339.         return(-1);
  340.     j=netxopen(m->hostip,tport,m->retrans,m->mtu,m->maxseg,m->window);    /* do the open call */
  341.     if(j>=0) {
  342.         Sptypes[j]=-1;            /* is allocated to user */
  343.         Stimerset(CONCLASS,CONFAIL,j,m->conto);
  344. #ifdef OLDWAY
  345.         Stimerset(SCLASS,RETRYCON,j,m->retrans/TICKSPERSEC+2);
  346. #else
  347.         Stimerset(SCLASS,RETRYCON,j,m->retrans);
  348. #endif
  349.       }
  350.     return(j);
  351. }
  352.  
  353. /***********************************************************************/
  354. /*
  355. *    Scwritemode ( mode )
  356. *
  357. *    Set write mode
  358. *
  359. */
  360. static int son=1;
  361.  
  362. void Scwritemode(mode)
  363. int mode;
  364. {
  365.     son=mode;
  366. }
  367.  
  368. /***********************************************************************/
  369. /*
  370. *    Scmode ()
  371. *
  372. *    Return what the current mode is 
  373. *
  374. */
  375. int Scmode(void )
  376. {
  377.     return(son);
  378. }
  379.  
  380. /***********************************************************************/
  381. /*
  382. *    Stekmode ( mode )
  383. *
  384. *    Set tek mode
  385. *
  386. */
  387. static int tekon=1;
  388.  
  389. void Stekmode(mode)
  390. int mode;
  391. {
  392.     tekon=mode;
  393. }
  394.  
  395. /***********************************************************************/
  396. /*
  397. *    Stmode ()
  398. *
  399. *    Return the value of the tekmode
  400. *
  401. */
  402. int Stmode(void )
  403. {
  404.     return(tekon);
  405. }
  406.  
  407. /***********************************************************************/
  408. /*    Srcpmode ( mode )
  409. *
  410. *    Set the RCP mode either on or off, install the proper watchers
  411. *
  412. */
  413. #ifdef PC
  414. static int rcpon=1;
  415.  
  416. void Srcpmode(mode)
  417. int mode;
  418. {
  419.     rcpon=mode;
  420.     if(rcpon)
  421.         setrshd();                                /* turn on the watcher */
  422.     else
  423.         unsetrshd();                            /* turn off the watcher */
  424. }
  425.  
  426. #ifdef NOT_USED
  427. /***********************************************************************/
  428. /*
  429. *    Srmode ()
  430. *
  431. *    Return the value of the rcp flag
  432. *
  433. */
  434. int Srmode(void )
  435. {
  436.     return(rcpon);
  437. }
  438. #endif
  439. #endif
  440.  
  441. /***********************************************************************/
  442. /*
  443. *    Sftpmode ( mode )
  444. *
  445. *    Turn on or off the ftp watcher
  446. *
  447. */
  448. static int ftpon=0;
  449.  
  450. int Sftpmode(mode)
  451. int mode;
  452. {
  453.     BUG("Sftpmode");
  454.     if(ftpon && mode)
  455.         return(-1);
  456.     ftpon=mode;
  457.     if(ftpon)
  458.         setftp();                                /* set the ftp watcher */
  459.     else
  460.         unsetftp();                                /* clear the ftp watcher */
  461.     return(0);
  462. }
  463.  
  464. /***********************************************************************/
  465. /*
  466. *    Sfmode ()
  467. *
  468. *    Return whether the ftp watcher is on or off
  469. *
  470. */
  471. int Sfmode(void )
  472. {
  473.     return(ftpon);
  474. }
  475.  
  476. /***********************************************************************/
  477. /*
  478. *    Snewcap ( s )
  479. *
  480. *    Set a mew capture file name
  481. *
  482. */
  483. int Snewcap(s)
  484. char *s;
  485. {
  486.     if(NULL==(Scon.capture=malloc(strlen(s)+1)))
  487.         return(1);
  488.     strcpy(Scon.capture,s);
  489.     return(0);
  490. }
  491.  
  492. /***********************************************************************/
  493. /*
  494. *    Snewps ( s )
  495. *
  496. *    Set a new postscript file name
  497. *
  498. */
  499. int Snewpsfile(s)
  500. char *s;
  501. {
  502.     if(NULL==(Scon.psfile=malloc(strlen(s)+1)))
  503.         return(1);
  504.     strcpy(Scon.psfile,s);
  505.     return(0);
  506. }
  507.  
  508. /***********************************************************************/
  509. /*
  510. *    Snewhpfile ( s )
  511. *
  512. *    Set a new HPGL file name
  513. *
  514. */
  515. int Snewhpfile(s)
  516. char *s;
  517. {
  518.     if(NULL==(Scon.hpfile=malloc(strlen(s)+1)))
  519.         return(1);
  520.     strcpy(Scon.hpfile,s);
  521.     return(0);
  522. }
  523.  
  524. /***********************************************************************/
  525. /*
  526. *    Snewtekfile ( s )
  527. *
  528. *    Set a new tek file name
  529. *
  530. */
  531. int Snewtekfile(s)
  532. char *s;
  533. {
  534.     if(NULL==(Scon.tekfile=malloc(strlen(s)+1)))
  535.         return(1);
  536.     strcpy(Scon.tekfile,s);
  537.     return(0);
  538. }
  539.  
  540. /***********************************************************************/
  541. /*
  542. *    Sopencap ()
  543. *
  544. *    Returns a file handle to an open capture file
  545. *
  546. */
  547. FILE *Sopencap(void )
  548. {
  549.     FILE *retfp;
  550.  
  551.     if(NULL==(retfp=fopen(Scon.capture,"ab"))) 
  552.         return(NULL);
  553.     fseek(retfp,0L,2);        /* seek to end */
  554.     return(retfp);
  555. }
  556.  
  557. /**************************************************************************/
  558. /*
  559. *    Stask ()
  560. *    A higher level version of net sleep -- manages the timer queue.  Always
  561. * call this in your main loop.
  562. *
  563. */
  564. static int32 recent=0L;
  565.  
  566. void Stask(void)
  567. {
  568.     long t;
  569.     int i;
  570.  
  571.     netsleep(0);
  572. /*
  573. *  Check the timer queue to see if something should be posted
  574. *  First check for timer wraparound
  575. */
  576.  
  577.     t=n_clicks();
  578.     if(t<recent) {
  579.         i=Stfirst;
  580.         while(i>=0) {
  581.             Stq[i].when-=WRAPTIME;
  582.             i=Stq[i].next;
  583.           }
  584.       }
  585.     recent=t;                            /* save most recent time */
  586.     while (Stfirst>=0 && t> Stq[Stfirst].when) {    /* Q is not empty and timer is going off */
  587.         i=Stfirst;
  588.         netputevent(Stq[i].eclass,Stq[i].event,Stq[i].idata);
  589.         Stfirst=Stq[Stfirst].next;    /* remove from q */
  590.         Stq[i].next=Stfree;
  591.         Stfree=i;                        /* add to free list */
  592.       }
  593. }
  594.  
  595. /**************************************************************************/
  596. /*
  597. *    Stimerset ( class, event, dat, howlong )
  598. *
  599. *    Set an async timer which is checked in Stask -- when time elapses sticks
  600. * an event in the network event queue
  601. *
  602. *    class, event, dat is what gets posted when howlong times out.
  603. *
  604. */
  605. int Stimerset(class,event,dat,howlong)
  606. int class,event,dat,howlong;
  607. {
  608.     int i,j,jlast,retval;
  609.     int32 gooff;
  610.  
  611.     retval=0;
  612.     gooff=n_clicks()+howlong;
  613.     if(Stfree<0) {                /* queue is full, post first event */
  614.         Stfree=Stfirst;
  615.         Stfirst=Stq[Stfirst].next;
  616.         Stq[Stfree].next=-1;
  617.         netputevent(Stq[Stfree].eclass,Stq[Stfree].event,Stq[Stfree].idata);
  618.         retval=-1;
  619.       }
  620.     Stq[Stfree].idata=dat;                /* event to occur at that time */
  621.     Stq[Stfree].event=(unsigned char)event;
  622.     Stq[Stfree].eclass=(unsigned char)class;
  623.     Stq[Stfree].when=gooff;
  624.     i=Stfree;                            /* remove from free list */
  625.     Stfree=Stq[i].next;
  626.     if(Stfirst<0) {                    /* if no queue yet */
  627.         Stfirst=i;
  628.         Stq[i].next=-1;                /* anchor active q */
  629.       }
  630.     else 
  631.         if(gooff<Stq[Stfirst].when) {    /* goes first on list */
  632.             Stq[i].next=Stfirst;                /* at beginning of list */
  633.             Stfirst=i;
  634.           }
  635.         else {                                    /* goes in middle */
  636.             j=jlast=Stfirst;                /* search q from beginning */
  637.             while (gooff>=Stq[j].when&&j>=0) {
  638.                 jlast=j;
  639.                 j=Stq[j].next;
  640.               }
  641.             Stq[i].next=j;                    /* insert in q */
  642.             Stq[jlast].next=i;
  643.           }
  644.     return(retval);
  645. }
  646.  
  647. /****************************************************************************/
  648. /*
  649. *    Stimerunset ( class, event, dat )
  650. *
  651. *    Remove all timer events from the queue that match the class/event/dat.
  652. *
  653. *
  654. */
  655. int Stimerunset(class,event,dat)
  656. unsigned char event,class;
  657. int dat;
  658. {
  659.     int i,ilast,retval;
  660.  
  661.     retval=ilast=-1;
  662.     i=Stfirst;
  663.     while (i>=0 ) {                    /* search list */
  664.         if(Stq[i].idata==dat&&Stq[i].eclass==class && Stq[i].event==event) {
  665.             retval=0;                    /* found at least one */
  666. /*
  667. * major bug fix -- if first element matched, old code could crash
  668. */
  669.             if(i==Stfirst) {
  670.                 Stfirst=Stq[i].next;            /* first one matches */
  671.                 Stq[i].next=Stfree;            /* attach to free list */
  672.                 Stfree=i;
  673.                 i=Stfirst;
  674.                 continue;                        /* start list over */
  675.               }
  676.             else {
  677.                 Stq[ilast].next=Stq[i].next;    /* remove this entry */
  678.                 Stq[i].next=Stfree;            /* attach to free list */
  679.                 Stfree=i;
  680.                 i=ilast;
  681.               }
  682.           }
  683.         ilast=i;
  684.         i=Stq[i].next;
  685.       }
  686.     return(retval);
  687. }
  688.  
  689. /****************************************************************************/
  690. /*
  691. *    Scheckpass ( us, ps )
  692. *
  693. *    Check the password file for the user/password combination from ftp.
  694. *
  695. *    Returns valid/invalid
  696. *
  697. */
  698. int Scheckpass(us,ps)
  699. char *us,*ps;
  700. {
  701.     char buf[81],*p;
  702.     FILE *fp;
  703.     
  704.     if(NULL==(fp=fopen(Scon.pass,"r"))) 
  705.         return(0);
  706.     while (NULL != fgets(buf,80,fp)) {
  707.         p=strchr(buf,'\n');
  708.         *p='\0';                            /* remove \n */
  709.         p=strchr(buf,':');                /* find delimiter */
  710.         *p++='\0';
  711.         if(!strcmp(buf,us) && Scompass(ps,p)) {            /* does password check ?*/
  712.             fclose(fp);
  713.             return(1);
  714.           }
  715.       }
  716.     fclose(fp);
  717.     return(0);
  718. }
  719.  
  720. /****************************************************************************/
  721. /*
  722. *    Sneedpass ()
  723. *
  724. *    Check to see if the password file is used -- 0 if not, 1 if it is.
  725. *
  726. */
  727. int Sneedpass(void )
  728. {
  729.     if(Scon.pass==NULL)
  730.         return(0);
  731.     return(1);
  732. }
  733.  
  734. /****************************************************************************/
  735. /*
  736. *    Scompass ( ps, en )
  737. *
  738. *    Compute and check the encrypted password
  739. *
  740. */
  741. int Scompass(ps,en)
  742. char *ps,*en;
  743. {
  744.     int ck;
  745.     char *p,c;
  746.  
  747.     ck=0;
  748.     p=ps;
  749.     while (*p)                            /* checksum the string */
  750.         ck+=(int)*p++;
  751.     c=(char)ck;
  752.     while (*en) {
  753.         if((((*ps^c)|32)&127)!=*en)        /* XOR with checksum */
  754.             return(0);
  755.         if(*ps)
  756.             ps++;
  757.         else
  758.             c++;                        /* increment checksum to hide length */
  759.         en++;
  760.       }
  761.     return(1);
  762. }
  763.  
  764. /****************************************************************************/
  765. /*
  766. *    Sgetevent ( class, what, datp )
  767. *
  768. *    Gets events from the network and filters those for session related
  769. */
  770. int Sgetevent(class,what,datp)
  771. int class,*what,*datp;
  772. {
  773.     int retval;
  774.  
  775.     if(retval=netgetevent(SCLASS,what,datp)) {    /* session event */
  776.         switch (retval) {
  777.             case FTPACT:
  778.                 ftpd(0,*datp);
  779.                 break;
  780.  
  781.             case RCPACT:                /* give CPU to rsh for rcp */
  782.                 rshd(0);
  783.                 break;
  784.  
  785.             case UDPTO:                    /* name server not responding */
  786.                 domto(*datp);
  787.                 break;
  788.  
  789.             case RETRYCON:
  790.                 if(0<netopen2(*datp))     /* connection open yet? */
  791.                     Stimerset(SCLASS,RETRYCON,*datp,4);  /* 4 is a kludge */
  792.                 break;
  793.  
  794.             default:
  795.                 break;
  796.           }
  797.       }
  798.  
  799.     Stask();                        /* allow net and timers to take place */
  800.  
  801.     if(!(retval=netgetevent((unsigned char)class,what,datp))) return(0);
  802.  
  803.     if(retval==CONOPEN) Stimerunset(CONCLASS,CONFAIL,*datp);   /* kill this timer */
  804.  
  805.     if((*datp==997) && (retval==UDPDATA))
  806.         udpdom();
  807.     else {
  808.         if((*what==CONCLASS)&&(Sptypes[*datp]>=0)) {    /* might be for session layer */
  809.             switch (Sptypes[*datp]) {
  810.                 case PFTP:
  811.                     rftpd(retval);
  812.                     break;
  813.  
  814.                 case PDATA:
  815.                     ftpd(retval,*datp);
  816.                     break;
  817.  
  818.                 case PRCP:
  819.                     rshd(retval);
  820.                     break;
  821.  
  822.                 default:
  823.                     break;
  824.               }    /* end switch */
  825.           }    /* end if */
  826.         else return(retval);                /* let higher layer have it */
  827.         }
  828.     return(0);
  829. }
  830.  
  831. char *fixdirnm(dirnm)
  832. char *dirnm;
  833. {
  834.     int len;
  835.  
  836.     if (!dirnm)
  837.         return (char *)NULL;            /* name is nil */
  838.     len = strlen(dirnm);
  839.     while (len > 1 &&                    /* name contains multiple characters */
  840.       (dirnm[len - 1] == '/' || dirnm[len - 1] == '\\') && /* trailing slash */
  841.       dirnm[len - 2] != ':')                    /* not "disk:/" or "disk:\"  */
  842.         dirnm[--len] = '\0';    /* strip off trailing slash character */
  843.  
  844.     return(dirnm);
  845. }
  846.