Retired Document
Important: This sample code may not represent best practices for current development. The project may use deprecated symbols and illustrate technologies and techniques that are no longer recommended.
QISAPlatformCFM/QISAPlatformCFM.c
/* |
File: QISAPlatformCFM.c |
Contains: Implementation of the traditional Mac OS platform specific code. |
Written by: DTS |
Copyright: Copyright © 2002 by Apple Computer, Inc., All Rights Reserved. |
Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple Computer, Inc. |
("Apple") in consideration of your agreement to the following terms, and your |
use, installation, modification or redistribution of this Apple software |
constitutes acceptance of these terms. If you do not agree with these terms, |
please do not use, install, modify or redistribute this Apple software. |
In consideration of your agreement to abide by the following terms, and subject |
to these terms, Apple grants you a personal, non-exclusive license, under AppleÕs |
copyrights in this original Apple software (the "Apple Software"), to use, |
reproduce, modify and redistribute the Apple Software, with or without |
modifications, in source and/or binary forms; provided that if you redistribute |
the Apple Software in its entirety and without modifications, you must retain |
this notice and the following text and disclaimers in all such redistributions of |
the Apple Software. Neither the name, trademarks, service marks or logos of |
Apple Computer, Inc. may be used to endorse or promote products derived from the |
Apple Software without specific prior written permission from Apple. Except as |
expressly stated in this notice, no other rights or licenses, express or implied, |
are granted by Apple herein, including but not limited to any patent rights that |
may be infringed by your derivative works or by other works in which the Apple |
Software may be incorporated. |
The Apple Software is provided by Apple on an "AS IS" basis. APPLE MAKES NO |
WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED |
WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND OPERATION ALONE OR IN |
COMBINATION WITH YOUR PRODUCTS. |
IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL OR |
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE |
GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION |
OF THE APPLE SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT, TORT |
(INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN |
ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
Change History (most recent first): |
*/ |
///////////////////////////////////////////////////////////////// |
#include "QISAPlatform.h" |
// System interfaces |
#include <OpenTransport.h> |
#include <OpenTransportProtocol.h> |
#include <NetworkSetup.h> |
#include <CFNumber.h> |
#include <StringCompare.h> |
#include <Folders.h> |
#include <PLStringFuncs.h> |
#include <stdio.h> |
#include <string.h> |
// MoreIsBetter interfaces |
#include "MoreCFQ.h" |
#include "MoreMemory.h" |
#include "MoreSCFCCLScanner.h" |
#include "NetworkSetupHelpers.h" |
// QISA interfaces |
#include "QISA.h" |
///////////////////////////////////////////////////////////////// |
#pragma mark ***** Exports |
#pragma export list QISACreateCCLArray |
#pragma export list QISACreatePortArray |
#pragma export list QISADoesNetworkConfigExist |
#pragma export list QISAMakeNetworkConfig |
#pragma export list QISAPlatformInit |
///////////////////////////////////////////////////////////////// |
#pragma mark ***** Implementation |
// IMPORTANT: |
// When converting network configuration user visible names to and from CFStrings, we |
// deliberately use CFStringGetSystemEncoding, and not GetApplicationTextEncoding. |
// If you're an English application running on a Japanese system, the network control |
// panels will be localised for Japanese (the system encoding), not English (the |
// application encoding), and thus the configurations names need to be treated as |
// Japanese. |
// This plug-in's bundle. It's passed to QISAPlatformInit by the |
// host application. We keep track of it just because it's generally |
// useful. Right now we don't use it anywhere outside of QISAPlatformInit. |
static CFBundleRef gPlatformBundle; |
// This key is used to store a port's OTPortRef within the port |
// dictionaries returned by QISACreatePortArray. |
#define kMyPropOTPortRef CFSTR("com.apple.dts.QISA.OTPortRef") /* CFNumber SInt32 -> OTPortRef */ |
static OTPortRef GetPortRefFromDict(CFDictionaryRef portDict) |
// Given a port dictionary (created QISACreatePortArray), get the |
// OTPortRef from the kMyPropOTPortRef key. |
{ |
Boolean junkBool; |
OTPortRef result; |
CFNumberRef portRef; |
assert(portDict != NULL); |
result = kOTInvalidPortRef; |
portRef = (CFNumberRef) CFDictionaryGetValue(portDict, kMyPropOTPortRef); |
assert( (portRef != NULL) && (CFGetTypeID(portRef) == CFNumberGetTypeID()) ); |
junkBool = CFNumberGetValue(portRef, kCFNumberSInt32Type, (SInt32 *) &result); |
assert(junkBool); |
return result; |
} |
extern pascal OSStatus QISACreateCCLArray(CFArrayRef *result, CFIndex *indexOfDefaultCCL) |
// See comment in "QISAPlatform.h". |
// Also see discussion of MoreSCCreateCCLArray in "MoreSCFCCLScanner.h". |
{ |
return MoreSCCreateCCLArray(result, indexOfDefaultCCL); |
} |
static CFComparisonResult PortSorter(const void *lhs, const void *rhs, void *context) |
// Compares two port dictionaries and orders them appropriately. |
// This is used by QISACreatePortArray to sort the returned |
// port list. |
{ |
#pragma unused(context) |
CFDictionaryRef lhsDict; |
CFDictionaryRef rhsDict; |
OTDeviceType lhsOrder; |
OTDeviceType rhsOrder; |
assert(lhs != NULL); |
assert(rhs != NULL); |
lhsDict = (CFDictionaryRef) lhs; |
assert( CFGetTypeID(lhsDict) == CFDictionaryGetTypeID() ); |
rhsDict = (CFDictionaryRef) rhs; |
assert( CFGetTypeID(rhsDict) == CFDictionaryGetTypeID() ); |
lhsOrder = OTGetDeviceTypeFromPortRef(GetPortRefFromDict(lhs)); |
rhsOrder = OTGetDeviceTypeFromPortRef(GetPortRefFromDict(lhs)); |
if (lhsOrder > rhsOrder) |
return kCFCompareGreaterThan; |
if (lhsOrder < rhsOrder) |
return kCFCompareLessThan; |
// objects are the same type, so order by name |
return CFStringCompare( |
(CFStringRef) CFDictionaryGetValue(lhsDict, kSCPropUserDefinedName), |
(CFStringRef) CFDictionaryGetValue(rhsDict, kSCPropUserDefinedName), kCFCompareLocalized); |
} |
extern pascal OSStatus QISACreatePortArray(CFArrayRef *portArray) |
// See comment in "QISAPlatform.h". |
{ |
OSStatus err; |
Boolean done; |
CFMutableArrayRef result; |
OTItemCount portIndex; |
OTPortRecord thisPort; |
assert( portArray != NULL); |
assert(*portArray == NULL); |
result = NULL; |
// Create the array. |
err = CFQArrayCreateMutable(&result); |
if (err == noErr) { |
// Iterate over the OT port registry looking for serial ports. For each |
// port found, create a dictionary that represents the port and add that |
// to the array. |
done = false; |
portIndex = 0; |
do { |
if ( OTGetIndexedPort(&thisPort, portIndex) ) { |
if (OTGetDeviceTypeFromPortRef(thisPort.fRef) == kOTSerialDevice) { |
Str255 portNameP; |
CFStringRef portName; |
CFNumberRef portRef; |
CFDictionaryRef portDict; |
portName = NULL; |
portRef = NULL; |
portDict = NULL; |
OTGetUserPortNameFromPortRef(thisPort.fRef, portNameP); |
portName = CFStringCreateWithPascalString(NULL, portNameP, CFStringGetSystemEncoding()); |
err = CFQError(portName); |
if (err == noErr) { |
portRef = CFNumberCreate(NULL, kCFNumberSInt32Type, &thisPort.fRef); |
err = CFQError(portRef); |
} |
if (err == noErr) { |
CFStringRef keys[3]; |
CFTypeRef values[3]; |
keys[0] = kSCPropUserDefinedName; |
values[0] = portName; |
keys[1] = kSCPropNetInterfaceHardware; |
values[1] = kSCEntNetModem; |
keys[2] = kMyPropOTPortRef; |
values[2] = portRef; |
portDict = CFDictionaryCreate(NULL, (const void **) keys, (const void **) values, 3, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); |
err = CFQError(portDict); |
} |
if (err == noErr) { |
CFArrayAppendValue(result, portDict); |
} |
CFQRelease(portDict); |
CFQRelease(portRef); |
CFQRelease(portName); |
} |
} else { |
done = true; |
} |
portIndex += 1; |
} while (err == noErr && !done); |
} |
// Sort the resulting array. |
if (err == noErr) { |
CFArraySortValues(result, CFRangeMake( 0, CFArrayGetCount( result )), PortSorter, NULL); |
} |
// Clean up. |
if (err != noErr) { |
CFQRelease(result); |
result = NULL; |
} |
*portArray = result; |
assert( (err == noErr) == (*portArray != NULL) ); |
return err; |
} |
static OSStatus FindNetworkConfig(OSType protocol, ConstStr255Param userVisibleName, |
Boolean *found, NSHConfigurationEntry *result) |
// Given a protocol (for example, kOTCfgTypeTCPv4) and a user visible name, |
// find the corresponding network configuration. |
// |
// If you just care about whether the configuration exists, you can pass NULL |
// to result. |
// |
// On error, *found is undefined and, if result is not NULL, *result is also undefined |
{ |
OSStatus err; |
NSHConfigurationListHandle configList; |
assert(userVisibleName != NULL); |
assert(found != NULL); |
// Create a handle containing every network configuration. |
configList = (NSHConfigurationListHandle) NewHandle(0); |
err = MoreMemError(configList); |
if (err == noErr) { |
err = NSHGetConfigurationList(protocol, configList); |
} |
// Iterate over that handle looking for one with a matching user visible name. |
if (err == noErr) { |
SInt8 s; |
ItemCount configCount; |
ItemCount configIndex; |
s = HGetState( (Handle) configList ); |
assert(MemError() == noErr); |
HLock( (Handle) configList ); |
assert(MemError() == noErr); |
configCount = NSHCountConfigurationList(configList); |
configIndex = 0; |
*found = false; |
while ( (configIndex < configCount) && ! *found ) { |
// I spent a lot of time trying to figure out the correct way to |
// compare network configuration names, and eventualy decided that |
// there's no good way to do this. The basic problem is that different |
// parts of the system do it in different ways. You can see this with |
// a simple test in the Modem control panel. Open the control panel |
// and create a configuration called "Test" and another configuration |
// called "Tst". The control panel lets you do this because diacritics |
// are considered distinct for duplicating and renaming a configuration. |
// Now make the configuration "Test" active and then bring up the |
// configuration dialog again and try to delete the "Tst" configuration. |
// You can't do it! Why? It's because diacriticals are not considered |
// distinct as far as highlighting the "Delete" button is concerned. |
// Whoops. |
// |
// It turns out that networking the control panels uses three different |
// mechanism to compare configuration names. |
// |
// 1. For sorting names, they use CompareText (actually IUMagString). |
// 2. For Duplicate and Rename comparison, they use RelString with |
// case insensitive and diacritical sensitive. |
// 3. For activating the Delete button, they use EqualString |
// (which has the same comparison table as RelString), however |
// this time it's case insensitive but diacritical *insensitive*. |
// |
// All in all, the control panels do not give a consistent story |
// about how to compare configuration names. |
// |
// In addition, the actually Network Setup backend never compares |
// the user-visible names of configurations, so I can't look to it |
// for guidance. |
// |
// This leaves me in a quandry. Eventually I decided to make my |
// code easier and use EqualString. This is definitely not the |
// right thing on non-Roman systems, but it isn't any worse than |
// the control panels themselves. Non-Roman users already have |
// to deal with the broken control panels, so they probably won't |
// mind me being equally broken. |
*found = EqualString((*configList)[configIndex].name, userVisibleName, false, true); |
if ( ! *found ) { |
configIndex += 1; |
} |
} |
// If the client requested a reference to the configuration, return it. |
if (*found && result != NULL) { |
*result = (*configList)[configIndex]; |
} |
HSetState( (Handle) configList, s ); |
assert(MemError() == noErr); |
} |
// Clean up. |
if (configList != NULL) { |
DisposeHandle( (Handle) configList ); |
assert(MemError() == noErr); |
} |
return err; |
} |
extern pascal OSStatus QISADoesNetworkConfigExist(CFStringRef userVisibleName, Boolean *exists) |
// See comment in "QISAPlatform.h". |
{ |
OSStatus err; |
Str255 userVisibleNameP; |
assert(userVisibleName != NULL); |
assert(exists != NULL); |
*exists = false; |
err = CFQErrorBoolean( CFStringGetPascalString(userVisibleName, userVisibleNameP, sizeof(userVisibleName), CFStringGetSystemEncoding()) ); |
if (err == noErr) { |
err = FindNetworkConfig(kOTCfgTypeTCPv4, userVisibleNameP, exists, NULL); |
} |
return err; |
} |
static OSStatus GetCCLFSSpec(ConstStr255Param cclName, FSSpec *fss) |
// Given a CCL name, return an FSSpec to the CCL file itself. |
// We should probably search each domain for the CCL, much like we |
// do in MoreSCCreateCCLArray, however I don't think that's necessary |
// because domains don't make a lot of sense on traditional Mac OS. |
{ |
OSStatus err; |
SInt16 vRef; |
SInt32 dirID; |
assert(cclName != NULL); |
assert(fss != NULL); |
err = FindFolder(kOnSystemDisk, kModemScriptsFolderType, false, &vRef, &dirID); |
if (err == noErr) { |
err = FSMakeFSSpec( vRef, dirID, cclName, fss); |
} |
return err; |
} |
static OSStatus SetupNetworkConfig(const NSHConfigurationDigest *digest, NSHConfigurationEntry *modifiedConfig) |
// Given a network configuration digest (a big parameter block containing |
// all of the information needed to set up a network configuration), create |
// that configuration. It overwrites the configuration if it already exists. |
// Returns a reference to the configuration that was created (or overwritten). |
{ |
OSStatus err; |
Boolean found; |
assert(digest != NULL); |
assert(modifiedConfig != NULL); |
err = FindNetworkConfig(digest->fCommon.fProtocol, digest->fCommon.fConfigName, &found, modifiedConfig); |
if (err == noErr) { |
// If we found the named configuration, overwrite it using |
// NSHSetConfiguration. If we didn't, create a new configuration |
// using NSHCreateConfiguration. This even sets up modifiedConfig for us. |
if (found) { |
err = NSHSetConfiguration(modifiedConfig, digest); |
} else { |
err = NSHCreateConfiguration(digest, modifiedConfig); |
} |
} |
return err; |
} |
static OSStatus MakeNetworkConfig(ConstStr255Param userVisibleName, |
OTPortRef portRef, |
ConstStr255Param chosenCCL, |
ConstStr255Param username, |
ConstStr255Param password, |
ConstStr255Param number, |
Boolean useTerminal) |
// A sub-routine called by QISAMakeNetworkConfig to actually create |
// a network configuration. |
{ |
OSStatus err; |
NSHConfigurationDigest tcpv4; // the following consumes a truly massive amount of stack space! |
NSHConfigurationDigest remote; |
NSHConfigurationDigest modem; |
NSHConfigurationEntry modemConfig; |
NSHConfigurationEntry remoteConfig; |
NSHConfigurationEntry tcpv4Config; |
// Set up the basic structures. |
// TCP/IP v4 |
memset(&tcpv4, 0, sizeof(tcpv4)); |
tcpv4.fTCPv4.fProtocol = kOTCfgTypeTCPv4; |
PLstrcpy(tcpv4.fTCPv4.fConfigName, userVisibleName); |
// tcpv4.fTCPv4.fPortRef handled below |
tcpv4.fTCPv4.fConfigMethod = kOTCfgManualConfig; |
tcpv4.fTCPv4.fIPAddress = 0; |
tcpv4.fTCPv4.fSubnetMask = 0; |
tcpv4.fTCPv4.fRouterList = NewHandle(0); |
assert(tcpv4.fTCPv4.fRouterList != NULL); |
tcpv4.fTCPv4.fDNSServerList = NewHandle(0); |
assert(tcpv4.fTCPv4.fDNSServerList != NULL); |
tcpv4.fTCPv4.fLocalDomain[0] = 0; |
tcpv4.fTCPv4.fAdminDomain[0] = 0; |
tcpv4.fTCPv4.fAppleTalkZone[0] = 0; |
tcpv4.fTCPv4.fFraming = 0; |
tcpv4.fTCPv4.fUnloadAttr = kOTCfgTCPActiveLoadedOnDemand; |
tcpv4.fTCPv4.fBelowIP = NULL; |
// Remote Access |
memset(&remote, 0, sizeof(remote)); |
remote.fRemote.fProtocol = kOTCfgTypeRemote; |
PLstrcpy(remote.fRemote.fConfigName, userVisibleName); |
remote.fRemote.fGuestLogin = (username[0] == 0); |
remote.fRemote.fPasswordValid = true; |
PLstrcpy(remote.fRemote.fUserName, username); |
PLstrcpy(remote.fRemote.fPassword, password); |
PLstrcpy(remote.fRemote.fPhoneNumber, number); |
remote.fRemote.fRedialMode = kOTCfgRemoteRedialNone; |
remote.fRemote.fRedialTimes = 0; |
remote.fRemote.fRedialDelay = 0; |
remote.fRemote.fAlternatePhoneNumber[0] = 0; |
remote.fRemote.fVerboseLogging = true; |
remote.fRemote.fFlashIconWhileConnected = true; |
remote.fRemote.fPromptToRemainConnected = false; |
remote.fRemote.fPromptInterval = 15; |
remote.fRemote.fDisconnectIfIdle = true; |
remote.fRemote.fDisconnectInterval = 10 * 60 * 1000; |
remote.fRemote.fLaunchStatusApp = false; |
remote.fRemote.fSerialProtocol = kOTCfgRemoteProtocolPPP; |
remote.fRemote.fPPPConnectAutomatically = true; |
remote.fRemote.fPPPAllowModemCompression = true; |
remote.fRemote.fPPPAllowTCPIPHeaderCompression = true; |
if (useTerminal) { |
remote.fRemote.fPPPConnectMode = kOTCfgRemotePPPConnectScriptTerminalWindow; |
} else { |
remote.fRemote.fPPPConnectMode = kOTCfgRemotePPPConnectScriptNone; |
} |
remote.fRemote.fPPPConnectScriptName[0] = 0; |
remote.fRemote.fPPPConnectScript = NewHandle(0); |
assert(remote.fRemote.fPPPConnectScript != NULL); |
// Modem |
memset(&modem, 0, sizeof(modem)); |
modem.fModem.fProtocol = kOTCfgTypeModem; |
PLstrcpy(modem.fModem.fConfigName, userVisibleName); |
modem.fModem.fPortRef = portRef; |
// modem.fModem.fModemScript handled below |
modem.fModem.fDialToneMode = kOTCfgModemDialToneNormal; |
modem.fModem.fSpeakerOn = true; |
modem.fModem.fPulseDial = false; |
// Set up the bits that might fail with an error. |
err = GetCCLFSSpec(chosenCCL, &modem.fModem.fModemScript); |
if (err == noErr) { |
OTPortRecord pppPort; |
if ( OTFindPort(&pppPort, "IPCP") ) { |
tcpv4.fTCPv4.fPortRef = pppPort.fRef; |
} else { |
err = kENXIOErr; |
} |
} |
// Create/overwrite each configuration. |
if (err == noErr) { |
err = SetupNetworkConfig(&modem, &modemConfig); |
} |
if (err == noErr) { |
err = SetupNetworkConfig(&remote, &remoteConfig); |
} |
if (err == noErr) { |
err = SetupNetworkConfig(&tcpv4, &tcpv4Config); |
} |
// Make each configuration active. We really should make all |
// of these changes as part of a single atomic transaction so |
// that, if one fails, they all fail. Right now it's possible |
// to commit the Modem changes, fail while committing the |
// Remote Access changes, and then never even try to commit |
// the TCP/IP changes, thus leaving the system in an inconsistent |
// state. Network Setup has the ability to do this, but it's |
// not exported via my Network Setup helpers library abstraction |
// (notably I didn't make the same mistake for MoreSCF). Right |
// now I don't think it's worth my while redoing Network Setup |
// helpers, so I'm just going to apply the ostrich algorithm |
// (put my head in the sand and hope it doesn't happen). |
if (err == noErr) { |
err = NSHSelectConfiguration(&modemConfig); |
} |
if (err == noErr) { |
err = NSHSelectConfiguration(&remoteConfig); |
} |
if (err == noErr) { |
err = NSHSelectConfiguration(&tcpv4Config); |
} |
return err; |
} |
extern pascal OSStatus QISAMakeNetworkConfig(CFMutableDictionaryRef configDict) |
// See comment in "QISAPlatform.h". |
// This routine simply unpacks all of the parameters from configDict |
// and then calls MakeNetworkConfig to do the real work. |
{ |
OSStatus err; |
CFStringRef usernameCF; |
CFStringRef passwordCF; |
CFStringRef numberCF; |
CFBooleanRef useTerminalCF; |
CFStringRef userVisibleNameCF; |
CFStringRef chosenCCLCF; |
CFDictionaryRef chosenPortCF; |
CFNumberRef portRefCF; |
Str255 username; |
Str255 password; |
Str255 number; |
Boolean useTerminal; |
Str255 userVisibleName; |
Str255 chosenCCL; |
OTPortRef portRef; |
assert(configDict != NULL); |
// Extract parameters from configDict. |
// Note that kQISAKeyTemporary is never set on current builds. |
if ( CFDictionaryContainsKey(configDict, kQISAKeyTemporary) ) { |
usernameCF = CFDictionaryGetValue(configDict, kQISAKeySetupUsername); |
passwordCF = CFDictionaryGetValue(configDict, kQISAKeySetupPassword); |
numberCF = CFDictionaryGetValue(configDict, kQISAKeySetupNumber); |
useTerminalCF = CFDictionaryGetValue(configDict, kQISAKeySetupUseTerminal); |
} else { |
usernameCF = CFDictionaryGetValue(configDict, kQISAKeyUsername); |
passwordCF = CFDictionaryGetValue(configDict, kQISAKeyPassword); |
numberCF = CFDictionaryGetValue(configDict, kQISAKeyNumber); |
useTerminalCF = CFDictionaryGetValue(configDict, kQISAKeyUseTerminal); |
} |
userVisibleNameCF = CFDictionaryGetValue(configDict, kQISAKeyUserVisibleName); |
chosenCCLCF = CFDictionaryGetValue(configDict, kQISAKeyChosenCCL); |
chosenPortCF = CFDictionaryGetValue(configDict, kQISAKeyChosenPort); |
// Check the parameters. |
err = noErr; |
if ( usernameCF == NULL || CFGetTypeID(usernameCF) != CFStringGetTypeID() ) { |
err = paramErr; |
} |
if ( passwordCF == NULL || CFGetTypeID(passwordCF) != CFStringGetTypeID() ) { |
err = paramErr; |
} |
if ( numberCF == NULL || CFGetTypeID(numberCF) != CFStringGetTypeID() ) { |
err = paramErr; |
} |
if ( useTerminalCF == NULL || CFGetTypeID(useTerminalCF) != CFBooleanGetTypeID() ) { |
err = paramErr; |
} |
if ( userVisibleNameCF == NULL || CFGetTypeID(userVisibleNameCF) != CFStringGetTypeID() ) { |
err = paramErr; |
} |
if ( chosenCCLCF == NULL || CFGetTypeID(chosenCCLCF) != CFStringGetTypeID() ) { |
err = paramErr; |
} |
if ( chosenPortCF == NULL || CFGetTypeID(chosenPortCF) != CFDictionaryGetTypeID() ) { |
err = paramErr; |
} else { |
portRefCF = CFDictionaryGetValue(chosenPortCF, kMyPropOTPortRef); |
if ( portRefCF == NULL || CFGetTypeID(portRefCF) != CFNumberGetTypeID() ) { |
err = paramErr; |
} |
} |
// Convert parameters to their non-CF equivalents. |
if (err == noErr) { |
err = CFQErrorBoolean( CFStringGetPascalString(usernameCF, username, sizeof(username), CFStringGetSystemEncoding()) ); |
} |
if (err == noErr) { |
err = CFQErrorBoolean( CFStringGetPascalString(passwordCF, password, sizeof(password), CFStringGetSystemEncoding()) ); |
} |
if (err == noErr) { |
err = CFQErrorBoolean( CFStringGetPascalString(numberCF, number, sizeof(number), CFStringGetSystemEncoding()) ); |
} |
if (err == noErr) { |
useTerminal = CFBooleanGetValue(useTerminalCF); |
} |
if (err == noErr) { |
err = CFQErrorBoolean( CFStringGetPascalString(userVisibleNameCF, userVisibleName, sizeof(userVisibleName), CFStringGetSystemEncoding()) ); |
} |
if (err == noErr) { |
err = CFQErrorBoolean( CFStringGetPascalString(chosenCCLCF, chosenCCL, sizeof(chosenCCL), CFStringGetSystemEncoding()) ); |
} |
if (err == noErr) { |
err = CFQErrorBoolean(CFNumberGetValue(portRefCF, kCFNumberSInt32Type, &portRef)); |
} |
// Call a function to do the real work. |
if (err == noErr) { |
err = MakeNetworkConfig(userVisibleName, portRef, chosenCCL, username, password, number, useTerminal); |
} |
return err; |
} |
extern pascal OSStatus QISAPlatformInit(CFBundleRef platformBundle) |
// See comment in "QISAPlatform.h". |
{ |
OSStatus err; |
CFStringRef defaultCCL; |
assert(platformBundle != NULL); |
gPlatformBundle = platformBundle; |
(void) CFRetain(gPlatformBundle); |
// Override the default CCL choice in MoreSCFCCLScanner. |
defaultCCL = CFBundleCopyLocalizedString(gPlatformBundle, CFSTR("DefaultCCL"), NULL, NULL); |
assert(defaultCCL != NULL); |
MoreSCSetDefaultCCL(defaultCCL); |
CFQRelease(defaultCCL); |
err = noErr; |
return err; |
} |
Copyright © 2003 Apple Computer, Inc. All Rights Reserved. Terms of Use | Privacy Policy | Updated: 2003-05-15