home *** CD-ROM | disk | FTP | other *** search
Text File | 1998-11-10 | 33.0 KB | 1,231 lines | [TEXT/CWIE] |
- /*
- File: NetworkSetupHelpers.c
-
- Contains: High-level network preference routines.
-
- Written by: Quinn
-
- Copyright: Copyright © 1998 by Apple Computer, Inc., all rights reserved.
-
- You may incorporate this Apple sample source code into your program(s) without
- restriction. This Apple sample source code has been provided "AS IS" and the
- responsibility for its operation is yours. You are not permitted to redistribute
- this Apple sample source code as "Apple sample source code" after having made
- changes. If you're going to re-distribute the source, we require that you make
- it clear in the source that the code was descended from Apple sample source
- code, but that you've made changes.
-
- Change History (most recent first):
-
- <7> 10/11/98 Quinn Fix = vs == in an assert.
- <6> 10/11/98 Quinn Convert "MorePrefix.h" to "MoreSetup.h".
- <5> 9/11/98 Quinn AppleTalk on/off support.
- <4> 9/11/98 Quinn Add "TCP will dial" code.
- <3> 5/11/98 Quinn Use MoreAssertQ instead of MoreAssert.
- <2> 5/11/98 Quinn Fix header.
- <1> 5/11/98 Quinn First checked in.
- */
-
- /////////////////////////////////////////////////////////////////
- // MoreIsBetter Setup
-
- #include "MoreSetup.h"
-
- /////////////////////////////////////////////////////////////////
- // Mac OS Interfaces
-
- #include <Types.h>
- #include <Files.h>
- #include <Errors.h>
- #include <Folders.h>
- #include <Resources.h>
- #include <Gestalt.h>
- #include <CodeFragments.h>
- #include <NetworkSetup.h>
- #include <OpenTptLinks.h>
-
- /////////////////////////////////////////////////////////////////
- // MIB Prototypes
-
- #include "MoreNetworkSetup.h"
- #include "OldOTConfigLib.h"
-
- /////////////////////////////////////////////////////////////////
- // Our Prototypes
-
- #include "NetworkSetupHelpers.h"
-
- /////////////////////////////////////////////////////////////////
- // Testing Parameters
-
- enum {
-
- // Throw this switch if you want to debug the direct preference
- // file access code on a machine with Network Setup installed.
-
- kUseNetworkSetup = true,
-
- // If you set kUseInetInterfaceInfo to false, NSHTCPWillDial will not
- // use the heuristic of "if the TCP/IP stack is loaded, it's safe
- // to open an endpoint". This is especially useful when debugging.
-
- kUseInetInterfaceInfo = true
-
- };
-
- /////////////////////////////////////////////////////////////////
-
- extern pascal ItemCount NSHCountConfigurationList(NSHConfigurationListHandle configList)
- // See comment in header file.
- {
- return GetHandleSize( (Handle) configList ) / sizeof(NSHConfigurationEntry);
- }
-
- /////////////////////////////////////////////////////////////////
- #pragma mark ----- Database Configuration List -----
-
- // Parameter structure for SetterIterator.
-
- struct TypeAndClassParam {
- OSType fType;
- OSType fClass;
- Boolean found;
- CfgEntityRef *currentEntity;
- };
- typedef struct TypeAndClassParam TypeAndClassParam;
-
- static pascal void TypeAndClassIterator(const MNSDatabadeRef *ref, CfgSetsElement *thisElement, void *p)
- // This routine is used as a callback for MNSIterateSet.
- // It looks for the entity specified by the fType and fClass
- // fields of the param, and puts its entityRef into the
- // variable pointed to by the currentEntity field of param.
- {
- TypeAndClassParam *param;
-
- param = (TypeAndClassParam *) p;
-
- MoreAssertQ(MNSValidDatabase(ref));
- MoreAssertQ(thisElement != nil);
- MoreAssertQ(param != nil);
- MoreAssertQ(param->currentEntity != nil);
-
- if (thisElement->fEntityInfo.fClass == param->fClass && thisElement->fEntityInfo.fType == param->fType) {
- MoreAssertQ( ! param->found );
- param->found = true;
- *(param->currentEntity) = thisElement->fEntityRef;
- }
- }
-
- static OSStatus FindCurrentConnection(const MNSDatabadeRef *ref, OSType protocol, CfgEntityRef *currentEntity)
- // This routine finds the current connection entity for the specified
- // protocol in the active set, returning it in currentEntity.
- {
- OSStatus err;
- CfgEntityRef activeSet;
- TypeAndClassParam param;
-
- MoreAssertQ(MNSValidDatabase(ref));
- MoreAssertQ(currentEntity != nil);
-
- param.fClass = kOTNetworkConnectionClass;
- param.fType = protocol;
- param.found = false;
- param.currentEntity = currentEntity;
-
- err = MNSFindActiveSet(ref, &activeSet);
- if (err == noErr) {
- err = MNSIterateSet(ref, &activeSet, TypeAndClassIterator, ¶m, false);
- }
- if (err == noErr) {
- if (param.found) {
- // Set preferences contain entities from weird areas because
- // of the way the database is committed. We can safely fix
- // that up here. I discussed with the Network Setup engineer
- // and he reassured me that this was cool -- Quinn, 9 Nov 1998
-
- currentEntity->fLoc = ref->area;
- } else {
- err = -6;
- }
- }
-
- return err;
- }
-
- static OSStatus AddEntityToConfigurationList(const MNSDatabadeRef *ref,
- const CfgEntityRef *entity,
- const CfgEntityInfo *entityInfo,
- NSHConfigurationListHandle configList)
- // This routines adds the entity specified by entity and entityInfo
- // in the database specified by ref to the configList.
- {
- OSStatus err;
- NSHConfigurationEntry thisEntry;
- StringPtr entityName;
- ByteCount junkSize;
-
- MoreAssertQ(configList != nil);
- MoreAssertQ(MNSValidDatabase(ref));
- MoreAssertQ(entity != nil);
- MoreAssertQ(entityInfo != nil);
-
- // Get the user-visible name from the configuration, which is
- // stored in the 'pnam' preferences. [This should have a proper
- // identifier in some future "NetworkSetup.h".]
-
- entityName = nil;
- err = MNSGetPref(ref, entity, 'pnam', &entityName, &junkSize);
- if (err == noErr) {
- MoreAssertQ(junkSize == (entityName[0] + 1));
- BlockMoveData(entityName, &thisEntry.name, entityName[0] + 1);
- thisEntry.selected = false;
- thisEntry.cookie = 0;
- thisEntry.cookie2 = *entity;
- thisEntry.cookie3 = *entityInfo;
- }
-
- if (err == noErr) {
- err = PtrAndHand(&thisEntry, (Handle) configList, sizeof(thisEntry));
- }
-
- // Clean up.
-
- if (entityName != nil) {
- DisposePtr( (Ptr) entityName);
- MoreAssertQ(MemError() == noErr);
- }
-
- return err;
- }
-
- // Parameter structure for SetterIterator.
-
- struct SetterParam {
- OSType fType;
- OSType fClass;
- const CfgEntityRef *chosenConfig;
- const CfgEntityInfo *chosenConfigInfo;
- };
- typedef struct SetterParam SetterParam;
-
- static pascal void SetterIterator(const MNSDatabadeRef *ref, CfgSetsElement *thisElement, void *p)
- // This routine is used as a callback for MNSIterateSet.
- // It looks for the entity specified by the fType and fClass
- // fields of the param, and replaces it with the chosen
- // entity and info from the param. It expects that the caller
- // of MNSIterateSet has specified writeAfterIterate so that
- // the changes get written back to the set.
- {
- SetterParam *param;
-
- param = (SetterParam *) p;
-
- MoreAssertQ(MNSValidDatabase(ref));
- MoreAssertQ(MNSDatabaseWritable(ref));
- MoreAssertQ(thisElement != nil);
- MoreAssertQ(param != nil);
- MoreAssertQ(param->chosenConfig != nil);
- MoreAssertQ(param->chosenConfigInfo != nil);
-
- if (thisElement->fEntityInfo.fClass == param->fClass && thisElement->fEntityInfo.fType == param->fType) {
- thisElement->fEntityRef = *param->chosenConfig;
- thisElement->fEntityInfo = *param->chosenConfigInfo;
- }
- }
-
- static OSStatus GetConfigurationListFromDatabase(OSType protocol, NSHConfigurationListHandle configList)
- // Implementation of NSHGetConfigurationList which uses the Network Setup
- // database. See NSHGetConfigurationList's comment in header
- // file for interface specification.
- {
- OSStatus err;
- OSStatus err2;
- MNSDatabadeRef ref;
- ItemCount entityCount;
- CfgEntityRef *entityRefs;
- CfgEntityInfo *entityInfos;
- CfgEntityRef activeConn;
- ItemCount i;
-
- entityRefs = nil;
- entityInfos = nil;
-
- err = MNSOpenDatabase(&ref, false);
- if (err == noErr) {
-
- // Find all the network connection entities for this protocol.
-
- err = MNSGetEntitiesList(&ref,
- kOTNetworkConnectionClass, protocol,
- &entityCount,
- &entityRefs,
- &entityInfos);
-
- // Add each to the list of possible connections.
-
- if (err == noErr) {
- for (i = 0; i < entityCount; i++) {
- err = AddEntityToConfigurationList(&ref, &entityRefs[i], &entityInfos[i], configList);
- }
- }
-
- // Find the current configuration and mark it as selected
- // in the list.
-
- if (err == noErr) {
- err = FindCurrentConnection(&ref, protocol, &activeConn);
- }
- if (err == noErr) {
- for (i = 0; i < entityCount; i++) {
- if ( OTCfgIsSameEntityRef(&activeConn, &(*configList)[i].cookie2, kOTCfgIgnoreArea) ) {
- (*configList)[i].selected = true;
- }
- }
- }
-
- err2 = MNSCloseDatabase(&ref, false);
- if (err == noErr) {
- err = err2;
- }
- }
-
- // Clean up.
-
- if (entityInfos != nil) {
- DisposePtr( (Ptr) entityInfos);
- MoreAssertQ(MemError() == noErr);
- }
- if (entityRefs != nil) {
- DisposePtr( (Ptr) entityRefs);
- MoreAssertQ(MemError() == noErr);
- }
- return err;
- }
-
- static OSStatus SelectConfigurationFromDatabase(OSType protocol, const NSHConfigurationEntry *chosenEntry)
- // Implementation of NSHSelectConfiguration which uses the Network Setup
- // database. See NSHSelectConfiguration's comment in header
- // file for interface specification.
- {
- OSStatus err;
- OSStatus err2;
- MNSDatabadeRef ref;
- CfgEntityRef activeSet;
- SetterParam param;
-
- err = MNSOpenDatabase(&ref, true);
- if (err == noErr) {
- param.fClass = kOTNetworkConnectionClass;
- param.fType = protocol;
- param.chosenConfig = &chosenEntry->cookie2;
- param.chosenConfigInfo = &chosenEntry->cookie3;
-
- err = MNSFindActiveSet(&ref, &activeSet);
- if (err == noErr) {
- err = MNSIterateSet(&ref, &activeSet, SetterIterator, ¶m, true);
- }
-
- err2 = MNSCloseDatabase(&ref, err == noErr);
- if (err == noErr) {
- err = err2;
- }
- }
- return err;
- }
-
- /////////////////////////////////////////////////////////////////
- #pragma mark ----- File Configuration List -----
-
- enum {
- kOTNetworkPrefFileType = 'pref',
- kOTTCPPrefFileCreator = 'ztcp',
- kOTAppleTalkPrefFileCreator = 'atdv'
- };
-
- static OSStatus FindNetworkPrefFile(OSType protocol, FSSpec *fss)
- // This routine scans the Preferences folder looking
- // for the specified network preferences file by type and creator.
- {
- OSStatus err;
- Boolean found;
- CInfoPBRec cpb;
- SInt16 index;
- OSType creatorToSearchFor;
-
- switch (protocol) {
- case kOTTCPv4NetworkConnection:
- creatorToSearchFor = kOTTCPPrefFileCreator;
- break;
- case kOTAppleTalkNetworkConnection:
- creatorToSearchFor = kOTAppleTalkPrefFileCreator;
- break;
- default:
- MoreAssertQ(false);
- break;
- }
-
- err = FindFolder(kOnSystemDisk, kPreferencesFolderType, kCreateFolder, &fss->vRefNum, &fss->parID);
- if (err == noErr) {
- found = false;
- index = 1;
- do {
- cpb.hFileInfo.ioVRefNum = fss->vRefNum;
- cpb.hFileInfo.ioDirID = fss->parID;
- cpb.hFileInfo.ioNamePtr = fss->name;
- cpb.hFileInfo.ioFDirIndex = index;
- err = PBGetCatInfoSync(&cpb);
- if (err == noErr) {
- found = ( cpb.hFileInfo.ioFlFndrInfo.fdType == kOTNetworkPrefFileType &&
- cpb.hFileInfo.ioFlFndrInfo.fdCreator == creatorToSearchFor );
- }
- index += 1;
- } while (err == noErr & ! found);
- }
- return err;
- }
-
- static OSStatus CheckResError(void *testH)
- // A trivial wrapper routine for ResError,
- // which is too lame to report an error code
- // in all cases when GetResource fails.
- {
- OSStatus err;
-
- err = ResError();
- if (err == noErr && testH == nil) {
- err = resNotFound;
- }
- return err;
- }
-
- static OSStatus CommitChangesToPrefFile(OSType protocol, SInt16 refNum, SInt16 config)
- {
- OSStatus err;
-
- err = noErr;
- switch (protocol) {
- case kOTTCPv4NetworkConnection:
- if ( TCPCheckChangeConfigurationConsequences(refNum, config) == kMustReboot ) {
- err = -7;
- }
- if ( err == noErr ) {
- err = TCPChangeConfiguration(refNum, config);
- }
- break;
- case kOTAppleTalkNetworkConnection:
- if ( ATCheckChangeConfigurationConsequences(refNum, config) == kMustReboot ) {
- err = -7;
- }
- if ( err == noErr ) {
- err = ATChangeConfiguration(refNum, config);
- }
- break;
- default:
- MoreAssertQ(false);
- err = -7;
- break;
- }
- return err;
- }
-
- static OSStatus GetCurrentConfig(SInt16 *config)
- {
- OSStatus err;
- Handle currentConfigResourceH;
-
- MoreAssertQ(config != nil);
-
- currentConfigResourceH = Get1Resource('ccfg', 1);
- err = CheckResError(currentConfigResourceH);
-
- if (err == noErr && GetHandleSize(currentConfigResourceH) != sizeof(SInt16) ) {
- // Assert: 'ccfg' is of the wrong size
- MoreAssertQ(false);
- err = -1;
- } else {
- *config = **(SInt16 **)currentConfigResourceH;
- }
- return err;
- }
-
- static OSStatus AddResourceToConfigurationList(Handle cnamHandle, NSHConfigurationListHandle configList)
- // Given a handle to a 'cnam' resource, generate a
- // NSHConfigurationEntry and append it to the list
- // of configurations.
- {
- OSStatus err;
- NSHConfigurationEntry thisEntry;
- SInt16 cnamID;
- ResType junkType;
-
- GetResInfo(cnamHandle, &cnamID, &junkType, thisEntry.name);
- MoreAssertQ(ResError() == noErr);
- MoreAssertQ(junkType == 'cnam');
- thisEntry.selected = false;
- thisEntry.cookie = cnamID;
- OTMemzero(&thisEntry.cookie2, sizeof(thisEntry.cookie2));
- OTMemzero(&thisEntry.cookie3, sizeof(thisEntry.cookie3));
-
- err = PtrAndHand(&thisEntry, (Handle) configList, sizeof(thisEntry));
- return err;
- }
-
- static OSStatus GetConfigurationListFromFile(OSType protocol, NSHConfigurationListHandle configList)
- // Implementation of NSHGetConfigurationList which uses the old-style
- // preference files. See NSHGetConfigurationList's comment in header
- // file for interface specification.
- {
- OSStatus err;
- FSSpec fss;
- Handle cnamHandle;
- SInt16 refNum;
- SInt16 resCount;
- SInt16 i;
- SInt16 **currentConfigH;
- SInt16 oldResFile;
-
- oldResFile = CurResFile();
- err = FindNetworkPrefFile(protocol, &fss);
- if (err == noErr) {
- SetResLoad(false);
- refNum = FSpOpenResFile(&fss, fsRdPerm);
- err = ResError();
- SetResLoad(true);
- if (err == noErr) {
-
- resCount = Count1Resources('cnam');
-
- for (i = 1; i <= resCount; i++) {
- SetResLoad(false);
- cnamHandle = Get1IndResource('cnam', i);
- err = CheckResError(cnamHandle);
- SetResLoad(true);
-
- if (err == noErr) {
- err = AddResourceToConfigurationList(cnamHandle, configList);
- }
-
- // Don't need to release the resource because CloseResFile will
- // clean it up.
-
- if (err != noErr) {
- break;
- }
- }
-
- if (err == noErr) {
- currentConfigH = (SInt16 **) Get1Resource('ccfg', 1);
- err = CheckResError(currentConfigH);
- }
- if (err == noErr) {
- for (i = 1; i <= resCount; i++) {
- if ( (*configList)[i].cookie == **currentConfigH ) {
- (*configList)[i].selected = true;
- }
- }
- }
-
- CloseResFile(refNum);
- MoreAssertQ(ResError() == noErr);
- }
- }
- UseResFile(oldResFile);
- MoreAssertQ(ResError() == noErr);
-
- return err;
- }
-
- static OSStatus SelectConfigurationFromFile(OSType protocol, const NSHConfigurationEntry *chosenEntry)
- // Implementation of NSHGetConfigurationList which uses the old-style
- // preference files. See NSHGetConfigurationList's comment in header
- // file for interface specification.
- {
- OSStatus err;
- FSSpec fss;
- SInt16 refNum;
- SInt16 oldResFile;
-
- oldResFile = CurResFile();
- err = FindNetworkPrefFile(protocol, &fss);
- if (err == noErr) {
-
- // ••• Gotcha •••
- // Really need to be careful here because it's possible
- // that fss is open in our current resource chain.
- // See DTS Technote 1120 "Opening Resource Files Twice Considered
- // Hard?" for details.
- //
- // <http://developer.apple.com/technotes/tn/tn1120.html>
- //
- // I'll probably put real code for this into MoreResources soon.
- // Meanwhile, you have to live with this limitation.
- // -- Quinn, 9 Nov 1998
-
- SetResLoad(false);
- refNum = FSpOpenResFile(&fss, fsRdWrPerm);
- err = ResError();
- SetResLoad(true);
- if (err == noErr) {
- err = CommitChangesToPrefFile(protocol, refNum, chosenEntry->cookie);
-
- CloseResFile(refNum);
- MoreAssertQ(ResError() == noErr);
- }
- }
- UseResFile(oldResFile);
- MoreAssertQ(ResError() == noErr);
-
- return err;
- }
-
- /////////////////////////////////////////////////////////////////
- #pragma mark ----- Configuration List Abstraction ------
-
- extern pascal OSStatus NSHGetConfigurationList(OSType protocol, NSHConfigurationListHandle configList)
- // See comment in header file.
- {
- OSStatus err;
-
- SetHandleSize( (Handle) configList, 0);
- MoreAssertQ(MemError() == noErr);
-
- if ( kUseNetworkSetup && IsNetworkSetupAvailable() ) {
- #if TARGET_RT_MAC_CFM
- err = GetConfigurationListFromDatabase(protocol, configList);
- #else
- // Network Setup has no Mixed Mode glue. When running
- // code on a PowerPC with Network Setup available, you
- // should either compile your code as Fat or, if that's
- // infeasible, write your own Mixed Mode glue.
- return -5;
- #endif
- } else {
- err = GetConfigurationListFromFile(protocol, configList);
- }
- return err;
- }
-
- extern pascal OSStatus NSHSelectConfiguration(OSType protocol, const NSHConfigurationEntry *chosenEntry)
- // See comment in header file.
- {
- OSStatus err;
-
- if ( kUseNetworkSetup && IsNetworkSetupAvailable() ) {
- #if TARGET_RT_MAC_CFM
- err = SelectConfigurationFromDatabase(protocol, chosenEntry);
- #else
- // Network Setup has no Mixed Mode glue. When running
- // code on a PowerPC with Network Setup available, you
- // should either compile your code as Fat or, if that's
- // infeasible, write your own Mixed Mode glue.
- return -5;
- #endif
- } else {
- err = SelectConfigurationFromFile(protocol, chosenEntry);
- }
- return err;
- }
-
- /////////////////////////////////////////////////////////////////
- #pragma mark ----- 'iitf' Parsing Code ------
-
- // The structure of an 'iitf' is the same regardless of whether it
- // comes from a resource or from the configuration database.
-
- // An 'iitf' preference consists of a UInt16 count followed
- // by 0 or more interface specifications. Each interface
- // specification is a variable length data structure, with
- // some fixed length and some variable length fields.
- // This structure is used to represent an interface as
- // a fixed size data structure, much more suitable for
- // C programming.
-
- // In current versions of OT, only one interface is allowed.
-
- struct TCPiitfPref {
- UInt8 fActive;
- InetHost fIPAddress;
- InetHost fSubnetMask;
- Str255 fAppleTalkZone;
- UInt8 fPath[36]; // Pascal string
- UInt8 fModuleName[31]; // Pascal string
- UInt32 fFramingFlags;
- };
- typedef struct TCPiitfPref TCPiitfPref;
-
- static void UnpackIITF(Ptr *buffer, TCPiitfPref *unpackedIITF)
- // This routine unpacks an interface from an 'iitf' preference
- // into a TCPiitfPref. *buffer must point to the beginning
- // of the interface, ie two bytes into the pref data if
- // if you're extracting the first interface. *buffer
- // is updated to point to the byte after the last byte
- // parsed, so you can parse multiple interfaces by
- // repeatedly calling this routine.
- {
- UInt8 *cursor;
-
- cursor = (UInt8 *) *buffer;
-
- unpackedIITF->fActive = *cursor;
- cursor += sizeof(UInt8);
- unpackedIITF->fIPAddress = *((InetHost *) cursor);
- cursor += sizeof(InetHost);
- unpackedIITF->fSubnetMask = *((InetHost *) cursor);
- cursor += sizeof(InetHost);
- BlockMoveData(cursor, unpackedIITF->fAppleTalkZone, *cursor + 1);
- cursor += (*cursor + 1);
- BlockMoveData(cursor, unpackedIITF->fPath, 36);
- cursor += 36;
- BlockMoveData(cursor, unpackedIITF->fModuleName, 32);
- cursor += 32;
- unpackedIITF->fFramingFlags = *((UInt32 *) cursor);
- cursor += sizeof(UInt32);
-
- *buffer = (Ptr) cursor;
- }
-
- static OSStatus GetPortNameFromIITF(Ptr buffer, SInt32 prefSize, char *portName)
- // This routine takes the address and size of an 'iitf' preference
- // and extracts the port name from the first interface.
- {
- OSStatus err;
- UInt16 interfaceCount;
- Ptr cursor;
- TCPiitfPref firstInterface;
- UInt8 portNameLength;
-
- // Get the count of interfaces, checking for possibly bogus
- // preference data.
-
- err = noErr;
- if (prefSize < sizeof(UInt16)) {
- err = -1;
- }
- if (err == noErr) {
- interfaceCount = *((UInt16 *)buffer);
- if (interfaceCount < 1) {
- err = -1;
- }
- }
-
- // Unpack the first interface out of the 'iitf'.
-
- if (err == noErr) {
- cursor = buffer + sizeof(UInt16);
- UnpackIITF(&cursor, &firstInterface);
-
- // Assert: Did not consume correct number of bytes
- MoreAssertQ( interfaceCount > 1 || (cursor == buffer + prefSize) );
- }
-
- // Copy the port name out of the unpacked interface.
-
- if (err == noErr) {
- portNameLength = firstInterface.fPath[0];
- if ( portNameLength > kMaxProviderNameLength) {
- err = -1;
- } else {
-
- // Poor Man's C2PString avoids me having to figure
- // out which wacky library CodeWarrior wants me to link with
- // today!
-
- BlockMoveData(firstInterface.fPath + 1, portName, portNameLength);
- portName[ portNameLength ] = 0;
- }
- }
-
- return err;
- }
-
- /////////////////////////////////////////////////////////////////
- #pragma mark ----- Database Will Dial ------
-
- static OSStatus GetInfoForTCPEntity(const MNSDatabadeRef *ref, const CfgEntityRef *entityID,
- Boolean *enabled, char *portName)
- // This routine returns the enabled status and port name
- // for the TCP/IP preferences entity described by entityID
- // in the ref database.
- {
- OSStatus err;
- SInt16 enabledInt;
- Ptr buffer;
- ByteCount prefSize;
-
- buffer = nil;
-
- // First return enabled using the simple API.
-
- err = MNSGetFixedSizePref(ref, entityID, 'unld', &enabledInt, sizeof(SInt16));
- if (err == noErr) {
- *enabled = (enabledInt != 3);
- }
-
- // Now return the port name. Now call the variable sized
- // API to get the 'iitf' resource and then extract the port name
- // from the preference buffer.
-
- if (err == noErr) {
- err = MNSGetPref(ref, entityID, 'iitf', &buffer, &prefSize);
- }
- if (err == noErr) {
- err = GetPortNameFromIITF(buffer, prefSize, portName);
- }
-
- // Clean up.
-
- if (buffer != nil) {
- DisposePtr(buffer);
- MoreAssertQ(MemError() == noErr);
- }
- return err;
- }
-
- static OSStatus GetTCPInfoFromDatabase(Boolean *enabled, char *portName)
- // The high-level entry point into the configuration database
- // implementation. We open the database, find the current
- // TCP entity and read the info we need out of that entity.
- {
- OSStatus err;
- OSStatus err2;
- MNSDatabadeRef ref;
- CfgEntityRef currentTCPEntity;
-
- err = MNSOpenDatabase(&ref, false);
- if (err == noErr) {
- err = FindCurrentConnection(&ref, kOTTCPv4NetworkConnection, ¤tTCPEntity);
- if (err == noErr) {
- err = GetInfoForTCPEntity(&ref, ¤tTCPEntity, enabled, portName);
- }
-
- err2 = MNSCloseDatabase(&ref, false);
- if (err == noErr) {
- err = err2;
- }
- }
- return err;
- }
-
- /////////////////////////////////////////////////////////////////
- #pragma mark ----- File Will Dial ------
-
- static OSStatus GetTCPInfoFromFile(Boolean *enabled, char *portName)
- // This is the high-level entry point into the direct file
- // access implementation. It simply finds the preferences
- // file and reads the preferences out directly.
- {
- OSStatus err;
- FSSpec fss;
- SInt16 oldResFile;
- SInt16 refNum;
- Handle unldResource;
- Handle iitfResource;
- SInt8 s;
- SInt16 config;
-
- oldResFile = CurResFile();
- err = FindNetworkPrefFile(kOTTCPv4NetworkConnection, &fss);
- if (err == noErr) {
- SetResLoad(false);
- refNum = FSpOpenResFile(&fss, fsRdPerm);
- err = ResError();
- SetResLoad(true);
- }
- if (err == noErr) {
- err = GetCurrentConfig(&config);
-
- if (err == noErr) {
- unldResource = Get1Resource('unld', config);
- err = CheckResError(unldResource);
- }
- if (err == noErr) {
- *enabled = ( **((SInt16 **) unldResource) != 3);
- }
-
- if (err == noErr) {
- iitfResource = Get1Resource('iitf', config);
- err = CheckResError(iitfResource);
- }
-
- if (err == noErr) {
- s = HGetState(iitfResource);
- HLock(iitfResource);
- err = GetPortNameFromIITF(*iitfResource, GetHandleSize(iitfResource), portName);
- HSetState(iitfResource, s);
- }
-
- CloseResFile(refNum);
- MoreAssertQ(ResError() == noErr);
- }
- UseResFile(oldResFile);
- MoreAssertQ(ResError() == noErr);
-
- return err;
- }
-
- /////////////////////////////////////////////////////////////////
- #pragma mark ----- Will Dial Abstraction -----
-
- static OSStatus GetTCPInfo(Boolean *enabled, char *portName)
- // A dispatcher. If the config database is available,
- // we call it, otherwise we fall back to reading the
- // preferences file directly.
- {
- OSStatus err;
-
- if ( kUseNetworkSetup && IsNetworkSetupAvailable() ) {
- #if TARGET_RT_MAC_CFM
- err = GetTCPInfoFromDatabase(enabled, portName);
- #else
- // Network Setup has no Mixed Mode glue. When running
- // code on a PowerPC with Network Setup available, you
- // should either compile your code as Fat or, if that's
- // infeasible, write your own Mixed Mode glue.
- return -5;
- #endif
- } else {
- err = GetTCPInfoFromFile(enabled, portName);
- }
- return err;
- }
-
- extern pascal OSStatus NSHTCPWillDial(UInt32 *willDial)
- // The main entry point. We call our core
- // implementation and then generate the result
- // based on the returned information.
- {
- OSStatus err;
- InetInterfaceInfo info;
- Boolean enabled;
- char currentPortName[kMaxProviderNameSize];
- OTPortRecord portRecord;
-
- MoreAssertQ(willDial != nil);
-
- *willDial = kNSHTCPDialUnknown;
-
- err = noErr;
- if ( kUseInetInterfaceInfo && OTInetGetInterfaceInfo(&info, kDefaultInetInterface) == noErr) {
-
- // The TCP/IP stack is already loaded. With the current
- // way TCP/IP is organised, the stack being loaded implies
- // that we're already dialled in.
-
- *willDial = kNSHTCPDialNo;
-
- } else {
- err = GetTCPInfo(&enabled, currentPortName);
- if (err == noErr) {
- if (enabled) {
- if ( OTStrEqual(currentPortName, "ddp") ) {
-
- // A special case for MacIP, because "ddp" does
- // not have an active port if AppleTalk is disabled.
-
- *willDial = kNSHTCPDialNo;
-
- } else if ( OTFindPort(&portRecord, currentPortName) ) {
-
- // We know the port. Look at the device type
- // to decide whether we might dial.
-
- switch ( OTGetDeviceTypeFromPortRef(portRecord.fRef) ) {
- case kOTADEVDevice:
- case kOTIRTalkDevice:
- case kOTSMDSDevice:
- // Assert: TCP shouldn't be using this link type
- MoreAssertQ(false);
- *willDial = kNSHTCPDialNo;
- break;
-
- case kOTISDNDevice:
- case kOTATMDevice:
- case kOTSerialDevice:
- case kOTModemDevice:
- // Assert: TCP shouldn't be using this link type
- MoreAssertQ(false);
- *willDial = kNSHTCPDialYes;
- break;
-
- case kOTLocalTalkDevice:
- case kOTTokenRingDevice:
- case kOTEthernetDevice:
- case kOTFastEthernetDevice:
- case kOTFDDIDevice:
- case kOTIrDADevice:
- case kOTATMSNAPDevice:
- case kOTFibreChannelDevice:
- case kOTFireWireDevice:
- *willDial = kNSHTCPDialNo;
- break;
-
- case kOTMDEVDevice:
- case kOTSLIPDevice:
- case kOTPPPDevice:
- *willDial = kNSHTCPDialYes;
- break;
-
- default:
- MoreAssertQ(*willDial == kNSHTCPDialUnknown);
- break;
- }
- } else {
- err = -1;
- }
- } else {
- *willDial = kNSHTCPDialTCPDisabled;
- }
- }
- }
-
- return err;
- }
-
- /////////////////////////////////////////////////////////////////
- #pragma mark ----- 'atpf' Constants -----
-
- // The value in the fLoadType field was originally designed to be
- // "minutes of inactivity till AppleTalk unloads", but then dynamic
- // load and unload of AppleTalk was disabled (it was basically
- // impossible to implement), so now we just use the values
- // inserted by the current control panels, ie 0xFF for active,
- // 0 for inactive.
- //
- // Note that a default prefs file may still have
- // 5 in this field. We handle this in IsAppleTalkActivePref but
- // never generate it.
-
- enum {
- kAppleTalkActive = 0xFF,
- kAppleTalkInactive = 0
- };
-
- /////////////////////////////////////////////////////////////////
- #pragma mark ----- Database AppleTalk On/Off -----
-
- static OSStatus IsAppleTalkActiveDatabase(Boolean *active)
- {
- OSStatus err;
- OSStatus err2;
- MNSDatabadeRef ref;
- CfgEntityRef currentAppleTalkEntity;
- atpfPreferences atpfPref;
-
- err = MNSOpenDatabase(&ref, false);
- if (err == noErr) {
- err = FindCurrentConnection(&ref, kOTAppleTalkNetworkConnection, ¤tAppleTalkEntity);
- if (err == noErr) {
- err = MNSGetFixedSizePref(&ref, ¤tAppleTalkEntity, 'atpf', &atpfPref, sizeof(atpfPref));
- }
- if (err == noErr) {
- *active = atpfPref.fDDP.fLoadType;
- }
-
- err2 = MNSCloseDatabase(&ref, false);
- if (err == noErr) {
- err = err2;
- }
- }
- return err;
- }
-
- static OSStatus SetAppleTalkActiveDatabase(Boolean active)
- {
- OSStatus err;
- OSStatus err2;
- MNSDatabadeRef ref;
- CfgEntityRef currentAppleTalkEntity;
- atpfPreferences atpfPref;
- Boolean changeNeeded;
- UInt8 newValue;
-
- err = MNSOpenDatabase(&ref, true);
- if (err == noErr) {
- changeNeeded = true;
-
- err = FindCurrentConnection(&ref, kOTAppleTalkNetworkConnection, ¤tAppleTalkEntity);
- if (err == noErr) {
- err = MNSGetFixedSizePref(&ref, ¤tAppleTalkEntity, 'atpf', &atpfPref, sizeof(atpfPref));
- }
- if (err == noErr) {
- if (active) {
- newValue = kAppleTalkActive;
- } else {
- newValue = kAppleTalkInactive;
- }
- changeNeeded = (newValue != atpfPref.fDDP.fLoadType);
- if (changeNeeded) {
- atpfPref.fDDP.fLoadType = newValue;
- err = MNSSetPref(&ref, ¤tAppleTalkEntity, 'atpf', &atpfPref, sizeof(atpfPref));
- }
- }
-
- err2 = MNSCloseDatabase(&ref, (err == noErr) && changeNeeded );
- if (err == noErr) {
- err = err2;
- }
- }
- return err;
- }
-
- /////////////////////////////////////////////////////////////////
- #pragma mark ----- File AppleTalk On/Off -----
-
- static OSStatus IsAppleTalkActiveFile(Boolean *active)
- {
- OSStatus err;
- FSSpec fss;
- SInt16 oldResFile;
- SInt16 refNum;
- Handle atpfResource;
- SInt16 config;
-
- oldResFile = CurResFile();
- err = FindNetworkPrefFile(kOTAppleTalkNetworkConnection, &fss);
- if (err == noErr) {
- SetResLoad(false);
- refNum = FSpOpenResFile(&fss, fsRdPerm);
- err = ResError();
- SetResLoad(true);
- }
- if (err == noErr) {
- err = GetCurrentConfig(&config);
-
- if (err == noErr) {
- atpfResource = Get1Resource('atpf', config);
- err = CheckResError(atpfResource);
- }
- if (err == noErr && GetHandleSize(atpfResource) != sizeof(atpfPreferences)) {
- err = -1;
- }
- if (err == noErr) {
- *active = (**(atpfPreferences **) atpfResource).fDDP.fLoadType != 0;
- }
- CloseResFile(refNum);
- MoreAssertQ(ResError() == noErr);
- }
- UseResFile(oldResFile);
- MoreAssertQ(ResError() == noErr);
-
- return err;
- }
-
- static OSStatus SetAppleTalkActiveFile(Boolean active)
- {
- OSStatus err;
- FSSpec fss;
- SInt16 refNum;
- SInt16 oldResFile;
- Handle atpfResource;
- SInt16 config;
- Boolean changeNeeded;
- UInt8 newValue;
-
- oldResFile = CurResFile();
- err = FindNetworkPrefFile(kOTAppleTalkNetworkConnection, &fss);
- if (err == noErr) {
-
- // ••• Gotcha •••
- // Really need to be careful here because it's possible
- // that fss is open in our current resource chain.
- // See DTS Technote 1120 "Opening Resource Files Twice Considered
- // Hard?" for details.
- //
- // <http://developer.apple.com/technotes/tn/tn1120.html>
- //
- // I'll probably put real code for this into MoreResources soon.
- // Meanwhile, you have to live with this limitation.
- // -- Quinn, 9 Nov 1998
-
- SetResLoad(false);
- refNum = FSpOpenResFile(&fss, fsRdWrPerm);
- err = ResError();
- SetResLoad(true);
- if (err == noErr) {
- err = GetCurrentConfig(&config);
-
- if (err == noErr) {
- atpfResource = Get1Resource('atpf', config);
- err = CheckResError(atpfResource);
- }
- if (err == noErr && GetHandleSize(atpfResource) != sizeof(atpfPreferences)) {
- err = -1;
- }
- if (err == noErr) {
- if (active) {
- newValue = kAppleTalkActive;
- } else {
- newValue = kAppleTalkInactive;
- }
- changeNeeded = (newValue != (**(atpfPreferences **) atpfResource).fDDP.fLoadType);
- if (changeNeeded) {
- (**(atpfPreferences **) atpfResource).fDDP.fLoadType = newValue;
- ChangedResource(atpfResource);
- err = ResError();
- if (err == noErr) {
- UpdateResFile(refNum);
- err = ResError();
- }
- if (err == noErr) {
- err = CommitChangesToPrefFile(kOTAppleTalkNetworkConnection, refNum, config);
- }
- }
- }
-
- CloseResFile(refNum);
- MoreAssertQ(ResError() == noErr);
- }
- }
- UseResFile(oldResFile);
- MoreAssertQ(ResError() == noErr);
-
- return err;
- }
-
- /////////////////////////////////////////////////////////////////
- #pragma mark ----- AppleTalk On/Off -----
-
- extern pascal OSStatus NSHIsAppleTalkActive(Boolean *active)
- // See comment in header file.
- {
- OSStatus err;
-
- if ( kUseNetworkSetup && IsNetworkSetupAvailable() ) {
- #if TARGET_RT_MAC_CFM
- err = IsAppleTalkActiveDatabase(active);
- #else
- // Network Setup has no Mixed Mode glue. When running
- // code on a PowerPC with Network Setup available, you
- // should either compile your code as Fat or, if that's
- // infeasible, write your own Mixed Mode glue.
- return -5;
- #endif
- } else {
- err = IsAppleTalkActiveFile(active);
- }
- return err;
- }
-
- extern pascal OSStatus HSHSetAppleTalkActive(Boolean active)
- // See comment in header file.
- {
- OSStatus err;
-
- if ( kUseNetworkSetup && IsNetworkSetupAvailable() ) {
- #if TARGET_RT_MAC_CFM
- err = SetAppleTalkActiveDatabase(active);
- #else
- // Network Setup has no Mixed Mode glue. When running
- // code on a PowerPC with Network Setup available, you
- // should either compile your code as Fat or, if that's
- // infeasible, write your own Mixed Mode glue.
- return -5;
- #endif
- } else {
- err = SetAppleTalkActiveFile(active);
- }
- return err;
- }
-
- /////////////////////////////////////////////////////////////////
-