TweetFollow Us on Twitter

Internet Config
Volume Number:11
Issue Number:4
Column Tag:Internet System Software

Using the Internet Configuration System

Use IC to access common Internet-related user settings.

By Quinn “The Eskimo!”, <internet-config@share.com>

Note: Source code files accompanying article are located on MacTech CD-ROM or source code disks.

How many times have you entered your Email address into different Internet-related applications? What about the file type and creator of your preferred viewer for JPEG files? If you’re a dedicated net.junkie like I am, you’ll find yourself using dozens of Internet-related applications, each with its own set of preferences tucked away in a multitude of obscure dialogs.

This situation gets even worse when you want to change this information. I’m sure you’ve had the pleasure of trying to make sure that your mail and news signatures are always synchronised, but that is easy in comparison to changing your preferred JPEG viewer in Fetch, MacWeb, StuffIt Expander, uuUndo, and so on.

Now multiply this wasted time by the millions of Macintosh users hooked up to the net today, or who will hook up in the next few years. That’s an awful lot of redundant information being rekeyed.

As a programmer, I’m sure you’ll realise that it is not just the users who are wasting time and energy here. While it is relatively easy to save, restore, and provide the user interface to change simple preferences like an Email address, the programming effort required to implement a file-extension-to-type mapping dialog is considerable. Which leads to the ridiculous situation where many small Internet programs do not provide any user interface for this; instead they use a hard-wired table or offer configuration only through ResEdit.

The Internet Configuration System is designed to solve these problems by providing a common database for user settings. Users employ the Internet Config application to set their preferences in this database and you can use a standard Application Programmer Interface (API) to get these preferences for use in your code.

This article describes how to use the Internet Configuration System, or IC for short, to access Internet-related user settings. It starts with a brief history of IC and then jumps straight into code, starting with the simplest possible IC aware application and then moving on to a useful sample program. Next comes a checklist for making your program IC aware and a discussion of some of the gotchas of that process. Then it takes a brief look at IC’s internals and concludes with a glimpse into the future of IC.

A Brief History of Internet Config

The Internet Config project has its roots in March 1994 when a discussion started in the USENET newsgroup comp.sys.mac.comm. The idea was proposed and the general consensus was “Hey, that’s a very good idea, we should do it.” Obviously they had no idea how much work it would be! Peter N Lewis moved the discussion to mail by creating the Internet Config mailing list, and added everyone involved in the discussion to the list without even asking them. Fortunately we didn’t get too many complaints about the unilateral action, despite the fact that some of the US correspondents arrived to work that morning with over 40 IC-related messages!

“Internet Config Mailing List”

The Internet Config mailing list is dedicated to the discussion of the technical details of the Internet Configuration System. You can subscribe to the list by sending mail to
<listserv@list.peter.com.au> with the body of the message containing “subscribe config Your Real Name”.

A fortnight of in-depth discussion followed, culminating in the design and implementation of the first IC API. Later that month we distributed the first implementation of the Internet Config component, the core of which has remained fairly stable since that time.

The project then went into limbo, partly because the movers and shakers all disappeared to WWDC ’94, but mainly because the big job in front of us was writing the Internet Config application, which was mostly user interface code that no one wanted to tackle. We procrastinated for almost six months before eventually resuming the project in September 1994. After burning months of Friday nights on the project (social life, what’s that?), we shipped the first beta of the Internet Config System proper on 30 October 1994. After going through the usual sequence of betas, we shipped Internet Config 1.0 to the world on 4 December 1994.

The Simplest IC Program

It is traditional to implement a “Hello World!” program in whatever new programming language or tool invented. Well maybe Western Australians are more cynical than others but around here the tradition is to have the program say “Hello Cruel World!”. This section shows how to do just that with IC and Think Pascal. In the process it demonstrates the Internet Config user experience.

Before beginning, I should point out that, although the examples here are in Think Pascal, Internet Config can be called from all common Macintosh development environments including: Think Pascal and C; MPW Pascal and C; and Metrowerks Pascal and C for both 68K and PPC.

To start with, run the Internet Config application, which displays the window shown in Figure 1.

Figure 1. The Internet Config application main window

If this is the first time you have run IC, it will ask you if you want to install the Internet Config Extension. You should agree to this even though (due to the magic of IC) the example will still work if you don’t.

Each of the buttons on the main window opens another window displaying a group of preferences. For this exercise, click the Personal button to open the window shown in Figure 2, and then enter “Hello Cruel World!” into the Real Name field.

Figure 2. The Internet Config Personal preferences window

A user would normally go through and set up the rest of their preferences but for now just close this window and save your changes. By default IC stores your preferences in a file called “Internet Preferences” in the Preferences folder.

You are now ready to start coding!

Listing 1: ICHelloCruelWorld.p

ICHelloCruelWorld

program ICHelloCruelWorld;
    (* ICHelloCruelWorld *)
    (* The simplest IC aware program.  It simply outputs *)
    (* Real Name preference, which is assumed to contain *)
    (* the text "Hello Cruel World!" *)

 uses
 ICTypes, ICAPI, ICKeys;  (* standard IC units *)

 var
 instance: ICInstance;
    (* opaque reference to IC session *)
 str: Str255;
    (* buffer to read real name into *)
 str_size: longint;
    (* size of above buffer *)
 junk: ICError;
    (* place to throw away error results *)
 junk_attr: ICAttr;
    (* place to throw away attributes *)
begin
    (* start IC *)
 if ICStart(instance, '????') = noErr then begin
    (* specify a database, in this case the default one *)
 if ICFindConfigFile(instance, 0, nil) = noErr then begin
    (* read the real name preferences *)
 str_size := sizeof(str);
 if ICGetPref(instance, kICRealName, junk_attr,
 @str, str_size) = noErr then begin
 writeln(str);
 end; (* if *)
    (* shut down IC *)
 junk := ICStop(instance);
 end; (* if *)
 end; (* if *)
end. (* ICHelloCruelWorld *)

There are four important lines in this program, each of which corresponds to a critical API call.

1 ICStart

Before using IC, your program must call ICStart, which initialises the system and returns an instance, which is your program’s connection to the system. Your program passes this instance back to all other API calls. The instance is a completely opaque type; all you know about instances is that IC hangs its internal state off them.

The term instance is inherited from IC’s internal design, which uses the Component Manager to implement a simple form of dynamic linking. See the later section, “Under the Bonnet”, for more details.

2 ICStop

Each successful call to ICStart must be balanced with a call to ICStop. IC uses this call to clean up after itself, disposing any memory that it has allocated and so on. ICStop effectively disposes the instance so be careful not to use it afterwards.

3 ICFindConfigFile

This call instructs IC on how to find the appropriate preference information. You can use this call to specify a preference search path but this example uses the default search path and so it gives simple default values for both the parameters.

4 ICGetPref

This call actually reads the preference data into a buffer that you supply. At this stage it is important that you understand something about preferences. Each preference has three conceptually unique parts. The first part is the key. A key is a plain text Str255 that uniquely identifies the preference. The key for the real name preference is “RealName”, although this example uses the constant kICRealName.

The second part of each preference is the value. The value of a preference is an arbitrarily long untyped block of data. The interpretation of this data is up to the application, although most of the existing preferences use common data structures, such as a Pascal string, for preference values.

The third part of each preference is the attributes. Each preference has one long word of attribute bits associated with. These attributes are used to store supplementary information about the preference. It is easy to write your program so that you can completely ignore attributes.

The parameters to the ICGetPref call in Listing 1 should now be obvious. The instance is the connection to IC that is common to all API calls. The kICRealName is a Pascal string that identifies the preference required. The junk_attr is a placeholder for the preference’s attributes which are returned and subsequently ignored. The pointer parameter is the address of the buffer where the preference value should be copied and the str_size parameter is the size of that buffer.

The Internet Config API contains eleven other routines, but all of the important functionality is embodied in the four routines demonstrated here. You can find out more about the API by reading the Internet Config Programming Documentation.

The Internet Configg Programmer’s Kit is included on the disk that accompanies this magazine. The latest version of the kit is kept on the following FTP sites:

ftp://ftp.share.com/internet-configuration/
ftp://redback.cs.uwa.edu.au//Others/Quinn/Config/

A Useful Sample

“Hello Cruel World” programs are, by their very nature, contrived examples. However the program in Listing 1 is actually a good demonstration of the level of technology required to use IC in a Real World™ situation. Accessing simple preferences really is that simple.

A more complicated situation arises when you want to work with the Mappings preference. This preference contains the information required to map file name extensions (such as .jpg) to their file type and creator (such as JPEG/JVWR). The value of this preference is a complicated table of entries, with each entry giving one mapping.

Fortunately, the IC system comes bundled with a library that lets you parse this table easily. The program shown in Listing 2 demonstrates this technique.

Listing 2: SpaceAliens.p

program SpaceAliens;
    (* Space Aliens Ate My Icons *)
    (* A drag and drop utility to fix the type and *)
    (* creator of any dropped on file based on its *)
    (* extension and the database of extension mappings *)
    (* provided by Internet Config. *)

 uses
    (* standard system units needed to do AppleEvents *)
    (* remember that Think Pascal automatically uses *)
    (* most of the base operating system *)
 EPPC, AppleEvents, 

    (* standard IC units *)
 ICTypes, ICAPI, ICKeys, 

    (* bonus IC units, extra libraries shipped as source code *)
 ICMappings, ICSubs;

GotRequireParams

 function GotRequiredParams (theAppleEvent: AppleEvent): OSErr;
    (* standard AppleEvent routine copied out of NIM:IAC *)
 var
 typeCode: DescType;
 actualSize: Size;
 err: OSErr;
 begin
 err := AEGetAttributePtr(theAppleEvent,
 keyMissedKeywordAttr, typeWildCard,
 typeCode, nil, 0, actualSize);
 if err = errAEDescNotFound then begin
 GotRequiredParams := noErr;
 end
 else if err = noErr then begin
 GotRequiredParams := errAEEventNotHandled;
 end
 else begin
 GotRequiredParams := err;
 end; (* if *)
 end; (* GotRequiredParams *)

Global Declarations

 const
 my_creator = 'SA8I';
    (* the application signature *)
 var
 quit_now: boolean;
    (* set to true when you want main loop to quit *)
 instance: ICInstance;
    (* global connection to IC *)
 mappings: Handle;
    (* the mapping preference as returned by IC *)


ProcessDocument

 function ProcessDocument (fss: FSSpec): OSErr;
    (* this is the core of the program *)
    (* the fss parameter is a file whose extension we'll look up in the IC database *)
    (* mappings global variable is already set up to contain that database *)
 var
 err: OSErr;
 count: longint;
    (* total number of entries in database *)
 i: longint;
    (* indexes over the database entries *)
 this: ICMapEntry;
    (* an unpacked element of the *)
    (* mappings database, used while stepping *)
    (* through database *)
 entry: ICMapEntry;
    (* a mappings database element *)
    (* used to record the best match *)
 longest_len: integer;
    (* longest extension we've found so far *)
 posndx: longint;
    (* the index into the mappings database *)
 info: FInfo;
    (* temporary for changing type and creator *)
 begin
    (* count the total number of entries *)
 err := ICMapErr(ICMCountEntries(mappings, count));
 if err <> noErr then begin
 count := 0;
 end; (* if *)
    (* loop through the entries looking for the longest match *)
 longest_len := 0;
 posndx := 0;
 for i := 1 to count do begin
    (* ICMGetEntry gets the entry from mappings *)
    (* that starts at posndx *)
    (* and puts it into the entry record *)
 if ICMGetEntry(mappings, 
 posndx, this) = noErr then begin
    (* increment posndx so that we get the next *)
    (* entry the next time around the loop *)
 posndx := posndx + this.total_length;
    (* the entry matches if *)
    (* not_incoming flag bit is clear *)
    (* it's longer than the previous max *)
    (* it's longer than the file name *)
    (* it matches the last N chars of the filename *)
 if not btst(this.flags, ICmap_not_incoming_bit)
 & (length(this.extension) > longest_len)
 & (length(this.extension) < length(fss.name))
 & (IUEqualString(copy(fss.name,
 length(fss.name)
   - length(this.extension)
   + 1,
 255),
 this.extension) = 0) 
         then begin
    (* record the new longest entry *)
 entry := this;
 longest_len := length(this.extension);
 end; (* if *)
 end; (* if *)
 end; (* for *)

    (* if we found any matches then *)
    (* set the file type and creator appropriately *)
 if longest_len > 0 then begin
 err := HGetFInfo(fss.vRefNum, fss.parID, 
 fss.name, info);
 if err = noErr then begin
 info.fdCreator := entry.file_creator;
 info.fdType := entry.file_type;
 err := HSetFInfo(fss.vRefNum, fss.parID, 
 fss.name, info);
 end; (* if *)
 end
 else begin
 err := noErr;
 end; (* if *)

 quit_now := true;
 ProcessDocument := err;
 end; (* ProcessDocument *)

HandleOpenApplication

 function HandleOpenApplication (theAppleEvent: AppleEvent;
 reply: AppleEvent;
 refcon: longint): OSErr;
    (* the 'oapp' event handler, displays the about box *)
    (* should most probably only do this if we're in *)
    (* the foreground but that's just too complicated *)
    (* for this example *)
 var
 err: OSErr;
 email_address: Str255;
 junk_attr: longint;
 junk: integer;
 junk_icerr: ICError;
 begin
 err := GotRequiredParams(theAppleEvent);
 if err = noErr then begin
 junk_icerr := ICGetPrefStr(instance, kICEmail, 
 junk_attr, email_address);
 ParamText(email_address, '', '', '');
 junk := Alert(128, nil);
 quit_now := true;
 end; (* if *)
 HandleOpenApplication := err;
 end; (* HandleOpenApplication *)

HandleOpenDocuments

 function HandleOpenDocuments (theAppleEvent:AppleEvent;
 reply: AppleEvent;
 refcon: longint): OSErr;
    (* a fairly standard 'odoc' event handler *)
    (* gets the document list, counts the items in it *)
    (* gets the FSSpec for each document and calls *)
    (* ProcessDocument on it *)
 var
 fss: FSSpec;
 doc_list: AEDescList;
 index, item_count: longint;
 junk_size: Size;
 junk_keyword: AEKeyword;
 junk_type: descType;
 err, junk: OSErr;
 begin
 err := AEGetParamDesc(theAppleEvent, keyDirectObject,
 typeAEList, doc_list);
 if err = noErr then begin
 err := GotRequiredParams(theAppleEvent);
 if err = noErr then begin
 err := AECountItems(doc_list, item_count);
 end
 else begin
 item_count := 0;
 end; (* if *)
 for index := 1 to item_count do begin
 if err = noErr then begin
 err := AEGetNthPtr(doc_list, index, typeFSS,
 junk_keyword, junk_type,
 @fss, sizeof(fss), junk_size);
 if err = noErr then begin
 err := ProcessDocument(fss);
 end; (* if *)
 end; (* if *)
 end; (* for *)
 junk := AEDisposeDesc(doc_list);
 end; (* if *)
 HandleOpenDocuments := err;
 end; (* HandleOpenDocuments *)

HandleQuit

 function HandleQuit (theAppleEvent:AppleEvent;
 reply: AppleEvent;
 refcon: longint): OSErr;
    (* a fairly standard 'quit' event handler *)
    (* sets quit_now so that the main event loop quits *)
 var
 err: OSErr;
 begin
 err := GotRequiredParams(theAppleEvent);
 if err = noErr then begin
 quit_now := true;
 end; (* if *)
 HandleQuit := err;
 end; (* HandleQuit *)

Main Program

 var
 junkbool: boolean;
 event: EventRecord;
 err: OSErr;
 junk: OSErr;
 response: longint;
 attr: longint;
begin
    (* First check for System 7.  OK, so we're supposed *)
    (* to test for functionality but this is example code. *)
 if (Gestalt(gestaltSystemVersion, response) <> noErr)
 | (response < $700) then begin
 ExitToShell;
 end; (* if *)

    (* Now install our AppleEvent handles. *)
 err := AEInstallEventHandler(kCoreEventClass,
 kAEOpenApplication,
 @HandleOpenApplication, 0, false);
 if err = noErr then begin
 err := AEInstallEventHandler(kCoreEventClass,
 kAEOpenDocuments,
 @HandleOpenDocuments, 0, false);
 end; (* if *)
 if err = noErr then begin
 err := AEInstallEventHandler(kCoreEventClass,
 kAEQuitApplication,
 @HandleQuit, 0, false);
 end; (* if *)

    (* startup Internet Config *)
 if err = noErr then begin
 err := ICMapErr(ICStart(instance, my_creator));
 if err = noErr then begin
 err := ICMapErr(ICFindConfigFile(instance, 0, nil));
 end; (* if *)

    (* fetch the mappings preference *)
 if err = noErr then begin
 err := ICMapErr(ICGetPrefHandle(instance, kICMapping, 
 attr, mappings));
 end; (* if *)

    (* enter main loop *)
 if err = noErr then begin
 quit_now := false;
 while not quit_now do begin
 junkbool := WaitNextEvent(everyEvent, event, 
 maxlongint, nil);
 case event.what of
 keyDown: 
 quit_now := true;
 kHighLevelEvent: 
 junk := AEProcessAppleEvent(event);
 otherwise
 ;
 end; (* case *)
 end; (* while *)
 end; (* if *)

    (* shut down IC, only if we successfully started it *)
 junk := ICStop(instance);
 end; (* if *)

    (* beep if we get any errors*)
    (* sophisticated error handling this is not *)
    (* a good place to put a breakpoint this is *)
 if err <> noErr then begin
 SysBeep(10);
 end; (* if *)
end. (* SpaceAliens *)

This program, “Space Aliens Ate My Icons!”, is a simple drag and drop utility that ‘fixes’ the type and creator of any file dropped on to it by looking up the file’s extension in the IC mappings database. It combines a standard drag and drop application shell with some simple IC operations. There are four interesting sections of this program: the global variables, the main line, the HandleOpenApplication routine and the ProcessDocument routine.

1 Global Variables

There are two IC-related global variables in Space Aliens. The first, instance, is the standard connection to IC that all programs must obtain before they use IC. The variable is global so that it can be accessed throughout the program. Although it is possible to start and stop IC multiple times during the execution of your program, it is normally easier to just start it at the beginning and stop it at the end.

The other IC-related global variable is mappings, which is a handle to the mappings database. More on this later.

2 Main Program

The main program does all of the things normally associated with the main line of an application, including checking the system configuration, installing AppleEvent handlers and running the main loop, but it also performs a number of IC-related operations. These include starting IC, finding a preferences file and stopping IC. These operations are done in almost the same way as in ICHelloCruelWorld; the only change is that Space Aliens has a proper signature and passes that to ICStart instead of '????'. IC currently ignores this parameter but it is important that applications pass their signature to this routine to support future extensions.

The other IC-related section of the main program reads the mappings database into the mappings global variable. This is done by calling ICGetPrefHandle, which is very similar to ICGetPref, but returns the result in a new handle. The main program stores this handle in a global variable so that ProcessDocument can use it to look for matching extensions.

The ICGetPrefHandle is not a IC API routine but instead is provided in a library, ICSubs. Its implementation is interesting because it highlights some useful features of the ICGetPref. The implementation is given in Listing 3.

Listing 3: ICSubs.p (extract)

ICGetPrefHandle

function ICGetPrefHandle (inst: ICInstance; key: Str255;
 var attr: ICAttr; var prefh: Handle): ICError;
 var
 err: ICError;
 prefsize: longint;
begin
 prefh := nil;
 prefsize := 0;
 err := ICGetPref(inst, key, attr, nil, prefsize);
 if err <> noErr then begin
 prefsize := 0;
 end; (* if *)
 prefh := NewHandle(prefsize);
 err := MemError;
 if err = noErr then begin
 HLock(prefh);
 err := ICGetPref(inst, key, attr, prefh^, prefsize);
 if err = icPrefNotFoundErr then begin
 attr := 0;
 err := noErr;
 end; (* if *)
 HUnlock(prefh);
 end; (* if *)
 if err <> noErr then begin
 if prefh <> nil then begin
 DisposeHandle(prefh);
 end; (* if *)
 prefh := nil;
 end; (* if *)
 ICGetPrefHandle := err;
end; (* ICGetPrefHandle *)

Notice that it first calls ICGetPref with a nil data pointer. ICGetPref then returns the current size of the preference in prefsize but doesn’t actually return the data. Next ICGetPrefHandle creates a handle of the appropriate size, locks it and then calls ICGetPref again, this time with the dereferenced handle as the destination for the data. This handle is then returned to the calling program.

3 HandleOpenApplication

The HandleOpenApplication routine displays the program’s about box, including (for no readily apparent reason) the user’s Email address. This is a classic application of Internet Config to return simple preferences, in this case a Pascal string.

Note that ICGetPrefStr is not a IC API routine, but instead is provided in a library, ICSubs. Its implementation is very boring.

Listing 4: ICSubs.p (extract)

ICGetPrefStr

function ICGetPrefStr (inst: ICInstance; key: Str255;
 var attr: ICAttr; var str: Str255): ICError;
 var
 err: ICError;
 size: longint;
begin
 size := 256;
 err := ICGetPref(inst, key, attr, @str, size);
 if err <> noErr then begin
 str := '';
 end; (* if *)
 ICGetPrefStr := err;
end; (* ICGetPrefStr *)

4 ProcessDocument

This routine is called by the HandleOpenDocuments AppleEvent handler for each document in the direct parameter. ProcessDocument walks the mappings data structure looking for the entry with suitable flags and the longest extension that matches the file name. If it finds a matching entry, it sets the type and creator of the file to the values stored in the entry.

The structure of the mappings database is quite complicated, so IC provides another library, ICMappings, containing routines to parse it. The mappings database can be viewed as a big array of entries, each entry having the structure shown in Listing 5.

Listing 5: ICKeys.p (extract)

ICMapEntry

ICMapEntry = record
 total_length: integer; (* from beginning of record *)
 fixed_length: integer; (* from beginning of record *)
 version: integer;
 file_type: OSType;
 file_creator: OSType;
 post_creator : OSType;
 flags: longint;
    (* variable part starts here *)
 extension: Str255;
 creator_app_name: Str255;
 post_app_name : Str255;
 MIME_type: Str255;
 entry_name: Str255;
 end;

The thing to note about this record is that it contains five Str255s, making it approximately 1.25 KB. There are hundreds of these records in the mappings database, which makes for quite a large preference! Obviously this would be a problem, so the mappings database is compressed, with the Str255s being laid out sequentially in memory. Given that most of these strings will typically be short, this represents a significant memory saving.

This has the disadvantage that it makes the data structure difficult to parse. The task is further complicated by the fact that applications can append arbitrary data after the strings, using a protocol defined in the IC programming documentation. For this reason it is a good idea to use the routines in ICMappings to access the database.

So there you go, a simple and yet useful Internet Config aware application in under 300 lines of code.

Adding IC Support to Your Application

The two previous sections have covered most of the important things that you need to know to add Internet Config support to your application. This section contains a checklist for making your application IC aware:

• The first thing is read the documentation! IC comes with comprehensive programming documentation that covers a lot more ground than this article can.

• Add ICGlue to your project. There are two libraries, one for 68K and one for PPC. Certain development environments require you to convert the 68K object file before you can use it, but this process is straightforward.

• Call ICStart at the beginning of your program and ICStop at the end.

• Call ICFindConfigFile, usually with the default parameters. If you implement double-clickable preference files then read the next section about a gotcha associated with them.

• Call ICGetPref when you need the value of a preference from IC. The list of these preferences is given in the programming documentation, but you can get a good idea of what is available by looking through the Internet Config application. If you are reading a lot of preferences at once, then you can make your program faster by bracketing your calls with calls to ICBegin and ICEnd.

• Remove any superfluous user interface for preferences that are better managed by IC.

If your program is small, you might want to discard your existing preference mechanism and use IC to store all of your preferences, including your private ones. The programming documentation gives details on how to store private preferences using IC.

Internet Config Gotchas

All system software has gotchas and IC is no exception. But “forewarned is forearmed”, so here is my list of potential pitfalls.

Double-Clickable Preference Files

Many applications implement double-clickable preference files so that multiple users can share the same Macintosh. If your application supports this, you need to make sure that you are using Internet Config 1.1. The details of the problem are beyond the scope of this article but suffice to say that, due to a design error, version 1.0 does not provide sufficient support for double-clickable preference files. The issue is discussed in detail in the programming documentation. [See, I told you it was important to read the documentation!]

ICError

ICError is a longint (or long for you C people) - it is not an integer (short) or an OSErr. Not recognising this fact could cause all sorts of problems in your code. There is a routine in ICSubs called ICMapErr which converts ICErrors to OSErrs.

User Interface Frowned Upon

I recommend that you do not provide a user interface for changing the preferences that are managed by Internet Config. I do however recognise that some developers will not heed this recommendation, so the API provides support for your programs to change preferences - I merely suggest that you not use it.

Version 1.1 of IC provides an API call to launch the Internet Config application, bring it to the front and display a specific preference. In many cases this is all the user interface you need.

Read-Only Preferences

One of the bits in the preference attributes is a read-only bit. If this bit is set, then any attempt to write the preference will result in an error. If you provide a user interface for changing IC preferences, then you should make sure that you pay attention to this read-only bit. Any future version of IC that renders your user interface obsolete will also mark the affected preferences as read-only so that you don’t attempt to change them. It is important that you indicate read-only preferences in your user interface, otherwise your users will get very confused as to why their preference changes are bouncing.

Why No User Interface? Well, for a start, it is more work for you, and one of the goals of IC was to reduce your workload. But the real reason is that future extensions to IC may render your user interface superfluous, or perhaps even counter-productive.

For example, if a future version of IC supports application-specific preferences, then your user interface would become obsolte because it would not have a way of specifying whether changes made by the user affect the application specific preference or the global default preference.

An even better example is the Internet Config Random Signature extension. This is an override component which returns a random signature each time a client asks for the signature preference. If your application provides a user interface for changing the signature, then the presence of this component renders it useless. For this reason, the Random Signature component marks the signature preference as read-only and returns an error when you attempt to get it.

Don’t Cache

IC essentially represents a shared database of preferences. This means that the value of a preference can change at any time. For this reason, it is important that you do not cache the value of a preference for any length of time. We recommend that you fetch the preference value every time that you need to use it.

It is possible that your current code base makes this awkward, in which case IC allows you to watch for preference changes. See the programming documentation for details.

One exception to this rule is the Mappings preference. This preference is large, expensive to fetch and expensive to parse. If you need to use it often, then you should probably cache the preference value. In this case you should make sure to read the documentation to learn about how to watch for changes to this preference.

The observant reader will notice that the Space Aliens program completely ignores the issue of caching. It can get away with this because, after the initial open document events have been processed, it quits and it always refetches the mappings preference when it is launched.

Under the Bonnet

Translator’s Note: In Australia, the cover to the engine compartment of a car is called a bonnet. A hood is the cover to the passenger compartment on a convertible. Oh yeah, and the luggage compartment is called the boot. Which means that all of those elephant jokes go right over our heads.

At first glance IC appears to be a simple set of library routines that use the Resource Manager to access preferences stored in a file. However IC is more complicated than that. The ICGlue file which you link to your application contains three parts: the switch glue, the link-in implementation and the component glue. The relationship between these is shown in Figure 3.

Figure 3. Structure of ICGlue

When you call ICStart, the switch glue attempts to open the Internet Config component. If this succeeds, then any other calls you make to IC are routed directly to the component. If ICStart fails to make a connection to the IC component, all subsequent calls to IC are routed to the link-in implementation. This code implements the basic functionality of IC using the Resource Manager.

Does This Dialogue Sound Familiar?

Quinn: [very enthusiastically] We should do it using components!

Peter: [perplexed] What’s a component?

Components are a lightweight form of dynamic linking which were originally designed by the QuickTime team, but have now escaped into the wider MacOS. Check out Inside Macintosh:More Macintosh Toolbox wherein the Component Manager is documented properly.

This scheme has a number of important benefits. Firstly, any program using IC can call it without having to worry about whether the component is installed. Secondly, the link-in implementation works with any system (well, at least back to System 6) which means IC can be used by any modern application without requiring the Component Manager or any other shared library mechanism. But the biggest benefit by far is that, if the component is present, then all calls are routed to the component; it acts as a dynamically linked library. So if we discover a bug in the link-in implementation (or the implementation becomes obsolete because of changes to the MacOS), we can replace the IC component and all old applications will benefit from the new implementation without recompilation.

Figure 4. Structure of the IC component

The IC component, whose structure is shown in Figure 4, uses exactly the same code as the link-in implementation used by the ICGlue. Layered on top is the component wrapper, which provides the support required by the Component Manager. In addition, the component ‘smarts’ are sandwiched between the component wrapper and the link-in implementation. As we develop IC, the component is getting smarter than the link-in implementation, providing improvements in internationalisation, efficiency and so on.

Finally, the link-in implementation is a pretty ordinary preference file implementation. The preferences are stored as ‘PREF’ resources in the Internet Preferences file in the Preferences folder. The resource name is used as the preference key and the first four bytes of the resource hold its attributes. The rest of the resource holds the preference’s value.

Oh, by the way, the full source code to all parts of the Internet Config System is in the public domain. So, if you’re worried about the quality of our code, you can take a look for yourself.

The Future

Internet Config can be extended in a number of ways. The first and most obvious mechanism for extending it is to release new versions of the Internet Config component. As we find bugs in IC, we will release new versions of the component that fix them - this is the raison d’être for components.

The second way of extending Internet Config is by using override components. The Component Manager has this cool ability to let one component capture another component and then selectively pass calls through to the captured component. This mechanism, very much like inheritance in object oriented design, allows very simple components to be written that capture the Internet Config component to patch just one routine. An example of this is the Internet Config RandomSignature extension. This component captures the Internet Config component and overrides the ICGetPref routine so that, if the call is requesting the signature preference, it returns a random signature instead of the one stored in the Internet Preferences file.

The possibilities for override components are endless. For example, let’s say your organisation wants to pre-configure all of its news clients to access the central news server. All you need to do is write a simple override component that watches for programs getting the NNTPHost preference and return a fixed value as a read-only preference. This way all news readers will use the correct host and the users won’t be able to change it. As we say in the system software business wonderful third party developer opportunity.

The third way of extending IC is by replacing the entire Internet Configuration System. If you replace both the Internet Config component and the Internet Config application, then you have total control over all aspects of the system. For example, imagine you want a version of IC that implements application-specific preferences. The first step would be to replace the component with a smarter component, capable of storing a set of preferences for each application and returning the right preferences to the right application. Then you would replace the Internet Config application with a more sophisticated application which can manage multiple sets of preferences. Your job is done - all IC aware programs will automatically benefit without recompilation.

As one final example, suppose you want to store your user preferences on a central server and access them through some network protocol. IC provides the flexibility to do this by replacing the standard component with a network-aware one. Of course, you would have to work out the user’s identity in some way, perhaps by requiring them to log on before using any IC aware programs. You can then choose whether to write a Macintosh application to administer the server or use tools from the server’s native environment.

IC is a very flexible system and I look forward to seeing it extended in ways I never anticipated.

Conclusion

The Internet is a cruel place for users. When a Macintosh user ventures onto the net, things that they take for granted, such as file types and the Chooser, suddenly stop working. Fortunately, the Macintosh offers superb Internet tools to ease that transition. Nevertheless, users need as much help as they can get, and one great way to help your users is to reduce the number of preferences they have to deal with - and the best way to do that is to support Internet Config.

Internet Config can be called from all common Macintosh development environments. Internet Config is easy to program and you can add it to your existing application with a minimum of fuss. Internet Config allows you to eliminate user interface code from your program, making it smaller and easier to maintain. Internet Config has full source code available in the public domain, so you can base commercial solutions around it without worrying about a single vendor hijacking your destiny. And finally, Internet Config is supported by a wide array of commercial, freeware and shareware Internet tool developers.

So there really is no excuse. Why aren’t you coding already???

Further Reading

If you want to find out more about IC and the technology that it is based upon then the following documents may be of interest.

Quinn, Internet Configuration System: User Documentation, 1994

Quinn, Internet Configuration System: Programming Documentation, 1994

Apple Computer, Inc, Inside Macintosh: More Macintosh Toolbox, 1993, Addison-Wesley

QuickTime Team & Dave Radcliffe, “QT 05 - Component Manager version 3.0”, New Technical Notes, Mar. 1994, Apple Developer Support

David Van Brink, “Be Our Guest: Components and C++ Classes Compared”, develop, Issue 12, Dec. 1992, Apple Developer Press

Bill Guschwan, “Inside QuickTime and Component-Based Managers”, develop, Issue 13, Mar. 1993, Apple Developer Press

John Wang, “Somewhere in QuickTime: Derived Media Handlers”, develop, Issue 14, June 1993, Apple Developer Press

Gary Woodcock, “Managing Component Registration”, develop, Issue 15, Sep. 1993, Apple Developer Press

 
AAPL
$116.47
Apple Inc.
+0.16
MSFT
$47.98
Microsoft Corpora
-0.72
GOOG
$537.50
Google Inc.
+2.67

MacTech Search:
Community Search:

Software Updates via MacUpdate

Cobook 3.0.7 - Intelligent address book....
Cobook Contacts is an intuitive, engaging address book. Solve the problem of contact management with Cobook Contacts and its simple interface and powerful syncing and integration possibilities.... Read more
StatsBar 1.9 - Monitor system processes...
StatsBar gives you a comprehensive and detailed analysis of the following areas of your Mac: CPU usage Memory usage Disk usage Network and bandwidth usage Battery power and health (MacBooks only)... Read more
Cyberduck 4.6 - FTP and SFTP browser. (F...
Cyberduck is a robust FTP/FTP-TLS/SFTP browser for the Mac whose lack of visual clutter and cleverly intuitive features make it easy to use. Support for external editors and system technologies such... Read more
Maya 2015 - Professional 3D modeling and...
Maya is an award-winning software and powerful, integrated 3D modeling, animation, visual effects, and rendering solution. Because Maya is based on an open architecture, all your work can be scripted... Read more
Evernote 6.0.1 - Create searchable notes...
Evernote allows you to easily capture information in any environment using whatever device or platform you find most convenient, and makes this information accessible and searchable at anytime, from... Read more
calibre 2.11 - Complete e-library manage...
Calibre is a complete e-book library manager. Organize your collection, convert your books to multiple formats, and sync with all of your devices. Let Calibre be your multi-tasking digital... Read more
Herald 5.0.1 - Notification plugin for M...
Note: Versions 2.1.3 (for OS X 10.7), 3.0.6 (for OS X 10.8), and 4.0.8 (for OS X 10.9) are no longer supported by the developer. Herald is a notification plugin for Mail.app, Apple's Mac OS X email... Read more
Firetask 3.7 - Innovative task managemen...
Firetask uniquely combines the advantages of classical priority-and-due-date-based task management with GTD. Stay focused and on top of your commitments - Firetask's "Today" view shows all relevant... Read more
TechTool Pro 7.0.6 - Hard drive and syst...
TechTool Pro is now 7, and this is the most advanced version of the acclaimed Macintosh troubleshooting utility created in its 20-year history. Micromat has redeveloped TechTool Pro 7 to be fully 64... Read more
PhotoDesk 3.0.1 - Instagram client for p...
PhotoDesk lets you view, like, comment, and download Instagram pictures/videos! (NO Uploads! / Image Posting! Instagram forbids that! AND you *need* an *existing* Instagram account). But you can do... Read more

Latest Forum Discussions

See All

Ubisoft Gives Everyone Two New Ways to E...
Ubisoft Gives Everyone Two New Ways to Earn In-Game Stuff for Far Cry 4 Posted by Jessica Fisher on November 21st, 2014 [ permalink ] | Read more »
Golfinity – Tips, Tricks, Strategies, an...
Dig this: Would you like to know what we thought of being an infinite golfer? Check out our Golfinity review! Golfinity offers unlimited ways to test your skills at golf. Here are a few ways to make sure your score doesn’t get too high and your... | Read more »
Dark Hearts, The Sequel to Haunting Meli...
Dark Hearts, The Sequel to Haunting Melissa, is Available Now Posted by Jessica Fisher on November 21st, 2014 [ permalink ] Universal App - Designed for iPhone and iPad | Read more »
Meowza! Toyze Brings Talking Tom to Life...
Meowza! | Read more »
Square Enix Announces New Tactical RPG f...
Square Enix Announces New Tactical RPG for Mobile, Heavenstrike Rivals. Posted by Jessica Fisher on November 21st, 2014 [ permalink ] With their epic stories and gorgeous graphics, | Read more »
Quest for Revenge (Games)
Quest for Revenge 1.0.0 Device: iOS Universal Category: Games Price: $4.99, Version: 1.0.0 (iTunes) Description: The great Kingdom of the west has fallen. The gods ignore the prayers of the desperate. A dark warlord has extinguished... | Read more »
Threadz is a New Writing Adventure for Y...
Threadz is a New Writing Adventure for You and Your Friends Posted by Jessica Fisher on November 21st, 2014 [ permalink ] In the tradition of round-robin storytelling, | Read more »
SteelSeries Stratus XL Hardware Review
Made by: SteelSeries Price: $59.99 Hardware/iOS Integration Rating: 4 out of 5 stars Usability Rating: 4.5 out of 5 stars Reuse Value Rating: 4.25 out of 5 stars Build Quality Rating: 4.5 out of 5 stars Overall Rating: 4.31 out of 5 stars | Read more »
ACDSee (Photography)
ACDSee 1.0.0 Device: iOS iPhone Category: Photography Price: $1.99, Version: 1.0.0 (iTunes) Description: Capture, perfect, and share your photos with ACDSee. The ACDSee iPhone app combines an innovative camera, a powerful photo... | Read more »
ProTube for YouTube (Entertainment)
ProTube for YouTube 2.0.2 Device: iOS Universal Category: Entertainment Price: $1.99, Version: 2.0.2 (iTunes) Description: ProTube is the ultimate, fully featured YouTube app. With it's highly polished design, ProTube offers ad-free... | Read more »

Price Scanner via MacPrices.net

Save up to $400 with Apple refurbished 2014 1...
The Apple Store has restocked Apple Certified Refurbished 2014 15″ Retina MacBook Pros for up to $400 off the cost of new models. An Apple one-year warranty is included with each model, and shipping... Read more
New 13-inch 1.4GHz MacBook Air on sale for $8...
 Adorama has the 2014 13″ 1.4GHz/128GB MacBook Air on sale for $899.99 including free shipping plus NY & NJ tax only. Their price is $100 off MSRP. B&H Photo has the 13″ 1.4GHz/128GB MacBook... Read more
Apple Expected to Reverse Nine-Month Tablet S...
Apple and Samsung combined accounted for 62 percent of the nearly 36 million branded tablets shipped in 3Q 2014, according to early vendor shipment share estimates from market intelligence firm ABI... Read more
Stratos: 30 Percent of US Smartphone Owners t...
Stratos, Inc., creator of the Bluetooth Connected Card Platform, has announced results from its 2014 Holiday Mobile Payments Survey. The consumer survey found that nearly one out of three (30 percent... Read more
2014 1.4GHz Mac mini on sale for $449, save $...
 B&H Photo has lowered their price on the new 1.4GHz Mac mini to $449.99 including free shipping plus NY tax only. Their price is $50 off MSRP, and it’s the lowest price available for this new... Read more
Check Apple prices on any device with the iTr...
MacPrices is proud to offer readers a free iOS app (iPhones, iPads, & iPod touch) and Android app (Google Play and Amazon App Store) called iTracx, which allows you to glance at today’s lowest... Read more
64GB iPod touch on sale for $249, save $50
Best Buy has the 64GB iPod touch on sale for $249 on their online store for a limited time. Their price is $50 off MSRP. Choose free shipping or free local store pickup (if available). Sale price for... Read more
15″ 2.2GHz Retina MacBook Pro on sale for $17...
 B&H Photo has the 2014 15″ 2.2GHz Retina MacBook Pro on sale for $1799.99 for a limited time. Shipping is free, and B&H charges NY sales tax only. B&H will also include free copies of... Read more
New Logitech AnyAngle Case/Stand Brings Flexi...
Logitec has announced the newest addition to its suite of tablet products — the Logitech AnyAngle. A protective case with an any-angle stand for iPad Air 2 and all iPad mini models, AnyAngle is the... Read more
Notebook PC Shipments Rise Year-Over-Year as...
According to preliminary results from the upcoming DisplaySearch Quarterly Mobile PC Shipment and Forecast Report, the global notebook PC market grew 10 percent year-over-year in Q3’14 to 49.4... Read more

Jobs Board

*Apple* Solutions Consultant (ASC) - Apple (...
**Job Summary** The ASC is an Apple employee who serves as an Apple brand ambassador and influencer in a Reseller's store. The ASC's role is to grow Apple Read more
*Apple* Solutions Consultant (ASC)- Retail S...
**Job Summary** The ASC is an Apple employee who serves as an Apple brand ambassador and influencer in a Reseller's store. The ASC's role is to grow Apple Read more
Project Manager, *Apple* Financial Services...
**Job Summary** Apple Financial Services (AFS) offers consumers, businesses and educational institutions ways to finance Apple purchases. We work with national and Read more
*Apple* Store Leader Program - College Gradu...
Job Description: Job Summary As an Apple Store Leader Program agent, you can continue your education as you major in the art of leadership at the Apple Store. You'll Read more
*Apple* Retail - Multiple Positions (US) - A...
Sales Specialist - Retail Customer Service and Sales Transform Apple Store visitors into loyal Apple customers. When customers enter the store, you're also the Read more
All contents are Copyright 1984-2011 by Xplain Corporation. All rights reserved. Theme designed by Icreon.