// Text of project Basic Modem written on 11/20/95 at 16:24
// Beginning of text file Project Data
// Copyright © 1994-1995 Apple Computer, Inc. All rights reserved

constant kAction_Connect := 'connect;
constant kAction_Listen := 'listen;

constant kState_Disconnected := 0;	// ready-to-go (default state)
constant kState_Listen := 1;		// preparation for (asynchronous) listen
constant kState_Listening := 2;		// in-process of (asynchronous) listen
constant kState_Connect := 3;		// preparation for (asynchronous) connect
constant kState_Connecting := 4;	// in-process of (asynchronous) connect
constant kState_Connected := 5;		// connected (requires disconnect)
constant kState_Disconnecting := 6;	// in-process of (asynchronous) disconnect

constant kMessage_Disconnected := "Ready to connect…";
constant kMessage_Listening := "Waiting for connection...";
constant kMessage_Connecting := "Connecting...";
constant kMessage_Connected := "Connected, awaiting disconnect...";
constant kMessage_Disconnecting := "Disconnecting, please wait...";
constant kMessage_NoPhoneNumber := "Please specify a phone number to dial.";
constant kMessage_ConnectFailed := "Connection not established; no response.";
constant kMessage_ConnectECFailed := "A reliable connection could not be established.";
constant kMessage_BufferOverrun := "The communications data buffer was overrun and has been reset.";
constant kMessage_LostConnection := "The connection seems to have dropped.";
constant kMessage_ModemNotResponding := "The modem is not responding.";
constant kMessage_ModemPhoneLineBusy := "The line is busy.";
constant kMessage_ModemLineNoAnswer := "There was no answer.";
constant kMessage_ModemNoDialtone := "There is no dialtone.";
constant kMessage_ModemNotFound := "There does not appear to be a modem attached to this unit.";
constant kMessage_Timeout := "The connection seems to have timed out.";
constant kMessage_PortInUse := "Another application seems to be using the communications port.";
// End of text file Project Data
// Beginning of file protoDisconnectSlip

// Before Script for "_userproto000"
// Copyright © 1994-1995 Apple Computer, Inc. All rights reserved.


_userproto000 :=
    {viewBounds: {left: 0, top: 0, right: 108, bottom: 44},
     viewJustify: 80,
     ReorientToScreen: ROM_DefRotateFunc,
     _proto: @179
    };

_view000 :=
    {viewBounds: {left: 8, top: 8, right: 104, bottom: 40},
     viewJustify: 2,
     text:
       "Disconnecting...
       Please Wait...",
     _proto: @218
    };
AddStepForm(_userproto000, _view000);




constant |layout_protoDisconnectSlip| := _userproto000;
// End of file protoDisconnectSlip
// Beginning of file Basic Modem.t

// Before Script for "vMainApp"
// Copyright © 1994-1995 Apple Computer, Inc. All rights reserved.


vMainApp :=
    {
     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 := fEndPoint: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(	"Modem Speed: "	& speedStr	& unicodeCR &
       				"EC Type: "		& ecTypeStr	& unicodeCR	);
       end,
     viewSetupDoneScript:
       func()
       begin
       	:MSetEndPointState(fEndPointState);		// do NOT change the endpoint state -- just update any views that depend on it
       	if fEndPointState = kState_Disconnected then
       		:MMessage(kMessage_Disconnected);
       	else
       		:MMessage("");
       end,
     MMessage:
       func(message)		// this routine can be called regardless of the value of SELF
       begin
       	local appBaseView := GetRoot().(kAppSymbol);
       	
       	if call kViewIsOpenFunc with (appBaseView) then
       		begin	
       			SetValue(appBaseView.vMessage, 'text, Clone(message));
       			RefreshViews();
       		end
       end,
     viewFormat: 83951953,
     viewQuitScript:
       func()
       begin
       	:MDisconnect();
       	RemoveSlot(GetRoot().(kAppSymbol), 'fEndPoint);
       end,
     MConnect:
       func(connectAction)
       begin
       	if fEndPointState <> kState_Disconnected then
       		return;
       	
       	fEndPoint.fConnectAction := connectAction;
       	fEndPoint.fQuiet := nil;
       	
       	if connectAction = kAction_Listen then
       		:MSetEndPointState(kState_Listen);
       	else if connectAction = kAction_Connect then
       		begin
       			if not StrFilled(vPhone.text) then
       				return :MNotify(kMessage_NoPhoneNumber);
       			
       			fEndPoint.fConnectAddress := MakePhoneOption(vPhone.text);
       		
       			:MSetEndPointState(kState_Connect);
       		end;
       	else
       		return;
       	
       	fEndPoint:MConnectAction();
       end,
     MDisconnectCompProc:
       func(options, result)	// SELF is the endpoint frame
       begin
       	try
       		:UnBind(nil)
       	onexception |evt.ex.comm| do
       		nil;
       	
       	try
       		:Dispose()
       	onexception |evt.ex.comm| do
       		nil;
       	
       	if fDisconnectSlip then begin
       			fDisconnectSlip:Close();
       			fDisconnectSlip := nil;
       		end;
       	
       	:MMessage(kMessage_Disconnected);
       	:MSetEndPointState(kState_Disconnected);
       	
       	if fPowerOffState then
       		begin
       			fPowerOffState := nil;
       			PowerOffResume(kAppSymbol);
       		end;
       	UnRegPowerOff(kAppSymbol);
       end,
     fEndPointOptions:
       nil		// see MBuildConfigOptions & MConnectAction for more info
       ,
     MDisconnectAction:
       func(fromState)		// SELF is the endpoint frame
       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,
     MBuildConfigOptions:
       func()		// SELF can be any frame that inherits to the app base view
       begin
       	local options :=
       		[
       			{	label:		kCMSModemID,			// "mods"
       				type:		'service,
       				result:		nil,
       				opCode:		opSetRequired	},		// 512
       			
       			{	label:		kCMOModemECType,		// "mecp"
       				type:		'option,
       				opCode:		opSetNegotiate,			// 256
       				result:		nil,
       				form: 		'template,
       				data:	{
       					arglist:[
       						0,	],
       					typelist:['struct,
       						'ulong,	],	},	},
       			
       			{	label:		kCMOMNPCompression,		// "mnpc"
       				type:		'option,
       				opCode:		opSetNegotiate,			// 256
       				result:		nil,
       				form: 		'template,
       				data:	{
       					arglist:[
       						kMNPCompressionV42bis + kMNPCompressionMNP5 + kMNPCompressionNone,	],	// 0000 0000 0000 1011
       					typelist:['struct,
       						'ulong,	],	},	},
       		];
       	
       	// set the negotiated error correction protocol (hardware and/or software and/or none)
       	local pos := ArrayPos(options, kCMOModemECType, 0, func(a,b) StrEqual(a,b.label));
       	if pos then
       		begin
       			if vECHardware.viewValue
       			or vECSoftware.viewValue then
       				begin
       					options[pos].data.arglist[0] := 0;
       					if vECHardware.viewValue then
       						options[pos].data.arglist[0] := Bor(options[pos].data.arglist[0], vECHardware.viewValue);
       					if vECSoftware.viewValue then
       						options[pos].data.arglist[0] := Bor(options[pos].data.arglist[0], vECSoftware.viewValue);
       				end;
       			else
       				options[pos].data.arglist[0] := kModemECProtocolNone;
       		end;
       	
       	options;
       end,
     viewBounds: {left: -2, top: -2, right: 230, bottom: 310},
     MExceptionHandler:
       func(exceptionFrame)		// SELF is the endpoint frame
       begin
       	if exceptionFrame
       	and exceptionFrame.data
       	and exceptionFrame.data <> -16005 then				// ignore -16005 (just the result of calling Cancel)
       		if exceptionFrame.data = -18003 then			// I/O buffer overrun
       			begin
       				AddDeferredCall(func(ep) ep:MResetConnection(true), [self]);
       				:MNotifyError(exceptionFrame.data);
       			end;
       		else begin										// handle all other (unexptected) exceptions by disconnecting the endpoint
       				AddDeferredCall(func(ep) ep:MDisconnect(), [self]);
       				:MNotifyError(exceptionFrame.data);
       			end;
       	
       	true;
       end,
     _proto: @157,
     MNotifyError:
       func(error)
       begin
       	if not error
       	or (fEndPoint and fEndPoint.fQuiet) then
       		return;
       	
       	if error = -10078 then
       		:MNotify(kMessage_PortInUse);
       	
       	else if error = -16013 then
       		:MNotify(kMessage_Timeout);
       	
       	else if error = -10008 then
       		:MNotify(kMessage_ModemNotFound);
       	
       	else if error = -24001 then
       		:MNotify(kMessage_ModemNoDialtone);
       	
       	else if error = -24002 or error = -24004 then
       		:MNotify(kMessage_ModemLineNoAnswer);
       	
       	else if error = -24003 then
       		:MNotify(kMessage_ModemPhoneLineBusy);
       	
       	else if error = -24000 or error = -24005 or error = -24007 then
       		:MNotify(kMessage_ModemNotResponding);
       	
       	else if error = -16009		// generic lost connection
       		 or error = -20003 then	// MNP lost connection
       		:MNotify(kMessage_LostConnection);
       	
       	else if error = -18003 then
       		:MNotify(kMessage_BufferOverrun);
       	
       	else if error = -20006 then
       		:MNotify(kMessage_ConnectECFailed);
       	
       	else if error = -38001 then
       		:MNotify(kMessage_ConnectFailed);
       	
       	else
       		:MNotify("An unexpected error has occured.  Error code = " & NumberStr(error));
       end,
     MResetConnection:
       func(cancel)		// SELF is the endpoint frame
       begin
       	if fEndPointState <> kState_Connected then
       		return;
       	
       	if cancel then
       		try
       			:Cancel(nil)
       		onexception |evt.ex.comm| do
       			nil;
       	
       	:SetInputSpec(fEndPointInputSpec);
       end,
     viewJustify: 80,
     title: kAppName,
     fEndPointState: kState_Disconnected,
     fEndPointOutputSpec:
       {
       	form:		'string,
       },
     MDisconnect:
       func()
       begin
       	if not fEndPoint
       	or fEndPointState <> kState_Connected
       	and fEndPointState <> kState_Connecting
       	and fEndPointState <> kState_Listening then
       		return;
       	
       	fEndPoint.fQuiet := true;		// supress user alerts and other interactions while disconnecting
       	
       	local fromState := fEndPointState;
       	:MSetEndPointState(kState_Disconnecting);
       	:MMessage(kMessage_Disconnecting);
       	
       	fEndPoint.fDisconnectSlip := BuildContext(GetLayout("protoDisconnectSlip"));
       	fEndPoint.fDisconnectSlip:Open();
       	
       	fEndPoint:MDisconnectAction(fromState);	
       end,
     fEndPoint: nil,
     fEndPointInputSpec:
       {
       	form:			'string,
       	termination:	{	endSequence:	[unicodeCR],	},
       	discardAfter:	256,
       	inputScript:	func(ep, data, terminator, options)
       					ep:MInput(data),
       },
     viewSetupFormScript:
       func()
       begin
       	// make view no bigger than the original MP
       	local b := GetAppParams();
       	viewBounds := RelBounds( b.appAreaLeft,	b.appAreaTop,
       						MIN( b.appAreaWidth, 240 ),
       						MIN( b.appAreaHeight, 336 ));
       	
       	self.fEndPoint :=	{	_proto:				protoBasicEndPoint,
       							_parent:			self,
       							exceptionHandler:	MExceptionHandler,
       							fConnectAction:		nil,
       							fConnectAddress:	nil,
       							fDisconnectSlip:	nil,
       							fPowerOffState:		nil,
       							fQuiet:				nil,	};
       end,
     MOutput:
       func(data)		// SELF can be any frame that inherits to the base app view
       begin
       	if fEndPointState = kState_Connected then
       		try
       			fEndPoint:Output(data & unicodeCR, nil, fEndPointOutputSpec)
       		onexception |evt.ex.comm| do
       			:MExceptionHandler(CurrentException());
       	else
       		:MNotify("Not connected.");
       end,
     MSetEndpointState:
       func(newState)		// this routine can be called regardless of the value of SELF
       begin
       	local appBaseView := GetRoot().(kAppSymbol);
       	
       	//	NOTE: We must be absolutely certain fEndPointState gets created/overridden in the app base view frame!
       	appBaseView.fEndPointState := newState;
       	
       	if not call kViewIsOpenFunc with (appBaseView) then
       		return;
       	
       	if appBaseView.fEndPointState = kState_Disconnected then begin
       			appBaseView.vConnect:Show();
       			appBaseView.vListen:Show();
       			appBaseView:MSetButtons("Connect", "Listen");
       		end;
       	
       	else if appBaseView.fEndPointState = kState_Listen then begin
       			appBaseView.vConnect:Hide();
       			appBaseView:MSetButtons("Listening", nil);
       		end;
       	
       	else if appBaseView.fEndPointState = kState_Listening then
       			appBaseView:MSetButtons("Stop Listening", nil);
       	
       	else if appBaseView.fEndPointState = kState_Connect then begin
       			appBaseView.vListen:Hide();
       			appBaseView:MSetButtons("Connecting", nil);
       		end;
       	
       	else if appBaseView.fEndPointState = kState_Connecting then
       			appBaseView:MSetButtons("Stop Connecting", nil);
       	
       	else if appBaseView.fEndPointState = kState_Connected then
       			appBaseView:MSetButtons("Disconnect", nil);
       	
       	else if appBaseView.fEndPointState = kState_Disconnecting then
       			appBaseView:MSetButtons("Disconnecting", nil);
       	
       	else
       			appBaseView:MSetButtons("I Am Confused", nil);
       	
       	RefreshViews();
       end,
     MInput:
       func(data)		// SELF is the endpoint frame
       begin
       	PlaySound(ROM_PlinkBeep);
       	:MMessage(data);
       end,
     MConnectCompProc:
       func(options, result)	// SELF is the endpoint frame
       begin
       	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;
       	
       	:MSetEndPointState(kState_Connected);
       	:MMessage(kMessage_Connected);
       	:MResetConnection(nil);
       	:MShowModemInfo();
       end,
     MConnectAction:
       func()		// SELF is the endpoint frame
       begin
       	fEndPointOptions := :MBuildConfigOptions();
       	
       	try
       		:Instantiate(self, fEndPointOptions)
       	onexception |evt.ex.comm| do
       		begin
       			:MNotifyError(CurrentException().error);
       			:MSetEndPointState(kState_Disconnected);
       			return;
       		end;
       	
       	try
       		:Bind(nil, nil)
       	onexception |evt.ex.comm| do
       		begin
       			:MNotifyError(CurrentException().error);
       			:MSetEndPointState(kState_Disconnected);
       			:Dispose();
       			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									// keep the unit awake whenever we're connected
       							or fEndPointState = kState_Disconnected then	// unless the user or an application explicitly
       								return true;								// wants it to sleep
       						end;
       					
       					else if what = 'powerOff then
       						begin
       							if why <> 'idle									// if we simply must go to sleep but we're still
       							and fEndPointState <> kState_Disconnected then	// connected then begin the disconnect process
       								begin
       									fPowerOffState := 'holdYourHorses;		// set a flag to indicate we're powering down
       									: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 -- for DEMO purposes only
       								completionScript:	func(ep, options, result)
       													ep:MConnectCompProc(options, result)	});
       				end;
       			else if fConnectAction = kAction_Connect then
       				begin
       					:MSetEndPointState(kState_Connecting);
       					:MMessage(kMessage_Connecting);
       					:Connect( [ fConnectAddress ],
       							{	async:				true,
       								reqTimeout:			45000,	// 45 seconds -- for DEMO purposes only
       								completionScript:	func(ep, options, result)
       													ep:MConnectCompProc(options, result),	});
       				end
       		end
       	onexception |evt.ex.comm| do
       		begin
       			:MNotifyError(CurrentException().error);
       			:MDisconnect();
       		end;
       end,
     debug: "vMainApp",
     MNotify:
       func(message)
       begin
       	GetRoot():Notify(kNotifyAlert, kAppName, message);	// no longer necessary to EnsureInternal params
       end,
     MSetButtons:
       func(connectText, listenText)
       begin
       	SetValue(vConnect, 'text, connectText);
       	if listenText then
       		SetValue(vListen, 'text, listenText);
       	else
       		SetValue(vListen, 'text, connectText);
       end
    };

_view001 :=
    {viewBounds: {left: 8, top: 16, right: 224, bottom: 32},
     text: "Messages & Received Data:",
     _proto: @218
    };
AddStepForm(vMainApp, _view001);



vMessage :=
    {viewBounds: {left: 9, top: 33, right: 223, bottom: 119},
     viewJustify: 0,
     viewFormat: 337,
     viewFont: simpleFont12,
     text: "",
     viewClickScript:
       func(unit)
       begin
       	SetValue(self, 'text, "");
       	true;
       end,
     viewFlags: 515,
     debug: "vMessage",
     _proto: @218
    };
AddStepForm(vMainApp, vMessage);
StepDeclare(vMainApp, vMessage, 'vMessage);



_view002 :=
    {viewBounds: {left: 8, top: 128, right: 168, bottom: 144},
     text: "Message To Send:",
     _proto: @218
    };
AddStepForm(vMainApp, _view002);



vInputArea :=
    {viewFlags: 64001,
     viewFormat: 12625,
     viewLineSpacing: 20,
     viewFont: 18434,
     viewBounds: {left: 9, top: 145, right: 167, bottom: 195},
     text: "This is a test!",
     debug: "vInputArea",
     viewClass: 81
    };
AddStepForm(vMainApp, vInputArea);
StepDeclare(vMainApp, vInputArea, 'vInputArea);



vConnect :=
    {
     buttonClickScript:
       func()
       begin
       	if fEndPointState = kState_Disconnected then
       		:MConnect(kAction_Connect);
       	else
       		:MDisconnect();
       end,
     viewBounds: {left: 122, top: 222, right: 222, bottom: 242},
     text: ""
     ,
     debug: "vConnect",
     _proto: @226
    };
AddStepForm(vMainApp, vConnect);
StepDeclare(vMainApp, vConnect, 'vConnect);



vListen :=
    {
     buttonClickScript:
       func()
       begin
       	if fEndPointState = kState_Disconnected then
       		:MConnect(kAction_Listen);
       	else
       		:MDisconnect();
       end,
     viewBounds: {left: 122, top: 250, right: 222, bottom: 270},
     text: ""
     ,
     debug: "vListen",
     _proto: @226
    };
AddStepForm(vMainApp, vListen);
StepDeclare(vMainApp, vListen, 'vListen);



vSend :=
    {
     buttonClickScript:
       func()
       begin
       	:MOutput(if vInputArea.text then vInputArea.text else "");
       end,
     viewBounds: {left: 178, top: 146, right: 222, bottom: 166},
     text: "Send",
     debug: "vSend",
     _proto: @226
    };
AddStepForm(vMainApp, vSend);
StepDeclare(vMainApp, vSend, 'vSend);



vInfo :=
    {
     buttonClickScript:
       func()
       begin
       	:MShowModemInfo();
       end,
     viewBounds: {left: 178, top: 174, right: 222, bottom: 194},
     text: "Info",
     debug: "vInfo",
     _proto: @226
    };
AddStepForm(vMainApp, vInfo);
StepDeclare(vMainApp, vInfo, 'vInfo);



_view003 :=
    {viewBounds: {left: 8, top: 204, right: 112, bottom: 220},
     text: "Phone Number:",
     _proto: @218
    };
AddStepForm(vMainApp, _view003);



vPhone :=
    {viewFlags: 305665,
     viewFormat: 12625,
     viewLineSpacing: 20,
     viewFont: 18434,
     viewBounds: {left: 9, top: 221, right: 111, bottom: 271},
     viewSetupFormScript:
       func()
       begin
       	// text := Clone(userConfiguration.mailPhone);
       	text := "257-8203";
       end,
     text: "",
     debug: "vPhone",
     viewClass: 81
    };
AddStepForm(vMainApp, vPhone);
StepDeclare(vMainApp, vPhone, 'vPhone);



_view004 :=
    {viewBounds: {left: 8, top: 279, right: 104, bottom: 295},
     text: "Use EC protocol in:",
     _proto: @218
    };
AddStepForm(vMainApp, _view004);



vECHardware :=
    {text: "Hardware",
     viewBounds: {left: 104, top: 276, right: 168, bottom: 292},
     buttonValue: kModemECProtocolExternal,
     debug: "vECHardware",
     _proto: @164
    };
AddStepForm(vMainApp, vECHardware);
StepDeclare(vMainApp, vECHardware, 'vECHardware);



vECSoftware :=
    {text: "Software",
     viewBounds: {left: 168, top: 276, right: 228, bottom: 292},
     buttonValue: kModemECProtocolMNP,
     debug: "vECSoftware",
     _proto: @164
    };
AddStepForm(vMainApp, vECSoftware);
StepDeclare(vMainApp, vECSoftware, 'vECSoftware);




constant |layout_Basic Modem.t| := vMainApp;
// End of file Basic Modem.t



