1 line
84 KiB
C
Executable File
1 line
84 KiB
C
Executable File
/* Copyright (c) 2017, Computer History Museum
|
|
All rights reserved.
|
|
Redistribution and use in source and binary forms, with or without modification, are permitted (subject to
|
|
the limitations in the disclaimer below) provided that the following conditions are met:
|
|
* Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
|
|
* Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following
|
|
disclaimer in the documentation and/or other materials provided with the distribution.
|
|
* Neither the name of Computer History Museum nor the names of its contributors may be used to endorse or promote products
|
|
derived from this software without specific prior written permission.
|
|
NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE
|
|
COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
|
HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
|
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
|
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
|
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
|
|
DAMAGE. */
|
|
|
|
#include "tcp.h"
|
|
#define FILE_NUM 37
|
|
/* Copyright (c) 1990-1992 by the University of Illinois Board of Trustees */
|
|
/************************************************************************
|
|
* functions for i/o over a pseudo-telnet MacTcp stream
|
|
* these functions are oriented toward CONVENIENCE, not performance
|
|
************************************************************************/
|
|
|
|
#pragma segment TcpTrans
|
|
|
|
/************************************************************************
|
|
* private functions
|
|
************************************************************************/
|
|
#define TcpTrouble(stream,which,err) TT(stream,which,err,FNAME_STRN+FILE_NUM,__LINE__)
|
|
int TT(TransStream stream,int which, int theErr, int file, int line);
|
|
uLong RandomAddr(uLong *addrs);
|
|
void NoteAddrGoodness(struct hostInfo *hip,uLong addr,short err);
|
|
pascal void BindDone(struct hostInfo *hostInfoPtr, char *userData);
|
|
pascal void TcpASR(StreamPtr tcpStream, unsigned short eventCode,UPtr userDataPtr, unsigned short terminReason, struct ICMPReport *icmpMsg);
|
|
|
|
/**********************************************************************
|
|
* ConnectTransLo - connect to a host
|
|
**********************************************************************/
|
|
OSErr ConnectTrans(TransStream stream, UPtr serverName, long port, Boolean silently,uLong timeout)
|
|
{
|
|
Str255 realHost;
|
|
|
|
PCopy(realHost,serverName);
|
|
|
|
SplitPort(realHost,&port);
|
|
|
|
return ConnectTransLo(stream,realHost,port,silently,timeout);
|
|
}
|
|
|
|
/**********************************************************************
|
|
* SplitPort - Split host:port into components
|
|
* returns true if port found
|
|
**********************************************************************/
|
|
Boolean SplitPort(PStr host,long *port)
|
|
{
|
|
UPtr colon;
|
|
long localPort;
|
|
|
|
if (colon=PIndex(host,':'))
|
|
{
|
|
*colon = *host - (colon-host);
|
|
*host = colon-host-1;
|
|
StringToNum(colon,&localPort);
|
|
ASSERT(localPort>0);
|
|
if (localPort>0 && port) *port = localPort;
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
/**********************************************************************
|
|
* RandomAddr - pick a random address out of a set of addresses
|
|
**********************************************************************/
|
|
uLong RandomAddr(uLong *addrs)
|
|
{
|
|
short count;
|
|
if (!PrefIsSet(PREF_DNS_BALANCE)) return(addrs[0]);
|
|
|
|
for (count=NUM_ALT_ADDRS;count;count--) if (addrs[count-1]) break;
|
|
return(addrs[count<2?0:TickCount()%count]);
|
|
}
|
|
|
|
/**********************************************************************
|
|
* NoteAddrGoodness - remove an address or all except an address
|
|
**********************************************************************/
|
|
void NoteAddrGoodness(struct hostInfo *hip,uLong addr,short err)
|
|
{
|
|
short count,i;
|
|
|
|
if (!PrefIsSet(PREF_DNS_BALANCE)) return;
|
|
|
|
for (count=NUM_ALT_ADDRS;count;count--) if (hip->addr[count-1]==addr) break;
|
|
|
|
if (err)
|
|
{
|
|
/* this addr didn't work. remove it */
|
|
for (i=count;i<NUM_ALT_ADDRS;i++) hip->addr[i-1] = hip->addr[i];
|
|
hip->addr[NUM_ALT_ADDRS-1] = 0;
|
|
if (count==1) *hip->cname = 0; /* if used last addr, kill the name to force another lookup */
|
|
}
|
|
else
|
|
{
|
|
/* mark the OTHERS as dead. */
|
|
WriteZero(hip->addr,sizeof(uLong)*NUM_ALT_ADDRS);
|
|
hip->addr[0] = addr;
|
|
}
|
|
}
|
|
|
|
#pragma segment Main
|
|
/************************************************************************
|
|
* BindDone - report that the resolver has done its duty
|
|
************************************************************************/
|
|
pascal void BindDone(struct hostInfo *hostInfoPtr, char *userData)
|
|
{
|
|
*(short *)userData = hostInfoPtr->rtnCode;
|
|
return;
|
|
}
|
|
#pragma segment TcpTrans
|
|
|
|
/************************************************************************
|
|
* TcpTrouble - report an error with TCP and break the connection
|
|
************************************************************************/
|
|
int TT(TransStream stream, int which, int theErr, int file, int line)
|
|
{
|
|
if (stream==0 || (!stream->BeSilent && (!CommandPeriod || stream->Opening&&!PrefIsSet(PREF_OFFLINE)&&!PrefIsSet(PREF_NO_OFF_OFFER))))
|
|
{
|
|
Str255 message;
|
|
Str255 tcpMessage;
|
|
Str63 debugStr;
|
|
Str31 rawNumber;
|
|
short realSettingsRef = SettingsRefN;
|
|
|
|
NumToString(theErr,rawNumber);
|
|
|
|
SettingsRefN = GetMainGlobalSettingsRefN();
|
|
GetRString(message, which);
|
|
if (-23000>=theErr && theErr >=-23048)
|
|
GetRString(tcpMessage,MACTCP_ERR_STRN-22999-theErr);
|
|
else if (2<=theErr && theErr<=9)
|
|
GetRString(tcpMessage,MACTCP_ERR_STRN+theErr+(23048-23000));
|
|
else
|
|
*tcpMessage = 0;
|
|
ComposeRString(debugStr,FILE_LINE_FMT,file,line);
|
|
SettingsRefN = realSettingsRef;
|
|
|
|
|
|
MyParamText(message,rawNumber,tcpMessage,debugStr);
|
|
if (stream==0 || stream->Opening)
|
|
{
|
|
if (2==ReallyDoAnAlert(OPEN_ERR_ALRT,Caution))
|
|
SetPref(PREF_OFFLINE,YesStr);
|
|
}
|
|
else ReallyDoAnAlert(BIG_OK_ALRT,Caution);
|
|
}
|
|
return(stream ? (stream->streamErr=theErr) : theErr);
|
|
}
|
|
|
|
/************************************************************************
|
|
* TcpASR - asynchronous notification routine
|
|
************************************************************************/
|
|
pascal void TcpASR(StreamPtr tcpStream, unsigned short eventCode,
|
|
UPtr userDataPtr, unsigned short terminReason, struct ICMPReport *icmpMsg)
|
|
{
|
|
//#pragma unused(userDataPtr)
|
|
if (tcpStream==((TransStreamPtr)userDataPtr)->TcpStream)
|
|
{
|
|
if (eventCode==TCPDataArrival) ((TransStreamPtr)userDataPtr)->CharsAvail = 1;
|
|
else if (eventCode==TCPICMPReceived)
|
|
{
|
|
ICMPAvail = 1;
|
|
ICMPMessage = *icmpMsg;
|
|
}
|
|
else if (eventCode==TCPTerminate)
|
|
{
|
|
WhyTCPTerminated = terminReason;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
#pragma segment TcpTrans
|
|
/*********************************************************************************
|
|
* Eudora might should take advantage of native Open Transport TCP/IP when it's
|
|
* installed. The following functions implement the same as the MacTCP ones above,
|
|
* but employ OT. There's also some PPP stuff here, too.
|
|
*********************************************************************************/
|
|
|
|
OSErr pppErr = noErr;
|
|
MyOTPPPInfoStruct MyOTPPPInfo;
|
|
unsigned long connectionSelection = kOtherSelected;
|
|
long oldDlogState = 0;
|
|
Boolean needPPPConnection = false; //used to determine when PPP is down but should be up.
|
|
Boolean OTinitialized = false;
|
|
Boolean dialingThePhone = false; //set to true after we've dialed the phone.
|
|
Boolean gUpdateTPWindow = false; // set to true when the connection method changes to invalidate the TP window
|
|
|
|
//setup
|
|
Boolean HasOTInetLib(void);
|
|
Boolean OTSupported(void);
|
|
OSErr OpenOTInternetServices(MyOTInetSvcInfo *myOTInfo);
|
|
pascal void MyOTNotifyProc(MyOTInetSvcInfo *info, OTEventCode theEvent, OTResult theResult, void *theParam);
|
|
OSErr CreateOTStream(TransStream stream);
|
|
OSErr OTTCPOpen(TransStream stream, InetHost tryAddr, InetPort port,uLong timeout);
|
|
void EnqueueMyTStream(MyOTTCPStreamPtr myStream);
|
|
void DestroyMyTStream(MyOTTCPStreamPtr myStream);
|
|
|
|
//communication
|
|
OSErr OTGetHostByName(InetDomainName hostName, InetHostInfo *hostInfoPtr);
|
|
OSErr OTGetHostByAddr(InetHost addr, InetHostInfo *domainNamePtr);
|
|
InetHost OTRandomAddr(InetHostInfo *host);
|
|
OSErr OTGetDomainMX(InetDomainName hostName, InetMailExchange *MXPtr, short *numMX);
|
|
void GetPreferredMX(InetDomainName preferred, InetMailExchange *MXPtr, short numMX);
|
|
short OTWaitForChars(TransStream stream, long timeout, UPtr line, long *size, OTResult *otResult);
|
|
pascal void MyOTStreamNotifyProc (MyOTTCPStream *myStream, OTEventCode code, OTResult theResult, void *theParam);
|
|
short SpinOnWithConnectionCheck(short *rtnCodeAddr,long maxTicks,Boolean allowCancel,Boolean forever);
|
|
|
|
//error reporting
|
|
OSErr OTTE(TransStream stream, OSErr generalError, OSErr specficError, short file, short line);
|
|
#define OTTCPError(stream,generalError,specficError) OTTE(stream,generalError,specficError,FNAME_STRN+FILE_NUM,__LINE__)
|
|
#define IsMyOTError(x) (x >= errOTInitFailed && x <= errMyLastOTErr)
|
|
#define IsOTPPPError(x) (x <= kCCLErrorStart && x >= kCCLErrorEnd)
|
|
|
|
//PPP functions
|
|
OSErr OTVerifyOpen(TransStream stream);
|
|
OSErr OTPPPConnect(Boolean *attemptedConnection);
|
|
OSErr GetPPPConnectionState(EndpointRef endPoint, unsigned long *PPPState);
|
|
pascal void MyPPPEndpointNotifier(void *context, OTEventCode code, OTResult result, void *cookie);
|
|
OSErr TurnOnPPPConnectionDialog(EndpointRef endPoint, Boolean on);
|
|
OSErr ResetPPPConnectionDialog(EndpointRef endPoint);
|
|
OSErr WaitForOTPPPDisconnect(Boolean showStatus);
|
|
OTResult NewPPPControlEndpoint(void);
|
|
OSErr GetCurrentUInt32Option(EndpointRef endPoint, OTXTIName theOption, UInt32 *value);
|
|
OSErr SetCurrentUInt32Option(EndpointRef endPoint, OTXTIName theOption, UInt32 value);
|
|
OSErr OTPPPDialingInformation(Boolean *redial, unsigned long *numRedials, unsigned long *delay);
|
|
Boolean SearchDirectoryForFile(CInfoPBRec *info, long dirToSearch, OSType type, OSType creator);
|
|
void UpdateCachedConnectionMethodInfo(void);
|
|
|
|
/*********************************************************************************
|
|
* OTInitOpenTransport - initialize open transport if present.
|
|
*********************************************************************************/
|
|
void OTInitOpenTransport(void)
|
|
{
|
|
//if we have OT && TCP, then try to initialize it
|
|
if (OTIs)
|
|
{
|
|
if (!HasOTInetLib())
|
|
{
|
|
gUseOT = false;
|
|
|
|
// Only warn the user if we know OT works on this machine
|
|
if (OTSupported()) OTTCPError(NULL,errOTInitFailed,errOTMissingLib);
|
|
}
|
|
else
|
|
{
|
|
gUseOT = true;
|
|
|
|
//Initialize if we haven't already.
|
|
if (!OTinitialized)
|
|
{
|
|
OSStatus osStatus;
|
|
|
|
if ((osStatus = InitOpenTransportInContext(kInitOTForApplicationMask,nil)) != kOTNoError)
|
|
{
|
|
gUseOT = false;
|
|
OTTCPError(NULL,errOTInitFailed,osStatus);
|
|
}
|
|
else //Open Transport is here.
|
|
{
|
|
//See if RemoteAcess/OT/PPP is present while we're here.
|
|
long result;
|
|
OSErr err = Gestalt(gestaltOpenTptRemoteAccess, &result);
|
|
|
|
if ((err == noErr)
|
|
&& (result & (1 << gestaltOpenTptRemoteAccessPresent))
|
|
&& (result & (1 << gestaltOpenTptPPPPresent)))
|
|
{
|
|
gHasOTPPP = true;
|
|
}
|
|
else
|
|
{
|
|
gHasOTPPP = false;
|
|
}
|
|
|
|
#ifdef USE_NETWORK_SETUP
|
|
// check for the network setup library as well ...
|
|
UseNetworkSetup();
|
|
#endif //UseNetworkSetup
|
|
|
|
|
|
OTinitialized = true; //remember that we started OT.
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/*********************************************************************************
|
|
* HasOTInetLib - (CFM Only) returns true if the OpenTptInetLib functions are present.
|
|
*********************************************************************************/
|
|
Boolean HasOTInetLib(void)
|
|
{
|
|
Boolean HasOTInetLib = true;
|
|
|
|
#if TARGET_RT_MAC_CFM
|
|
HasOTInetLib = (long)(&OTInetGetInterfaceInfo) != kUnresolvedCFragSymbolAddress
|
|
&& (long)(&OTInetStringToAddress) != kUnresolvedCFragSymbolAddress
|
|
&& (long)(&OTInetAddressToName) != kUnresolvedCFragSymbolAddress
|
|
&& (long)(&OTInetMailExchange) != kUnresolvedCFragSymbolAddress;
|
|
#endif //TARGET_RT_MAC_CFM
|
|
|
|
return(HasOTInetLib);
|
|
}
|
|
|
|
/*********************************************************************************
|
|
* OTSupported - (CFM Only) returns true if OT can be used on this 68K machine
|
|
*********************************************************************************/
|
|
Boolean OTSupported(void)
|
|
{
|
|
Boolean OTSupported = true;
|
|
long result;
|
|
|
|
#if TARGET_RT_MAC_CFM
|
|
// OT can't be used if this is a 68K machine AND an OT version less than 1.2 is installed.
|
|
OTSupported = false;
|
|
if (Gestalt(gestaltOpenTptVersions, &result) == noErr)
|
|
{
|
|
if ((result & 0xFFFF0000) >= 0x01200000) OTSupported = true;
|
|
}
|
|
#endif //TARGET_RT_MAC_CFM
|
|
|
|
return(OTSupported);
|
|
}
|
|
|
|
/*********************************************************************************
|
|
* OTCloseOpenTransport - cleanup after Open Transport has been used
|
|
*********************************************************************************/
|
|
void OTCleanUpAfterOpenTransport(void)
|
|
{
|
|
if (OTinitialized)
|
|
{
|
|
//shut down OT/PPP if appropriate ...
|
|
if (gHasOTPPP)
|
|
if (MyOTPPPInfo.weConnectedPPP == true)
|
|
OTPPPDisconnect(false, true);
|
|
|
|
CloseOpenTransportInContext(nil);
|
|
}
|
|
}
|
|
|
|
/*********************************************************************************
|
|
* OTTCPConnectTrans - connect to the remote host. This version uses OT TCP.
|
|
*********************************************************************************/
|
|
OSErr OTTCPConnectTrans(TransStream stream, UPtr serverName, long port,Boolean silently,uLong timeout)
|
|
{
|
|
InetHostInfo hostInfo;
|
|
Str255 scratch;
|
|
InetMailExchange MXRecords[NUM_MX];
|
|
short numMX = NUM_MX;
|
|
InetDomainName hostName;
|
|
Boolean useMX = PrefIsSet(PREF_IGNORE_MX) && (port == GetRLong(SMTP_PORT)) && GetOSVersion()<0x1030;
|
|
InetHost tryAddr;
|
|
long receiveBufferSize = 0;
|
|
OSErr err = noErr;
|
|
|
|
#ifdef DEBUG
|
|
if (BUG12) port += 10000;
|
|
#endif
|
|
|
|
ASSERT(stream);
|
|
ASSERT(stream->OTTCPStream == 0);
|
|
|
|
stream->streamErr = noErr;
|
|
stream->Opening = true;
|
|
stream->BeSilent = silently;
|
|
|
|
//allocate memory for a new connection
|
|
stream->OTTCPStream = New(MyOTTCPStream);
|
|
if (stream->OTTCPStream != 0)
|
|
{
|
|
WriteZero(stream->OTTCPStream,sizeof(MyOTTCPStream));
|
|
|
|
ProgressMessageR(kpSubTitle,WHO_AM_I);
|
|
//Make sure TCP is up and going. Connect with OTPPP or something at this point.
|
|
if ((err=OTVerifyOpen(stream)) == noErr)
|
|
{
|
|
gActiveConnections++; // a TCP connection has been established
|
|
|
|
PCat(GetRString(scratch, DNR_LOOKUP), serverName);
|
|
ProgressMessage(kpSubTitle, scratch);
|
|
|
|
strncpy(hostName,serverName+1,(*serverName > kMaxHostNameLen? kMaxHostNameLen : *serverName));
|
|
hostName[*serverName] = 0;
|
|
|
|
//MX allows us to pick the best address to send mail to.
|
|
if (useMX)
|
|
{
|
|
if ((err = OTGetDomainMX(hostName, MXRecords, &numMX)) != noErr) useMX = false;
|
|
else GetPreferredMX(hostName, MXRecords, numMX);
|
|
}
|
|
|
|
if (err != userCancelled)
|
|
{
|
|
//Lookup the host by its name
|
|
if ((err = OTGetHostByName(hostName, &hostInfo)) == noErr)
|
|
{
|
|
tryAddr = OTRandomAddr(&hostInfo);
|
|
|
|
//OTGetHostByName succeeded. Create the myStream structure, and allocate a buffer
|
|
ProgressMessageR(kpSubTitle,HOUSEKEEPING);
|
|
if ((err = CreateOTStream(stream)) == noErr)
|
|
{
|
|
// allocate a buffer for tcp, and create the stream
|
|
receiveBufferSize = GetRLong(RCV_BUFFER_SIZE);
|
|
if ((stream->RcvBuffer=NuHTempOK(receiveBufferSize))!=nil)
|
|
{
|
|
//Create stream succeeded. Now try opening the connection.
|
|
ComposeRString(scratch,CNXN_OPENING,serverName,tryAddr);
|
|
ProgressMessageR(kpSubTitle,PREPARING_CONNECTION);
|
|
ProgressMessage(kpMessage,scratch);
|
|
|
|
// log the connection we're about to make
|
|
ComposeLogS(LOG_PROTO,nil,"\pConnecting to %i:%d",tryAddr,port);
|
|
|
|
if ((err = OTTCPOpen(stream, tryAddr, port, timeout)) == noErr)
|
|
{
|
|
//open succeeded.
|
|
stream->RcvSpot = -1;
|
|
ComposeLogS(LOG_PROTO,nil,"\pConnected to %i:%d",tryAddr,port);
|
|
}
|
|
else if (err != userCancelled)
|
|
{
|
|
OTTCPError(stream,errOpenStream, stream->streamErr);
|
|
ComposeLogS(LOG_PROTO,nil,"\pConnection to %i:%d failed. Error %d",tryAddr,port,err);
|
|
}
|
|
}
|
|
else WarnUser(MEM_ERR, stream->streamErr); // Memory error while creating buffer
|
|
}
|
|
else if (err != userCancelled) OTTCPError(stream,errCreateStream, stream->streamErr=err);
|
|
}
|
|
else
|
|
{
|
|
if (err != userCancelled) OTTCPError(stream,errDNR,stream->streamErr=err);
|
|
// else OTTCPError(stream,errUserCancelledConnection,stream->streamErr=err);
|
|
|
|
// Log the DNS Error
|
|
ComposeLogS(LOG_PROTO,nil,"\pConnection failed. DNS error %d", err);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (stream->streamErr == -7109) stream->streamErr = userCancelled;
|
|
if (stream->streamErr != userCancelled) OTTCPError(stream,errPPPConnect, stream->streamErr);
|
|
}
|
|
}
|
|
else WarnUser(OT_CON_MEM_ERR, stream->streamErr);
|
|
|
|
stream->Opening = false;
|
|
return ((OSErr)stream->streamErr);
|
|
}
|
|
|
|
#define SWING_THE_THING 60
|
|
/*********************************************************************************
|
|
* OTTCPSendTrans - send some text to the remote host. This version uses OT TCP.
|
|
*********************************************************************************/
|
|
OSErr OTTCPSendTrans(TransStream stream, UPtr text,long size, ...)
|
|
{
|
|
OTResult result = noErr;
|
|
va_list extra_buffers;
|
|
UPtr curBuf;
|
|
long curSize = 0;
|
|
long last = TickCount();
|
|
long now = 0;
|
|
Boolean slow = False;
|
|
|
|
ASSERT(stream);
|
|
ASSERT(stream->OTTCPStream);
|
|
|
|
stream->streamErr = noErr;
|
|
|
|
if (CommandPeriod) return(userCancelled);
|
|
|
|
if (size==0) return(noErr); // allow vacuous sends
|
|
|
|
va_start(extra_buffers,size);
|
|
|
|
//We'll send the text buffer first.
|
|
curBuf = text;
|
|
curSize = size;
|
|
do
|
|
{
|
|
//send the current buffer.
|
|
while (curSize > 0)
|
|
{
|
|
now = TickCount();
|
|
result = OTSnd(stream->OTTCPStream->ref, curBuf, curSize, 0);
|
|
if (result >= 0)
|
|
{
|
|
//log what we sent
|
|
if (LogLevel&LOG_TRANS && !stream->streamErr && result) CarefulLog(LOG_TRANS,LOG_SENT,curBuf,result);
|
|
CycleBalls();
|
|
curSize -= result;
|
|
curBuf += result;
|
|
last = now;
|
|
if (IsSendAudit(stream)) stream->bytesTransferred += result;
|
|
}
|
|
else //no data was sent
|
|
{
|
|
if (result != kOTFlowErr) //something happened to the connection. Stop the transfer
|
|
{
|
|
if (stream->OTTCPStream->otherSideClosed)
|
|
{
|
|
stream->streamErr = result = errLostConnection;
|
|
}
|
|
else stream->streamErr = errMiscSend;
|
|
|
|
break;
|
|
}
|
|
else //just some flow control issue or something. Swing the thing, and check for a command-.
|
|
{
|
|
// check to see if we need ppp, but the connection is down
|
|
if (needPPPConnection && MyOTPPPInfo.state != kPPPUp) return(stream->streamErr = result = errLostConnection);
|
|
}
|
|
}
|
|
|
|
if (slow || (now - last) > SWING_THE_THING)
|
|
{
|
|
if (slow) YieldTicks = 0;
|
|
MiniEvents();
|
|
if (CommandPeriod) return(stream->streamErr = userCancelled);
|
|
if ((now - last) > SWING_THE_THING)
|
|
{
|
|
slow = True;
|
|
CyclePendulum();
|
|
last = now - SWING_THE_THING/2;
|
|
}
|
|
}
|
|
}
|
|
|
|
//point to the next buffer to send
|
|
if (!stream->streamErr)
|
|
{
|
|
curBuf = va_arg(extra_buffers,UPtr);
|
|
curSize = va_arg(extra_buffers,long);
|
|
}
|
|
|
|
} while (!stream->streamErr && curBuf);
|
|
|
|
va_end(extra_buffers);
|
|
|
|
if (stream->streamErr)
|
|
{
|
|
if (stream->streamErr!=commandTimeout && stream->streamErr!=userCancelled)
|
|
OTTCPError(stream,stream->streamErr,result);
|
|
}
|
|
|
|
return (stream->streamErr);
|
|
}
|
|
|
|
/*********************************************************************************
|
|
* OTTCPRecvTrans - get some text from the remote host. This version uses OT TCP.
|
|
*********************************************************************************/
|
|
OSErr OTTCPRecvTrans(TransStream stream, UPtr line,long *size)
|
|
{
|
|
OTResult result = noErr;
|
|
Str31 scratch;
|
|
long timeout = InAThread() ? GetRLong(THREAD_RECV_TIMEOUT) : GetRLong(RECV_TIMEOUT);
|
|
|
|
ASSERT(stream);
|
|
ASSERT(stream->OTTCPStream);
|
|
|
|
stream->streamErr = noErr;
|
|
|
|
// Spin until something comes in.
|
|
do
|
|
{
|
|
// read characters from the network, or die trying.
|
|
stream->streamErr = OTWaitForChars(stream, timeout, line, size, &result);
|
|
if (stream->streamErr == noErr)
|
|
{
|
|
if (result >= 0) // got something
|
|
*size = result;
|
|
else if (stream->OTTCPStream->otherSideClosed) // lost connection
|
|
stream->streamErr = errLostConnection;
|
|
else if (result == kOTNoDataErr) // got nothing
|
|
*size = 0;
|
|
else // got some other error
|
|
stream->streamErr = errMiscRec;
|
|
}
|
|
}
|
|
while (stream->streamErr == commandTimeout &&
|
|
AlertStr(TIMEOUT_ALRT,Caution,GetRString(scratch,InAThread() ? THREAD_RECV_TIMEOUT : RECV_TIMEOUT))==1);
|
|
|
|
if (stream->streamErr)
|
|
{
|
|
if (stream->streamErr!=commandTimeout && stream->streamErr!=userCancelled)
|
|
OTTCPError(stream,stream->streamErr,(result < 0 ? result : kOTNoDataErr));
|
|
// Note: result could be 0 if OTWaitForChars fails. We want a real error message displayed in that case, too.
|
|
}
|
|
else
|
|
{
|
|
if (*size) ResetAlertStage();
|
|
if (*size && LogLevel&LOG_TRANS) CarefulLog(LOG_TRANS,LOG_GOT,line,*size); //log what we got ...
|
|
if (*size && IsRecAudit(stream)) stream->bytesTransferred += *size;
|
|
}
|
|
|
|
return (stream->streamErr);
|
|
}
|
|
|
|
/*********************************************************************************
|
|
* TCPDisTrans - disconnect from the remote host. This version uses OT TCP.
|
|
*********************************************************************************/
|
|
OSErr OTTCPDisTrans(TransStream stream)
|
|
{
|
|
if (stream && stream->OTTCPStream)
|
|
{
|
|
stream->streamErr = noErr;
|
|
|
|
//We're going to do an orderly disconnect on this stream.
|
|
stream->OTTCPStream->weAreClosing = true;
|
|
|
|
if ((stream->OTTCPStream->ref) && (!stream->OTTCPStream->ourSideClosed))
|
|
{
|
|
//close our end if the other side has aborted.
|
|
if (stream->OTTCPStream->otherSideClosed)
|
|
{
|
|
OTSndDisconnect(stream->OTTCPStream->ref, nil);
|
|
stream->OTTCPStream->ourSideClosed = true;
|
|
stream->OTTCPStream->releaseMe = true; //we can destroy this connection completely.
|
|
}
|
|
else
|
|
{
|
|
if (OTSndOrderlyDisconnect(stream->OTTCPStream->ref)!=noErr) stream->OTTCPStream->releaseMe = true;
|
|
stream->OTTCPStream->ourSideClosed = true;
|
|
stream->OTTCPStream->age = TickCount();
|
|
}
|
|
}
|
|
|
|
return (stream->streamErr);
|
|
}
|
|
else return (noErr);
|
|
}
|
|
|
|
/*********************************************************************************
|
|
* OTTCPDestroyTrans - destroy the connection. This version uses OT TCP
|
|
*********************************************************************************/
|
|
OSErr OTTCPDestroyTrans(TransStream stream)
|
|
{
|
|
OSStatus status = noErr;
|
|
|
|
if ((stream == 0) || (stream->OTTCPStream == 0)) return (noErr);
|
|
|
|
//We are destroying the stream without disconnecting it. An error occured, or the the user cancelled.
|
|
//Do an abortive disconnect.
|
|
if (!stream->OTTCPStream->weAreClosing)
|
|
{
|
|
DestroyMyTStream(stream->OTTCPStream);
|
|
ZapPtr(stream->OTTCPStream);
|
|
}
|
|
else //otherwise, queue up the stream for an orderly disconnect.
|
|
{
|
|
if (stream->OTTCPStream)
|
|
{
|
|
//if both sides are closed, throw out this connection immediately
|
|
if (stream->OTTCPStream->ourSideClosed && stream->OTTCPStream->otherSideClosed) stream->OTTCPStream->releaseMe = true;
|
|
|
|
if (!stream->OTTCPStream->releaseMe)
|
|
{
|
|
//Queue it up in our queue of MyTStreams waiting to hear an orderly disconnect
|
|
EnqueueMyTStream(stream->OTTCPStream);
|
|
stream->OTTCPStream = 0;
|
|
}
|
|
else
|
|
{
|
|
//an error occurred disconnecting our stream. Just kill it.
|
|
DestroyMyTStream(stream->OTTCPStream);
|
|
ZapPtr(stream->OTTCPStream);
|
|
}
|
|
}
|
|
}
|
|
|
|
//dispose our receive buffer.
|
|
if (stream->RcvBuffer) ZapHandle(stream->RcvBuffer);
|
|
|
|
return (stream->streamErr);
|
|
}
|
|
|
|
|
|
/*********************************************************************************
|
|
* OTTCPTransError - report our most recent error
|
|
*********************************************************************************/
|
|
OSErr OTTCPTransError(TransStream stream)
|
|
{
|
|
ASSERT(stream);
|
|
ASSERT(stream->OTTCPStream);
|
|
|
|
return (stream->streamErr);
|
|
}
|
|
|
|
/*********************************************************************************
|
|
* OTTCPSilenceTrans - turn off error reports from ot tcp routines
|
|
*********************************************************************************/
|
|
void OTTCPSilenceTrans(TransStream stream, Boolean silence)
|
|
{
|
|
ASSERT(stream);
|
|
|
|
stream->BeSilent = silence;
|
|
}
|
|
|
|
/********************************************************************************
|
|
* OTTCPWhoAmI - return the mac's tcp name. This version uses OT TCP.
|
|
********************************************************************************/
|
|
UPtr OTTCPWhoAmI(TransStream stream, Uptr who)
|
|
{
|
|
#pragma unused(stream)
|
|
|
|
InetInterfaceInfo localInfo;
|
|
MyOTInetSvcInfo myOTInfo;
|
|
short len;
|
|
OSErr whoAmIErr = noErr;
|
|
|
|
if (!*MyHostname)
|
|
{
|
|
whoAmIErr = OTInetGetInterfaceInfo(&localInfo, kDefaultInetInterface);
|
|
if (whoAmIErr == kOTNotFoundErr) //OT hasn't been loaded yet ...
|
|
{
|
|
if (whoAmIErr = OpenOTInternetServices(&myOTInfo))
|
|
return (who);
|
|
whoAmIErr = OTInetGetInterfaceInfo(&localInfo, kDefaultInetInterface);
|
|
OTCloseProvider(myOTInfo.ref);
|
|
myOTInfo.ref = 0;
|
|
}
|
|
if (whoAmIErr != noErr)
|
|
return (who);
|
|
ComposeRString(who,TCP_ME,localInfo.fAddress);
|
|
SetPref(PREF_LASTHOST,who);
|
|
PCopy(MyHostname,who);
|
|
}
|
|
PCopy(who,MyHostname);
|
|
|
|
//remove the '.' from the end of who, if there is one.
|
|
len = strlen(who);
|
|
if (who[len-1]=='.') who[len-1]=0;
|
|
|
|
return(who);
|
|
}
|
|
|
|
/********************************************************************************
|
|
* DNSHostid - return the mac's dns server hostid. This version uses OT TCP.
|
|
********************************************************************************/
|
|
OSErr DNSHostid(uLong *dnsAddr)
|
|
{
|
|
InetInterfaceInfo localInfo;
|
|
MyOTInetSvcInfo myOTInfo;
|
|
OSErr dnsHostidErr = noErr;
|
|
|
|
dnsHostidErr = OTInetGetInterfaceInfo(&localInfo, kDefaultInetInterface);
|
|
if (dnsHostidErr == kOTNotFoundErr) //OT hasn't been loaded yet ...
|
|
{
|
|
if (!(dnsHostidErr = OpenOTInternetServices(&myOTInfo)))
|
|
{
|
|
dnsHostidErr = OTInetGetInterfaceInfo(&localInfo, kDefaultInetInterface);
|
|
OTCloseProvider(myOTInfo.ref);
|
|
myOTInfo.ref = 0;
|
|
}
|
|
}
|
|
|
|
if (!dnsHostidErr) *dnsAddr = *(long*)&localInfo.fDNSAddr;
|
|
|
|
return(dnsHostidErr);
|
|
}
|
|
|
|
/********************************************************************************
|
|
* OTMyHostid - return the mac's hostid. This version uses OT TCP.
|
|
********************************************************************************/
|
|
OSErr OTMyHostid(uLong *myAddr,uLong *myMask)
|
|
{
|
|
InetInterfaceInfo localInfo;
|
|
MyOTInetSvcInfo myOTInfo;
|
|
OSErr myHostidErr=noErr;
|
|
|
|
myHostidErr = OTInetGetInterfaceInfo(&localInfo, kDefaultInetInterface);
|
|
if (myHostidErr == kOTNotFoundErr) //OT hasn't been loaded yet ...
|
|
{
|
|
if (!(myHostidErr = OpenOTInternetServices(&myOTInfo)))
|
|
{
|
|
myHostidErr = OTInetGetInterfaceInfo(&localInfo, kDefaultInetInterface);
|
|
OTCloseProvider(myOTInfo.ref);
|
|
myOTInfo.ref = 0;
|
|
}
|
|
}
|
|
|
|
if (!myHostidErr)
|
|
{
|
|
*myAddr = *(long*)&localInfo.fAddress;
|
|
*myMask = *(long*)&localInfo.fNetmask;
|
|
}
|
|
|
|
return(myHostidErr);
|
|
}
|
|
|
|
/********************************************************************************
|
|
* OTMyHostid - return the mac's hostid. This version uses OT TCP.
|
|
********************************************************************************/
|
|
OSErr GetMyHostid(uLong *addr,uLong *mask)
|
|
{
|
|
return(OTMyHostid(addr,mask));
|
|
}
|
|
|
|
/************************************************************************
|
|
* OTGetHostByName - get host information, given a hostname
|
|
* this routine maintains a small, unflushable cache.
|
|
************************************************************************/
|
|
OSErr OTGetHostByName(InetDomainName hostName, InetHostInfo *hostInfoPtr)
|
|
{
|
|
MyOTInetSvcInfo myOTInfo;
|
|
OSErr nameErr = noErr;
|
|
|
|
if (nameErr = OpenOTInternetServices(&myOTInfo))
|
|
return (nameErr);
|
|
myOTInfo.status = inProgress;
|
|
nameErr = OTInetStringToAddress(myOTInfo.ref,hostName,hostInfoPtr);
|
|
if (nameErr == noErr) nameErr = SpinOnWithConnectionCheck(&(myOTInfo.status),0,True,False);
|
|
if (nameErr == noErr) nameErr = myOTInfo.result;
|
|
OTCloseProvider(myOTInfo.ref);
|
|
myOTInfo.ref = 0;
|
|
//return without changing the name of the server we wish to look up.
|
|
if (nameErr == noErr) strcpy(hostInfoPtr->name,hostName);
|
|
|
|
// log the result of the name lookup. Be careful not to overrun buffers.
|
|
if (LogLevel&LOG_PROTO)
|
|
{
|
|
short count;
|
|
Str63 logHostName;
|
|
|
|
MakePStr(logHostName,hostName,strlen(hostName));
|
|
ComposeLogS(LOG_PROTO,nil,"\pDNS Lookup of \"%p\"",logHostName);
|
|
if (nameErr == noErr)
|
|
{
|
|
for (count=0;count<kMaxHostAddrs;count++)
|
|
if (hostInfoPtr->addrs[count])
|
|
ComposeLogS(LOG_PROTO,nil,"\p %i (%d)",hostInfoPtr->addrs[count],count+1);
|
|
}
|
|
else ComposeLogS(LOG_PROTO,nil,"\pLookup failed (error %d)",nameErr);
|
|
}
|
|
|
|
return (nameErr);
|
|
}
|
|
|
|
/*********************************************************************************
|
|
* OTGetHostByAddr - get host information, given an address. This version uses OT
|
|
* this routine maintains a small, unflushable cache.
|
|
*********************************************************************************/
|
|
OSErr OTGetHostByAddr(InetHost addr, InetHostInfo *domainNamePtr)
|
|
{
|
|
MyOTInetSvcInfo myOTInfo;
|
|
short len = 0;
|
|
OSErr addrErr = noErr;
|
|
|
|
domainNamePtr->addrs[0] = addr;
|
|
if (addrErr = OpenOTInternetServices(&myOTInfo))
|
|
return (addrErr);
|
|
myOTInfo.status = inProgress;
|
|
addrErr = OTInetAddressToName(myOTInfo.ref,domainNamePtr->addrs[0],domainNamePtr->name);
|
|
if (addrErr == noErr) addrErr = SpinOnWithConnectionCheck(&(myOTInfo.status),0,True,False);
|
|
if (addrErr == noErr) addrErr = myOTInfo.result;
|
|
OTCloseProvider(myOTInfo.ref);
|
|
myOTInfo.ref = 0;
|
|
|
|
//remove the '.' from the end of name, if there is one.
|
|
if (addrErr == noErr)
|
|
{
|
|
len = strlen(domainNamePtr->name);
|
|
if (domainNamePtr->name[len-1]=='.') domainNamePtr->name[len-1]=0;
|
|
}
|
|
|
|
return (addrErr);
|
|
}
|
|
|
|
/**********************************************************************
|
|
* OTRandomAddr - pick a random address out of a set of addresses we
|
|
* got from our OT DNR lookip.
|
|
**********************************************************************/
|
|
InetHost OTRandomAddr(InetHostInfo *host)
|
|
{
|
|
short count;
|
|
|
|
if (!PrefIsSet(PREF_DNS_BALANCE))
|
|
return (host->addrs[0]);
|
|
|
|
for (count=kMaxHostAddrs;count;count--) if (host->addrs[count-1]) break;
|
|
return (host->addrs[count<2?0:TickCount()%count]);
|
|
}
|
|
|
|
/************************************************************************
|
|
* OTGetDomainMX - Get the mail exchange info for a particular host.
|
|
************************************************************************/
|
|
OSErr OTGetDomainMX(InetDomainName hostName, InetMailExchange *MXPtr, short *numMX)
|
|
{
|
|
OSErr err = noErr;
|
|
MyOTInetSvcInfo myOTInfo;
|
|
short i;
|
|
|
|
if (MXPtr == 0 // must have a place to store the MX records
|
|
|| numMX == 0 // must have an idea of how many records will fit there
|
|
|| *numMX <= 0) // and must have allocated room for at least one
|
|
return (paramErr);
|
|
|
|
//clear out the MXPtr
|
|
for (i = 0; i < *numMX; i++)
|
|
(MXPtr[i]).exchange[0] = (MXPtr[i]).preference = 0;
|
|
|
|
//do the MX lookup
|
|
if ((err = OpenOTInternetServices(&myOTInfo)) == noErr)
|
|
{
|
|
myOTInfo.status = inProgress;
|
|
err = OTInetMailExchange(myOTInfo.ref, hostName, numMX, MXPtr);
|
|
if (err == noErr) err = SpinOnWithConnectionCheck(&(myOTInfo.status),0,True,False);
|
|
OTCloseProvider(myOTInfo.ref);
|
|
myOTInfo.ref = 0;
|
|
|
|
if (err == noErr)
|
|
if (MXPtr->exchange[0] == 0) return (errNoMXRecords);
|
|
}
|
|
|
|
return (err);
|
|
}
|
|
|
|
/**********************************************************************
|
|
* GetPreferredMX - return the preferred host to send mail to.
|
|
**********************************************************************/
|
|
void GetPreferredMX(InetDomainName preferredName, InetMailExchange *MXPtr, short numMX)
|
|
{
|
|
short lowestPref, preferredHost;
|
|
short count = numMX - 1;
|
|
short len;
|
|
|
|
preferredHost = count;
|
|
lowestPref = MXPtr[count].preference;
|
|
for (count; count >= 0; count--)
|
|
{
|
|
if (MXPtr[count].preference < lowestPref)
|
|
{
|
|
lowestPref = MXPtr[count].preference;
|
|
preferredHost = count;
|
|
}
|
|
}
|
|
strcpy(preferredName, MXPtr[preferredHost].exchange);
|
|
|
|
//remove the '.' from the end of preferredName, if there is one.
|
|
len = strlen(preferredName);
|
|
if (preferredName[len-1]=='.') preferredName[len-1]=0;
|
|
}
|
|
|
|
#pragma segment Main
|
|
/*********************************************************************************
|
|
* MyOTNotifyProc - This callback handles the results of all asynch OT calls.
|
|
*********************************************************************************/
|
|
pascal void MyOTNotifyProc(MyOTInetSvcInfo *info, OTEventCode theEvent, OTResult theResult, void *theParam)
|
|
{
|
|
switch (theEvent)
|
|
{
|
|
case T_OPENCOMPLETE: // The OTAsyncOpenInternetServices function has completed
|
|
case T_DNRSTRINGTOADDRCOMPLETE: // The OTInetStringToAddress function has finished
|
|
case T_DNRADDRTONAMECOMPLETE: // The OTInetAddressToName function has finished
|
|
case T_DNRMAILEXCHANGECOMPLETE: // The OTInetMailExchange function has finished
|
|
info->status = 0;
|
|
info->result = theResult;
|
|
info->cookie = theParam;
|
|
break;
|
|
|
|
default: // All other network events can be ignored
|
|
break;
|
|
}
|
|
}
|
|
#pragma segment TcpTrans
|
|
|
|
/*********************************************************************************
|
|
* OpenOTInternetServices - Open up the internet service provider OT gives us.
|
|
*********************************************************************************/
|
|
OSErr OpenOTInternetServices(MyOTInetSvcInfo *myOTInfo)
|
|
{
|
|
OSErr err = noErr;
|
|
DECLARE_UPP(MyOTNotifyProc,OTNotify);
|
|
|
|
INIT_UPP(MyOTNotifyProc,OTNotify);
|
|
myOTInfo->status = inProgress;
|
|
if ((err = OTAsyncOpenInternetServicesInContext(kDefaultInternetServicesPath, 0, MyOTNotifyProcUPP, myOTInfo,NULL)) == noErr)
|
|
if ((err = SpinOnWithConnectionCheck(&(myOTInfo->status),0,True,False)) == noErr)
|
|
{
|
|
myOTInfo->ref = myOTInfo->cookie;
|
|
}
|
|
|
|
if (err != noErr && err != userCancelled) err = errOTInetSvcs;
|
|
|
|
return (err);
|
|
}
|
|
|
|
#pragma segment Main
|
|
/*********************************************************************************
|
|
* MyOTStreamNotifyProc - my OT notifier proc for TCP streams.
|
|
*********************************************************************************/
|
|
pascal void MyOTStreamNotifyProc (MyOTTCPStream *myStream, OTEventCode code, OTResult theResult, void *cookie)
|
|
{
|
|
OSStatus err;
|
|
|
|
switch (code)
|
|
{
|
|
case T_DISCONNECT: // Other side has aborted
|
|
myStream->otherSideClosed = true;
|
|
myStream->status = 0;
|
|
break;
|
|
|
|
case T_ORDREL: // Other side has closed in an orderly fashion
|
|
myStream->otherSideClosed = true;
|
|
myStream->status = 0;
|
|
err = OTRcvOrderlyDisconnect(myStream->ref);
|
|
if (!myStream->ourSideClosed)
|
|
{
|
|
err = OTSndOrderlyDisconnect(myStream->ref);
|
|
myStream->ourSideClosed = true;
|
|
}
|
|
myStream->releaseMe = true; // we don't need this stream anymore.
|
|
break;
|
|
|
|
case T_OPENCOMPLETE: // OTOpenAsyncEndpoint has finished
|
|
case T_BINDCOMPLETE: // OTBind has finished
|
|
case T_UNBINDCOMPLETE: // OTUnbind has finished
|
|
case T_CONNECT: // OTConnect has finished
|
|
case T_PASSCON: // state is now T_DATAXFER
|
|
myStream->status = 0;
|
|
myStream->code = code;
|
|
myStream->result = theResult;
|
|
myStream->cookie = cookie;
|
|
break;
|
|
}
|
|
}
|
|
#pragma segment TcpTrans
|
|
|
|
/*********************************************************************************
|
|
* CreateOTStream - create a MyOTTCPStreamPtr
|
|
*********************************************************************************/
|
|
OSErr CreateOTStream(TransStream stream)
|
|
{
|
|
OSStatus OTErr = noErr;
|
|
DECLARE_UPP(MyOTStreamNotifyProc,OTNotify);
|
|
|
|
INIT_UPP(MyOTStreamNotifyProc,OTNotify);
|
|
ASSERT(stream);
|
|
|
|
stream->streamErr = noErr;
|
|
|
|
//Open a TCP endpoint asynchronously
|
|
stream->OTTCPStream->status = inProgress;
|
|
stream->streamErr = OTAsyncOpenEndpointInContext(OTCreateConfiguration(kTCPName),0,0,MyOTStreamNotifyProcUPP,stream->OTTCPStream,nil);
|
|
if (stream->streamErr == noErr) stream->streamErr = SpinOnWithConnectionCheck(&(stream->OTTCPStream->status),0,True,False);
|
|
if ((stream->streamErr == noErr) || ((stream->streamErr = stream->OTTCPStream->result) == noErr))
|
|
{
|
|
if (stream->OTTCPStream->code != T_OPENCOMPLETE)
|
|
return (stream->streamErr = errOpenStream);
|
|
stream->OTTCPStream->ref = stream->OTTCPStream->cookie;
|
|
if (stream->OTTCPStream->ref == kOTInvalidEndpointRef)
|
|
return (stream->streamErr = errOpenStream);
|
|
|
|
//Initialize the MyOTTCPStreamPtr flags
|
|
stream->OTTCPStream->weAreClosing = false;
|
|
stream->OTTCPStream->otherSideClosed = false;
|
|
stream->OTTCPStream->ourSideClosed = false;
|
|
stream->OTTCPStream->releaseMe = false;
|
|
}
|
|
|
|
if (stream->streamErr != noErr)
|
|
{
|
|
if (stream->OTTCPStream->ref) OTCloseProvider(stream->OTTCPStream->ref);
|
|
stream->OTTCPStream->ref = 0;
|
|
}
|
|
return (stream->streamErr);
|
|
}
|
|
|
|
/*********************************************************************************
|
|
* OTTCPOpen - actually open a connection
|
|
*
|
|
* 3/18/99 no longer using OT memory allocation routines.
|
|
*********************************************************************************/
|
|
OSErr OTTCPOpen(TransStream stream, InetHost tryAddr, InetPort port,uLong timeout)
|
|
{
|
|
InetAddress connectAddr;
|
|
TCall sndCall;
|
|
|
|
ASSERT(stream);
|
|
ASSERT(stream->OTTCPStream);
|
|
|
|
stream->streamErr = noErr;
|
|
stream->OTTCPStream->status = inProgress;
|
|
if (stream->streamErr = OTBind(stream->OTTCPStream->ref, 0, 0)) // OTBind doesn't need any parameters. This is an outgoing connection. jdboyd 04/11/02
|
|
return (stream->streamErr);
|
|
if (stream->streamErr = SpinOnWithConnectionCheck(&(stream->OTTCPStream->status),60*timeout,True,False))
|
|
return (stream->streamErr);
|
|
if (stream->OTTCPStream->code != T_BINDCOMPLETE)
|
|
{
|
|
stream->streamErr = stream->OTTCPStream->result;
|
|
return (errOpenStream);
|
|
}
|
|
|
|
// set up the TCall structure needed to connect to tryAddr
|
|
OTInitInetAddress(&connectAddr, port, tryAddr);
|
|
WriteZero(&sndCall, sizeof(TCall));
|
|
sndCall.addr.len = sizeof(InetAddress);
|
|
sndCall.addr.buf = (unsigned char*) &connectAddr;
|
|
|
|
// now connect to the address asynchronously
|
|
stream->OTTCPStream->status = inProgress;
|
|
stream->streamErr = OTConnect(stream->OTTCPStream->ref, &sndCall, 0);
|
|
if (stream->streamErr != noErr && stream->streamErr != kOTNoDataErr)
|
|
return (stream->OTTCPStream->otherSideClosed ? errLostConnection : stream->streamErr);
|
|
if (stream->streamErr = SpinOnWithConnectionCheck(&(stream->OTTCPStream->status),60*timeout,True,False))
|
|
return (stream->OTTCPStream->otherSideClosed ? errLostConnection : stream->streamErr);
|
|
|
|
// did we connect?
|
|
if (stream->OTTCPStream->code != T_CONNECT)
|
|
{
|
|
stream->streamErr = errLostConnection;
|
|
return (errOpenStream);
|
|
}
|
|
if (stream->streamErr = OTRcvConnect(stream->OTTCPStream->ref, 0))
|
|
return (stream->streamErr);
|
|
|
|
return (stream->streamErr);
|
|
}
|
|
|
|
/*********************************************************************************
|
|
* OTWaitForChars - spin, giving everybody else time, until chars available
|
|
*********************************************************************************/
|
|
short OTWaitForChars(TransStream stream, long timeout, UPtr line, long *size, OTResult *otResult)
|
|
{
|
|
EventRecord event;
|
|
long ticks=TickCount();
|
|
static long waitTicks=0;
|
|
long tookTicks;
|
|
Boolean result = false;
|
|
long timeoutTicks = ticks + 60*timeout;
|
|
Boolean slow = False;
|
|
OTFlags junkFlags = 0;
|
|
|
|
ASSERT(stream);
|
|
ASSERT(stream->OTTCPStream);
|
|
|
|
if (!InBG) waitTicks = 0;
|
|
|
|
// spin until we see data on the network ...
|
|
do
|
|
{
|
|
// check to see if our connection is still up. Only care if remote end has closed.
|
|
if (stream->OTTCPStream->otherSideClosed) return(errLostConnection);
|
|
|
|
// check to see if we need ppp, but the connection is down
|
|
if (needPPPConnection && MyOTPPPInfo.state != kPPPUp) return(errLostConnection);
|
|
|
|
//check to see if cmd-. has been pressed.
|
|
if (CommandPeriod) return (userCancelled);
|
|
|
|
if (TickCount()-ticks > 10)
|
|
{
|
|
slow = True;
|
|
CyclePendulum();
|
|
ticks=TickCount();
|
|
if (ticks >timeoutTicks) return(commandTimeout);
|
|
}
|
|
|
|
// receive size bytes and put it in line. We expect some data, so wait around until we see it.
|
|
*otResult = OTRcv(stream->OTTCPStream->ref, line, *size, &junkFlags);
|
|
|
|
// we'll spin until we see data or an error.
|
|
if (*otResult == kOTNoDataErr) *otResult = 0;
|
|
|
|
if (slow) YieldTicks = 0;
|
|
|
|
// To speed up threaded xfers when app is in bg, don't call WaitNextEvent as often
|
|
// also speeded up typing by changing NEED_YIELD -- it checks Typing when in a thread. (though I'm not quite sure how thread gets time when Typing is true)
|
|
if (NEED_YIELD || ((*otResult == 0) && !stream->DontWait))
|
|
{
|
|
tookTicks = TickCount();
|
|
|
|
// 11-13-97 change to fix cmd period bug when in main thread
|
|
result = WNE(MINI_MASK|keyDownMask,&event,waitTicks);
|
|
if (CommandPeriod) return(userCancelled);
|
|
//was:
|
|
// result = WNE(MINI_MASK,&event,waitTicks);
|
|
|
|
tookTicks = TickCount()-tookTicks;
|
|
if (InBG)
|
|
if (tookTicks > waitTicks+1)
|
|
waitTicks = MIN(120,tookTicks);
|
|
else
|
|
waitTicks = waitTicks>>1;
|
|
else
|
|
waitTicks = 1;
|
|
if (result) (void) MiniMainLoop(&event);
|
|
}
|
|
}
|
|
while ((*otResult == 0) && !stream->DontWait);
|
|
stream->CharsAvail = 0;
|
|
return(0);
|
|
}
|
|
|
|
|
|
/*********************************************************************************
|
|
* OTFlushInput - dump all chars that arrive on a stream, until there are no
|
|
* chars for a given period of time
|
|
*********************************************************************************/
|
|
void OTFlushInput(TransStream stream,uLong timeout)
|
|
{
|
|
Str255 junk;
|
|
OTResult result;
|
|
long got;
|
|
|
|
do
|
|
{
|
|
got = sizeof(junk);
|
|
if (OTWaitForChars(stream, timeout, junk, &got, &result)) break;
|
|
if (LogLevel&LOG_TRANS && !stream->streamErr && result>0) CarefulLog(LOG_TRANS,LOG_FLUSHED,junk,result);
|
|
}
|
|
while (result>0);
|
|
}
|
|
|
|
static short errorMessages[errMyLastOTErr-errOTInitFailed] =
|
|
{
|
|
OT_INIT_ERR, //errOTInitFailed,
|
|
OT_INIT_ERR, //errOTInetSvcs,
|
|
BIND_ERR, //errDNR,
|
|
0, //errNoMXRecords,
|
|
TCP_TROUBLE, //errCreateStream,
|
|
NO_SMTP_SERVER, //errOpenStream,
|
|
TCP_TROUBLE, //errLostConnection,
|
|
TCP_TROUBLE, //errMiscRec,
|
|
TCP_TROUBLE, //errMiscSend
|
|
OT_DIALUP_CONNECT_ERR,//errPPPConnect
|
|
0, //errPPPPrefNotFound
|
|
0, //errPPPStateUnknown
|
|
OT_MISSING_LIBRARY //errOTMissingLib:
|
|
};
|
|
|
|
|
|
|
|
static void OTTELo ( OSErr generalError, OSErr specificError, StringPtr message ) {
|
|
if (IsMyOTError(generalError))
|
|
GetRString(message, errorMessages[generalError - errOTInitFailed]);
|
|
else
|
|
GetRString(message, TCP_TROUBLE);
|
|
}
|
|
|
|
/*********************************************************************************
|
|
* OTTE - give the user some helpful information if an error occurs.
|
|
* generalError contains a general description of the error, set by me.
|
|
* specificError contains the actual error returned by the failed call
|
|
*********************************************************************************/
|
|
OSErr OTTE(TransStream stream, OSErr generalError, OSErr specificError, short file, short line)
|
|
{
|
|
short errorString = 0;
|
|
OSErr MacTCPErr = noErr;
|
|
|
|
if ((generalError != noErr)
|
|
&& (stream==0 || !stream->BeSilent)
|
|
&& !AmQuitting
|
|
&& (!CommandPeriod || stream==0 || stream->Opening && !PrefIsSet(PREF_OFFLINE) && !PrefIsSet(PREF_NO_OFF_OFFER)))
|
|
{
|
|
Str255 message;
|
|
Str255 tcpMessage;
|
|
Str63 debugStr;
|
|
Str31 rawNumber;
|
|
short realSettingsRef = SettingsRefN;
|
|
|
|
tcpMessage[0] = 0;
|
|
|
|
NumToString(specificError,rawNumber);
|
|
|
|
SettingsRefN = GetMainGlobalSettingsRefN();
|
|
OTErrorToString(specificError, tcpMessage);
|
|
OTTELo ( generalError, specificError, message );
|
|
ComposeRString(debugStr,FILE_LINE_FMT,file,line);
|
|
SettingsRefN = realSettingsRef;
|
|
|
|
|
|
MyParamText(message,rawNumber,tcpMessage,debugStr);
|
|
if (stream==0 || stream->Opening)
|
|
{
|
|
if (2==ReallyDoAnAlert(OPEN_ERR_ALRT,Caution))
|
|
SetPref(PREF_OFFLINE,YesStr);
|
|
}
|
|
else ReallyDoAnAlert(BIG_OK_ALRT,Caution);
|
|
|
|
}
|
|
|
|
return (generalError);
|
|
}
|
|
|
|
/*********************************************************************************
|
|
* OTErrorToString - pick an error string that best describes the
|
|
* specific error.
|
|
*********************************************************************************/
|
|
void OTErrorToString(short specificError, Str255 tcpMessage)
|
|
{
|
|
short errorString = 0;
|
|
tcpMessage[0] = 0;
|
|
|
|
//Was this some error that I defined?
|
|
if (IsMyOTError(specificError))
|
|
{
|
|
switch (specificError)
|
|
{
|
|
case errOTInetSvcs:
|
|
errorString = OT_INET_SVCS_ERR;
|
|
break;
|
|
|
|
case errLostConnection:
|
|
specificError = TCPRemoteAbort;
|
|
break;
|
|
|
|
case errPPPStateUnknown:
|
|
errorString = OT_PPP_STATE_ERR;
|
|
break;
|
|
|
|
case errPPPPrefNotFound:
|
|
errorString = OT_TCPIP_PREF_ERR;
|
|
break;
|
|
|
|
case errOTMissingLib:
|
|
errorString = OT_MISSING_LIBRARY;
|
|
break;
|
|
|
|
default:
|
|
errorString = OT_UNKNOWN_ERR;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (errorString!=0) GetRString(tcpMessage,errorString);
|
|
else
|
|
{
|
|
if (IsXTIError(specificError))
|
|
GetRString(tcpMessage,OTTCP_ERR_STRN + XTI2OSStatus(specificError));
|
|
else if (IsOTPPPError(specificError)) // was this an OT/PPP related error?
|
|
GetRString(tcpMessage,OTPPP_ERR_STRN - specificError + kCCLErrorBaseCode - 1);
|
|
else if (-23000>=specificError && specificError >=-23048) // was this a MacTCP error code?
|
|
GetRString(tcpMessage,MACTCP_ERR_STRN-22999-specificError);
|
|
else if (2<=specificError && specificError<=9)
|
|
GetRString(tcpMessage,MACTCP_ERR_STRN+specificError+(23048-23000));
|
|
else
|
|
tcpMessage = 0;
|
|
}
|
|
}
|
|
|
|
|
|
/*********************************************************************************
|
|
* DestroyMyTStream - deallocate everything a MyStream grabs for itself.
|
|
*********************************************************************************/
|
|
void DestroyMyTStream(MyOTTCPStreamPtr myStream)
|
|
{
|
|
OSErr destroyErr = noErr;
|
|
|
|
if (myStream)
|
|
{
|
|
//clean up after the myStream
|
|
if (myStream->ref != 0)
|
|
{
|
|
//make sure the connection is closed.
|
|
if (!myStream->otherSideClosed || !myStream->ourSideClosed) OTSndDisconnect(myStream->ref, nil);
|
|
|
|
//unbind the endpoint
|
|
myStream->status = inProgress;
|
|
destroyErr = OTUnbind(myStream->ref);
|
|
if (destroyErr == noErr) destroyErr = SpinOnWithConnectionCheck(&(myStream->status),0,True,False);
|
|
|
|
// remove the endpoint's notifier. We won't be needing it anymore.
|
|
OTRemoveNotifier(myStream->ref);
|
|
|
|
// now we can kill the endpoint.
|
|
destroyErr = OTCloseProvider(myStream->ref);
|
|
myStream->ref = 0;
|
|
}
|
|
|
|
if (gActiveConnections) gActiveConnections--;
|
|
}
|
|
}
|
|
|
|
/*********************************************************************************
|
|
* EnqueueMyTStream - put myStream in the queue of streams waiting to close.
|
|
*********************************************************************************/
|
|
void EnqueueMyTStream(MyOTTCPStreamPtr myStream)
|
|
{
|
|
MyOTTCPStreamPtr queueScan = 0;
|
|
OSStatus status = noErr;
|
|
|
|
ASSERT(myStream);
|
|
|
|
if (pendingCloses == 0) //this is the only stream in the queue
|
|
{
|
|
pendingCloses = myStream;
|
|
myStream->next = 0;
|
|
myStream->prev = 0;
|
|
}
|
|
else //there are some other streams waiting to close
|
|
{
|
|
queueScan = pendingCloses;
|
|
while (queueScan->next != 0) queueScan = queueScan->next;
|
|
queueScan->next = myStream;
|
|
myStream->prev = queueScan;
|
|
myStream->next = 0;
|
|
}
|
|
}
|
|
|
|
/*********************************************************************************
|
|
* KillDeadMyTStreams - deallocate memory and TStreams that have received an
|
|
* orderly disconnect. destroy determines whether to kill all the streams, or
|
|
* only the ones that have been disconnected in an orderly fashion.
|
|
*********************************************************************************/
|
|
void KillDeadMyTStreams(Boolean destroy)
|
|
{
|
|
MyOTTCPStreamPtr queueScan = pendingCloses;
|
|
MyOTTCPStreamPtr releaseThisOne = 0;
|
|
|
|
//loop through and find stream that can be released.
|
|
while (queueScan != 0)
|
|
{
|
|
OSStatus queueScanStatus;
|
|
|
|
if (queueScan->ref == 0) queueScan->releaseMe = true; //this should never happen ...
|
|
else
|
|
{
|
|
queueScanStatus = OTLook(queueScan->ref);
|
|
|
|
//if this endpoint has some data waiting to be read, read it.
|
|
if (queueScanStatus == T_DATA || queueScanStatus == T_EXDATA)
|
|
{
|
|
do {
|
|
queueScanStatus = OTRcv(queueScan->ref, queueScan->dummyBuffer, sizeof(queueScan->dummyBuffer), nil);
|
|
} while (queueScanStatus >= 0);
|
|
|
|
queueScan->age = TickCount(); //this stream made a noise, earning it a new minute.
|
|
}
|
|
|
|
if ((TickCount() - queueScan->age) > 3600)
|
|
queueScan->releaseMe = true; //keep silent connections around for 1 minute.
|
|
}
|
|
|
|
//the MyOTStream callback will set releaseMe once this stream can die quietly
|
|
if (destroy || queueScan->releaseMe)
|
|
{
|
|
releaseThisOne = queueScan;
|
|
queueScan = queueScan->next;
|
|
|
|
if (releaseThisOne == pendingCloses) pendingCloses = releaseThisOne->next;
|
|
|
|
if (releaseThisOne->prev) (releaseThisOne->prev)->next = releaseThisOne->next;
|
|
if (releaseThisOne->next) (releaseThisOne->next)->prev = releaseThisOne->prev;
|
|
DestroyMyTStream(releaseThisOne);
|
|
ZapPtr(releaseThisOne);
|
|
}
|
|
else
|
|
queueScan = queueScan->next;
|
|
}
|
|
}
|
|
|
|
|
|
/*********************************************************************************
|
|
* OTVerifyOpen - Make sure OT TCP is ready to go. May have to conenct with PPP
|
|
* or SLIP, depending on what is selected in the TCP/IP control panel
|
|
*********************************************************************************/
|
|
OSErr OTVerifyOpen(TransStream stream)
|
|
{
|
|
Boolean weAttemptedPPP = false;
|
|
|
|
stream->streamErr = noErr;
|
|
|
|
//signal everyone else that, no, PPP is not needed for the connection
|
|
needPPPConnection = false;
|
|
gPPPConnectFailed = false;
|
|
|
|
if (!PrefIsSet(PREF_IGNORE_PPP)) //this pref lets us ignore MacSLIP/PPP if we want
|
|
{
|
|
if ((stream->streamErr = SelectedConnectionMode(&connectionSelection, true)) == noErr)
|
|
{
|
|
if (dialingThePhone)
|
|
{
|
|
//sit and wait for a connection.
|
|
if (connectionSelection == kPPPSelected)
|
|
{
|
|
ProgressMessageR(kpSubTitle,OT_PPP_WAIT);
|
|
do
|
|
{
|
|
MiniEvents();
|
|
if (CommandPeriod) return (stream->streamErr = userCancelled);
|
|
}
|
|
while (dialingThePhone);
|
|
if (PPPDown()) return(stream->streamErr = errPPPConnect);
|
|
}
|
|
}
|
|
else if (connectionSelection == kPPPSelected)
|
|
{
|
|
dialingThePhone = true;
|
|
needPPPConnection = true; //let everyone know the connection is being made over PPP.
|
|
gConnecting = true; //likewise, tell the world we're dialing the phone.
|
|
if (stream->streamErr = OTPPPConnect(&weAttemptedPPP))
|
|
{
|
|
gPPPConnectFailed = true; //flag to tell the world that our PPP connection attempt failed.
|
|
|
|
// Holy crap, Batman! This has been broken all these years. Only force clase the connection
|
|
// if we were the fools to think we could connect it to begin with. -JDB 12/16/98
|
|
OTPPPDisconnect(weAttemptedPPP, true);
|
|
}
|
|
gConnecting = false;
|
|
dialingThePhone = false;
|
|
}
|
|
}
|
|
}
|
|
return (stream->streamErr);
|
|
}
|
|
|
|
/*********************************************************************************
|
|
* OTPPPConnect - Cause an OTPPP connection to happen. I will create one single
|
|
* OTPPP control endpoint, and keep it around. Apple says there's a bug with the
|
|
* current OT/PPP that causes OTCloseProvider() to crash when closing a PPP control
|
|
* endpoint.
|
|
*
|
|
* 6/18/97 This routine can be called from multiple threads. The first call
|
|
* will initiate the PPP connection. Subsequent calls will wait for the PPP
|
|
* connection.
|
|
*
|
|
* 12/16/98 Added attemotedConnection paramter to let caller know whether we make
|
|
* the connection attempt or not. There might be one underway, in which case
|
|
* we wait for it.
|
|
*
|
|
* May, 1999 Added a delay after (a) the connection is made, or (b) the connection
|
|
* we were waiting for finishes. We delat for <x-eudora-setting:13102> seconds
|
|
* to allow ARA to actually connect.
|
|
*********************************************************************************/
|
|
OSErr OTPPPConnect(Boolean *attemptedConnection)
|
|
{
|
|
OSErr err = noErr;
|
|
OTResult result = kOTNoError;
|
|
unsigned long PPPState = 0;
|
|
Boolean PPPInForeGround = PrefIsSet(PREF_PPP_FOREGROUND);
|
|
Str255 scratch;
|
|
Boolean redial = false;
|
|
long numRedials = 0;
|
|
long delay = 0;
|
|
long dialCount = 0;
|
|
Boolean doDelay = false; // do we need to delay for stupid ARA?
|
|
|
|
#ifdef DEBUG
|
|
ASSERT(attemptedConnection); // must have this parameter
|
|
#endif
|
|
|
|
pppErr = noErr;
|
|
*attemptedConnection = false;
|
|
|
|
//Make a new PPP endpoint. We're only going to keep one around.
|
|
if (MyOTPPPInfo.ref == 0) result = NewPPPControlEndpoint();
|
|
|
|
if ((result == kOTNoError) && (MyOTPPPInfo.ref != kOTInvalidEndpointRef))
|
|
{
|
|
// Check the current state of the PPP connection.
|
|
err = GetPPPConnectionState(MyOTPPPInfo.ref, &PPPState);
|
|
if (err == noErr)
|
|
{
|
|
// have we already connected PPP at some point in the past?
|
|
if (MyOTPPPInfo.weConnectedPPP==true && MyOTPPPInfo.state==kPPPUp && PPPState==kPPPStateOpened) return noErr;
|
|
|
|
//If we don't already have an open connection, open one.
|
|
if ((PPPState != kPPPStateOpened && PPPState != kPPPStateOpening) || MyOTPPPInfo.state == kPPPClosing)
|
|
{
|
|
// remember that we're the one starting this connection
|
|
*attemptedConnection = true;
|
|
|
|
// we'll have to delay for ARA
|
|
doDelay = true;
|
|
|
|
// Get the redial information
|
|
if (!PPPInForeGround)
|
|
{
|
|
err = OTPPPDialingInformation(&redial, &numRedials, &delay);
|
|
if (err != noErr || numRedials < 1) redial = false; // couldn't get redial data. Ignore it.
|
|
|
|
dialCount = redial ? numRedials + 1 : 1;
|
|
}
|
|
else dialCount = 1; //redials are handled in the PPP connection dialog already.
|
|
|
|
// Establish a new connection
|
|
TurnOnPPPConnectionDialog(MyOTPPPInfo.ref, PPPInForeGround);
|
|
|
|
// force the current connection to close if it hasn't been to to already
|
|
if (PPPState == kPPPStateOpened || PPPState == kPPPStateOpening)
|
|
{
|
|
OTPPPDisconnect(true, false);
|
|
if (pppErr = WaitForOTPPPDisconnect(true)) return (pppErr);
|
|
MyOTPPPInfo.state = kPPPDown;
|
|
}
|
|
|
|
MyOTPPPInfo.result = noErr;
|
|
ProgressMessageR(kpSubTitle,OT_PPP_CONNECT);
|
|
if (!PPPInForeGround)
|
|
{
|
|
GetRString(scratch, OT_PPP_CONNECT_MESSAGE);
|
|
ProgressMessage(kpMessage,scratch);
|
|
}
|
|
|
|
// Actually connect OT/PPP
|
|
MyOTPPPInfo.code = 0;
|
|
MyOTPPPInfo.state = kPPPOpening;
|
|
result = kCCLErrorLineBusyErr;
|
|
pppErr = OTIoctl(MyOTPPPInfo.ref, I_OTConnect, NULL);
|
|
|
|
// Bug 1648 - if we're connecting PPP with the connection dialog, we should sit and spin until it finishes dialig the phone.
|
|
if (PPPInForeGround)
|
|
{
|
|
MyOTPPPInfo.status = inProgress;
|
|
if (pppErr == noErr) pppErr = SpinOn(&(MyOTPPPInfo.status),0,True,False);
|
|
}
|
|
|
|
// Spin until we can do TCP/IP over the connection
|
|
while (dialCount > 0 && result == kCCLErrorLineBusyErr && !PPPInForeGround && pppErr == noErr)
|
|
{
|
|
while (true)
|
|
{
|
|
MyOTPPPInfo.event = 0;
|
|
MyOTPPPInfo.result = noErr;
|
|
MyOTPPPInfo.status = inProgress;
|
|
if (pppErr == noErr) pppErr = SpinOn(&(MyOTPPPInfo.status),0,True,False);
|
|
|
|
result = MyOTPPPInfo.result;
|
|
if (MyOTPPPInfo.state == kPPPUp || MyOTPPPInfo.state == kPPPDown || pppErr != noErr || MyOTPPPInfo.result < 0) break;
|
|
|
|
// Update the progress dialog.
|
|
GetRString(scratch, MyOTPPPInfo.event);
|
|
ProgressMessage(kpMessage,scratch);
|
|
}
|
|
dialCount--;
|
|
if (redial && result == kCCLErrorLineBusyErr) ProgressMessageR(kpSubTitle,OT_PPP_REDIALING);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//there's a connection current trying to open
|
|
if (PPPState == kPPPStateOpening)
|
|
{
|
|
// do the ARA delay ...
|
|
doDelay = true;
|
|
|
|
//Spin until we can talk TCP over the connection
|
|
ProgressMessageR(kpSubTitle,OT_PPP_CONNECT);
|
|
GetRString(scratch, OT_PPP_CONNECT_MESSAGE);
|
|
ProgressMessage(kpMessage,scratch);
|
|
|
|
MyOTPPPInfo.state = kPPPOpening;
|
|
while (true)
|
|
{
|
|
MyOTPPPInfo.event = 0;
|
|
MyOTPPPInfo.result = noErr;
|
|
MyOTPPPInfo.status = inProgress;
|
|
err = SpinOn(&(MyOTPPPInfo.status),0,True,False);
|
|
|
|
result = MyOTPPPInfo.result;
|
|
if (MyOTPPPInfo.state == kPPPUp || MyOTPPPInfo.state == kPPPDown || err != noErr || MyOTPPPInfo.result < 0) break;
|
|
|
|
// Update the progress dialog.
|
|
GetRString(scratch, MyOTPPPInfo.event);
|
|
ProgressMessage(kpMessage,scratch);
|
|
}
|
|
|
|
if (err == noErr) err = MyOTPPPInfo.result;
|
|
}
|
|
|
|
if (err == noErr)
|
|
{
|
|
MyOTPPPInfo.state = kPPPUp;
|
|
*attemptedConnection = false; // PPP is up, but we didn't connect it.
|
|
pppErr = noErr;
|
|
}
|
|
else return (pppErr = err);
|
|
}
|
|
}
|
|
else //could not determine the state of the PPP connection
|
|
{
|
|
return (pppErr = errPPPStateUnknown);
|
|
}
|
|
}
|
|
else
|
|
return (pppErr = result);
|
|
|
|
// The connection is up because we connected it, or someone else did
|
|
if (pppErr == noErr)
|
|
{
|
|
if (MyOTPPPInfo.state == kPPPUp)
|
|
{
|
|
// must we delay for ARA?
|
|
if (doDelay)
|
|
{
|
|
// PPP Race Condition Hack.
|
|
//
|
|
// Since ARA and PPP have been combined, it's now possible to get the kPPPConnectCompletedEvent
|
|
// *before* ARA does. This will cause the first network operation to fail. So, let's Pause
|
|
// for a while, and let ARA know about it's successful connection.
|
|
long delay = GetRLong(OT_PPP_RACE_HACK);
|
|
Str255 delayStr;
|
|
|
|
if (delay > 0)
|
|
{
|
|
NumToString(delay, delayStr);
|
|
ComposeRString(scratch,OT_PPP_SMART_ASS,delayStr);
|
|
ProgressMessage(kpMessage,scratch);
|
|
|
|
Pause(60*delay);
|
|
}
|
|
}
|
|
|
|
MyOTPPPInfo.weConnectedPPP = *attemptedConnection; // remember if we started the connections ourselves or not.
|
|
}
|
|
else
|
|
{
|
|
if (!PPPInForeGround) pppErr = MyOTPPPInfo.result ? MyOTPPPInfo.result : kCCLErrorGeneric; //return some sort of error
|
|
else pppErr = userCancelled; //errors are handled in the PPP connection dialog
|
|
}
|
|
}
|
|
|
|
return (pppErr);
|
|
}
|
|
|
|
/*********************************************************************************
|
|
* NewPPPControlEndpoint - Set up the global PPP enpoint we use to control PPP.
|
|
*********************************************************************************/
|
|
OTResult NewPPPControlEndpoint(void)
|
|
{
|
|
OTResult result = kOTNoError;
|
|
TEndpointInfo epInfo;
|
|
short oldResFile = CurResFile();
|
|
DECLARE_UPP(MyPPPEndpointNotifier,OTNotify);
|
|
|
|
INIT_UPP(MyPPPEndpointNotifier,OTNotify);
|
|
|
|
MyOTPPPInfo.ref = OTOpenEndpointInContext(OTCreateConfiguration(kPPPControlName),0, &epInfo, &result,nil);
|
|
UseResFile(oldResFile); // bug in Modem control panel resets curresfile SD 8/5/98
|
|
|
|
if((result == kOTNoError) && (MyOTPPPInfo.ref != kOTInvalidEndpointRef))
|
|
{
|
|
result = OTInstallNotifier(MyOTPPPInfo.ref, MyPPPEndpointNotifierUPP, (void *)NULL);
|
|
if(result == kOTNoError)
|
|
{
|
|
if ((result = OTIoctl(MyOTPPPInfo.ref, I_OTGetMiscellaneousEvents, (void*)1)) == kOTNoError )
|
|
{
|
|
MyOTPPPInfo.state = kPPPDown; //kPPPDown means PPP has not been touched by us yet.
|
|
}
|
|
OTSetAsynchronous(MyOTPPPInfo.ref);
|
|
}
|
|
}
|
|
|
|
//if some error occurred, return 0, but don't close the endpoint.
|
|
if (result != kOTNoError) MyOTPPPInfo.ref = kOTInvalidEndpointRef;
|
|
|
|
return (result);
|
|
}
|
|
|
|
|
|
/*********************************************************************************
|
|
* TurnOnPPPConnectionDialog - make the PPP connection a modal event
|
|
*
|
|
* If on is true, then we will turn the connection dialog ON. If on is false,
|
|
* we will restore the conenction dialog to its previous state.
|
|
*********************************************************************************/
|
|
OSErr TurnOnPPPConnectionDialog(EndpointRef endPoint, Boolean on)
|
|
{
|
|
OSErr err = noErr;
|
|
long dlogState = 0;
|
|
|
|
err = GetCurrentUInt32Option(endPoint, OPT_ALERTENABLE, &dlogState);
|
|
if (err == noErr)
|
|
{
|
|
if (oldDlogState == 0) oldDlogState = dlogState;
|
|
|
|
if (on) //set the kPPPConnectionStatusDialogsFlag
|
|
dlogState = dlogState | kPPPConnectionStatusDialogsFlag;
|
|
else //turn the kPPPConnectionStatusDialogsFlag off.
|
|
dlogState = dlogState & (kPPPAllAlertsEnabledFlag - kPPPConnectionStatusDialogsFlag);
|
|
|
|
if (dlogState != oldDlogState)
|
|
err = SetCurrentUInt32Option(endPoint, OPT_ALERTENABLE, dlogState);
|
|
}
|
|
|
|
return (err);
|
|
}
|
|
|
|
/*********************************************************************************
|
|
* ResetPPPConnectionDialog - rest the statusDialogFlag to what it was before we
|
|
* started messing with it.
|
|
*********************************************************************************/
|
|
OSErr ResetPPPConnectionDialog(EndpointRef endPoint)
|
|
{
|
|
OSErr err = noErr;
|
|
long dlogState = 0;
|
|
|
|
err = GetCurrentUInt32Option(endPoint, OPT_ALERTENABLE, &dlogState);
|
|
if (err == noErr)
|
|
{
|
|
if (dlogState != oldDlogState)
|
|
{
|
|
if (!(oldDlogState&kPPPConnectionStatusDialogsFlag)) //if it was off to begin with, turn it off to reset
|
|
dlogState = dlogState & (kPPPAllAlertsEnabledFlag - kPPPConnectionStatusDialogsFlag);
|
|
else //if it was on before, turn it back on to reset.
|
|
dlogState = dlogState | kPPPConnectionStatusDialogsFlag;
|
|
|
|
err = SetCurrentUInt32Option(endPoint, OPT_ALERTENABLE, dlogState);
|
|
}
|
|
oldDlogState = 0;
|
|
}
|
|
|
|
return (err);
|
|
}
|
|
|
|
/*********************************************************************************
|
|
* GetPPPConnectionState - determine the state of PPP
|
|
*********************************************************************************/
|
|
OSErr GetPPPConnectionState(EndpointRef endPoint, unsigned long *PPPState)
|
|
{
|
|
OSErr err = noErr;
|
|
|
|
err = GetCurrentUInt32Option(endPoint, PPP_OPT_GETCURRENTSTATE, PPPState);
|
|
|
|
if (err != noErr) *PPPState = kPPPStateInitial;
|
|
|
|
return (err);
|
|
}
|
|
|
|
/*********************************************************************************
|
|
* GetCurrentUInt32Option - gets a UInt32 option from a PPP control point.
|
|
*********************************************************************************/
|
|
OSErr GetCurrentUInt32Option(EndpointRef endPoint, OTXTIName theOption, UInt32 *value)
|
|
{
|
|
OSErr err = noErr;
|
|
unsigned char buf[sizeof(TOption)];
|
|
TOption *option;
|
|
TOptMgmt command;
|
|
|
|
*value = 0;
|
|
|
|
command.opt.buf = buf;
|
|
command.opt.len = sizeof(TOption);
|
|
command.opt.maxlen = sizeof(TOption);
|
|
command.flags = T_CURRENT;
|
|
|
|
option = (TOption *)buf;
|
|
option->len = sizeof(TOption);
|
|
option->level = COM_PPP;
|
|
option->name = theOption;
|
|
option->status = 0;
|
|
option->value[0] = 0;
|
|
|
|
//get the current alert flags
|
|
err = OTOptionManagement(endPoint, &command, &command);
|
|
|
|
if ((err != noErr) || (option->status == T_FAILURE) || (option->status == T_NOTSUPPORT))
|
|
*value = 0L;
|
|
else
|
|
*value = option->value[0];
|
|
|
|
return (err);
|
|
}
|
|
|
|
/*********************************************************************************
|
|
* SetCurrentUInt32Option - sets a UInt32 option for PPP control point options.
|
|
*********************************************************************************/
|
|
OSErr SetCurrentUInt32Option(EndpointRef endPoint, OTXTIName theOption, UInt32 value)
|
|
{
|
|
OSErr err = noErr;
|
|
unsigned char buf[sizeof(TOption)];
|
|
TOption *option;
|
|
TOptMgmt command;
|
|
|
|
command.opt.buf = buf;
|
|
command.opt.len = sizeof(TOption);
|
|
command.opt.maxlen = sizeof(TOption);
|
|
command.flags = T_NEGOTIATE;
|
|
|
|
option = (TOption *)buf;
|
|
option->len = sizeof(TOption);
|
|
option->level = COM_PPP;
|
|
option->name = theOption;
|
|
option->status = 0;
|
|
option->value[0] = value;
|
|
|
|
//get the current alert flags
|
|
err = OTOptionManagement(endPoint, &command, &command);
|
|
|
|
return (err);
|
|
}
|
|
|
|
/*********************************************************************************
|
|
* OTPPPDisconnect - disconnect OTPPP if Eudora connected it in the first place.
|
|
* if (forceDisconnect) then we disconnect no matter who connected PPP
|
|
* if (endConnectionAttempt) then we reset the PPP connection dialog.
|
|
*********************************************************************************/
|
|
OSErr OTPPPDisconnect(Boolean forceDisconnect, Boolean endConnectionAttempt)
|
|
{
|
|
OSErr err = noErr;
|
|
|
|
if ((gHasOTPPP == true)
|
|
&& ((MyOTPPPInfo.ref && PrefIsSet(PREF_PPP_DISC) && MyOTPPPInfo.weConnectedPPP) || forceDisconnect))
|
|
{
|
|
err = OTIoctl(MyOTPPPInfo.ref, I_OTDisconnect, 0);
|
|
|
|
if (endConnectionAttempt)
|
|
{
|
|
ResetPPPConnectionDialog(MyOTPPPInfo.ref);
|
|
}
|
|
|
|
MyOTPPPInfo.weConnectedPPP = false;
|
|
MyOTPPPInfo.status = MyOTPPPInfo.result = 0;
|
|
}
|
|
|
|
return (err);
|
|
}
|
|
|
|
/*********************************************************************************
|
|
* OTPPPConnectForLink - connect OT/PPP to follow a link. Ignore the fact that
|
|
* we connected it, so we don't go try to close the connection later.
|
|
*********************************************************************************/
|
|
OSErr OTConnectForLink(void)
|
|
{
|
|
OSErr err = userCanceledErr;
|
|
unsigned long conMethod = 0;
|
|
Boolean weAttemptedPPP = false;
|
|
|
|
// Only makes sense to do this when OT is present
|
|
if (gUseOT)
|
|
{
|
|
// How are we connecting to the internet? Read from the preference files or NS database
|
|
err = SelectedConnectionMode(&conMethod,true);
|
|
|
|
// do we have PPP?
|
|
if (gHasOTPPP)
|
|
{
|
|
// Is OT/PPP the mode of connection?
|
|
if (conMethod == kPPPSelected)
|
|
{
|
|
dialingThePhone = true;
|
|
needPPPConnection = true;
|
|
gConnecting = true;
|
|
if (err = OTPPPConnect(&weAttemptedPPP))
|
|
{
|
|
OTPPPDisconnect(weAttemptedPPP, true);
|
|
}
|
|
gConnecting = false;
|
|
dialingThePhone = false;
|
|
|
|
// Forget about the fact that we connected OT/PPP.
|
|
MyOTPPPInfo.weConnectedPPP = false;
|
|
}
|
|
}
|
|
}
|
|
|
|
return (err);
|
|
}
|
|
|
|
/*********************************************************************************
|
|
* SelectedConnectionMode - determine the connection mode set in the TCP/IP control
|
|
* panel.
|
|
*
|
|
* 12-16-98 JDB
|
|
* Added the forceRead paramter to read from the TCP file, even if cache time
|
|
* has not yet run out. We really want to know the state of TCP/IP at each
|
|
* connection attempt. We don't care as much at idle time for things like
|
|
* the next check menu item.
|
|
*
|
|
* 5-19-99 JDB
|
|
* Added calls to the Network Setup library. This should prevent breakage.
|
|
*
|
|
* 7-16-99 JDB
|
|
* Use the cached connection method unless told not to
|
|
*
|
|
* 12-3-99 JDB
|
|
* Use the cached connection method if we just read the preferences
|
|
*********************************************************************************/
|
|
OSErr SelectedConnectionMode(unsigned long *connectionSelection, Boolean forceRead)
|
|
{
|
|
OSErr err = noErr;
|
|
char currentPortName[kMaxProviderNameSize];
|
|
char junk[kMaxProviderNameSize];
|
|
Boolean enabled;
|
|
static uLong method;
|
|
static uLong lastRead = 0;
|
|
|
|
if (HaveOSX())
|
|
{
|
|
// there's no way to tell if we're dialed up or not under OS X.
|
|
*connectionSelection = kOtherSelected;
|
|
return (noErr);
|
|
}
|
|
|
|
// do NOT call this unless OT is installed
|
|
if (OTIs == false) return (fnfErr);
|
|
|
|
// did we just read the preferences recently?
|
|
if (!forceRead && (lastRead>0) && ((TickCount()-lastRead) < GetRLong(TCP_PREF_REUSE_INTERVAL)))
|
|
{
|
|
*connectionSelection = method;
|
|
return (noErr);
|
|
}
|
|
|
|
// are we falling asleep? Then return value from the last time, no matter what.
|
|
if (UserIdle(TICKS2MINS) && (lastRead>0))
|
|
{
|
|
*connectionSelection = method;
|
|
return (noErr);
|
|
}
|
|
|
|
#ifdef DEBUG
|
|
Log(LOG_TRANS,"\pReading TCP/IP preferences from the disk now.");
|
|
#endif
|
|
|
|
#ifdef USE_NETWORK_SETUP
|
|
if (UseNetworkSetup())
|
|
{
|
|
if (IsNetworkSetupAvailable())
|
|
{
|
|
err = GetConnectionModeFromDatabase(connectionSelection);
|
|
|
|
lastRead = TickCount();
|
|
method = *connectionSelection;
|
|
}
|
|
else
|
|
{
|
|
// we have to use the Network Setup Library, but it's not available.
|
|
// Assume non-PPP and non-MacSLIP connection.
|
|
lastRead = TickCount();
|
|
method = *connectionSelection = kOtherSelected;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
#endif
|
|
*connectionSelection = kOtherSelected;
|
|
|
|
// read the port name from the TCP/IP preference file
|
|
err = GetCurrentPortNameFromFile(currentPortName, junk, &enabled);
|
|
if (err == noErr)
|
|
{
|
|
if (StringSame(currentPortName,PPP_NAME))
|
|
*connectionSelection = kPPPSelected;
|
|
}
|
|
|
|
if (!err)
|
|
{
|
|
lastRead = TickCount();
|
|
method = *connectionSelection;
|
|
}
|
|
#ifdef USE_NETWORK_SETUP
|
|
}
|
|
#endif
|
|
|
|
return (err);
|
|
}
|
|
|
|
/*******************************************************************************
|
|
* UserIdle - see if the user has been idle.
|
|
*******************************************************************************/
|
|
Boolean UserIdle(uLong ticks)
|
|
{
|
|
Boolean result = false;
|
|
#ifdef HAVE_GETLASTACTIVITY
|
|
static uLong idleTicks;
|
|
ActivityInfo info;
|
|
OSErr err = noErr;
|
|
|
|
if (((GestaltBits(gestaltPowerMgrAttr)&(1<<gestaltPMgrDispatchExists))!=0))
|
|
{
|
|
info.ActivityTime = 0;
|
|
info.ActivityType = UsrActivity;
|
|
if (!(err=GetLastActivity(&info)))
|
|
idleTicks = TickCount()-info.ActivityTime;
|
|
|
|
if (idleTicks > ticks)
|
|
result = true;
|
|
}
|
|
#endif
|
|
|
|
return (result);
|
|
}
|
|
|
|
/*******************************************************************************
|
|
* CanCheckPPPState - is it possible for us to check PPP's state?
|
|
*******************************************************************************/
|
|
Boolean CanCheckPPPState(void)
|
|
{
|
|
return !PrefIsSet(PREF_IGNORE_PPP) && (HaveTheDiseaseCalledOSX()||!gMissingNSLib);
|
|
}
|
|
|
|
/*******************************************************************************
|
|
* CanChangePPPState - is it possible for us to change PPP's state?
|
|
*******************************************************************************/
|
|
Boolean CanChangePPPState(void)
|
|
{
|
|
return !PrefIsSet(PREF_IGNORE_PPP) && !gMissingNSLib && !HaveTheDiseaseCalledOSX();
|
|
}
|
|
|
|
/*******************************************************************************
|
|
* PPPDown - is PPP installed, the selected mode of connection & disconnected?
|
|
*******************************************************************************/
|
|
Boolean PPPDown(void)
|
|
{
|
|
unsigned long con = 0;
|
|
static Boolean ret = false;
|
|
static uLong lastCheck;
|
|
|
|
ASSERT(!PrefIsSet(PREF_IGNORE_PPP));
|
|
|
|
if (HaveTheDiseaseCalledOSX())
|
|
{
|
|
if (TickCount()-lastCheck > GetRLong(TCP_PREF_REUSE_INTERVAL)/10+1)
|
|
{
|
|
Str255 host;
|
|
|
|
// grab a specific host to check; if there
|
|
// isn't one, use the mailhost
|
|
if (!*GetRString(host,PPP_REACHABLE_HOST))
|
|
GetPOPInfo(nil,host);
|
|
|
|
// check it
|
|
if (*host && CHostUnreachableByPPP(host+1)) ret = true;
|
|
else ret = false;
|
|
|
|
lastCheck = TickCount();
|
|
}
|
|
}
|
|
else if (gHasOTPPP)
|
|
{
|
|
SelectedConnectionMode(&con,false);
|
|
if (con == kPPPSelected)
|
|
{
|
|
if (MyOTPPPInfo.ref == 0) NewPPPControlEndpoint();
|
|
GetPPPConnectionState(MyOTPPPInfo.ref, &con);
|
|
if (con != kPPPStateOpened) ret = true;
|
|
}
|
|
}
|
|
|
|
return (ret);
|
|
}
|
|
|
|
#pragma segment Main
|
|
/*********************************************************************************
|
|
* MyPPPEndpointNotifier - notifier function for PPP endpoint events. It directly
|
|
* modifies the MyOTPPPInfo global structure.
|
|
*********************************************************************************/
|
|
pascal void MyPPPEndpointNotifier(void *context, OTEventCode code, OTResult result, void *cookie)
|
|
{
|
|
if (code > kPPPEvent && code <= kPPPDCECallFinishedEvent)
|
|
{
|
|
MyOTPPPInfo.status = 0;
|
|
MyOTPPPInfo.result = (OTResult)cookie;
|
|
|
|
if ((code == kPPPConnectCompleteEvent) && (MyOTPPPInfo.result != kOTNoError))
|
|
MyOTPPPInfo.event = OTPPP_MSG_STRN + (kPPPDCECallFinishedEvent + 1) - kPPPEvent + 1;
|
|
else
|
|
MyOTPPPInfo.event = OTPPP_MSG_STRN + code - kPPPEvent + 1;
|
|
}
|
|
|
|
if (code == kPPPDisconnectCompleteEvent) // Disconnect has completed.
|
|
MyOTPPPInfo.state = MyOTPPPInfo.result ? kPPPClosing : kPPPDown;
|
|
if (code == kPPPLowerLayerDownEvent) //remote server isn't responding added this 11-21-97
|
|
MyOTPPPInfo.state = kPPPDown;
|
|
else if ((code == kPPPConnectCompleteEvent) && (MyOTPPPInfo.result == kOTNoError))
|
|
MyOTPPPInfo.state = kPPPUp;
|
|
}
|
|
#pragma segment TcpTrans
|
|
|
|
/*********************************************************************************
|
|
* WaitForOTPPPDisconnect - sit and spin until the PPP state is kPPPStateInitial
|
|
*********************************************************************************/
|
|
OSErr WaitForOTPPPDisconnect(Boolean showStatus)
|
|
{
|
|
OSErr err = noErr;
|
|
long ticks=TickCount();
|
|
long startTicks=ticks+120;
|
|
long now;
|
|
Str255 scratch;
|
|
unsigned long PPPState;
|
|
|
|
//wait for the connection to close before we start another
|
|
if (showStatus)
|
|
{
|
|
GetRString(scratch, OT_PPP_DISCONNECT);
|
|
ProgressMessage(kpMessage,scratch);
|
|
}
|
|
|
|
do
|
|
{
|
|
now = TickCount();
|
|
if (now>startTicks && now-ticks>10)
|
|
{
|
|
CyclePendulum();
|
|
ticks=now;
|
|
}
|
|
MiniEvents();
|
|
if (CommandPeriod) return(pppErr = userCancelled);
|
|
err = GetPPPConnectionState(MyOTPPPInfo.ref, &PPPState);
|
|
}
|
|
while ((PPPState != kPPPStateInitial) && (err == noErr));
|
|
|
|
if (err != noErr && err != userCancelled) err = errPPPStateUnknown;
|
|
|
|
return (err);
|
|
}
|
|
|
|
|
|
/*********************************************************************************
|
|
* OTPPPDialingInformation - retrieve the redial options from the PPP settings file.
|
|
*
|
|
* - Look in Preferences folder for lzcn/rmot, the Remote Access Connections file
|
|
* - Open the resource fork
|
|
* - Fetch 'cdia' id 128, which contains the info we need.
|
|
*
|
|
* the fourth long in this resource contains 3 or 4 if we are to redial.
|
|
* the fifth long contains the number of redials to do before giving up.
|
|
* the sixth long contains 1000*number of seconds to delay.
|
|
*
|
|
* If any of this fails, we continue on as if nothing happened. Redialing just won't
|
|
* happen.
|
|
*
|
|
* The spec locating the rmot preference file is cached. This way, we can check
|
|
* the preference file periodically, and make sure the setting hasn't changed.
|
|
*
|
|
* This will break in a future OT.
|
|
*
|
|
* 5-19-99 JDB
|
|
* Added calls to the Network Setup library. This should prevent breakage.
|
|
*********************************************************************************/
|
|
OSErr OTPPPDialingInformation(Boolean *redial, unsigned long *numRedials, unsigned long *delay)
|
|
{
|
|
OSErr err = noErr;
|
|
short vRef = 0;
|
|
long dirId = 0;
|
|
CInfoPBRec hfi;
|
|
Str31 name;
|
|
short refNum = 0;
|
|
Handle probe = 0;
|
|
short oldRes;
|
|
|
|
oldRes = CurResFile();
|
|
|
|
//do NOT call this unless OT/PPP is installed and being used
|
|
if (gHasOTPPP == false) return (fnfErr);
|
|
|
|
*numRedials = *delay = 0;
|
|
*redial = false;
|
|
|
|
#ifdef USE_NETWORK_SETUP
|
|
// grok the settings from the TCP/IP preference file using the Network Setup Library.
|
|
if (UseNetworkSetup())
|
|
{
|
|
err = GetPPPDialingInformationFromDatabase(redial, numRedials, delay);
|
|
return (err);
|
|
}
|
|
#endif
|
|
|
|
if (PPPprefFileSpec.name[0] == 0) //have we not yet already located the PPP pref file?
|
|
{
|
|
/* Locate the PPP preferences file */
|
|
|
|
//find the active Preferences folder
|
|
err = FindFolder(kOnSystemDisk,kPreferencesFolderType,False,&vRef,&dirId);
|
|
if (err == noErr)
|
|
{
|
|
hfi.hFileInfo.ioNamePtr = name;
|
|
hfi.hFileInfo.ioVRefNum = vRef;
|
|
SearchDirectoryForFile(&hfi, dirId, PPP_PREF_FILE_TYPE, PPP_PREF_FILE_CREATOR);
|
|
}
|
|
}
|
|
|
|
if (PPPprefFileSpec.name[0] != 0) //have we located the PPP pref file?
|
|
{
|
|
refNum = FSpOpenResFile(&PPPprefFileSpec,fsRdPerm);
|
|
err = ResError();
|
|
if (err == noErr && refNum >= 0)
|
|
{
|
|
//this could breka in future versions of OT
|
|
probe = Get1Resource(DIAL_RESOURCE,DIAL_RESOURCE_ID);
|
|
err = ResError();
|
|
if (err == noErr && probe != 0)
|
|
{
|
|
//this is agonna break in future versions ot fer sure
|
|
if (((long *)*probe)[3] == 2)
|
|
{
|
|
*redial = false;
|
|
*numRedials = *delay = 0;
|
|
}
|
|
else
|
|
{
|
|
*redial = true;
|
|
*numRedials = ((long *)*probe)[4];
|
|
*delay = ((long *)*probe)[5]/1000;
|
|
}
|
|
}
|
|
}
|
|
CloseResFile(refNum);
|
|
}
|
|
|
|
if ((err != noErr) || (PPPprefFileSpec.name[0] == 0)) err = errPPPPrefNotFound;
|
|
|
|
UseResFile(oldRes);
|
|
|
|
return (err);
|
|
}
|
|
|
|
/*********************************************************************************
|
|
* SearchDirectoryForFile - Recursively search a directory for a file with a
|
|
* given creator and file type. This is an expensive function to call.
|
|
*********************************************************************************/
|
|
Boolean SearchDirectoryForFile(CInfoPBRec *info, long dirToSearch, OSType type, OSType creator)
|
|
{
|
|
short index = 1;
|
|
OSErr err = noErr;
|
|
Boolean static foundIt;
|
|
|
|
foundIt = false;
|
|
|
|
do
|
|
{
|
|
info->hFileInfo.ioFDirIndex = index;
|
|
info->hFileInfo.ioDirID = dirToSearch;
|
|
|
|
err = PBGetCatInfoSync(info);
|
|
|
|
if (err == noErr)
|
|
{
|
|
//found a directory
|
|
if ((info->hFileInfo.ioFlAttrib & ioDirMask) != 0)
|
|
{
|
|
SearchDirectoryForFile(info, info->hFileInfo.ioDirID, type, creator);
|
|
err = noErr;
|
|
}
|
|
else //found a file
|
|
{
|
|
if ((info->hFileInfo.ioFlFndrInfo.fdType == type &&
|
|
info->hFileInfo.ioFlFndrInfo.fdCreator == creator))
|
|
{
|
|
// Found it. Stop the search!
|
|
foundIt = true;
|
|
FSMakeFSSpec(info->hFileInfo.ioVRefNum, info->hFileInfo.ioFlParID, info->hFileInfo.ioNamePtr, &PPPprefFileSpec);
|
|
}
|
|
}
|
|
++index;
|
|
}
|
|
} while (err == noErr && !foundIt);
|
|
|
|
return (foundIt);
|
|
}
|
|
|
|
/*********************************************************************************
|
|
* SpinOnWithConnectionCheck - spin until a return code is not inProgress. Check
|
|
* connection while spinning.
|
|
*********************************************************************************/
|
|
short SpinOnWithConnectionCheck(short *rtnCodeAddr,long maxTicks,Boolean allowCancel,Boolean forever)
|
|
{
|
|
long ticks=TickCount();
|
|
long startTicks=ticks+120;
|
|
long now;
|
|
#ifdef CTB
|
|
extern ConnHandle CnH;
|
|
#endif
|
|
Boolean oldCommandPeriod = CommandPeriod;
|
|
Boolean slow = False;
|
|
static short slowThresh;
|
|
|
|
if (!slowThresh) slowThresh = GetRLong(SPIN_LENGTH);
|
|
|
|
if (allowCancel) YieldTicks = 0;
|
|
if (allowCancel || *rtnCodeAddr==inProgress)
|
|
{
|
|
CommandPeriod = False;
|
|
do
|
|
{
|
|
// check to see if we need ppp, but the connection is down
|
|
if (needPPPConnection && MyOTPPPInfo.state != kPPPUp) return(errLostConnection);
|
|
|
|
now = TickCount();
|
|
if (now>startTicks && now-ticks>slowThresh) {slow = True;if (!InAThread()) CyclePendulum(); else MyYieldToAnyThread();ticks=now;}
|
|
MiniEvents();
|
|
if (CommandPeriod && !forever) return(userCancelled);
|
|
if (maxTicks && startTicks+maxTicks < now+120) break;
|
|
}
|
|
while (*rtnCodeAddr == inProgress);
|
|
if (CommandPeriod) return(userCancelled);
|
|
CommandPeriod = oldCommandPeriod;
|
|
}
|
|
return(*rtnCodeAddr);
|
|
}
|
|
|
|
//Some sticky stuff
|
|
|
|
/*********************************************************************************
|
|
* GetHostByAddr - Call either TCPGetHostByAddr or OTGetHostByAddr, depending on
|
|
* whether OT is installed or not.
|
|
*********************************************************************************/
|
|
OSErr GetHostByAddr(struct hostInfo *hostInfoPtr,long addr)
|
|
{
|
|
// Do we have a NAT?
|
|
if (0x0A000000 == (addr&0xff000000) ||
|
|
0xAC100000 == (addr&0xfff00000) ||
|
|
0xC0A80000 == (addr&0xffff0000))
|
|
{
|
|
Str31 literal;
|
|
ComposeRString(literal,NAT_FMT,addr);
|
|
literal[*literal+1] = 0;
|
|
strcpy(hostInfoPtr->cname,literal+1);
|
|
hostInfoPtr->addr[1] = addr;
|
|
hostInfoPtr->rtnCode = 0;
|
|
return noErr;
|
|
}
|
|
|
|
if (gUseOT == true) // OT is installed
|
|
{
|
|
InetHostInfo domainName;
|
|
OSErr err = OTGetHostByAddr(addr, &domainName);
|
|
|
|
if (err == noErr) // our caller expects the hostInfoPtr to point a hostInfo struct.
|
|
{
|
|
short count;
|
|
|
|
strcpy(hostInfoPtr->cname,domainName.name);
|
|
for (count = 0; count < MIN(NUM_ALT_ADDRS,kMaxHostAddrs); count ++)
|
|
hostInfoPtr->addr[count] = domainName.addrs[count];
|
|
hostInfoPtr->rtnCode = 0;
|
|
}
|
|
return (err);
|
|
}
|
|
ASSERT ( false );
|
|
return unimpErr; /* unreachable, I think */
|
|
}
|
|
|
|
|
|
/*********************************************************************************
|
|
* GetHostByName - Call either TCPGetHostByName or OTGetHostByName, depending on
|
|
* whether OT is installed or not.
|
|
*
|
|
* The caller expects hostInfoPtr to be pointing to a TCP hostInfo struct. So
|
|
* if we do the OT thing, point hostInfoPtr at a hostInfo struct we fill with
|
|
* the results of the OTGetHostByName call.
|
|
*********************************************************************************/
|
|
int GetHostByName(UPtr name, struct hostInfo **hostInfoPtr)
|
|
{
|
|
static struct hostInfo trickCaller;
|
|
|
|
if (gUseOT == true) // OT is installed
|
|
{
|
|
InetHostInfo domainName;
|
|
int err = noErr;
|
|
short count;
|
|
InetDomainName hostName;
|
|
|
|
PtoCcpy(hostName,name);
|
|
|
|
err = OTGetHostByName(hostName, &domainName);
|
|
|
|
if (err == noErr) // our caller expects the hostInfoPtr to point a hostInfo struct.
|
|
{
|
|
*hostInfoPtr = &trickCaller;
|
|
|
|
strcpy(trickCaller.cname,domainName.name);
|
|
for (count = 0; count < MIN(NUM_ALT_ADDRS,kMaxHostAddrs); count ++)
|
|
trickCaller.addr[count] = domainName.addrs[count];
|
|
trickCaller.rtnCode = 0;
|
|
}
|
|
return (err);
|
|
}
|
|
ASSERT ( false );
|
|
return unimpErr; /* unreachable, I think */
|
|
}
|
|
|
|
/*********************************************************************************
|
|
* PPPIsMostDefinitelyUpAndRunning - return true if we're connected with PPP, or
|
|
* it's not an issue.
|
|
*********************************************************************************/
|
|
Boolean PPPIsMostDefinitelyUpAndRunning(void)
|
|
{
|
|
Boolean connected = true;
|
|
unsigned long con = 0;
|
|
|
|
if (gHasOTPPP)
|
|
{
|
|
SelectedConnectionMode(&con,false);
|
|
if ((con == kPPPSelected) && (MyOTPPPInfo.state != kPPPUp)) connected = false;
|
|
}
|
|
|
|
return (connected);
|
|
}
|
|
|
|
/*********************************************************************************
|
|
* UpdateCachedTCPIPPrefInfo - read from the preference files or NS Library now
|
|
*********************************************************************************/
|
|
void UpdateCachedConnectionMethodInfo(void)
|
|
{
|
|
unsigned long con = 0;
|
|
static uLong method;
|
|
|
|
if (SelectedConnectionMode(&con, true)==noErr)
|
|
{
|
|
// return true if the method has changed
|
|
if (con != method)
|
|
{
|
|
method = con;
|
|
gUpdateTPWindow = true; // update the TP window
|
|
}
|
|
}
|
|
}
|
|
|
|
/*********************************************************************************
|
|
* NeedToUpdateTP - do we need to adjust the next check time in the TP window?
|
|
*********************************************************************************/
|
|
Boolean NeedToUpdateTP(void)
|
|
{
|
|
Boolean updateIt = false;
|
|
|
|
if (gUpdateTPWindow)
|
|
{
|
|
updateIt = true;
|
|
gUpdateTPWindow = false;
|
|
}
|
|
|
|
return (updateIt);
|
|
}
|
|
|
|
/*********************************************************************************
|
|
* AutoCheckOKWithDBRead - read from the preference files or NS Library and see
|
|
* if an autocheck is appropriate.
|
|
*********************************************************************************/
|
|
Boolean AutoCheckOKWithDBRead(Boolean updatePers)
|
|
{
|
|
Boolean result = false;
|
|
OSErr err = noErr;
|
|
|
|
// are we set up to not check when not connected?
|
|
if (gUseOT && !PrefIsSet(PREF_IGNORE_PPP) && PrefIsSet(PREF_PPP_NOAUTO))
|
|
{
|
|
// make sure we're really, truly connected
|
|
UpdateCachedConnectionMethodInfo();
|
|
result = AutoCheckOK();
|
|
|
|
// we're not. Tell this personality to cram it.
|
|
if (!result && updatePers)
|
|
{
|
|
PersSkipNextCheck();
|
|
gUpdateTPWindow = true;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// not set to not check when not connected. Do the normal thing.
|
|
result = AutoCheckOK();
|
|
}
|
|
|
|
return (result);
|
|
}
|
|
|
|
#ifdef ESSL
|
|
// Declare the routine to set up the TransVector for doing SSL
|
|
TransVector ESSLSetupVector(TransVector theTrans);
|
|
#endif
|
|
|
|
TransVector GetTCPTrans()
|
|
{
|
|
TransVector theTrans;
|
|
|
|
theTrans = OTTCPTrans;
|
|
#ifdef ESSL
|
|
return ESSLSetupVector(theTrans);
|
|
#else
|
|
return theTrans;
|
|
#endif
|
|
}
|
|
|
|
/************************************************************************
|
|
* TcpFastFlush - run through the queue, killing off defunct streams
|
|
* Call KillDeadKyTStreams if we happen to be using open transport.
|
|
************************************************************************/
|
|
void TcpFastFlush(Boolean destroy)
|
|
{
|
|
static Boolean flushing = false;
|
|
|
|
// are we already flushing streams from somewhere?
|
|
if (flushing) return;
|
|
|
|
// kill defunct streams
|
|
flushing = true;
|
|
|
|
if (gUseOT)
|
|
KillDeadMyTStreams(destroy);
|
|
|
|
// we're done flushing streams for now.
|
|
flushing = false;
|
|
}
|
|
|
|
|
|
/**********************************************************************
|
|
* CheckConnectionSettings - Attempt to connect to a host/port pair.
|
|
**********************************************************************/
|
|
OSErr CheckConnectionSettings ( UPtr host, long port, StringPtr errorMessage ) {
|
|
OSErr err = noErr;
|
|
TransStream stream = NULL;
|
|
Boolean oldPref = PrefIsSet(PREF_IGNORE_PPP);
|
|
|
|
|
|
// Init the TransStream
|
|
if ( noErr == ( err = NewTransStream ( &stream ))) {
|
|
|
|
// See if the host is there....
|
|
SetPref(PREF_IGNORE_PPP,YesStr);
|
|
err = ConnectTrans ( stream, host, port, true, GetRLong(SHORT_OPEN_TIMEOUT));
|
|
SetPref(PREF_IGNORE_PPP,oldPref ? YesStr : NoStr);
|
|
|
|
// Grab an error message if we failed
|
|
if ( noErr != err && errorMessage != NULL ) {
|
|
short realSettingsRef = SettingsRefN;
|
|
|
|
SettingsRefN = GetMainGlobalSettingsRefN();
|
|
OTTELo ( errOpenStream, stream->streamErr, errorMessage );
|
|
SettingsRefN = realSettingsRef;
|
|
}
|
|
|
|
// That's all we wanted. Cleanup.
|
|
if ( noErr == err )
|
|
DestroyTrans(stream);
|
|
ZapTransStream ( &stream );
|
|
}
|
|
|
|
return err;
|
|
}
|
|
|