home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Internet Tools 1995 April / Internet Tools.iso / ip / ppp / mac / macppp2.0.1-src.hqx / MacPPP 2.0.1 src / link.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-10-28  |  26.0 KB  |  962 lines

  1. /*
  2.  *  link.c    - routines to open/close serial link for PPP
  3.  *
  4.  * Copyright 1992-1993 Merit Network, Inc. and The Regents of the
  5.  *  University of Michigan.  Usage of this source code is restricted
  6.  *  to non-profit, non-commercial purposes.  The source is provided
  7.  *  "as-is", without warranty.
  8.  */
  9. #include "ppp.h"
  10. #include <Folders.h>
  11. #include <GestaltEqu.h>
  12. #include <CommResources.h>
  13. #include <CRMSerialDevices.h>
  14. #include <ShutDown.h>
  15.  
  16. /* Trap numbers */
  17. #define TN_UnknownOS        0xA09F
  18. #define TN_CommToolbox        0xA08B
  19. #define TN_DTInstall        0xA082
  20.  
  21. unsigned char PortBUse : 0x291;
  22.  
  23. /* function prototypes */
  24. OSErr waitstr(LapInfo *, b_8 *, short);
  25. OSErr sendstr(b_8 *);
  26. void adjustbuf(LapInfo *, short);
  27. void install_tm(LapInfo *, struct TMprocess *, ProcPtr);
  28. void init_dt(LapInfo *, struct DeferredTask *, ProcPtr);
  29. void AppendStr(b_8 *, b_8 *);
  30. OSErr parsestr(b_8 *, Boolean);
  31. OSErr TermMode();
  32. void sendlcpecho();
  33. void time_check();
  34. void MySetText(b_8);
  35. pascal Boolean nullfilt(DialogPtr, EventRecord *, short *);
  36.  
  37. /* define some globals */
  38. b_8 **gmessages;
  39. Handle ghandle;
  40. b_8 reserrmes[]="\pMacPPP: resource error";
  41. b_8 okmes[]={1, 2,'O','K',0};
  42. extern struct NMRec errnmrec;
  43. b_8 resFile[] = "\pPPP";
  44. b_8 sys6resFile[] = "\p:System Folder:PPP";
  45.  
  46. /* resource defines */
  47. #define SYS6FOLDER -4034
  48. #define PREFFILENAME -4033
  49.  
  50. #define MODEMRESPONSES 128 /* resource id of modem responses */
  51. #define STATUSSTRINGS 129
  52. #define MODEMCOMMANDS 130
  53. #define PHASETEXT 131
  54.  
  55. #define MODEMCONNECT 1    /* # for connect message */
  56. #define MODEMBUSY 2        /* # for busy message */
  57.  
  58. #define MESSCHECK 1
  59. #define MESSINIT 2
  60. #define MESSDIAL 3
  61. #define MESSBUSY 4
  62. #define MESSERROR 5
  63. #define MESSSENDING 6
  64. #define MESSWAITING 7
  65. #define MESSTERM 8
  66. #define MESSTIMEOUT 9
  67. #define MESSPHASE 10
  68.  
  69. #define MODEMALERT    128        /* Modem connect failure alert */
  70. #define NOPREFALERT    129        /* no preferences alert */
  71. #define SERIALALERT 130        /* alert for error when opening serial port */
  72. #define CTSALERT    131        /* CTS signal not present */
  73. #define IDLEALERT    132
  74. #define ECHOALERT    133
  75. #define OLDPREFSALERT 135
  76. #define INUSEALERT    136        /* port in use alert */
  77.  
  78. /* dialogs */
  79. #define PPPSTATUS    129        /* status dialog */
  80. #define TERMDLOG    130        /* terminal window dialog box */
  81. #define PAPMESDLOG  131        /* display message returned by PAP */
  82. #define TIMEOUTDLOG 132        /* timeout waiting for a string */
  83.  
  84. #define IGNOREIDLE 2
  85. #define IGNOREECHO    2
  86. #define CLOSEPPP    3
  87.  
  88. void
  89. link_open(register LapInfo *lap)
  90. {
  91. register OSErr        rc, savrc;
  92. OSErr        waitresult;
  93. register b_8    *hshake;
  94. Boolean        HaveFindFolder = false, HavePrefFolder = false;
  95. long        ffresp, count, whichDir, oldA4, oldA5, timeout;
  96. Byte        i;
  97. short        whichVol, rn = -1, len, prefref;
  98. short        savresfile, itemhit, type;
  99. b_8            *strptr;
  100. register DialogPtr    statusdlog;
  101. DialogPtr    dlog;
  102. Rect        rect;
  103. Handle        itemH, itemH2;
  104. pascal        Boolean modemfilt();
  105. struct        bufheader *bufptr;
  106. b_8            curphase, curstate;
  107. b_8            **modemstrings;
  108. b_8            tempstr[MAXSLEN + 4];
  109. b_8            indriv[128],outdriv[128];
  110. long        qd_save;
  111.  
  112.     /* save current Resource file */
  113.     savresfile = CurResFile();
  114.     
  115.     oldA4 = seta4((long)lap->LapA4);    /* setup PPP's A4 for globals */
  116.     oldA5 = seta5((long) CurrentA5);
  117.     qd_save = *((long *)geta5());    /* save current pointer to QD globals */
  118.     InitGraf(&thePort);        /* init our QD globals */
  119.     if (WWExist != 0) {        /* see if initwindows has been called yet */
  120.         InitFonts();            /* init fonts */
  121.         InitWindows();            /* init window manager port */
  122.         TEInit();
  123.         InitDialogs(nil);
  124.         DeskHook = 0;
  125.     }
  126.     InitCursor();    /* make the cursor an arrow */
  127.  
  128.     /* see if findfolder is available */
  129.     if ( Gestalt(gestaltFindFolderAttr, &ffresp) == noErr) {
  130.         if ( ( 1L << gestaltFindFolderPresent ) & ffresp )
  131.             HaveFindFolder = true;
  132.     }
  133.     
  134.     if ( HaveFindFolder ) {
  135.         if ( FindFolder(kOnSystemDisk,kExtensionFolderType,
  136.                 kDontCreateFolder,&whichVol,&whichDir) == noErr)
  137.             rn = HOpenResFile(whichVol,whichDir,resFile,fsRdPerm);
  138.     } else {
  139.         GetVRefNum(SysMap, &whichVol);    /* get system Vol ref */
  140.         rn = OpenRFPerm(sys6resFile,whichVol,fsRdPerm);
  141.     }
  142.     
  143.     if (rn == -1) {
  144.         errnmrec.nmStr = reserrmes;    /* initialize pointer to error message */
  145.         NMInstall(&errnmrec);        /* Install the notification */
  146.         goto noresbye;
  147.     }
  148.  
  149.     if (lap->ppp_flags & ECHO_FAIL) {
  150.         itemhit = NoteAlert(ECHOALERT, nil);
  151.         if (itemhit == IGNOREECHO) {
  152.             lap->echo_count = 0;
  153.             PrimeTime((QElemPtr) &lap->echo_task, (long)lap->prefdata.echo * 1000L);
  154.             goto exitout;
  155.         }
  156.         if (itemhit == CLOSEPPP) {
  157.             ppp_iostatus(lap, PARAM_DOWN);    /* link must be down */
  158.             goto close_ppp;            /* close drivers */
  159.         }
  160.         link_close();        /* must want to restart */
  161.     }
  162.         
  163.     if (lap->ppp_flags & IDLE_TIMEOUT) {
  164.         if (!lap->prefdata.quiet) {
  165.             itemhit = NoteAlert(IDLEALERT, nil);
  166.             if (itemhit == IGNOREIDLE) {
  167.                  lap->idle_timer = 0;
  168.                 PrimeTime((QElemPtr) &lap->timeout_task, 60000L); /* one minute interval */
  169.                 goto exitout;
  170.             }
  171.         }
  172.         goto close_ppp;
  173.     }
  174.     
  175.     lap->ppp_flags &= ~(ECHO_FAIL | IDLE_TIMEOUT);
  176.  
  177.     if (lap->ppp_phase != pppDEAD)
  178.         return;        /* return if not in DEAD phase */
  179.  
  180.     if (HaveFindFolder) {
  181.         if (noErr == FindFolder(kOnSystemDisk,kPreferencesFolderType,
  182.                 kCreateFolder,&whichVol,&whichDir))
  183.             HavePrefFolder = true;
  184.     }
  185.  
  186.     tempstr[0] = 0;
  187.     if (!HavePrefFolder) {
  188.         itemH = GetResource('STR ',SYS6FOLDER); /* system 6 folder */
  189.         AppendStr(tempstr, *((b_8 **) itemH));
  190.         ReleaseResource(itemH);
  191.     }
  192.     itemH = GetResource('STR ',PREFFILENAME); /* get pref file */
  193.     AppendStr(tempstr, *((unsigned char **) itemH));
  194.     ReleaseResource(itemH);
  195.  
  196.     if (HavePrefFolder)
  197.         rc = HOpen(whichVol,whichDir,tempstr,fsRdPerm,&prefref);
  198.     else {
  199.     /* if we don't have PrefFolder, just use System Folder */
  200.         GetVRefNum(SysMap, &whichVol);    /* get system Vol ref */
  201.         rc = FSOpen(tempstr,whichVol,&prefref);
  202.     }
  203.     savrc = rc;
  204.  
  205.     count = sizeof (struct ppp_pref);
  206.     if (rc == opWrErr )  /* must already be opened by control panel */
  207.         rc = SetFPos(prefref,fsFromStart,0L);
  208.     if (rc == noErr)
  209.         rc = FSRead(prefref, &count, &(lap->prefdata)); /* read in preferences data */
  210.  
  211.     if (lap->prefdata.version < PREF_VERSION) {
  212.         NoteAlert(OLDPREFSALERT,nil);
  213.         FSClose(prefref);
  214.         goto exitout;
  215.     }
  216.     if (rc == noErr) {
  217.         if    (count != sizeof (struct ppp_pref))  /* check number of bytes */
  218.             rc = -1;    /* set return code to non-zero */
  219.     }
  220.     if (rc == noErr)
  221.         rc = SetFPos(prefref, fsFromMark,
  222.                 lap->prefdata.active_config * sizeof(struct ppp_config));
  223.     if (rc == noErr) {
  224.             count = sizeof(struct ppp_config);
  225.             rc = FSRead(prefref, &count, &(lap->configdata));
  226.     }
  227.     if (savrc != opWrErr )
  228.         FSClose(prefref);        /* close the preferences file */
  229.  
  230.     if ( rc != noErr ) {
  231.         NoteAlert(NOPREFALERT, nil);
  232.         goto exitout;
  233.     }
  234.     indriv[0] = 0;
  235.     outdriv[0] = 0;
  236.     if (NGetTrapAddress(TN_CommToolbox, OSTrap)
  237.             != GetTrapAddress(TN_UnknownOS)) {
  238.         CRMRec *crmrecptr, acrmrec;
  239.         CRMSerialRecord *serrec;
  240.         long old = 0;
  241.         int index = 1;
  242.  
  243.         InitCRM();
  244.         acrmrec.qType = crmType;
  245.         while (true) {
  246.             acrmrec.crmDeviceType = crmSerialDevice;
  247.             acrmrec.crmDeviceID = old;
  248.             if (!(crmrecptr = (CRMRec *)CRMSearch((QElemPtr)(&acrmrec))))
  249.                 break;
  250.             serrec = (CRMSerialRecord *)crmrecptr->crmAttributes;
  251.             old = crmrecptr->crmDeviceID;
  252.             ++index;
  253.             if (EqualString(lap->prefdata.portname, *serrec->name,
  254.                     FALSE, TRUE))
  255.                 break;
  256.         }
  257.         if (!crmrecptr)
  258.             goto sererr;
  259.         AppendStr(indriv, *serrec->inputDriverName);
  260.         AppendStr(outdriv, *serrec->outputDriverName);
  261.  
  262.     } else {
  263.         if (!(itemH = GetNamedResource('Port', lap->prefdata.portname)))
  264.             goto sererr;
  265.         strptr = * ((b_8 **) itemH);
  266.         AppendStr(indriv,strptr);
  267.         strptr += *strptr + 1;
  268.         AppendStr(outdriv,strptr);
  269.         ReleaseResource(itemH);
  270.     }
  271.     rc = OpenDriver(indriv, &lap->serinrefnum);
  272.     if (rc == portInUse) {
  273.         if (EqualString(indriv,"\p.BIn", FALSE, FALSE)) {
  274.             if (NoteAlert(INUSEALERT, nil) == OK) {
  275.                 PortBUse = (Byte) 0xff;        /* Hack to mark port as free */
  276.                 rc = OpenDriver(indriv, &lap->serinrefnum);
  277.             }
  278.         }
  279.     }
  280.     if (rc == noErr) {
  281.         rc = OpenDriver(outdriv, &lap->seroutrefnum);
  282.         if (rc != noErr)
  283.             CloseDriver(lap->serinrefnum);
  284.     }
  285.     
  286.     if (rc != noErr)
  287.         goto sererr;
  288.     rc = SerReset(lap->serinrefnum,stop10+noParity+data8);
  289.     if (rc == noErr)
  290.         rc = SerReset(lap->seroutrefnum,stop10+noParity+data8);
  291.     if (rc == noErr)
  292.         rc = SerSetBuf(lap->serinrefnum, (Ptr) lap->sdinbuf, SDINBUFLEN);    /* give driver a new buffer */
  293.  
  294.     lap->stat_pb.csCode = 13;        /* baud rate routine */
  295.     *( (unsigned int *) lap->stat_pb.csParam) = lap->configdata.baudrate;
  296.     lap->stat_pb.ioCRefNum = lap->serinrefnum;
  297.     PBControlImmed((ParmBlkPtr)  &lap->stat_pb);
  298.  
  299.     *( (unsigned int *) lap->stat_pb.csParam) = lap->configdata.baudrate;
  300.     lap->stat_pb.ioCRefNum = lap->seroutrefnum;
  301.     PBControlImmed((ParmBlkPtr)  &lap->stat_pb);
  302.  
  303.     hshake = (b_8 *) lap->stat_pb.csParam;
  304.     *hshake++ = false;    /* fXOn */
  305.     *hshake++ = lap->configdata.flags & CTSBIT; /* fCTS */
  306.     hshake += 2;    /* skip Xon/Xoff character settings */
  307.     *hshake++ = 0;    /* errs */
  308.     *hshake++ = 0;    /* evts */
  309.     *hshake++ = false;    /* fInX */
  310.     *hshake = lap->configdata.flags & RTSBIT;     /* fDTR */
  311.  
  312.     lap->stat_pb.csCode = 14;        /* new SerHShake routine */
  313.     lap->stat_pb.ioCRefNum = lap->seroutrefnum;
  314.     PBControlImmed((ParmBlkPtr)  &lap->stat_pb);
  315.  
  316.     lap->stat_pb.ioCRefNum = lap->serinrefnum;
  317.     PBControlImmed((ParmBlkPtr)  &lap->stat_pb);
  318.  
  319.     if (rc != noErr) {
  320.         SerSetBuf(lap->serinrefnum, (Ptr) lap->sdinbuf, 0); /* reset buffer */
  321.         CloseDriver(lap->serinrefnum);
  322.         CloseDriver(lap->seroutrefnum);
  323. sererr:
  324.         NoteAlert(SERIALALERT, nil);
  325.         goto exitout;
  326.     }
  327.     
  328.     /* Initialize lists of buffers */
  329.     lap->buflist = (struct bufheader * ) nil;
  330.     for ( i = 0; i < NUMBUFFERS; i++ ) {
  331.         bufptr = (struct bufheader *) lap->blockarray[i].block;
  332.         bufptr->dataptr = (b_8 *) lap->buflist;
  333.         lap->buflist = bufptr;
  334.     }
  335.     
  336.     lap->rds.rdsparm.lnb.lnb_ptr = nil;        /* clear rcv buffer pointer */
  337.  
  338.     lap->active = nil;
  339.     lap->out_q.qFlags = 0;
  340.     /* initialize queue of iopbs */
  341.     lap->pppbq.qFlags = 0;
  342.     lap->pppbq.qHead = nil;
  343.     lap->pppbq.qTail = nil;
  344.     for (i = 0; i < NUMIOPBS; i++)
  345.         Enqueue( (QElemPtr) &lap->pppiopbs[i], (QHdrPtr) &lap->pppbq);
  346.  
  347.     /* initialize FIFO params */
  348.     lap->XmitQHead = 0;
  349.     lap->XmitQTail = 0;
  350.     lap->XmitQSize = 0;
  351.     
  352.     /* initialize our serial driver iopb's */
  353.     lap->w_iopb.lap = lap;
  354.     lap->w_iopb.iop.ioCompletion = hdlcwioc;    /* where to go when done */
  355.     lap->w_iopb.iop.ioRefNum = lap->seroutrefnum;    /* set output to serial port*/
  356.     
  357.     lap->r_iopb.lap = lap;
  358.     lap->r_iopb.iop.ioRefNum = lap->serinrefnum;
  359.     lap->r_iopb.iop.ioBuffer = (Ptr) lap->rxbuf;
  360.     lap->r_iopb.iop.ioCompletion = SerReadDone;
  361.  
  362.     lap->stat_pb.ioCRefNum = lap->serinrefnum;
  363.     
  364.     lap->read_state = s_Init;
  365.     lap->write_state = s_Init;
  366.     lap->needTxPrime = true;
  367.     lap->term_mode = false;    /* not in terminal emulation mode */
  368.     
  369.     lap->bufptr = getbuffer();    /* allocate initial rcv. buffer */
  370.     lap->rddata = lap->bufptr->dataptr;    /* point to data area */
  371.     lap->ok_to_xmit = true;
  372.  
  373.     SystemTask();        /* some serial drivers need SystemTask time to open */
  374.     Delay(60L, &count);    /* wait some (if DTR need to "wake up" device */
  375.     SystemTask();        /* more system task time for good measure */
  376.  
  377.     /* check if deferred task manager available */
  378.     lap->HasDeferredTasks = (NGetTrapAddress(TN_DTInstall, OSTrap) !=
  379.                                     GetTrapAddress(TN_UnknownOS));
  380.  
  381.     /* initialize Deferred Task queue entries */
  382.     init_dt(lap, &lap->defer_rx, RcvDeferred);
  383.     init_dt(lap, &lap->defer_tx, XmtDeferred);
  384.     init_dt(lap, &lap->defer_txcomplete, TxCDeferred);
  385.  
  386.     /* set up receive time manager task */
  387.     install_tm(lap, &lap->rxp_task, ProcRcvPPP);
  388.     PrimeTime( (QElemPtr) &lap->rxp_task, 4L);    /* Prime receive task */
  389.  
  390.     /* set up transmit time manager task (gets primed as needed) */
  391.     install_tm(lap, &(lap->txp_task), XmtTMProc);
  392.     
  393.     if (lap->prefdata.echo != 0)    /* LCP echo test */
  394.          install_tm(lap, &lap->echo_task, sendlcpecho);
  395.      if (lap->prefdata.timeout != 0)    /* idle timeout */
  396.          install_tm(lap, &lap->timeout_task, time_check);
  397.  
  398.     statusdlog = GetNewDialog(PPPSTATUS, nil, (WindowPtr) -1L);
  399.     DrawDialog(statusdlog);
  400.     SetCursor(&qd.arrow);
  401.     GetDItem(statusdlog, 3, &type, &ghandle, &rect);
  402.     GetDItem(statusdlog, 4, &type, &itemH2, &rect);
  403.     SetIText(itemH2, "\p");    /* set to nil */
  404.     gmessages = (b_8 **) Get1Resource('STR#', STATUSSTRINGS);
  405.     
  406.     if (lap->prefdata.use_term) {
  407.         if (TermMode() != noErr)
  408.             goto getout;
  409.         goto start_ppp;
  410.     }
  411.     
  412.     if (lap->configdata.phonenum[0] != 0) {
  413. retrymodem:
  414.         DrawDialog(statusdlog);
  415.         MySetText(MESSCHECK);
  416.         rc = sendstr("\pATE0V1\r");        /* see if modem is there */
  417.         if ( rc == 0 )
  418.             rc = waitstr(lap, okmes, 5);
  419.         if ( rc == -1 )
  420.             goto getout;
  421.  
  422.         rc = 0;
  423.         if ( i = lap->configdata.modeminit[0] ) {
  424.             MySetText(MESSINIT);
  425.             lap->configdata.modeminit[0] = 2;
  426.             if (! EqualString(lap->configdata.modeminit, "\pAT", FALSE, FALSE) )
  427.                 rc = sendstr("\pAT");
  428.             lap->configdata.modeminit[0] = i;
  429.             if (rc == 0)
  430.                 rc = sendstr(lap->configdata.modeminit); /* send modem init command */
  431.             if (rc == 0)
  432.                 rc = sendstr("\p\r");    /* add a carriage return */
  433.             if (rc == 0)
  434.                 rc = waitstr(lap, okmes, 5);
  435.             if (rc == -1)
  436.                 goto getout;
  437.         }
  438.  
  439.         MySetText(MESSDIAL);
  440. doredial:
  441.         modemstrings = (b_8 **) Get1Resource('STR#',MODEMRESPONSES);
  442.         DrawDialog(statusdlog);
  443.         if (lap->configdata.flags & USE_PULSE)
  444.             rc = sendstr("\pATDP");
  445.         else
  446.             rc = sendstr("\pATDT");
  447.         if (rc == 0)
  448.             rc = sendstr(lap->configdata.phonenum);
  449.         if (rc == 0)
  450.             rc = sendstr("\p\r");
  451.         if (rc == -1)
  452.             goto getout;
  453.         HLock((Handle) modemstrings);
  454.         rc = waitstr(lap, *modemstrings + 1,
  455.                         lap->configdata.connecttimeout);
  456.         HUnlock((Handle) modemstrings);
  457.         ReleaseResource((Handle) modemstrings);
  458.         if (rc == MODEMBUSY) {
  459.             MySetText(MESSBUSY);
  460.             if (sendstr("\pAT\r") == -1)    /* get the modems' attention */
  461.                 goto getout;
  462.             Delay(120L, &count);            /* add some delay before we redial */
  463.             goto doredial;
  464.         }
  465.         if (rc == -1)
  466.             goto getout;
  467.         if (rc != MODEMCONNECT) {
  468.             ResetAlrtStage();
  469.             if ( NoteAlert(MODEMALERT, nil) == 1 ) {    /* alert user */
  470.                 goto getout;
  471.             }
  472.             goto doredial;
  473.         }
  474.     }
  475.  
  476.     DrawDialog(statusdlog);
  477.     for ( i=0 ; i < NUMCOMMANDS; i++) {
  478.         strptr = tempstr;
  479.         *strptr++ = 1;
  480.         *strptr = 0;
  481.         AppendStr(strptr, lap->configdata.commands[i].scriptstr);
  482.         if (lap->configdata.commands[i].addreturn)
  483.             AppendStr(strptr, "\p\\r");
  484.         if ( *strptr != 0 ) {
  485.             if ( lap->configdata.commands[i].sendout ) {
  486.                 MySetText(MESSSENDING);
  487.                 SetIText(itemH2, strptr);
  488.                 rc = parsestr(strptr, true);
  489.             } else {
  490.                 MySetText(MESSWAITING);
  491.                 SetIText(itemH2, strptr);
  492.                 parsestr(strptr, false);
  493.                 rc = waitstr(lap, tempstr, lap->configdata.waittimeout);
  494.             }
  495.             if (rc == -1)
  496.                 goto getout;
  497.         }
  498.     }
  499.  
  500. start_ppp:
  501.     
  502.     lap->write_state = s_Idle;        /* serial port now ready for PPP */
  503.     lap->read_state = s_Idle;
  504.  
  505.     ppp_iostatus(lap, PARAM_UP);    /* let PPP know that link is up */
  506.     
  507.     curphase = 255;        /* initialize state holder */
  508.  
  509.     MySetText(MESSPHASE);
  510.     ReleaseResource( (Handle) gmessages);    /* release messages resource */
  511.     gmessages = (b_8 **) Get1Resource('STR#', PHASETEXT);
  512.     ghandle = itemH2;
  513.     while (lap->ppp_fsm[IPcp].state != fsmOPENED) {    /* wait for IPCP */
  514.         ModalDialog((ProcPtr) nullfilt, &itemhit);
  515.         if (itemhit == 1) {        /* check if user wants to quit */
  516.             goto getout;
  517.         }
  518.         if (lap->ppp_phase != curphase) {
  519.             curphase = lap->ppp_phase;
  520.             MySetText(curphase + 1);    /* display the PPP phase */
  521.         }
  522.         if (lap->pap_i.IOFlag == TRUE && lap->pap_i.message[0] == 0)
  523.             if (pap_userio(&(lap->ppp_fsm[Pap])) != noErr ) { /* get user name and password */
  524.                 goto getout;
  525.             }
  526.         if (lap->pap_i.message[0] != 0) {
  527.             if (!lap->prefdata.quiet || lap->pap_i.IOFlag == true) {
  528.                 dlog = GetNewDialog(PAPMESDLOG, 0L, (WindowPtr) -1L);
  529.                 DrawDialog(dlog);
  530.                 GetDItem(dlog, 3, &type, &itemH, &rect);
  531.                 SetIText(itemH, lap->pap_i.message);    /* set mess field */
  532.                 do
  533.                     ModalDialog( (ProcPtr) nullfilt, &itemhit);
  534.                 while (itemhit != OK );
  535.                 DisposDialog(dlog);
  536.             }
  537.             lap->pap_i.message[0] = 0;    /* reset the message */
  538.         }
  539.     }
  540.  
  541.     DisposDialog(statusdlog);
  542.  
  543.     if (lap->prefdata.hangup)    /* hangup modem on restart/shutdown */
  544.         ShutDwnInstall((ProcPtr) link_close, sdOnDrivers);
  545.  
  546.      if (lap->prefdata.echo != 0) {
  547.          lap->echo_count = 0;
  548.         PrimeTime((QElemPtr) &lap->echo_task, (long)lap->prefdata.echo * 1000L);
  549.     }
  550.  
  551.      if (lap->prefdata.timeout != 0) {
  552.          lap->idle_timer = 0;
  553.         PrimeTime((QElemPtr) &lap->timeout_task, 60000L); /* one minute interval */
  554.     }
  555.     goto exitout;        /* everything okey-dokey */
  556.  
  557. getout:
  558.     DisposDialog(statusdlog);    /* get rid of status dialog */
  559.     ReleaseResource((Handle) gmessages);    /* release resource */
  560. close_ppp:
  561.     if (lap->ppp_phase > pppESTABLISH && lap->ppp_phase < pppTERMINATE)
  562.         PPPClose(lap);
  563.     else
  564.         link_close();        /* just Close link */
  565. exitout:
  566.     CloseResFile(rn);    /* make sure to close the resource file */
  567. noresbye:
  568.     *((long *)geta5()) = qd_save;    /* restore QD globals ptr */
  569.     seta4(oldA4);        /* restore previous value of A4 */
  570.     seta5(oldA5);
  571.     UseResFile(savresfile);    /* restore resource file */
  572. }
  573.  
  574. void
  575. link_close(void)
  576. {
  577.     register LapInfo *lap;
  578.     short    i;
  579.     long    count;
  580.     register b_8    *xbufptr;
  581.  
  582.     lap = GetLAPPtr();
  583.     ppp_iostatus(lap, PARAM_DOWN);    /* link is going down */
  584.     if (lap->transProc != nil)
  585.         (*(lap->transProc))(TransitionClose);    /* let MacTCP know we are down */
  586.  
  587.      if (lap->prefdata.echo != 0)
  588.         RmvTime((QElemPtr) &lap->echo_task);
  589.      if (lap->prefdata.timeout != 0)
  590.         RmvTime((QElemPtr) &lap->timeout_task);
  591.     RmvTime((QElemPtr) &lap->rxp_task);
  592.     KillIO(lap->serinrefnum);
  593.     RmvTime((QElemPtr) &lap->txp_task);
  594.     KillIO(lap->seroutrefnum);        /* kill pending writes */
  595.     SerSetBuf(lap->serinrefnum, (Ptr) lap->sdinbuf, 0); /* reset buffer */
  596.  
  597.     if (lap->prefdata.hangup) {    /* hangup modem */
  598.         ShutDwnRemove((ProcPtr) link_close);    /* remove routine */
  599.         lap->XmitQSize = 0;        /* don't send any queued data */
  600.         lap->ok_to_xmit = true;    /* set flag so we can send hangup */
  601.         Delay(65L, &count);        /* wait ~1 second */
  602.         for (i = 0 ; i < 3 ; i++) {
  603.             lap->xbuf[0] = '+';
  604.             xmitfifo(lap, 1);    /* send a '+' 3 times */
  605.             Delay(12L, &count);    /* wait 200 milliseconds */
  606.         }
  607.         Delay(65L, &count);        /* wait ~1 second */
  608.         xbufptr = lap->xbuf;
  609.         *xbufptr++ = 'A';
  610.         *xbufptr++ = 'T';
  611.         *xbufptr++ = 'H';
  612.         *xbufptr = '\r';
  613.         xmitfifo(lap, 4);        /* send the hang-up command */
  614.         Delay(30L, &count);        /* wait another 1/2 second */
  615.     }
  616.     KillIO(lap->seroutrefnum);        /* kill pending writes */
  617.     CloseDriver(lap->serinrefnum);
  618.     CloseDriver(lap->seroutrefnum);
  619. }
  620.  
  621. void
  622. MySetText(b_8 stringnum)
  623. {
  624. register b_8 *strptr;
  625.  
  626.     strptr = *gmessages;
  627.     strptr++;
  628.     if (stringnum > *strptr++ )        /* check if string is out of range */
  629.         return;
  630.     while (--stringnum > 0)            /* find string in list */
  631.         strptr += *strptr + 1;
  632.     HLock((Handle) gmessages);        /* lock down the Handle */
  633.     SetIText(ghandle, strptr);    /* set the text in the dialog */
  634.     HUnlock((Handle) gmessages);
  635. }
  636.  
  637. pascal Boolean modemfilt(DialogPtr dlog, EventRecord *evt, short *item)
  638. {
  639. b_8        c;
  640. ioParam        iopb;
  641. LapInfo        *lap;
  642.  
  643.     lap = GetLAPPtr();
  644.     *item = 0;
  645.     if (evt->what == keyDown || evt->what == autoKey) {
  646.         lap->xbuf[0] = 1;
  647.         lap->xbuf[1] = evt->message & charCodeMask;        
  648.         *item = 3;
  649.     } else if (evt->what == mouseDown)
  650.         return FALSE;
  651.         
  652.     return TRUE;
  653. }
  654.  
  655. pascal Boolean nullfilt(DialogPtr dlog, EventRecord *evt, short *item)
  656. {
  657.     *item = 0;
  658.     if (evt->what == mouseDown)
  659.         return false;
  660.     return true;
  661. }
  662.  
  663. OSErr parsestr(b_8 *instr, Boolean sendout)
  664. {
  665. OSErr            rc;
  666. long            count;
  667. register b_8    *outptr;
  668. register b_8    *inptr;
  669. b_8        inlen;
  670. register b_8    c;
  671.  
  672.     outptr = inptr = instr;
  673.     if ( (inlen = (*outptr++ = *inptr++) ) == 0 )
  674.         return;
  675.     while ( inlen-- != 0 ) {
  676.         if ( ( c = *inptr++ ) == '^' ) {
  677.             if ( inlen-- == 0)        /*  and check for 0 */
  678.                 break;
  679.             c = *inptr++ & 0x1F;    /* generate the control char */
  680.             *outptr++ = c;
  681.         } else if (c == '\\') {
  682.             c = *inptr++;
  683.             if ( inlen-- == 0)
  684.                 break;
  685.             switch (c) {
  686.             case '^':            /* literals */
  687.             case '\\':
  688.                 *outptr++ = c;
  689.                 break;
  690.             case 'r':
  691.                 *outptr++ = 13;        /* carriage return */
  692.                 break;
  693.             case 'b':
  694.             case 'd':
  695.             case 't':
  696.                 if (!sendout)        /* only allow on outgoing strings */
  697.                     break;
  698.                 *instr = (unsigned char) (outptr - instr - 1);
  699.                 if (sendstr(instr) == -1)        /* send the current string */
  700.                     return -1;
  701.                 instr = outptr - 1;    /* point to current place in string */
  702.                 if ( c == 'd' )
  703.                     Delay(60L, &count);        /* Delay 1 second */
  704.                 else if (c == 'b') {
  705.                     LapInfo *lap;
  706.                     
  707.                     lap = GetLAPPtr();        /* get our Lap Pointer */
  708.                     SerSetBrk(lap->seroutrefnum);    /* put line in breaking state */
  709.                     Delay(6L, &count);                /* wait a huner' milliseconds */
  710.                     SerClrBrk(lap->seroutrefnum);    /* clear break condition */
  711.                 } else {
  712.                     if ( (rc = TermMode()) != noErr)
  713.                         return rc;
  714.                 }
  715.                 break;
  716.             default:
  717.                 if  ( c >= '0' && c <= '7' ) {
  718.                     *outptr = 0;
  719.                     count = 3;
  720.                     do {
  721.                         *outptr <<= 3;
  722.                         *outptr += c - '0';
  723.                         c = *inptr++;
  724.                     } while ( c >= '0' && c <= '7' && --count != 0 && inlen-- != 0);
  725.                     inptr--;    /* point back to charcter */
  726.                     outptr++;
  727.                     if (inlen == 0xff)
  728.                         inlen = 0;
  729.                 }
  730.                 break;
  731.             }
  732.         } else {
  733.             *outptr++ = c;
  734.         }
  735.     }
  736.     *instr = (unsigned char) (outptr - instr - 1); /* store len byte */
  737.     if (sendout)
  738.         return (sendstr(instr));        /* send the string */
  739. }
  740.  
  741.  /* simple terminal window routine */
  742.  
  743. OSErr TermMode()
  744. {
  745. LapInfo     *lap;
  746. TEHandle    teH;
  747. Rect        rect;
  748. register DialogPtr    dlog;
  749. Handle        itemH;
  750. short        type, len, nlines, itemhit;
  751. GrafPtr        oldport;
  752.     
  753.     lap = GetLAPPtr();
  754.     lap->term_mode = true;        /* in terminal emulation mode */
  755.     MySetText(MESSTERM);
  756.     dlog = GetNewDialog(TERMDLOG, nil, (WindowPtr) -1L);
  757.     GetPort(&oldport);
  758.     SetPort(dlog);
  759.     DrawDialog(dlog);    /* draw the dialog so title shows up */
  760.  
  761.     GetDItem(dlog, 3, &type, &itemH, &rect);
  762.     TextFont(courier);
  763.     TextSize(10);
  764.  
  765.     teH = TENew(&rect, &rect);    
  766.     len = 0;
  767.     nlines = 10;    
  768.     FrameRect(&rect);
  769.  
  770.     do {
  771.         ModalDialog(modemfilt, &itemhit);
  772.         if (itemhit == 3) {
  773.             if (sendstr(lap->xbuf) == -1) {
  774.                 itemhit = Cancel;
  775.                 break;
  776.             }
  777.         }
  778.  
  779.         if (lap->bufptr->length != len) {
  780.             if (len > 512)
  781.                 adjustbuf(lap, 128);
  782.             len = lap->bufptr->length;
  783.             EraseRect(&rect);
  784.             TESetText(lap->bufptr->dataptr, (long)len, teH);
  785.             TECalText(teH);
  786.             if ((**teH).nLines > nlines) {
  787.                 TEScroll(0, (**teH).lineHeight * -1 * ((**teH).nLines - nlines), teH);
  788.                 nlines = (**teH).nLines;
  789.             }
  790.             TEUpdate(&rect, teH);
  791.             FrameRect(&rect);
  792.         }
  793.     } while (itemhit != OK && itemhit != Cancel);
  794.         
  795.     lap->term_mode = false;
  796.     DisposeDialog(dlog);    /* Dispose the Dialog */
  797.     SetPort(oldport);
  798.     if (itemhit == Cancel)
  799.         return -1;
  800.     return noErr;
  801. }
  802.  
  803. /* routine to send out a string.  may want to add timeout code. */
  804.  
  805. OSErr sendstr(b_8 *s)
  806. {
  807. long    timeout;
  808. short    itemhit;
  809. LapInfo    *lap;
  810. b_16    len;
  811.  
  812.     lap = GetLAPPtr();
  813.     len = *s++;        /* get length */
  814.     while (len > 0) {
  815.         lap->xbuf[0] = *s++;
  816.         xmitfifo(lap, 1);
  817.         len--;
  818.     }
  819.  
  820.     timeout = TickCount() + 3*60;    /* seconds before timing out */
  821.     while (!lap->ok_to_xmit) {    /* wait for transmitter to empty */
  822.         SystemTask();
  823.         if (TickCount() > timeout) {
  824.             NoteAlert(CTSALERT,nil);
  825.                 return -1;
  826.         }
  827.     }
  828.     return 0;
  829. }
  830.  
  831. void 
  832. adjustbuf(LapInfo *lap, short i)
  833. {
  834. long    savsr;
  835. struct    bufheader *bufptr = lap->bufptr;
  836.     
  837.     savsr = set_sr(0x2100);    /* disable timer ints, so we don't buffer more */
  838.     bufptr->length -= i;        /* subtract from count */
  839.     lap->rddata -= i;        /* adjust pointer */
  840.     BlockMove(bufptr->dataptr + i, bufptr->dataptr, bufptr->length);    /*move down buffer */
  841.     set_sr(savsr);        /* restore timer interrupts */
  842. }
  843.  
  844. OSErr waitstr(LapInfo *lap, b_8 *s, short waitseconds )
  845. {
  846. long    timeout;
  847. register short    i;
  848. short    itemhit, type;
  849. Rect    rect;
  850. Handle    itemH;
  851. DialogPtr    dlog;
  852. b_8        len, numstrs, j;
  853. b_8        *lenptr;
  854.  
  855.     timeout = TickCount() + waitseconds*60;    /* seconds before timing out */
  856.     
  857.     for (i=1; true; i++) {
  858.         ModalDialog( (ProcPtr) nullfilt, &itemhit);
  859.         if (itemhit == 1) {        /* check if user wants to quit */
  860.             return -1;
  861.         }
  862.                     
  863.         if (TickCount() > timeout) {        /* don't sit in for loop forever */
  864.             dlog = GetNewDialog(TIMEOUTDLOG, 0L, (WindowPtr) -1L);
  865.             DrawDialog(dlog);
  866.             GetDItem(dlog, 3, &type, &itemH, &rect);
  867.             SetIText(itemH, s+1);    /* set mess field */
  868.             do
  869.                 ModalDialog( (ProcPtr) nullfilt, &itemhit);
  870.             while (itemhit != OK );
  871.             DisposDialog(dlog);
  872.             return -1;
  873.         }
  874.             
  875.         if (lap->bufptr->length < i) {    /* check if any chars came in */
  876.             --i;
  877.             continue;
  878.         }
  879.         
  880.         if (i > 255) {        /* don't let buffer get too full */
  881.             adjustbuf(lap, 128);
  882.             i -= 128;
  883.         }
  884.  
  885.         lenptr = s;        /* point to number of string field */
  886.         numstrs = *lenptr++;    /* get the number of strings */
  887.         j = 0;
  888.         while ( j < numstrs ) {
  889.             j++;
  890.             if ((len = *lenptr++) == 0 )
  891.                 continue;
  892.             if (i >= len) {            /* do we have enough to do a compare? */
  893.                 if ( bytecmp(lap->bufptr->dataptr + i - len, lenptr, len)
  894.                          == 0) {    /* compare and exit if equal */
  895.                     adjustbuf(lap, i);    /* shift the data in the buffer */
  896.                     return j;            /* return success */
  897.                 }
  898.             }
  899.             lenptr += len;        /* point to next string */
  900.         }
  901.     }
  902. }
  903.  
  904. void sendlcpecho() {
  905.     register LapInfo    *lap;
  906.     struct TMprocess    *tmprocp;
  907.  
  908.     asm {
  909.         move.l    a1,tmprocp
  910.     }
  911.  
  912.     lap = tmprocp->tmsavptr.lap;
  913.     if (lap->echo_count++ >= lap->prefdata.echo_tries) {
  914.         if (!(lap->ppp_flags & IDLE_TIMEOUT) && lap->transProc != nil) {
  915.             lap->ppp_flags |= ECHO_FAIL;
  916.             (*(lap->transProc))(TransitionClose);    
  917.             (*(lap->transProc))(TransitionOpen);    /* a hack to get system time */
  918.             return;
  919.         } else
  920.             lap->echo_count = 0;
  921.     }
  922.      /* send a LCP echo request */
  923.     lap->lcp_echo_buf.header.dataptr = lap->lcp_echo_buf.buffer
  924.             + LCP_ECHO_BUFSIZE;        /* initialize dataptr */
  925.     lap->lcp_echo_buf.header.length = 0;    /* initialize count */
  926.     fsm_send(&lap->ppp_fsm[Lcp], ECHO_REQ, 0, &lap->lcp_echo_buf.header);
  927. }
  928.  
  929. void time_check() {
  930.     register LapInfo    *lap;
  931.     struct TMprocess    *tmprocp;
  932.  
  933.     asm {
  934.         move.l    a1,tmprocp
  935.     }
  936.  
  937.     lap = tmprocp->tmsavptr.lap;
  938.     if (lap->idle_timer++ >= lap->prefdata.timeout) {
  939.         if (!(lap->ppp_flags & ECHO_FAIL) && lap->transProc != nil) {
  940.             lap->ppp_flags |= IDLE_TIMEOUT;
  941.             (*(lap->transProc))(TransitionClose);    
  942.             (*(lap->transProc))(TransitionOpen);    /* a hack to get system time */
  943.         } else
  944.             lap->idle_timer = 0;        /* reset idle timer */
  945.     }
  946.     PrimeTime((QElemPtr) &lap->timeout_task, 60000L);    /* re-prime for 1 minute */
  947. }
  948.  
  949. void init_dt(LapInfo *lap, struct DeferredTask *dtptr, ProcPtr task)
  950. {
  951.     bzero((b_8 *) dtptr, sizeof(struct DeferredTask));
  952.     dtptr->qType = dtQType;
  953.     dtptr->dtAddr = (ProcPtr) task;
  954.     dtptr->dtParm = (long) lap;
  955. }
  956.  
  957. void install_tm (LapInfo *lap, register struct TMprocess *tmptr, ProcPtr task) {
  958.     bzero((b_8 *) tmptr, (short) sizeof(TMTask));
  959.     tmptr->atm.tmAddr = task;
  960.     tmptr->tmsavptr.lap = lap;
  961.     InsTime((QElemPtr) tmptr);
  962. }