MIB-Libraries/MoreSCF/ReadMeAboutMoreSCF.html

<HTML>
<HEAD>
   <TITLE>Read Me About MoreSCF</TITLE>
</HEAD>
<BODY BGCOLOR="#FFFFFF">
<H1>Read Me About MoreSCF</H1>
 
<P>1.0b4</P>
 
<P>Mac OS X 10.1 introduced a new API, the System Configuration
framework (SCF), that allows you to programmatically configure
network settings. SCF provides a nice, abstract, extensible API for
manipulating persistent preferences, however it is not a high-level
API. Doing common operations, like creating a new set (known as a
"location" in the user interface), requires you to combine a number
of diverse APIs from I/O Kit, System Configuration, and Core
Foundation.</P>
 
<P>MoreSCF is an attempt to make this easier. It is modeled after the
MoreNetworkSetup sample code for traditional Mac OS. It provides a
library of code to do all of the common things that the user might do
in the Network preferences panel. For example, you can create a new
location, duplicate a location, active and inactivate services (known
as "ports" in the user interface), and so on. MoreSCF also provides
high-level APIs to do common operations, such as creating a new set
that contains a single PPP dialup service.</P>
 
<P>System Configuration framework was introduced in Mac OS X 10.1.
MoreSCF requires that system or later.</P>
 
<H2>Packing List</H2>
 
<P>The sample contains the following items:</P>
 
<UL>
   <LI>Read Me.txt -- A document that redirects you to this
   document.</LI>
   
   <LI>MoreSCF -- A folder containing MoreSCF and various support
   files.
 
            <UL>
      <LI>ReadMeAboutMoreSCF.html -- This document.</LI>
      
      <LI>MoreSCFHelpers.h -- Interface to the following.</LI>
      
      <LI>MoreSCFHelpers.c -- A high-level module that provides
      commonly used System Configuration framework functions, such as
      creating a new set that contains a single PPP dialup
      service.</LI>
      
      <LI>MoreSCF.h -- Interface to the following.</LI>
      
      <LI>MoreSCF.c -- A mid-level module layered on top of the
      SCPreferences component of System Configuration framework. This
      module recasts the SCPreferences API in terms that you would
      recognize from looking at the Network preferences panel.</LI>
      
      <LI>MoreSCFDigest.h -- Interface to the following.</LI>
      
      <LI>MoreSCFDigest.c -- Code to create SCPreferences entities
      from simple C structures.</LI>
      
      <LI>MoreSCFPortScanner.h -- Interface to the following.</LI>
      
      <LI>MoreSCFPortScanner.c -- Code to scan the I/O Registry for
      network-capable ports.</LI>
      
      <LI>MoreSCFCCLScanner.h -- Interface to the following.</LI>
      
      <LI>MoreSCFCCLScanner.c -- Code to scan the system for modem
      scripts (CCLs).</LI>
      
      <LI>MoreSCFTest -- A program that both tests MoreSCF and gives
      an example of its use.</LI>
   </UL>
            <LI>MoreCFQ -- MoreIsBetter Core Foundation utilities.</LI>
            <LI>MoreSetup.h -- The standard MoreIsBetter include file.</LI>
</UL>
 
<H2>Using the Sample</H2>
 
<P>The sample includes a compiled version of the
<CODE>MoreSCFTest-Debug</CODE> command line tool. This tool modifies
the SCF preferences, which means you must run it as root. To do this,
launch Terminal, change to the MoreSCFTest directory, and run
<CODE>MoreSCFTest-Debug</CODE> using the <CODE>sudo</CODE> command.
The following is an example of doing this.</P>
 
<PRE>&#91;localhost:~&#93; quinn% <B>cd /Volumes/Tweedlebug/DTS\ \
Work/MIBWork/MoreIsBetter/MIB-Libraries/MoreSCF/MoreSCFTest/
</B>&#91;localhost:MIB-Libraries/MoreSCF/MoreSCFTest&#93; quinn% <B>sudo MoreSCFTest-Debug -lq
</B>Password: <B>enter your password here
</B>MoreSCFTest-Debug
Running all tests
 
LeakTest(TestPortScanner)
MoreSCFPortScanner.c: You should install a port name callback.
LeakTest(TestCopySetsDict)
LeakTest(TestSetEnumerationAndSwitch)
LeakTest(TestDuplicateAndDeleteSet)
LeakTest(TestRenameSet)
LeakTest(TestServiceEnumerate)
LeakTest(TestDuplicateAndDeleteService)
LeakTest(TestRenameService)
LeakTest(TestEnumerateEntities)
LeakTest(TestCreateSet)
LeakTest(TestISP)
LeakTest(TestAppleTalk)
&#91;localhost:MIB-Libraries/MoreSCF/MoreSCFTest&#93; quinn% </PRE>
 
<P>The tool takes quite some time to run (up to a few minutes on my ancient test machine). As long as it runs to completion it should leave your network preferences how it found them. However, if you stop it halfway through you may need to manually restore your preferences.</P>
 
<P>Two of the tests requires that you have a location called &quot;DefaultLocationForMoreSCFTest&quot;. You should create this location using the Network panel of System Preferences. Just create the location and leave its settings unmodified. The test uses this location to verify that a new set created by MoreSCF exactly matches a default set created by the control panel.</P>
 
<CENTER><TABLE BORDER=0 CELLPADDING=3 WIDTH=500>
   <TR>
      <TD BGCOLOR="#EEEEE0">
         <P><B>Note:</B><BR>
         Under some circumstances the TestCreateSet test will fail
         because the newly created set doesn't exactly match the
         contents of "DefaultLocationForMoreSCFTest". There are a few
         common reasons for this.</P>
         
         <UL>
            <LI>Your "DefaultLocationForMoreSCFTest" set might be is
            out of date; to rectify this simply open the control
            panel, deleting the existing
            "DefaultLocationForMoreSCFTest" location and create a new
            one.</LI>
            
            <LI>You might have NetInfo enabled; to rectify this, turn
            off NetInfo using the "Directory Setup" application, then
            update your "DefaultLocationForMoreSCFTest" set as
            described previously.</LI>
            
            <LI>The "DefaultLocationForMoreSCFTest" might be set to
            use non-DHCP address acquisition (in the "Configure"
            popup menu). This happens if you create the new set when
            your current set is not using DHCP. In that case the
            Network preferences panel creates a set with the same
            address acquisition mode as your current set. This
            anomalous behavior is not replicated by MoreSCF. To make
            TestCreateSet run without error, open the Network
            preferences panel and modify the services within the
            "DefaultLocationForMoreSCFTest" set to acquire address
            via PPP.</LI>
         </UL>
      </TD>
   </TR>
</TABLE>
</CENTER>
 
<H2>Building the Sample</H2>
 
<P>The sample was built using CodeWarrior Pro 8.3 on Mac OS X 10.2.x. It also builds with Project Builder 2.1 (from the Mac OS X December 2002 developer tools). Your mileage may vary with other environments.</P>
 
<P>The project is built as a Mach-O binary. It is not possible to
call SCF directly from a CFM binary. If you need to do this you
should either factor your SCF code into a separate Mach-O bundle or
use one of the techniques illustrated in the <A HREF="http://developer.apple.com/samplecode/Sample_Code/Runtime_Architecture/CallMachOFramework.htm">CallMachOFramework</A>
sample code.</P>
 
<P>The CodeWarrior project contains two targets. You should build the &quot;Mach-O&quot; target. I use the &quot;Mach-O, C++&quot; to test C++ compatibility. You typically wouldn't use this target.</P>
 
<H2>SCF Hints and Tips</H2>
 
<P>This section describes a number of things to keep in mind while
working with SCF, or indeed MoreSCF.</P>
 
<UL>
   <LI>Documentation -- At the time this sample was written Apple
   still hasn't published full documentation for SCF. However, the
   framework is partially documented by comments in its headers.
   There is also a <A HREF="http://developer.apple.com/techpubs/macosx/Networking/SysConfigOverview926/index.html">brief
   overview of SCF</A> available on the developer web site. You
   should read this before doing any serious work with MoreSCF.</LI>
   
   <LI>Running with Privileges -- Code that modifies the System
   Configuration framework preferences must run as root (with
   effective user ID of 0). There are simple ways to work around this
   during development (<A HREF="#EnablingRoot">described below</A>),
   however, your final product will need to be smarter about this,
   possibly including a "set user ID" binary that does your actual
   SCF work. The DTS sample code <A HREF="http://developer.apple.com/samplecode/Sample_Code/Security/MoreAuthSample.htm">MoreAuthSample</A>
   shows the recommended technique for doing this.</LI>
   
   <LI>SCF Preferences -- In current versions of Mac OS X SCF stores
   its preferences in "/var/db/SystemConfiguration/preferences.xml".
   You should never code this full path into your application, but
   this knowledge can be helpful when debugging. For example,
 
            <UL>
      <LI>You can launch PropertyListEditor (in
      "/Developer/Applications") and open this file for a structured
      view of the current preferences.</LI>
      
      <LI>You can back up and restore your preferences using the
      following Terminal commands. This is especially useful when
      debugging SCF code that has gone bad.</LI>
   </UL>
        </UL>
 
<PRE>&#91;localhost:~&#93; quinn% <B>cp /var/db/SystemConfiguration/preferences.xml \
/var/db/SystemConfiguration/preferencesBU.xml
</B>&#91;localhost:~&#93; quinn% <B>cp /var/db/SystemConfiguration/preferencesBU.xml \
/var/db/SystemConfiguration/preferences.xml</B></PRE>
 
<UL>
   <LI>SCUtil -- Apple provides a command line utility,
   <CODE>scutil</CODE>, that lets you look at the current state of
   the SCF dynamic store. You can use this utility to see how your
   SCF code affects the actual network configuration. The following
   is a simple example of how to use <CODE>scutil</CODE>.</LI>
</UL>
 
<PRE>&#91;localhost:~&#93; quinn% <B>scutil
</B>&gt; <B>open
</B>&gt; <B>list
</B>  subKey &#91;0&#93; = File:/var/run/lookupd.pid
  subKey &#91;1&#93; = File:/var/run/nibindd.pid
  subKey &#91;2&#93; = Plugin:IPConfiguration
  subKey &#91;3&#93; = Setup:
  subKey &#91;4&#93; = Setup:/
  subKey &#91;5&#93; = Setup:/Network/Global/IPv4
  subKey &#91;6&#93; = Setup:/Network/Service/26
  subKey &#91;7&#93; = Setup:/Network/Service/26/AirPort
  subKey &#91;8&#93; = Setup:/Network/Service/26/DNS
  subKey &#91;9&#93; = Setup:/Network/Service/26/IPv4
  subKey &#91;10&#93; = Setup:/Network/Service/26/Interface
  subKey &#91;11&#93; = Setup:/Network/Service/26/Proxies
  subKey &#91;12&#93; = Setup:/System
  subKey &#91;13&#93; = State:/Network/Global/DNS
  subKey &#91;14&#93; = State:/Network/Global/IPv4
  subKey &#91;15&#93; = State:/Network/Global/Proxies
  subKey &#91;16&#93; = State:/Network/Interface
  subKey &#91;17&#93; = State:/Network/Interface/en0/Link
  subKey &#91;18&#93; = State:/Network/Interface/en1/IPv4
  subKey &#91;19&#93; = State:/Network/Interface/en1/Link
  subKey &#91;20&#93; = State:/Network/Interface/lo0/IPv4
  subKey &#91;21&#93; = State:/Network/Service/26/IPv4
  subKey &#91;22&#93; = State:/Users/ConsoleUser
  subKey &#91;23&#93; = daemon:AppleFileServer
&gt; <B>get Setup:/Network/Service/26/AirPort
</B>&gt; <B>d.show
</B>&lt;dictionary&gt; {
  MACAddress : 00:30:65:14:1e:1e
  PreferredNetwork : QuinnNet
}
&gt; <B>help
 
</B>Available commands:
 
 help                          : list available commands
 f.read file                   : process commands from file
 
 d.init                        : initialize (empty) dictionary
 d.show                        : show dictionary contents
 d.add key &#91;*#?&#93; val &#91;v2 ...&#93;  : add information to dictionary
       (*=array, #=number, ?=boolean)
 d.remove key                  : remove key from dictionary
 
 open                          : open a session with "configd"
 close                         : close current "configd" session
 
 list &#91;pattern&#93;                : list keys in data store
 add key &#91;"temporary"&#93;         : add key in data store w/current dict
 get key                       : get dict from data store w/key
 set key                       : set key in data store w/current dict
 remove key                    : remove key from data store
 notify key                    : notify key in data store
 
 n.list &#91;"pattern"&#93;            : list notification keys
 n.add key &#91;"pattern"&#93;         : add notification key
 n.remove key &#91;"pattern"&#93;      : remove notification key
 n.changes                     : list changed keys
 n.watch &#91;verbose&#93;             : watch for changes
 n.cancel                      : cancel notification requests
 
&gt; <B>quit
</B>&#91;localhost:~&#93; quinn% </PRE>
 
<H3><A NAME=EnablingRoot></A>Debugging Root Binaries</H3>
 
<P>If you are using SCF to modify system preferences, you'll quickly
discover that your program needs to run as root (with an effective
user ID of 0) to avoid the dreaded error 1003
(<CODE>kSCStatusAccessError</CODE>). There are two simple ways to get
around this during debugging.</P>
 
<UL>
   <LI>You can <A HREF="http://developer.apple.com/carbon/tipsandtricks.html#EnableRoot">enable
   the root account</A>, log out, and then log back in as root. At
   that point all of the programs you run will run as root. This
   approach has the advantage that it's very simple. However, it's
   not particularly secure; I recommend you avoid this approach if
   your Mac OS X machine lives outside of a firewall.</LI>
   
   <LI>If you have administrative privileges, you can launch
   CodeWarrior or Project Builder from within a root Terminal window.
   The following listing shows the general procedure. The first
   command, <CODE>sudo -s</CODE>, turns your normal Terminal window
   into a root window. The second command launches CodeWarrior as
   root. Note that the command you actually execute is
   <CODE>LaunchCFMApp</CODE>, passing it as a parameter the full path
   to your CodeWarrior executable; you'll have to customize this path
   depending on where you installed CodeWarrior. Also note the
   '&amp;' at the end of the command line, which requests the shell
   not to wait for CodeWarrior to quit before accepting a new
   command. The third command launches Project Builder as root.</LI>
</UL>
 
<PRE>&#91;localhost:~&#93; quinn% <B>sudo -s</B> 
Password:<B>********</B> 
&#91;localhost:~&#93; root# <B>/System/Library/Frameworks/Carbon.framework/\</B> 
<B>Versions/A/Support/LaunchCFMApp /Volumes/Tweedlebug/Languages/CWPro7MIB/\</B> 
<B>CodeWarrior\ IDE\ 4.2.5\ \* &amp;</B> 
&#91;1&#93; 2030
&#91;localhost:~&#93; root# <B>/Developer/Applications/Project\ Builder.app/\</B> 
<B>Contents/MacOS/Project\ Builder &amp;</B> 
&#91;2&#93; 2031
&#91;localhost:~&#93; root# </PRE>
 
<CENTER id=p1><TABLE BORDER=0 CELLPADDING=3 WIDTH=500>
   <TR>
      <TD BGCOLOR="#EEEEE0">
         <P><B>IMPORTANT:</B><BR>
                            This approach, while fine for debugging, is not appropriate for your final product. Ultimately you will need a better solution, possibly including a &quot;set user ID&quot; binary that does your actual SCF work. The DTS sample code <A HREF="http://developer.apple.com/samplecode/Sample_Code/Security/MoreAuthSample.htm">MoreAuthSample</A> shows the recommended technique for doing this.</P>
      </TD>
   </TR>
</TABLE>
</CENTER>
 
<H2>Using MoreSCF In Your Code</H2>
 
<P>The correct way to use MoreSCF depends on the exact needs of your
program. The following sections explore this issue in detail.</P>
 
<H3>Coding Conventions</H3>
 
<P>MoreSCF is built as part of the DTS sample code library MoreIsBetter. It only uses the CoreServices framework, which means you should be able to use it in non-Carbon programs. For example, Cocoa application developers can use MoreSCF very easily. Making MoreSCF independent of CoreServices would be tricky because MoreSCF needs to be able to locate the Modem Scripts folder which can only be done with CoreServices APIs.</P>
 
<P>MoreSCF makes extensive use of asserts. When you integrate MoreSCF
into your build system you should ensure that
<CODE>assert</CODE> maps to whatever assert mechanism you are
using in your project.</P>
 
<P>MoreSCF's asserts act like comments for the exact function
semantics. Specifically, if you want to know whether NULL is legal
for a particular parameter, look at the asserts at the top of the
routine.</P>
 
<P>MoreSCF follows the Core Foundation (CF) coding convention in that
routines with "Create" or "Copy" in the name return a reference which
you must release, whereas other routines (most commonly with "Get" in
the name) return a reference that you don't need to release. However,
unlike CF, MoreSCF returns <CODE>OSStatus</CODE> error codes from
virtually all functions. When you call a MoreSCF routine that
allocates an object, you get the result by passing the address of a
variable as a parameter to the routine. You must initialize this
variable to NULL before calling the routine. The value of the
variable will be NULL if the routine returns an error.</P>
 
<H3>Big Picture</H3>
 
<P>MoreSCF consists of a number of related modules. As a rule I
recommend that you use the highest level routines that will get the
job done. This section describes each of the MoreSCF modules, how
they relate, and what you can do with them.</P>
 
<H4>MoreSCFCCLScanner</H4>
 
<P>This module contains a routine that a creates a list of CCLs
(modem scripts) installed in the system and returns that list along
with an indication of which CCL should be the default. An Internet
setup assistant would use this routine to present the user with a
list of CCLs to choose from if they are connecting via a modem.</P>
 
<P>It is unlikely that you would need to customize the routines in
this module.</P>
 
<H4>MoreSCFPortScanner</H4>
 
<P>This module contains code that searches the I/O Registry for all
possible network ports. For each port it returns the information
necessary to create an SCF service that uses the port. This facility
is crucial when you create a new set using SCF.</P>
 
<P>This is not as easy as it sounds. The code is derived from code
originally written by the engineer who wrote the Network preferences
panel. It contains many interesting heuristics to decide whether a
port is suitable for networking and to determine its user visible
name.</P>
 
<P>If you link this module into a GUI-based application you should
install a port name callback (using
<CODE>MoreSCFSetPortNameCallback</CODE>) so that you can localize the
user visible names of the ports.</P>
 
<P>You should probably use the routines in this module unmodified unless you experience compatibility problems.</P>
 
<H4>MoreSCFDigest</H4>
 
<P>This module contains code that allows you to easily create a SCF
entity from a C structure. It takes care of many of the fiddly
details of this process, such as converting IP addresses to strings,
encoding PPP passwords, and so on.</P>
 
<P>In most cases you would use the routines from this module
unmodified, although sometimes the routines provide a simplified view
of certain preferences and you might want to override some of their
default decisions.</P>
 
<H4>MoreSCF</H4>
 
<P>This module is layered on top of the previous two modules. It provides a mid-level API for manipulating SCF preferences. The module exports four categories of routines:</P>
 
<UL>
   <LI>trivial utilities, primarily to map SCF's error strategy into a CoreServices-based environment</LI>
   
   <LI>open/close routines, which provide a reference counted
   facility for opening and closing the SCF preferences; this is
   convenient because it ensures that changes are committed only at
   the end of a transaction</LI>
   
   <LI>dictionary-based routines, which provide basic access to the
   most important SCF preferences</LI>
   
   <LI>mid-level routines, for manipulating the SCF preferences in
   terms of common user operations (for example, creating a set,
   deactivating a service, modifying an entity)</LI>
</UL>
 
<P>I expect that you would use the routines from this module
unmodified. If you need to do complex SCF operations you'll probably
find that either a) an appropriate routine is already provided in
MoreSCFHelpers, or b) you can achieve the results you want by calling
various routines exported by this module.</P>
 
<H4>MoreSCFHelpers</H4>
 
<P>This module is layered on top of MoreSCF and exports routines for
doing very high-level operations using SCF, such as</P>
 
<UL>
   <LI>turning AppleTalk on and off
   (<CODE>MoreSCSetAppleTalkActive</CODE>),</LI>
   
   <LI>forcing a DHCP release (<CODE>MoreSCDHCPRelease</CODE>),
   and</LI>
   
   <LI>creating a new dialup set (or PPPoE) from preferences provided via a number of parameter blocks (<CODE>MoreSCMakeNewDialupSet</CODE> and <code>MoreSCMakeNewPPPoESet</code>).</LI>
</UL>
 
<P>You should treat these routines as sample code; if they don't meet your exact needs you should modify them appropriately. For example, <code>MoreSCMakeNewPPPoESet</code> provides no way to create a PPPoE location for an AirPort interface, but it is simple to modify it to do so.</P>
 
<H3>Getting Started</H3>
 
<P>This section describes the MoreSCF routines needed to do the most
common high-level operations.</P>
 
<H4>Opening, Closing, Locking</H4>
 
<P>MoreSCF uses a single connection to SCF preferences for all of its
work. To support a flexible API MoreSCF references counts that
reference. The first time you call <CODE>MoreSCOpen</CODE>, MoreSCF
creates a <CODE>SCPreferencesRef</CODE> and stores it in a global
variable. Every subsequent time you call the <CODE>MoreSCOpen</CODE>,
it simply increments the reference count. Every time you call
<CODE>MoreSCClose</CODE>, it decrements the reference count. When the
reference count drops to zero, MoreSCF commits any changes you might
have made, unlocks the preferences if you have locked them, and then
closes the <CODE>SCPreferencesRef</CODE>.</P>
 
<P>The primary rationale for this approach is that I did not want clients of MoreSCF to be forced to call <CODE>MoreSCOpen</CODE>. Thus, each
exported MoreSCF routine calls <CODE>MoreSCOpen</CODE> when it starts
and <CODE>MoreSCClose</CODE> when it finishes. This presented an
interesting problem when MoreSCF routines called other MoreSCF
routines. I wanted all of the MoreSCF routines to share the same
<CODE>SCPreferencesRef</CODE> (otherwise they wouldn't see each
others changes until they committed them), however I didn't want to
cache the <CODE>SCPreferencesRef</CODE> forever because that caused
other problems with preference coherency. My ultimate solution was to
simply reference count the <CODE>SCPreferencesRef</CODE>.</P>
 
<P>Given the above there are some cases when you don't need to call
<CODE>MoreSCOpen</CODE> at all. Each MoreSCF API routine will call
<CODE>MoreSCOpen</CODE> for you. However, in most circumstances you
should call <CODE>MoreSCOpen</CODE> and <CODE>MoreSCClose</CODE>.
This has a number of advantages.</P>
 
<UL>
   <LI>When you call <CODE>MoreSCOpen</CODE>, MoreSCF creates an
   <CODE>SCPreferencesRef</CODE>. This in turn holds a snapshot of
   the current preferences. You can then make subsequent MoreSCF
   calls and be assured that you're seeing a coherent copy of the
   preferences.</LI>
   
   <LI>Calls to MoreSCF routines within a
   <CODE>MoreSCOpen</CODE>/<CODE>MoreSCClose</CODE> pair will be
   faster because they won't be continually creating and disposing of
   their connection to SCF preferences.</LI>
   
   <LI>If you're making changes to the preferences you generally need
   to call <CODE>MoreSCOpen</CODE> so that you can lock the
   preferences and ensure that your changes are coherent.</LI>
</UL>
 
<P>The standard calling sequence, used for the first two cases above,
is shown below.</P>
 
<PRE>(void) MoreSCSetClient(CFSTR("MyClientName")); // optional
 
err = MoreSCOpen(false, false);                // no locking
if (err == noErr) {
    // use various MoreSCF routines in here
}
MoreSCClose(&amp;err, false);                      // no changes</PRE>
 
<P>If you are making changes you would probably use the next
sequence.</P>
 
<PRE>err = MoreSCOpen(true, true);                  // lock prefs
if (err == noErr) {
    // read preferences using MoreSCF routines
    // make decisions based on what you read
    // write preferences using MoreSCF routines
}
MoreSCClose(&amp;err, true);                       // force commit</PRE>
 
<P>MoreSCF also provides a routine
(<CODE>MoreSCGetSCPreferencesRef</CODE>) that allows you to access
the underlying <CODE>SCPreferencesRef</CODE>. This is useful in cases
where you need to call SCF preferences routines that do things
outside of the realm of MoreSCF (for example, calling
<CODE>SCPreferencesGetSignature</CODE>).</P>
 
<H4>Creating a New Dialup Set</H4>
 
<P>Most people look at MoreSCF because they're writing an Internet
setup assistant (ISA). MoreSCF contains routines that specifically
help you to do this. However, before I discuss these routines I
should stress one key point.</P>
 
<P>Apple strongly recommends that ISA developers create a new set
(known as a "location" in the user interface) for their specific
service. This prevents your settings from overwriting the user's
prized network setup and allows the user a quick escape (switching
back to their previous location) if your setup assistant doesn't work
properly.</P>
 
<P>If you're writing an ISA, the three keys routines are <CODE>MoreSCFindSetByUserVisibleNameAndCopyID</CODE>, <code>MoreSCMakeNewDialupSet</code> and <code>MoreSCMakeNewPPPoESet</code>. The first routine lets you determine whether your ISA has already been run and created your service's location. The other two let you create a new location with one active dialup or PPPoE service. All of these routines are described in comments in &quot;MoreSCFHelpers.h&quot;. You can also look at the TestISP routine in &quot;MoreSCFTest.c&quot; for a very simple example of their use.</P>
 
<P>The above routines are very easy to use if you want to use the default modem (or Ethernet) port. If you want to provide the user a list of modem ports to choose from, you should call the <CODE>MoreSCCreatePortArray</CODE> routine (declared in
"MoreSCFPortScanner.h") to get the list of network ports and their
associated user-visible names and then supply the BSD name of the
port to <CODE>MoreSCMakeNewDialupSet</CODE> or <code>MoreSCMakeNewPPPoESet</code>. For dialup you should also use <CODE>MoreSCCreateCCLArray</CODE> (from "MoreSCFCCLScanner.h") to
build a list of CCLs (modem scripts) that the user can use for that
modem.</P>
 
<H4>Enumerating and Switching Sets</H4>
 
<P>The routines to enumerate and switch sets are all declared in
"MoreSCF.h". You can use <CODE>MoreSCCopySetIDs</CODE> to get an
array of set IDs, <CODE>MoreSCCopyUserVisibleNameOfSet</CODE> to get
the user-visible name of a set given its set ID, and
<CODE>MoreSCSetCurrentSet</CODE> to make a particular set the active
set.</P>
 
<H4>Manipulating Sets, Services, and Entities</H4>
 
<P>MoreSCF exports routines to</P>
 
<UL>
   <LI>enumerate, create, duplicate, and delete sets</LI>
   
   <LI>get and set properties of sets (the active set, user-visible
   name)</LI>
   
   <LI>enumerate, create, duplicate, and delete services within a
   set</LI>
   
   <LI>get and set properties for services (active, user-visible
   name, BSD name)</LI>
   
   <LI>read, write, and delete entities within a service</LI>
   
   <LI>read, write, and delete global entities within a set</LI>
   
   <LI>get and set properties of an entity (active)</LI>
</UL>
 
<P>These routines are fairly well documented by the comments in the
"MoreSCF.h" header file. Most of the routines are used somewhere
within MoreSCF, which you can look at for an example of their
use.</P>
 
<H2><A NAME=Caveats></A>Caveats</H2>
 
<P>The following is a list of odd things you might encounter while
working with MoreSCF and things I would improve within MoreSCF if I
had the time.</P>
 
<UL>
   <LI>The Network preferences panel in Mac OS X 10.1.x does not
   correctly reflect changes made by other applications using SCF.
   You will not see any MoreSCF changes in the Network panel until
   you quit and relaunch System Preferences. The problem is in the
   UI; the changes do apply to the actual network stack. Apple hopes
   to address this issue in a future release of Mac OS X.</LI>
   
   <LI>Apple currently provides no APIs to determine the list of
   network-capable ports and their user-visible names. We will
   eventually add APIs to do this &#91;2851695, 2851696,
   2851697&#93;, however, until those APIs become available you will
   have to make do with the hardwired code in MoreSCFPortScanner. See
   the comments in "MoreSCFPortScanner.h" for a description of the
   consequences of this.</LI>
            <li><CODE>MoreSCDeleteService</CODE> allows you can delete the
   last service for a hardware port within a set. This is bad because
   the Network preferences panel doesn't let you do this (in the
   Network panel you would inactivate rather than delete that port).
<CODE>MoreSCDeleteService</CODE> should enforce this restriction.
   I know how to code this but it wasn't of sufficiently high
   priority to make this release.
            <LI><CODE>MoreSCCreateAirPortEntity</CODE> isn't flexible enough
   to create all types of AirPort entities. There are a number of
   keys that are described in "SCSchemaDefinitions.h" that can't be
   set by calling <CODE>MoreSCCreateAirPortEntity</CODE>. I need to
   research what these keys do and how best to reflect them in
   <CODE>MoreSCAirPortDigest</CODE> [3138423]. See the comment in    <CODE>MoreSCCreateAirPortEntity</CODE> for a list of the keys in
   question.</LI>
            <LI>I should implement a mutable version of
   <CODE>MoreSCCopyEntities</CODE>
   (<CODE>MoreSCCopyEntitiesMutable</CODE>).</LI>
   
   <LI><CODE>MoreSCCreateCCLArray</CODE> (in &quot;MoreSCFCCLScanner.c&quot;) contains a hardwired name for the &quot;Apple Internal 56K Modem (v.90)&quot; modem script. If this script isn't present it chooses the first script in the first Modem Scripts folder. This is the same behavior as the Network panel of System Preferences. You can (and generally should) override this default when you create a new modem service. You can do this using <code>MoreSCSetDefaultCCL</code>. Ideally Apple should provide an intelligent modem detection library that can query the modem and determine the correct script. As this currently isn't available, MoreSCF provides a routine to return the information necessary to build a modem scripts popup menu so that the user can choose the correct script by hand.</LI>
   
   <LI>Many of the functions tagged with "&#149;more testing needed"
   in the headers have been tested implicitly because other functions
   call them, however I should test them explicitly by adding more
   code to "MoreSCFTest.c".</LI>
   
   <LI>I have gone to great lengths to track down any reference count
   leaks in my use of the SCF preferences database. However, it's
   possible that there are other non-database leaks in MoreSCF,
   particularly in my use of Core Foundation.</LI>
   
   <LI>When you open an <CODE>SCPreferencesRef</CODE>, SCF creates a
   coherent in-memory copy of the preferences database. When you make
   changes to the <CODE>SCPreferencesRef</CODE>, you're actually
   making changes to the memory copy. When you commit those changes,
   SCF writes the database to disk and notifies other users that the
   database has changed. This sequence has important consequences for
   the design of MoreSCF. I used to open one
   <CODE>SCPreferencesRef</CODE> and keep it open for the lifetime of
   the library in memory. However, this architecture meant that, if
   someone else changed the database, clients of MoreSCF would never
   see that change. My new design involves reference counting. When
   the reference count drops to zero, MoreSCF closes its
   <CODE>SCPreferencesRef</CODE>. The next time a client calls
   <CODE>MoreSCOpen</CODE> MoreSCF creates a new copy of the
   <CODE>SCPreferencesRef</CODE> and picks up any changes made by any
   other SCF clients.</LI>
            <LI>Another consequence of the above occurs when you attempt to
   commit your changes and the commit fails. The symptom you will see
   is that <CODE>MoreSCClose</CODE> will return an error. Because we
   only commit when the reference count drops to zero, an error from
   <CODE>MoreSCClose</CODE> indicates that we attempted to commit and
   failed (hence the changes aren't on disk) and we also closed the
   <CODE>SCPreferencesRef</CODE> (hence the changes are no longer in
   memory). When you next call <CODE>MoreSCOpen</CODE> you will get a
   fresh, coherent copy of the preferences from disk, including any
   changes made by other SCF clients. In summary, the outermost
   <CODE>MoreSCClose</CODE> is a commit or rollback operation; if it
   returns <CODE>noErr</CODE>, the commit was successful; if it
   returns an error, the commit failed and we roll you back to the
   last coherent database state (which may not be the state that you
   last saw).</LI>
        </UL>
 
<H2>Credits and Version History</H2>
 
<P>If you find any problems with this sample, mail <a href="mailto:dts@apple.com">DTS</a> and we will try to fix them up.</P>
        <UL>
   <LI>1.0d1 (Nov 2001) was released to a single developer for
   testing.</LI>
   
   <LI>1.0d2 (Dec 2001) was released to small number of developers
   for testing.</LI>
   
   <LI>1.0d3 (Dec 2001) was released to the same small number of
   developers.</LI>
   
   <LI>1.0a1 (Jan 2002) was sent out for Apple internal review.</LI>
   
   <LI>1.0b1 (Feb 2002) is the first widely released version.</LI>
   
   <LI>1.0b2 (Aug 2002) is a fix to ensure compatibility with Mac OS
   X 10.2. The primary change is a workaround for Radar ID 3024328 in
   <CODE>MakeNewSeAndCopyIDAndPath</CODE> in "MoreSCF.c". While I had
   the code open I also fixed some minor stuff, like changing the
   default PPP option values.</LI>
   
   <LI>1.0b3 (Aug 2002) is a minor update to incorporate some engineering feedback about the previous change.</LI>
            <li>1.0b4 (Feb 2003) is a significant update that will only be distributed to a small number of people pending more testing.
            <ul>
                <li>Overall
                <ul>
                    <li>Reworked how the pre-compiled headers and C++ compatibility work.
                    <li>Updated to latest MoreIsBetter coding standards.
                    <li>Updated to the latest MoreCFQ code.
                    <li>Added support for <a href="rdar://problem/3183087">V.92 modem hold</a>.
                    <li>Fixed code that sets the default config method for IPv4 entities.
                    <li>Updated to latest CodeWarrior and Project Builder.
                </ul>
                <li>CCL Scanner
                <ul>
                    <li>Scanner now compiles for traditional Mac OS (needed for another project).
                    <li>A new exported routine, <code>MoreSCSetDefaultCCL</code>.
                    <li>Eliminated dependency on Launch Services. I was only using it to test for file visibility, but using it brings in all of Application Services.
                </ul>
                <li>Port Scanner
                <ul>
                    <li>Corrected a <a href="rdar://problem/3050679">bug</a> where some devices would cause MoreSCF to crash.
                    <li>We now <a href="rdar://problem/3182842">translate slot names</a> into user friendly numbers, just like the Mac OS X 10.2 Network preferences panel.
                    <li>We now <a href="rdar://problem/3182889">handle USB &quot;Product Name&quot;</a> more like the Network preferences panel.
                    <li>Fixed a <a href="rdar://problem/3084354">bug</a> related to the handling of the BSD name.
                </ul>
                <li>Helpers
                <ul>
                    <li>Reworked the code used to implement <code>MoreSCMakeNewDialupSet</code> to support new features (<code>MoreSCMakeNewPPPoESet</code>) and the newly exported routine (<code>MoreSCMakeNewSingleServiceSet</code>).
                </ul>
            </ul>
        </UL>
        <P>Share and Enjoy.</P>
        <P>Worldwide Developer Technical Support<BR>26 Feb 2003</P>
        <P></P>
</BODY>
</HTML>