// Beginning of file ept.t _v74_0 := { MOutputNoRet: func(data) // SELF can be any frame that inherits to the base app view begin if strlen(data) then begin if fEndPointState = kState_Connected then begin if strlen(data) then begin try :Output(data, nil, fEndPointOutputSpec); onexception |evt.ex.comm| do begin :MExceptionHandler(CurrentException()); end; end; end else :MNotifyError("Not connected."); end; end, MBuildConfigOptionsmodem: func() begin local options := [ { label: kCMSModemID, type: 'service, result: nil, opCode: opSetRequired, }, { label: kCMOModemECType, type: 'option, opCode: opSetNegotiate, result: nil, form: 'template, data: { arglist: [ kModemECProtocolNone ], typelist: [ 'struct, 'ulong, ], }, }, { label: kCMOMNPCompression, type: 'option, opCode: opSetNegotiate, result: nil, form: 'template, data: { arglist: [ kMNPCompressionV42bis + kMNPCompressionMNP5 + kMNPCompressionNone, ], typelist: [ 'struct, 'ulong, ], }, }, { label: kCMOOutputFlowControlParms, type: 'option, opCode: opSetRequired, result: nil, // not needed; returned form: 'template, // not needed data : { arglist: [ unicodeDC1, // xonChar unicodeDC3, // xoffChar true, // useSoftFlowControl true, // useHardFlowControl 0, // returned 0, // returned ], typelist: [ 'struct, 'char, 'char, 'boolean, 'boolean, 'boolean, 'boolean, ], } }, { label: kCMOInputFlowControlParms, type: 'option, opCode: opSetRequired, result: nil, // not needed; returned form: 'template, // not needed data : { arglist: [ unicodeDC1, // xonChar unicodeDC3, // xoffChar true, // useSoftFlowControl true, // useHardFlowControl 0, // returned 0, // returned ], typelist: [ 'struct, 'char, 'char, 'boolean, 'boolean, 'boolean, 'boolean, ], } }, { label: kCMOSerialIOParms, type: 'option, opCode: opSetNegotiate, result: nil, form: 'template, data: { arglist: [ k1StopBits, // 1 stop bit kNoParity, // no parity bit k8DataBits, // 8 data bits k2400bps, ], // data rate in bps typelist: ['struct, 'long, // stop bits 'long, // parity 'long, // data bits 'long, ], // bps }, }, { type: 'option, label: kCMOSerialBuffers, opCode: opSetRequired, form: 'template, // not needed result: nil, // not needed; returned data : { arglist: [ 256, // use 256 byte transmit buffer 2048, // use 2K byte receive buffer 8, // remember up to 8 error characters ], typelist: [ 'struct, 'ulong, // output buffer size in bytes 'ulong, // input buffer size in bytes 'ulong, // error characters to remember ], }, }, ]; // set the flow control params (hardware or software or none) local fc := { // Note, these labels must agree with kFlowNone, kFlowHard, and kFlowSoft None: { hard: nil, soft: nil }, Hardware: { hard: true, soft: nil }, Software: { hard: nil, soft: true }, }.(if theSession.advanced.flow exists then Intern(theSession.advanced.flow) else 'Software); local pos := ArrayPos(options, kCMOOutputFlowControlParms, 0, func(a,b) StrEqual(a, b.label)); if pos then begin options[pos].data.arglist[kFlowSoftIndex] := fc.soft; options[pos].data.arglist[kFlowHardIndex] := fc.hard; end; pos := ArrayPos(options, kCMOInputFlowControlParms, 0, func(a,b) StrEqual(a, b.label)); if pos then begin options[pos].data.arglist[kFlowSoftIndex] := fc.soft; options[pos].data.arglist[kFlowHardIndex] := fc.hard; end; // set the negotiate error correction protocol (hardware and/or software and/or none) pos := ArrayPos(options, kCMOModemECType, 0, func(a,b) StrEqual(a, b.label)); if pos then begin options[pos].data.arglist[kECIndex] := if theSession.advanced.eCorr then // This is a documentation bug. // Using kModemECProtocolNone does NOT work. // Use '0' instead. 0 + kModemECProtocolMNP else 0; end; pos := ArrayPos(options, kCMOSerialIOParms, 0, func(a,b) StrEqual(a, b.label)); if nil then begin options[pos].data.arglist[kSerialSpeed] := kSerialSpeedLookup.(if theSession.advanced exists and theSession.advanced.speed exists then Intern(theSession.advanced.speed) else '9600); options[pos].data.arglist[kSerialParity] := kSerialParityLookup.(if theSession.advanced exists and theSession.advanced.parity exists then Intern(theSession.advanced.parity) else 'N); options[pos].data.arglist[kSerialStopBits] := kSerialStopBitsLookup.(if theSession.advanced exists and theSession.advanced.stop exists then Intern(theSession.advanced.stop) else '1); options[pos].data.arglist[kSerialData] := kSerialDataLookup.(if theSession.advanced exists and theSession.advanced.data exists then Intern(theSession.advanced.data) else '8); if kdebugOn then print(options[pos]); end; options; end, MShowModemInfo: DefConst('kModemInfoOptions, [ { label: kCMOModemConnectSpeed, type: 'option, opCode: opGetCurrent, result: nil, form: 'number, data: 0, }, { label: kCMOModemECType, type: 'option, opCode: opGetCurrent, result: nil, form: 'number, data: 0, }, ]); func() begin if fEndPointState <> kState_Connected then return :MNotify("Not connected."); local option := :Option(kModemInfoOptions, nil); if not option then return; local speed := option[0].data; local speedStr := NumberStr(speed); local ecType := option[1].data; local ecTypeStr := ( if BAND(ecType, kModemECProtocolExternal) <> 0 then "Hardware" else if BAND(ecType, kModemECProtocolMNP) <> 0 then "Software" else if BAND(ecType, kModemECProtocolNone) <> 0 then "None" else "Unknown" ) & " (" & NumberStr(ecType) & ")"; :MMessage( "Speed: " & speedStr & ", " & "EC: " & ecTypeStr & unicodeCR ); end, TLookupCallback: func(results, error) begin if error or length(results) < 1 then begin // XXX Put some error reporting code here. return; end; :MMessage("Address received."); self.theAddress := results[0].resultIPAddress; :MConnectAction(:TBuildConfigOptions(theLinkID)); end, resetTimer: func(start) begin self.sessionStart := TimeInSeconds(); if start then self.sessionActualStart := TimeInSeconds(); end, SetUpInputSpecs: InputSpecsDef := { telnet: [ kEndPointTelnetInputSpec, kEndPointOneCharTelnetInputSpec, ], serial: [ kEndPointInputSpec, kEndPointOneCharInputSpec, ], }; DefineGlobalConstant('kInputSpecsDef, InputSpecsDef); func(type) begin inputSpecs := Clone(kInputSpecsDef.(if type = 'telnet then 'telnet else 'serial)); inputSpecs[0] := { partialFrequency: prefs.timing.partial, _proto: inputSpecs[0], }; end, DoTelnet: func() begin // Gotta do this somewhere. // Why not here? lex:StartupTelnet(); // Just call the open slip, and wait for the callback InetOpenConnectionSlip(nil, self, 'TGrabActionCallback); end, MConnect: func(connectAction, phoneNumber) begin if fEndPointState <> kState_Disconnected then return; self.fConnectAction := connectAction; self.fQuiet := nil; if connectAction = kAction_Listen then :MSetEndPointState(kState_Listen); else if connectAction = kAction_Connect then begin self.fConnectAddress := MakePhoneOption(phoneNumber); :MSetEndPointState(kState_Connect); end else return; self:MConnectSetOptions(); end, MBuildConfigOptionsSerial: func() // SELF can be any frame that inherits to the app base view begin local options := [ { label: kCMSAsyncSerial, type: 'service, opCode: opSetRequired, result: nil, }, { label: kCMOSerialHWChipLoc, type: 'option, opCode: opSetRequired, result: nil, form: 'template, data: { argList: [ kHWLocExternalSerial , // kHWLocExternalSerial, kHWLocBuiltInIR, kHWLocPCMCIASlot1 0, ], typeList: ['struct, ['array, 'char, 4], 'ulong, ], }, }, { label: kCMOSerialIOParms, type: 'option, opCode: opSetRequired, result: nil, form: 'template, data: { arglist: [ k1StopBits, // 1 stop bit kNoParity, // no parity bit k8DataBits, // 8 data bits k9600bps, ], // date rate in bps typelist: ['struct, 'long, // stop bits 'long, // parity 'long, // data bits 'long, ], }, }, // bps { label: kCMOInputFlowControlParms, type: 'option, opCode: opSetRequired, result: nil, form: 'template, data: { arglist: [ 17, // xonChar 19, // xoffChar 1, // useSoftFlowControl 0, // useHardFlowControl 0, // not needed; returned 0, ], // not needed; returned typelist: ['struct, 'char, // XON character 'char, // XOFF character 'boolean, // software flow control 'boolean, // hardware flow control 'boolean, // hardware flow blocked 'boolean, ], }, }, // software flow blocked { label: kCMOOutputFlowControlParms, type: 'option, opCode: opSetRequired, result: nil, form: 'template, data: { arglist: [ 17, // xonChar 19, // xoffChar 1, // useSoftFlowControl 0, // useHardFlowControl 0, // not needed; returned 0, ], // not needed; returned typelist: ['struct, 'char, // XON character 'char, // XOFF character 'boolean, // software flow control 'boolean, // hardware flow control 'boolean, // hardware flow blocked 'boolean, ], }, }, // software flow blocked { type: 'option, label: kCMOSerialBuffers, opCode: opSetRequired, form: 'template, // not needed result: nil, // not needed; returned data : { arglist: [ 256, // use 256 byte transmit buffer 2048, // use 2K byte receive buffer 8, // remember up to 8 error characters ], typelist: [ 'struct, 'ulong, // output buffer size in bytes 'ulong, // input buffer size in bytes 'ulong, // error characters to remember ], }, }, ]; // set the flow control params (hardware or software or none) local fc := { // Note, these labels must agree with kFlowNone, kFlowHard, and kFlowSoft None: { hard: nil, soft: nil }, Hardware: { hard: true, soft: nil }, Software: { hard: nil, soft: true }, }.(if theSession.advanced.flow exists then Intern(theSession.advanced.flow) else 'Software); local pos := ArrayPos(options, kCMOOutputFlowControlParms, 0, func(a,b) StrEqual(a, b.label)); if pos then begin options[pos].data.arglist[kFlowSoftIndex] := fc.soft; options[pos].data.arglist[kFlowHardIndex] := fc.hard; end; pos := ArrayPos(options, kCMOInputFlowControlParms, 0, func(a,b) StrEqual(a, b.label)); if pos then begin options[pos].data.arglist[kFlowSoftIndex] := fc.soft; options[pos].data.arglist[kFlowHardIndex] := fc.hard; end; pos := ArrayPos(options, kCMOSerialIOParms, 0, func(a,b) StrEqual(a, b.label)); if pos then begin options[pos].data.arglist[kSerialSpeed] := kSerialSpeedLookup.(if theSession.advanced exists and theSession.advanced.speed exists then Intern(theSession.advanced.speed) else '9600); options[pos].data.arglist[kSerialParity] := kSerialParityLookup.(if theSession.advanced exists and theSession.advanced.parity exists then Intern(theSession.advanced.parity) else 'N); options[pos].data.arglist[kSerialStopBits] := kSerialStopBitsLookup.(if theSession.advanced exists and theSession.advanced.stop exists then Intern(theSession.advanced.stop) else '1); options[pos].data.arglist[kSerialData] := kSerialDataLookup.(if theSession.advanced exists and theSession.advanced.data exists then Intern(theSession.advanced.data) else '8); end; options; end, MDisconnectCompProc: func(options, result) begin try :UnBind(nil); onexception |evt.ex.comm| do nil; try :Dispose() onexception |evt.ex.comm| do nil; if theLinkID then begin InetReleaseLink(theLinkID, self, 'MDisconnectInet); self.theLinkID := nil; end; /* if lex and lex.ClosedownTelnet exists then begin lex:ClosedownTelnet(); end; */ :MMessage(kMessage_Disconnected); :MSetEndPointState(kState_Disconnected); // Disconnect slip stuff here -gam XXX !!! if fPowerOffState then begin fPoserOffState := nil; PowerOffResume(kAppSymbol); end; UnRegPowerOff(kAppSymbol); end, MDisconnectAction: func(fromState) begin try :Cancel(nil); onexception |evt.ex.comm| do nil; if fromState = kState_Connected then try :Disconnect(nil, { async: true, reqTimeout: 3600, completionScript: func(ep, options, result) ep:MDisconnectCompProc(options, result), }); onexception |evt.ex.comm| do :MDisconnectCompProc(nil, CurrentException().error); else :MDisconnectCompProc(nil, nil); end, TGrabActionCallback: func(symbol) begin // Then just quit. if symbol = 'close then begin :MSetEndPointState(kState_Disconnected); return; end; TStatusView := InetDisplayStatus(nil, nil, nil); InetGrabLink(nil, self, 'TGrabStatusCallback); end, MSetInputSpec: func(type) begin local ret := inputSpecs[if type = 'normal then 0 else 1]; :SetInputSpec(ret); end, TLookupName: func() begin // Just use Craig's machine for now. name := theSession.advanced.machineName; :MMessage("Looking up machine address..."); DNSGetAddressFromName(name, self, 'TLookupCallback); end, MDisconnectInet: func(linkID, linkStatus, err) begin end, MResetConnection: func(cancel) begin if fEndPointState <> kState_Connected then return; if cancel then try :Cancel(nil); onexception |evt.ex.comm| do nil; :MSetInputSpec('normal); end, icon: GetPictAsBits("extras icon", nil), SetPartialTime: func(newTime) begin if inputSpecs and inputSpecs[0] then begin inputSpecs[0].partialFrequency := newTime; end; end, TBuildConnectOptions: // address - a four element array containing the IP address // port - the port to connect to. func(address, port) begin [ { label: "itrs", type: 'option, opCode: opSetRequired, result: nil, form: 'template, data: { arglist: [ address[0], address[1], address[2], address[3], port, ], typelist: [ 'struct, 'byte, 'byte, 'byte, 'byte, 'short, ], }, } ] end, fEndPointOutputSpec: { form: 'string, aSync: true, CompletionScript: func(a,b,c) begin return nil; end, }, New: // For this little abstraction to work, certain things are // required: // // fEndPointState must be declared somewhere in the Parent. // fEndPointInputSpec must be declared somewhere in the Parent, // and is used as the default input spec. // MSetEndPointState(state) must exist in the Parent and // change the state of fEndPointState. // MNotifyError(msg) must exist in the Parent and should // display the error message somehow. // MMessage(msg) must exist in the Parent and should // display the message somehow. // MInput(data, partial) must exist in the Parent and is in charge of // handling the data in the default InputSpec. // If it is being called from a partialScript, then partial = 'partial. func(parent, exceptionHandler) begin { _proto: self, _Parent: parent, // exceptionHandler: exceptionHandler, exceptionHandler: if kDebugOn then nil else exceptionHandler, fConnectAction: nil, fConnectAddress: nil, fDisconnectSlip: nil, fPowerOffState: nil, fQuiet: nil, sessionStart: 0, theAddress: nil, // encoding: nil, theLinkID: nil, inputSpecs: nil, crChar: unicodeCR, }; end, MDisconnect: func() begin if fEndPointState <> kState_Connected and fEndPointState <> kState_Connecting and fEndPointState <> kState_Listening then return; self.fQuiet := true; local fromState := fEndPointState; :MSetEndPointState(kState_Disconnecting); :MMessage(kMessage_Disconnecting); // XXX !!! gam // Put the disconnect slip stuff here. :MDisconnectAction(fromState); end, TBuildConfigOptions: func(linkID) begin [ { label: "inet", type: 'service, opCode: opSetRequired, result: nil, }, { label: "ilid", type: 'option, opCode: opSetRequired, result: nil, form: 'template, data: { arglist: [ linkID ], typelist: [ 'struct, 'ulong ], }, }, { label: "itsv", type: 'option, opCode: opSetRequired, result: nil, form: 'template, data: { arglist: [ 1 ], // kTCP typelist: [ 'struct, 'ulong ], }, }, // Bind options - I don't think I need any. ] end, MConnectSetOptions: func () begin if theSession.type = 'dialup then :MConnectAction(:MBuildConfigOptionsModem()); else if theSession.type = 'serial then :MConnectAction(:MBuildConfigOptionsSerial()); else if theSession.type = 'telnet then :DoTelnet(); end, TStatusView: nil, MOutput: func(data) // SELF can be any frame that inherits to the base app view begin if fEndPointState = kState_Connected then try :Output(data & crChar, nil, fEndPointOutputSpec) onexception |evt.ex.comm| do :MExceptionHandler(CurrentException()); else :MNotifyError("Not connected."); end, TGrabStatusCallback: func(linkID, status, err) begin if err then begin // XXX Some sort of better error reporting here. InetDisplayStatus(linkID, TStatusView, nil); end else if status.linkStatus <> 'connected then begin InetDisplayStatus(linkID, TStatusView, status); end else begin self.theLinkID := linkID; InetDisplayStatus(linkID, TStatusView, nil); :TLookupName(); end; end, MConnectCompProc: func(options, result) begin if kDebugOn then :MMessage("In MConnectCompProc"); if result then begin :MNotifyError(result); :MDisconnect(); return; end; if fConnectAction = kAction_Listen then try :Accept(nil, nil); onexception |evt.ex.comm| do begin :MNotifyError(CurrentException().error); :MDisconnect(); return; end; // Setting this here because I don't know where else to do it. self.crChar := if theSession.type = 'telnet then unicodeLF else unicodeCR; // Have to set the speed here. if theSession.type = 'dialup or theSession.type = 'serial then begin local options := :MBuildConfigOptionsModem(); local pos := ArrayPos(options, kCMOSerialIOParms, 0, func(a,b) StrEqual(a, b.label)); if (pos) then begin // Debugging code. // :Option([options[pos]],nil); end; end; :ResetTimer(true); :MSetEndPointState(kState_Connected); :MMessage(kMessage_Connected); :SetUpInputSpecs(theSession.type); :MResetConnection(nil); if theSession.type <> 'telnet then :MShowModemInfo(); AddDelayedSend(dialBox, 'Close, nil, 1000); end, viewClass: 74 /* clView */, MConnectAction: func(EndPointOptions) begin try begin :MMessage("Instantiating..."); :Instantiate(self, EndPointOptions); end onexception |evt.ex.comm| do begin :MNotifyError(CurrentException().error); :MSetEndPointState(kState_Disconnected); end; try begin :Bind(nil, nil); :MMessage("Binding..."); end onexception |evt.ex.comm| do begin :MNotifyError(CurrentException().error); :MSetEndPointState(kState_Disconnected); //:Dispose; // -gam !!! XXX return; end; RegPowerOff(kAppSymbol, func(what, why) // we create the closure here so as to set up SELF as the endpoint frame in the closure begin if what = 'okToPowerOff then begin if why <> 'idle or fEndPointState = kState_Disconnected then return true; end else if what = 'powerOff then begin if why <> 'idle and fEndPointState <> kState_Disconnected then begin fPowerOffState := 'holdYourHorses; :MDisconnect(); return 'holdYourHorses; end end; nil; // ALWAYS return nil here end); try begin if fConnectAction = kAction_Listen then begin :MSetEndPointState(kState_Listening); :MMessage(kMessage_Listening); :Listen(nil, { async: true, reqTimeOut: 90000, // 90 seconds, you really should look into something better here. completionScript: func(ep, options, result) ep:MConnectCompProc(options, result) }); end else if fConnectAction = kAction_Connect then begin :MSetEndPointState(kState_Connecting); :MMessage(kMessage_Connecting); local opts := if theSession.type = 'telnet then :TBuildConnectOptions(theAddress, Floor(StringToNumber(StringFilter(theSession.advanced.portNumber, "0123456789.", 'passAll)))); else [ fconnectAddress ]; :Connect(opts, { async: true, reqTimeout: 45000, // 45 seconds completionScript: func(ep, options, result) ep:MConnectCompProc(options, result), }); end end onexception |evt.ex.comm| do begin :MNotifyError(CurrentException().error); :MDisconnect(); end; end }; // After Script for _v74_0 thisView := _v74_0; RemoveSlot(thisView, 'viewClass); thisView._proto := protoBasicEndPoint; constant |layout_ept.t| := _v74_0; // End of file ept.t