DumpNetworkSetup.c

/*
    File:       DumpNetworkSetup.c
 
    Contains:   Program to render Network Setup database as text.
 
    Written by: Quinn "The Eskimo!" 
 
    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):
 
                21 Nov 2000 Quinn           Integrated more changes from Joss Graessley, this time 
                                            AppleTalk preference printing.
                28 Sep 2000 Quinn           Integrated vector printing changes from Joss Graessley.
                                            Updated to build with UI 3.3.1 Network Setup headers.
                7/22/1999   Karl Groethe    Updated for Metrowerks Codewarror Pro 2.1
 
*/
 
/////////////////////////////////////////////////////////////////
 
// MoreIsBetter Setup
 
#include "MoreSetup.h"
 
// Pick up lots of OT interfaces.
 
#include <OpenTransport.h>
#include <OpenTptInternet.h>
#include <OpenTptLinks.h>
 
// Pick up standard system interfaces.
 
#include <CodeFragments.h>
#include <Resources.h>
#include <Errors.h>
#include <Fonts.h>
#include <Windows.h>
#include <Menus.h>
#include <TextEdit.h>
#include <Dialogs.h>
#include <StandardFile.h>
#include <DateTimeUtils.h>
 
// Pick up ANSI C interfaces
 
#include <stdio.h>
#include <FSp_fopen.h>
#include <string.h>
 
// Pick up Network Setup stuff.
 
#include <NetworkSetup.h>
 
/////////////////////////////////////////////////////////////////
#pragma mark ----- Binary to String  -----
 
static char gFormatInetHostBuffer[256];
 
static char *FormatInetHost(InetHost ipAddr)
    // Non-reentrant, but I don't care.
{
    OTInetHostToString(ipAddr, gFormatInetHostBuffer);
    return gFormatInetHostBuffer;
}
 
static char *ClassToString(OSType class)
{
    switch (class) {
        case kCfgClassAnyEntity:
            return "kCfgClassAnyEntity";
            break;
        case kCfgClassUnknownEntity:
            return "kCfgClassUnknownEntity";
            break;
        case kOTCfgClassNetworkConnection:
            return "kOTCfgClassNetworkConnection";
            break;
        case kOTCfgClassGlobalSettings:
            return "kOTCfgClassGlobalSettings";
            break;
        case kOTCfgClassServer:
            return "kOTCfgClassServer";
            break;
        case kOTCfgClassSetOfSettings:
            return "kOTCfgClassSetOfSettings";
            break;
        default:
            return "unknown";
    }
}
 
static char *TypeToString(OSType class)
{
    switch (class) {
        case kCfgTypeAnyEntity:
            return "kCfgTypeAnyEntity";
            break;
        case kCfgTypeUnknownEntity:
            return "kCfgTypeUnknownEntity";
            break;
        case kOTCfgTypeAppleTalk:
            return "kOTCfgTypeAppleTalk";
            break;
        case kOTCfgTypeTCPv4:
            return "kOTCfgTypeTCPv4";
            break;
        case kOTCfgTypeTCPv6:   
            return "kOTCfgTypeTCPv6";
            break;
        case kOTCfgTypeRemote:  
            return "kOTCfgTypeRemote";
            break;
        case kOTCfgTypeDial:
            return "kOTCfgTypeDial";
            break;
        case kOTCfgTypeModem:   
            return "kOTCfgTypeModem";
            break;
        case kOTCfgTypeInfrared:
            return "kOTCfgTypeInfrared";
            break;
        case kOTCfgTypeSetOfSettings:
            return "kOTCfgTypeSetOfSettings";
            break;
        case kOTCfgTypeDNS:
            return "kOTCfgTypeDNS";
            break;
        case kOTCfgTypeGeneric:
            return "kOTCfgTypeGeneric";
            break;
        default:
            return "unknown";
    }
}
 
static char *TCPConfigMethodToString(UInt8 configMethod)
{
    switch (configMethod) {
        case 0:
            return "Manual";
            break;
        case 1:
            return "RARP";
            break;
        case 2:
            return "BOOTP";
            break;
        case 3:
            return "DHCP";
            break;
        case 4:
            return "MacIP";
            break;
        default:
            return "unknown";
    }
}
 
static FILE *gOutput;
 
static void DefaultPrinter(UInt8 *data, ByteCount length, void *cookie)
{
    #pragma unused(cookie)
    UInt32 row;
    UInt32 col;
    UInt32 rowCount;
    UInt8 ch;
 
    rowCount = (length - 1) / 16 + 1;
    for (row = 0; row < rowCount; row++) {
        fprintf(gOutput, "      %04lX : ", row * 16);
        for (col = 0; col < 16; col++) {
            if ( (row * 16) + col < length ) {
                fprintf(gOutput, "%02X ", data[(row * 16) + col]);
            } else {
                fprintf(gOutput, "   ");
            }
        }
        for (col = 0; col < 16; col++) {
            if ( (row * 16) + col < length ) {
                ch = data[(row * 16) + col];
                if ( ch < ' ' || ch == 127 ) {
                    fprintf(gOutput, ".");
                } else {
                    fprintf(gOutput, "%c", ch);
                }
            }
        }
        fprintf(gOutput, "\n");
    }
}
 
static void DecimalPrinter(UInt8 *data, ByteCount length, void *cookie)
{
    #pragma unused(cookie)
    
    switch (length) {
        case sizeof(SInt8):
            fprintf(gOutput, "      value = %d\n", *((SInt8*) data));
            break;
        case sizeof(SInt16):
            fprintf(gOutput, "      value = %ld\n", *((SInt16*) data));
            break;
        case sizeof(SInt32):
            fprintf(gOutput, "      value = %ld\n", *((SInt32*) data));
            break;
        default:
            fprintf(gOutput, "¥¥¥ DecimalPrinter: Weird size preference data\n");
            DefaultPrinter(data, length, nil);
            break;
    }
}
 
static void PStringPrinter(UInt8 *data, ByteCount length, void *cookie)
{
    #pragma unused(cookie)
    
    if ((*data + 1) != length) {
        fprintf(gOutput, "¥¥¥ PStringPrinter: Weird size preference data\n");
        DefaultPrinter(data, length, nil);
    } else {
        fprintf(gOutput, "      Ò\\p%#sÓ\n", data);
    }
}
 
static void CStringPrinter(UInt8 *data, ByteCount length, void *cookie)
{
    #pragma unused(cookie)
    
    if ((strlen((char *) data) + 1) != length) {
        fprintf(gOutput, "¥¥¥ CStringPrinter: Weird size preference data\n");
        DefaultPrinter(data, length, nil);
    } else {
        fprintf(gOutput, "      Ò%sÓ\n", data);
    }
}
 
static void DateTimePrinter(UInt8 *data, ByteCount length, void *cookie)
{
    #pragma unused(cookie)
    UInt32 dateTime;
    Str255 dateStr;
    Str255 timeStr;
    
    if (length != sizeof(UInt32)) {
        fprintf(gOutput, "¥¥¥ DateTimePrinter: Weird size preference data\n");
        DefaultPrinter(data, length, nil);
    } else {
        dateTime = *((UInt32 *) data);
        DateString(dateTime, shortDate, dateStr, nil);
        TimeString(dateTime, true, timeStr, nil);
        fprintf(gOutput, "      %#s, %#s\n", dateStr, timeStr);
    }
}
 
static void DeviceTypePrinter(UInt8 *data, ByteCount length, void *cookie)
{
    #pragma unused(cookie)
    char *str;
    Boolean printRaw;
    UInt16 value;
    
    if (length != sizeof(UInt16)) {
        fprintf(gOutput, "¥¥¥ DeviceTypePrinter: Weird size preference data\n");
        DefaultPrinter(data, length, nil);
    } else {
        printRaw = false;
        value = *((UInt16 *) data);
        switch ( value ) {
            case kOTNoDeviceType: str = "kOTNoDeviceType"; break;
            case kOTADEVDevice: str = "kOTADEVDevice"; break;
            case kOTMDEVDevice: str = "kOTMDEVDevice"; break;
            case kOTLocalTalkDevice: str = "kOTLocalTalkDevice"; break;
            case kOTIRTalkDevice: str = "kOTIRTalkDevice"; break;
            case kOTTokenRingDevice: str = "kOTTokenRingDevice"; break;
            case kOTISDNDevice: str = "kOTISDNDevice"; break;
            case kOTATMDevice: str = "kOTATMDevice"; break;
            case kOTSMDSDevice: str = "kOTSMDSDevice"; break;
            case kOTSerialDevice: str = "kOTSerialDevice"; break;
            case kOTEthernetDevice: str = "kOTEthernetDevice"; break;
            case kOTSLIPDevice: str = "kOTSLIPDevice"; break;
            case kOTPPPDevice: str = "kOTPPPDevice"; break;
            case kOTModemDevice: str = "kOTModemDevice"; break;
            case kOTFastEthernetDevice: str = "kOTFastEthernetDevice"; break;
            case kOTFDDIDevice: str = "kOTFDDIDevice"; break;
            case kOTIrDADevice: str = "kOTIrDADevice"; break;
            case kOTATMSNAPDevice: str = "kOTATMSNAPDevice"; break;
            case kOTFibreChannelDevice: str = "kOTFibreChannelDevice"; break;
            case kOTFireWireDevice: str = "kOTFireWireDevice"; break;
            case kOTPseudoDevice: str = "kOTPseudoDevice"; break;
            default: str = "unknown"; printRaw = true; break;
        }
        fprintf(gOutput, "      %s (%d)\n", str, value);
        if (printRaw){
            DefaultPrinter(data, length, nil);
        }
    }
}
 
static Boolean UnpackTCPSearchList(const UInt8 *data, ByteCount length, OTCfgTCPSearchList *searchListPref)
{
    const UInt8 *cursor;
    MoreAssertQ(data != nil);
    MoreAssertQ(searchListPref != nil);
    
    cursor = data;
    if (cursor + sizeof(SInt8) <= data + length) {
        searchListPref->fPrimaryInterfaceIndex = *cursor;
        cursor += sizeof(SInt8);
    }
    if (cursor + *cursor + 1 <= data + length) {
        BlockMoveData(cursor, searchListPref->fLocalDomainName, *cursor + 1);
        cursor += (*cursor + 1);
    }
    if (cursor + *cursor + 1 <= data + length) {
        BlockMoveData(cursor, searchListPref->fAdmindomain, *cursor + 1);
        cursor += (*cursor + 1);
    }
    return (cursor == data + length);
}
 
static void TCPSearchListPrinter(UInt8 *data, ByteCount length, void *cookie)
{
    #pragma unused(cookie)
    OTCfgTCPSearchList searchListPref;
    
    if ( ! UnpackTCPSearchList(data, length, &searchListPref) ) {
        fprintf(gOutput, "¥¥¥ TCPSearchListPrinter: Weird size preference data\n");
        DefaultPrinter(data, length, nil);
    } else {
        fprintf(gOutput, "      fPrimaryInterfaceIndex = %d\n", searchListPref.fPrimaryInterfaceIndex);
        fprintf(gOutput, "      fLocalDomainName = Ò\\p%#sÓ\n", searchListPref.fLocalDomainName);
        fprintf(gOutput, "      fAdmindomain = Ò\\p%#sÓ\n", searchListPref.fAdmindomain);
    }
}
 
static void TCPServersListPrinter(UInt8 *data, ByteCount length, void *cookie)
{
    #pragma unused(cookie)
    SInt16 serverCount;
    ItemCount serverIndex;
    
    serverCount = ((OTCfgTCPDNSServersList *) data)->fCount;
    if ( length < sizeof(SInt16) || length != (sizeof(SInt16) + serverCount * sizeof(InetHost))) {
        fprintf(gOutput, "¥¥¥ TCPSearchListPrinter: Weird size preference data\n");
        DefaultPrinter(data, length, nil);
    } else {
        fprintf(gOutput, "      fCount = %d\n", serverCount);
        for (serverIndex = 0; serverIndex < serverCount; serverIndex++) {
            fprintf(gOutput, "        fAddressesList[%d] = %s\n", serverIndex,
                    FormatInetHost((((OTCfgTCPDNSServersList *)data)->fAddressesList)[serverIndex]));
        }
    }
}
 
static void TCPUnloadTypeAtrrPrinter(UInt8 *data, ByteCount length, void *cookie)
{
    #pragma unused(cookie)
    SInt16 value;
    char *name;
 
    if ( length != sizeof(SInt16) ) {
        fprintf(gOutput, "¥¥¥ TCPUnloadTypeAtrrPrinter: Weird size preference data\n");
        DefaultPrinter(data, length, nil);
    } else {
        value = *((SInt16*)data);
        switch ( value ) {
            case 1: name = "kActiveLoadedOnDemand"; break;
            case 2: name = "kActiveAlwaysLoaded"; break;
            case 3: name = "kInactive"; break;
            default: name = "unknown"; break;
        }
        fprintf(gOutput, "      %s (%d)\n", name, value);
    }
}
 
static Boolean UnpackOTCfgIITFPrefs(const UInt8 *data, ByteCount length, UInt8 **cursorPtr,
                                        OTCfgTCPInterfacesUnpacked *unpacked, Str255 appleTalkZone)
{
    Boolean ok;
    UInt8 *cursor;
    
    MoreAssertQ(data != nil);
    MoreAssertQ(cursorPtr != nil);
    MoreAssertQ(*cursorPtr >= data && *cursorPtr < data + length);
    MoreAssertQ(unpacked != nil);
    MoreAssertQ(appleTalkZone != nil);
    
    cursor = *cursorPtr;
    ok = true;
    unpacked->fCount = 0;
 
    if ( ok && (cursor + sizeof(UInt8) <= data + length) ) {
        unpacked->fConfigMethod = *cursor;
        cursor += sizeof(UInt8);
    } else {
        ok = false;
    }
    if ( ok && (cursor + sizeof(InetHost) <= data + length) ) {
        BlockMoveData(cursor, &unpacked->fIPAddress, sizeof(InetHost));
        cursor += sizeof(InetHost);
    } else {
        ok = false;
    }
    if ( ok && (cursor + sizeof(InetHost) <= data + length) ) {
        BlockMoveData(cursor, &unpacked->fSubnetMask, sizeof(InetHost));
        cursor += sizeof(InetHost);
    } else {
        ok = false;
    }
    if ( ok && (cursor + sizeof(SInt8) <= data + length) ) {
        // OTCfgIITFPrefs only defines 1 byte of storage for fAppleTalkZone,
        // so we have to return it in an extra Str255 parameter.
        unpacked->fAppleTalkZone[0] = 0;
        appleTalkZone[0] = *cursor;
        cursor += sizeof(UInt8);
    } else {
        ok = false;
    }
 
    // Who the hell thought putting a packed pascal string into the middle
    // of a structure was a good idea!?!
    
    if ( ok && (cursor + appleTalkZone[0] <= data + length) ) {
        BlockMoveData(cursor, &appleTalkZone[1], appleTalkZone[0]);
        cursor += appleTalkZone[0];
    } else {
        ok = false;
    }
 
    if ( ok && (cursor + 36 <= data + length) ) {
        BlockMoveData(cursor, unpacked->path, 36);
        cursor += 36;
    } else {
        ok = false;
    }
    if ( ok && (cursor + 32 <= data + length) ) {
        BlockMoveData(cursor, unpacked->module, 32);
        cursor += 32;
    } else {
        ok = false;
    }
    if ( ok && (cursor + sizeof(UInt32) <= data + length) ) {
        BlockMoveData(cursor, &unpacked->framing, sizeof(UInt32));
        cursor += sizeof(UInt32);
    } else {
        ok = false;
    }
    
    *cursorPtr = cursor;
    return ok;
}
 
static void TCPPrefsPrinter(UInt8 *data, ByteCount length, void *cookie)
{
    #pragma unused(cookie)
    UInt8 *cursor;
    SInt16 prefCount;
    SInt16 prefIndex;
    OTCfgTCPInterfacesUnpacked prefData;
    Str255 appleTalkZone;
    
    if ( length < sizeof(SInt16) ) {
        fprintf(gOutput, "¥¥¥ TCPPrefsPrinter: Weird size preference data\n");
        DefaultPrinter(data, length, nil);
    } else {
        cursor = data;
        prefCount = *((SInt16 *)cursor);
        cursor += sizeof(SInt16);
        
        fprintf(gOutput, "      fCount = %d\n", prefCount);
        for (prefIndex = 0; prefIndex < prefCount; prefIndex++) {
            fprintf(gOutput, "        [%d]\n", prefIndex);
            if ( UnpackOTCfgIITFPrefs(data, length, &cursor, &prefData, appleTalkZone) ) {
                fprintf(gOutput, "          fConfigMethod = %s (%d)\n", TCPConfigMethodToString(prefData.fConfigMethod), prefData.fConfigMethod);
                fprintf(gOutput, "          fIPAddress = %s\n", FormatInetHost(prefData.fIPAddress));
                fprintf(gOutput, "          fSubnetMask = %s\n", FormatInetHost(prefData.fSubnetMask));
                fprintf(gOutput, "          fAppleTalkZone = Ò%#sÓ\n", appleTalkZone);
                fprintf(gOutput, "          path = Ò%#sÓ\n", prefData.path);
                fprintf(gOutput, "          module = Ò%#sÓ\n", prefData.module);
                fprintf(gOutput, "          framing = %08x\n", prefData.framing);
            } else {
                fprintf(gOutput, "¥¥¥ TCPPrefsPrinter: Error parsing data data\n");
                DefaultPrinter(data, length, nil);
                break;
            }
        }
        if (prefIndex == prefCount) {
            if (cursor != data + length) {
                fprintf(gOutput, "¥¥¥ TCPPrefsPrinter: Didn't consume all the data\n");
                DefaultPrinter(data, length, nil);
            }
        } else {
            fprintf(gOutput, "¥¥¥ TCPPrefsPrinter: Didn't iterate far enough\n");
            DefaultPrinter(data, length, nil);
        }
    }
}
 
static void DomainListPrinter(UInt8 *data, ByteCount length, void *cookie)
{
    #pragma unused(cookie)
    UInt8 *cursor;
    SInt16 domainCount;
    SInt16 domainIndex;
    Str255 thisDomain;
    
    if ( length < sizeof(SInt16) ) {
        fprintf(gOutput, "¥¥¥ DomainListPrinter: Weird size preference data\n");
        DefaultPrinter(data, length, nil);
    } else {
        cursor = data;
        domainCount = *((SInt16 *)cursor);
        cursor += sizeof(SInt16);
        fprintf(gOutput, "      fCount = %d\n", domainCount);
        for (domainIndex = 0; domainIndex < domainCount; domainIndex++) {
            if ( cursor + sizeof(UInt8) <= data + length ) {
                thisDomain[0] = *cursor;
                cursor += 1;
                if ( cursor + thisDomain[0] <= data + length ) {
                    BlockMoveData(cursor, &thisDomain[1], thisDomain[0]);
                    cursor += thisDomain[0];
                    fprintf(gOutput, "        [%d] = Ò%#sÓ\n", domainIndex, thisDomain);
                } else {
                    break;
                }
            } else {
                break;
            }
        }
        if (domainIndex == domainCount) {
            if (cursor != data + length) {
                fprintf(gOutput, "¥¥¥ DomainListPrinter: Didn't consume all the data\n");
                DefaultPrinter(data, length, nil);
            }
        } else {
            fprintf(gOutput, "¥¥¥ DomainListPrinter: Didn't iterate far enough\n");
            DefaultPrinter(data, length, nil);
        }
    }
}
 
static void RouterListPrinter(UInt8 *data, ByteCount length, void *cookie)
{
    #pragma unused(cookie)
    SInt16 routeCount;
    SInt16 routeIndex;
    OTCfgTCPRoutersList *prefData;
    
    prefData = (OTCfgTCPRoutersList *)data;
    routeCount = prefData->fCount;
    if ( length < sizeof(SInt16) || ( length != sizeof(SInt16) + routeCount * sizeof(OTCfgTCPRoutersListEntry)) ) {
        fprintf(gOutput, "¥¥¥ RouterListPrinter: Weird size preference data\n");
        DefaultPrinter(data, length, nil);
    } else {
        fprintf(gOutput, "      fCount = %d\n", routeCount);
        for (routeIndex = 0; routeIndex < routeCount; routeIndex++) {
            fprintf(gOutput, "      fList[%d].fToHost = %s\n", routeIndex, FormatInetHost(prefData->fList[routeIndex].fToHost));
            fprintf(gOutput, "      fList[%d].fViaHost = %s\n", routeIndex, FormatInetHost(prefData->fList[routeIndex].fViaHost));
            fprintf(gOutput, "      fList[%d].fLocal = %d\n", routeIndex, prefData->fList[routeIndex].fLocal);
            fprintf(gOutput, "      fList[%d].fHost = %d\n", routeIndex, prefData->fList[routeIndex].fHost);
        }
    }
}
 
static void UserLevelPrinter(UInt8 *data, ByteCount length, void *cookie)
{
    #pragma unused(cookie)
    SInt16 value;
    char *name;
 
    if ( length != sizeof(SInt16) ) {
        fprintf(gOutput, "¥¥¥ UserLevelPrinter: Weird size preference data\n");
        DefaultPrinter(data, length, nil);
    } else {
        value = *((SInt16*)data);
        switch ( value ) {
            case 1: name = "kBasicMode"; break;
            case 2: name = "kAdvancedMode"; break;
            case 3: name = "kAdminMode"; break;
            default: name = "unknown"; break;
        }
        fprintf(gOutput, "      %s (%d)\n", name, value);
    }
}
 
static void VectorPrinter( UInt8* data, ByteCount length, void* cookie )
{
#pragma unused( cookie )
    CfgSetsVector*          pVectorData = (CfgSetsVector*)data;
    UInt32                  i = 0;
    
    if ( length != (sizeof( CfgSetsElement ) * pVectorData->fCount) + sizeof(pVectorData->fCount) )
    {
        fprintf( gOutput, "Vector data corrupt, size invalid" );
        return;
    }
    
    fprintf( gOutput, "    Elements: %d\n", pVectorData->fCount );
    for ( i = 0; i < pVectorData->fCount; i++ )
    {
        CfgSetsElement*     pElement = &pVectorData->fElements[ i ];
        
        fprintf( gOutput, "        Vector %d\n", i );
        fprintf( gOutput, "            fEntityRef.fLoc:       %d\n", pElement->fEntityRef.fLoc );
        fprintf( gOutput, "            fEntityRef.fReserved:  %d\n", pElement->fEntityRef.fReserved );
        fprintf( gOutput, "            fEntityRef.fID:        %#s\n", pElement->fEntityRef.fID );
        fprintf( gOutput, "            fEntityInfo.fClass:    '%4.4s'\n", &pElement->fEntityInfo.fClass );
        fprintf( gOutput, "            fEntityInfo.fType:     '%4.4s'\n", &pElement->fEntityInfo.fType );
        fprintf( gOutput, "            fEntityInfo.fName:     %#s\n", pElement->fEntityInfo.fName );
        fprintf( gOutput, "            fEntityInfo.fIcon:\n" );
        
        DefaultPrinter((UInt8*)&pElement->fEntityInfo.fIcon, sizeof(pElement->fEntityInfo.fIcon), nil);
    }
}
 
#define TrueOrFalse( inBool ) (inBool ? "true" : "false")
 
static void AppleTalkPrefPrinter(UInt8 *data, ByteCount length, void *cookie)
{
    #pragma unused(cookie)
    OTCfgATalkGeneral*  pPrefs = (OTCfgATalkGeneral*)data;
    if ( length != sizeof( OTCfgATalkGeneral ) )
    {
        DefaultPrinter(data, length, cookie);
    }
    else
    {
        fprintf(gOutput, "      fVersion = %d\n", pPrefs->fVersion );
        fprintf(gOutput, "      fNumPrefs = %d\n", pPrefs->fNumPrefs );
        fprintf(gOutput, "      fPort = 0x%.8X\n", pPrefs->fPort );
        fprintf(gOutput, "      fLink = 0x%.8X\n", pPrefs->fLink );
        fprintf(gOutput, "      fPrefs[0-7] not displayed, valid at runtime only\n" );
//      fprintf(gOutput, "      fPrefs[0] = 0x%.8X\n", pPrefs->fPrefs[0] );
//      fprintf(gOutput, "      fPrefs[1] = 0x%.8X\n", pPrefs->fPrefs[1] );
//      fprintf(gOutput, "      fPrefs[2] = 0x%.8X\n", pPrefs->fPrefs[2] );
//      fprintf(gOutput, "      fPrefs[3] = 0x%.8X\n", pPrefs->fPrefs[3] );
//      fprintf(gOutput, "      fPrefs[4] = 0x%.8X\n", pPrefs->fPrefs[4] );
//      fprintf(gOutput, "      fPrefs[5] = 0x%.8X\n", pPrefs->fPrefs[5] );
//      fprintf(gOutput, "      fPrefs[6] = 0x%.8X\n", pPrefs->fPrefs[6] );
//      fprintf(gOutput, "      fPrefs[7] = 0x%.8X\n", pPrefs->fPrefs[7] );
        fprintf(gOutput, "      aarpPrefs.fVersion = %d\n", pPrefs->aarpPrefs.fVersion );
        fprintf(gOutput, "      aarpPrefs.fSize = %d\n", pPrefs->aarpPrefs.fSize );
        fprintf(gOutput, "      aarpPrefs.fAgingCount = %d\n", pPrefs->aarpPrefs.fAgingCount );
        fprintf(gOutput, "      aarpPrefs.fAgingInterval = %d\n", pPrefs->aarpPrefs.fAgingInterval );
        fprintf(gOutput, "      aarpPrefs.fProtAddrLen = %d\n", pPrefs->aarpPrefs.fProtAddrLen );
        fprintf(gOutput, "      aarpPrefs.fHWAddrLen = %d\n", pPrefs->aarpPrefs.fHWAddrLen );
        fprintf(gOutput, "      aarpPrefs.fMaxEntries = %d\n", pPrefs->aarpPrefs.fMaxEntries );
        fprintf(gOutput, "      aarpPrefs.fProbeInterval = %d\n", pPrefs->aarpPrefs.fProbeInterval );
        fprintf(gOutput, "      aarpPrefs.fProbeRetryCount = %d\n", pPrefs->aarpPrefs.fProbeRetryCount );
        fprintf(gOutput, "      aarpPrefs.fRequestInterval = %d\n", pPrefs->aarpPrefs.fRequestInterval );
        fprintf(gOutput, "      aarpPrefs.fRequestRetryCount = %d\n", pPrefs->aarpPrefs.fRequestRetryCount );
        fprintf(gOutput, "      ddpPrefs.fVersion = %d\n", pPrefs->ddpPrefs.fVersion );
        fprintf(gOutput, "      ddpPrefs.fSize = %d\n", pPrefs->ddpPrefs.fSize );
        fprintf(gOutput, "      ddpPrefs.fTSDUSize = %d\n", pPrefs->ddpPrefs.fTSDUSize );
        fprintf(gOutput, "      ddpPrefs.fLoadType = %d (Ignored in OT 3.0)\n", pPrefs->ddpPrefs.fLoadType );
        fprintf(gOutput, "      ddpPrefs.fNode = %u\n", pPrefs->ddpPrefs.fNode );
        fprintf(gOutput, "      ddpPrefs.fNetwork = %u\n", pPrefs->ddpPrefs.fNetwork );
        fprintf(gOutput, "      ddpPrefs.fRTMPRequestLimit = %u\n", pPrefs->ddpPrefs.fRTMPRequestLimit );
        fprintf(gOutput, "      ddpPrefs.fRTMPRequestInterval = %u\n", pPrefs->ddpPrefs.fRTMPRequestInterval );
        fprintf(gOutput, "      ddpPrefs.fAddressGenLimit = %u\n", pPrefs->ddpPrefs.fAddressGenLimit );
        fprintf(gOutput, "      ddpPrefs.fBRCAgingInterval = %u\n", pPrefs->ddpPrefs.fBRCAgingInterval );
        fprintf(gOutput, "      ddpPrefs.fRTMPAgingInterval = %u\n", pPrefs->ddpPrefs.fRTMPAgingInterval );
        fprintf(gOutput, "      ddpPrefs.fMaxAddrTries = %u\n", pPrefs->ddpPrefs.fMaxAddrTries );
        fprintf(gOutput, "      ddpPrefs.fDefaultChecksum = %s\n", TrueOrFalse( pPrefs->ddpPrefs.fDefaultChecksum ) );
        fprintf(gOutput, "      ddpPrefs.fIsFixedNode = %s\n", TrueOrFalse( pPrefs->ddpPrefs.fIsFixedNode ) );
        fprintf(gOutput, "      ddpPrefs.fMyZone = %#s\n", pPrefs->ddpPrefs.fMyZone );
        fprintf(gOutput, "      nbpPrefs.fVersion = %u\n", pPrefs->nbpPrefs.fVersion );
        fprintf(gOutput, "      nbpPrefs.fSize = %u\n", pPrefs->nbpPrefs.fSize );
        fprintf(gOutput, "      nbpPrefs.fTSDUSize = %u\n", pPrefs->nbpPrefs.fTSDUSize );
        fprintf(gOutput, "      nbpPrefs.fDefaultRetryInterval = %u\n", pPrefs->nbpPrefs.fDefaultRetryInterval );
        fprintf(gOutput, "      nbpPrefs.fDefaultRetryCount = %u\n", pPrefs->nbpPrefs.fDefaultRetryCount );
        fprintf(gOutput, "      nbpPrefs.fDefaultRetryCount = %u\n", pPrefs->nbpPrefs.fDefaultRetryCount );
        fprintf(gOutput, "      nbpPrefs.fCaseSensitiveCompare = %s\n", TrueOrFalse( pPrefs->nbpPrefs.fCaseSensitiveCompare ) );
        fprintf(gOutput, "      nbpPrefs.fPad = %u\n", pPrefs->nbpPrefs.fPad );
        fprintf(gOutput, "      zipPrefs.fVersion = %u\n", pPrefs->zipPrefs.fVersion );
        fprintf(gOutput, "      zipPrefs.fSize = %u\n", pPrefs->zipPrefs.fSize );
        fprintf(gOutput, "      zipPrefs.fGetZoneInterval = %u\n", pPrefs->zipPrefs.fGetZoneInterval );
        fprintf(gOutput, "      zipPrefs.fZoneListInterval = %u\n", pPrefs->zipPrefs.fZoneListInterval );
        fprintf(gOutput, "      zipPrefs.fDDPInfoTimeout = %u\n", pPrefs->zipPrefs.fDDPInfoTimeout );
        fprintf(gOutput, "      zipPrefs.fGetZoneRetries = %u\n", pPrefs->zipPrefs.fGetZoneRetries );
        fprintf(gOutput, "      zipPrefs.fZoneListRetries = %u\n", pPrefs->zipPrefs.fZoneListRetries );
        fprintf(gOutput, "      zipPrefs.fChecksumFlag = %s\n", TrueOrFalse( pPrefs->zipPrefs.fChecksumFlag) );
        fprintf(gOutput, "      zipPrefs.fPad = %u\n", pPrefs->zipPrefs.fPad );
        fprintf(gOutput, "      atpPrefs.fVersion = %u\n", pPrefs->atpPrefs.fVersion );
        fprintf(gOutput, "      atpPrefs.fSize = %u\n", pPrefs->atpPrefs.fSize );
        fprintf(gOutput, "      atpPrefs.fTSDUSize = %u\n", pPrefs->atpPrefs.fTSDUSize );
        fprintf(gOutput, "      atpPrefs.fDefaultRetryInterval = %u\n", pPrefs->atpPrefs.fDefaultRetryInterval );
        fprintf(gOutput, "      atpPrefs.fDefaultRetryCount = %u\n", pPrefs->atpPrefs.fDefaultRetryCount );
        fprintf(gOutput, "      atpPrefs.fDefaultReleaseTimer = %u\n", pPrefs->atpPrefs.fDefaultReleaseTimer );
        fprintf(gOutput, "      atpPrefs.fDefaultALOSetting = %u\n", pPrefs->atpPrefs.fDefaultALOSetting );
        fprintf(gOutput, "      adspPrefs.fVersion = %u\n", pPrefs->adspPrefs.fVersion );
        fprintf(gOutput, "      adspPrefs.fSize = %u\n", pPrefs->adspPrefs.fSize );
        fprintf(gOutput, "      adspPrefs.fDefaultSendBlocking = %u\n", pPrefs->adspPrefs.fDefaultSendBlocking );
        fprintf(gOutput, "      adspPrefs.fTSDUSize = %u\n", pPrefs->adspPrefs.fTSDUSize );
        fprintf(gOutput, "      adspPrefs.fETSDUSize = %u\n", pPrefs->adspPrefs.fETSDUSize );
        fprintf(gOutput, "      adspPrefs.fDefaultOpenInterval = %u\n", pPrefs->adspPrefs.fDefaultOpenInterval );
        fprintf(gOutput, "      adspPrefs.fDefaultProbeInterval = %u\n", pPrefs->adspPrefs.fDefaultProbeInterval );
        fprintf(gOutput, "      adspPrefs.fMinRoundTripTime = %u\n", pPrefs->adspPrefs.fMinRoundTripTime );
        fprintf(gOutput, "      adspPrefs.fDefaultSendInterval = %u\n", pPrefs->adspPrefs.fDefaultSendInterval );
        fprintf(gOutput, "      adspPrefs.fDefaultRecvWindow = %u\n", pPrefs->adspPrefs.fDefaultRecvWindow );
        fprintf(gOutput, "      adspPrefs.fDefaultOpenRetries = %u\n", pPrefs->adspPrefs.fDefaultOpenRetries );
        fprintf(gOutput, "      adspPrefs.fDefaultBadSeqMax = %u\n", pPrefs->adspPrefs.fDefaultBadSeqMax );
        fprintf(gOutput, "      adspPrefs.fDefaultProbeRetries = %u\n", pPrefs->adspPrefs.fDefaultProbeRetries );
        fprintf(gOutput, "      adspPrefs.fMaxConsecutiveDataPackets = %u\n", pPrefs->adspPrefs.fMaxConsecutiveDataPackets );
        fprintf(gOutput, "      adspPrefs.fDefaultChecksum = %s\n", TrueOrFalse( pPrefs->adspPrefs.fDefaultChecksum ) );
        fprintf(gOutput, "      adspPrefs.fDefaultEOM = %s\n", TrueOrFalse( pPrefs->adspPrefs.fDefaultEOM ) );
        fprintf(gOutput, "      papPrefs.fVersion = %u\n", pPrefs->papPrefs.fVersion );
        fprintf(gOutput, "      papPrefs.fSize = %u\n", pPrefs->papPrefs.fSize );
        fprintf(gOutput, "      papPrefs.fDefaultOpenInterval = %u\n", pPrefs->papPrefs.fDefaultOpenInterval );
        fprintf(gOutput, "      papPrefs.fDefaultTickleInterval = %u\n", pPrefs->papPrefs.fDefaultTickleInterval );
        fprintf(gOutput, "      papPrefs.fDefaultOpenRetries = %u\n", pPrefs->papPrefs.fDefaultOpenRetries );
        fprintf(gOutput, "      papPrefs.fDefaultTickleRetries = %u\n", pPrefs->papPrefs.fDefaultTickleRetries );
        fprintf(gOutput, "      papPrefs.fDefaultReplies = %u\n", pPrefs->papPrefs.fDefaultReplies );
        fprintf(gOutput, "      papPrefs.fDefaultPAPEOMEnabled = %s\n", TrueOrFalse( pPrefs->papPrefs.fDefaultPAPEOMEnabled ) );
        fprintf(gOutput, "      aspPrefs.fVersion = %u\n", pPrefs->aspPrefs.fVersion );
        fprintf(gOutput, "      aspPrefs.fSize = %u\n", pPrefs->aspPrefs.fSize );
        fprintf(gOutput, "      aspPrefs.fDefaultTickleInterval = %u\n", pPrefs->aspPrefs.fDefaultTickleInterval );
        fprintf(gOutput, "      aspPrefs.fDefaultTickleRetries = %u\n", pPrefs->aspPrefs.fDefaultTickleRetries );
        fprintf(gOutput, "      aspPrefs.fDefaultReplies = %u\n", pPrefs->aspPrefs.fDefaultReplies );
    }
}
 
typedef void (*PrinterProc)(UInt8 *data, ByteCount length, void *cookie);
 
static void GetPrefTypeInfo(OSType prefType, char **userVisibleString, PrinterProc *printerProc, void **printerCookie)
{
    *userVisibleString = "unknown";
    *printerProc = DefaultPrinter;
    *printerCookie = nil;
 
    switch (prefType) {
 
        // Backward Compatibility Preferences
        
        case 'resn':
            *userVisibleString = "Backward Compatibility Resource Name";
            *printerProc = PStringPrinter;
            break;
        
        case 'resi':
            *userVisibleString = "Backward Compatibility Resource ID";
            *printerProc = DecimalPrinter;
            break;
            
        case 'time':
            *userVisibleString = "Backward Compatibility Timestamp";
            *printerProc = DateTimePrinter;
            break;
 
        case 'ccfg':
            *userVisibleString = "kSelectedConfigType";
            *printerProc = DecimalPrinter;
            break;
            
        // Generic
 
        case 'pnam':
            *userVisibleString = "Preference Name";
            *printerProc = PStringPrinter;
            break;
 
        case kOTCfgSetsStructPref:
            *userVisibleString = "kOTCfgSetsStructPref";
            break;
        case kOTCfgSetsElementPref:
            *userVisibleString = "kOTCfgSetsElementPref";
            break;
        case kOTCfgSetsVectorPref:
            *userVisibleString = "kOTCfgSetsVectorPref";
            *printerProc = VectorPrinter;
            break;
        case kCfgFreePref:
            *userVisibleString = "kCfgTypefree";
            break;
 
        // Common to all the control panels
        
        case kOTCfgPrefWindowPositionPref:
            *userVisibleString = "kOTCfgPrefWindowPositionPref";
            break;
//      case kInfraredWindowPosAttr:
//          *userVisibleString = "kInfraredWindowPosAttr";
//          break;
//      case kTCPWindowPositionAttr:
//          *userVisibleString = "kTCPWindowPositionAttr";
//          break;
        case kOTCfgVersionPref:
            *userVisibleString = "kOTCfgVersionPref";
            *printerProc = DecimalPrinter;
            break;
//      case kCVRSResType:
//          *userVisibleString = "kCVRSResType";
//          break;
//      case kTCPVersionAttr:
//          *userVisibleString = "kTCPVersionAttr";
//          break;
        case kOTCfgPortUserVisibleNamePref:
            *userVisibleString = "kOTCfgPortUserVisibleNamePref";
            *printerProc = PStringPrinter;
            break;
//      case kPORTResType:
//          *userVisibleString = "kPORTResType";
//          break;
//      case kTCPPortAttr:
//          *userVisibleString = "kTCPPortAttr";
//          break;
//      case kRAConfigTypePort:
//          *userVisibleString = "kRAConfigTypePort";
//          break;
        case 'cnam':
            *userVisibleString = "kResourceCount";
            break;
//      case kATResourceCount:
//          *userVisibleString = "kATResourceCount";
//          break;
//      case kTCPResourceCount:
//          *userVisibleString = "kTCPResourceCount";
//          break;
//      case kModemResourceCount:
//          *userVisibleString = "kModemResourceCount";
//          break;
//      case kRAConfigNameType:
//          *userVisibleString = "kRAConfigNameType";
//          break;
        case kOTCfgProtocolUserVisibleNamePref:
            *userVisibleString = "kOTCfgProtocolUserVisibleNamePref";
            *printerProc = CStringPrinter;
            break;
//      case kTCPProtocolAttr:
//          *userVisibleString = "kTCPProtocolAttr";
//          break;
        case kOTCfgAdminPasswordPref:
            *userVisibleString = "kOTCfgAdminPasswordPref";
            break;
//      case kTCPPasswordAttr:
//          *userVisibleString = "kTCPPasswordAttr";
//          break;
        case kOTCfgUserModePref:
            *userVisibleString = "kOTCfgUserModePref";
            *printerProc = UserLevelPrinter;
            break;
//      case kUserModeResType:
//          *userVisibleString = "kUserModeResType";
//          break;
//      case kTCPUserLevelAttr:
//          *userVisibleString = "kTCPUserLevelAttr";
//          break;
//      case kTCPSelectedConfigType:
//          *userVisibleString = "kTCPSelectedConfigType";
//          break;
//      case kModemSelectedConfigType:
//          *userVisibleString = "kModemSelectedConfigType";
//          break;
//      case kRemoteSelectedConfigType:
//          *userVisibleString = "kRemoteSelectedConfigType";
//          break;
 
        // AppleTalk
        
        case kOTCfgATalkGeneralPref:
            *userVisibleString = "kOTCfgATalkGeneralPref";
            *printerProc = AppleTalkPrefPrinter;
            break;
        case kOTCfgATalkLocksPref:
            *userVisibleString = "kOTCfgATalkLocksPref";
            break;
        case kOTCfgATalkPortDeviceTypePref:
            *userVisibleString = "kOTCfgATalkPortDeviceTypePref";
            break;
            
        // Infrared
 
//      case kInfraredPrefsAttr:
//          *userVisibleString = "kInfraredPrefsAttr";
//          break;
        case 'irgo':
            *userVisibleString = "Infrared Globals";
            break;
            
        // TCP/IP
 
        case 'alis':
            *userVisibleString = "TCP/IP alias";
            break;
        case kOTCfgTCPDHCPClientIDPref:
            *userVisibleString = "kOTCfgTCPDHCPClientIDPref";
            break;
        case kOTCfgTCPDeviceTypePref:
            *userVisibleString = "kOTCfgTCPDeviceTypePref";
            *printerProc = DeviceTypePrinter;
            break;
//      case kIDNSResType:
//          *userVisibleString = "kIDNSResType";
//          break;
//      case kIHSTResType:
//          *userVisibleString = "kIHSTResType";
//          break;
//      case kIITFResType:
//          *userVisibleString = "kIITFResType";
//          break;
//      case kARAResType:
//          *userVisibleString = "kARAResType";
//          break;
//      case kIRTEResType:
//          *userVisibleString = "kIRTEResType";
//          break;
//      case kISDMResType:
//          *userVisibleString = "kISDMResType";
//          break;
//      case kSTNGResType:
//          *userVisibleString = "kSTNGResType";
//          break;
//      case kUNLDResType:
//          *userVisibleString = "kUNLDResType";
//          break;
        case 'dvty':
            *userVisibleString = "'dvty'";
            break;
        case kOTCfgTCPInterfacesPref:
            *userVisibleString = "kOTCfgTCPInterfacesPref";
            *printerProc = TCPPrefsPrinter;
            break;
        case kOTCfgTCPDNSServersListPref:
            *userVisibleString = "kOTCfgTypeTCPServersList";
            *printerProc = TCPServersListPrinter;
            break;
        case kOTCfgTCPSearchListPref:
            *userVisibleString = "kOTCfgTCPSearchListPref";
            *printerProc = TCPSearchListPrinter;
            break;
        case kOTCfgTCPRoutersListPref:
            *userVisibleString = "kOTCfgTCPRoutersListPref";
            *printerProc = RouterListPrinter;
            break;
        case kOTCfgTCPSearchDomainsPref:
            *userVisibleString = "kOTCfgTCPSearchDomainsPref";
            *printerProc = DomainListPrinter;
            break;
        case kOTCfgTCPLocksPref:
            *userVisibleString = "kOTCfgTCPLocksPref";
            break;
        case kOTCfgTCPUnloadAttrPref:
            *userVisibleString = "kOTCfgTCPUnloadAttrPref";
            *printerProc = TCPUnloadTypeAtrrPrinter;
            break;
 
        // Modem
        
        case kOTCfgModemGeneralPrefs:
            *userVisibleString = "kOTCfgModemGeneralPrefs";
            break;
        case kOTCfgModemLocksPref:
            *userVisibleString = "kOTCfgModemLocksPref";
            break;
        case kOTCfgModemAdminPasswordPref:
            *userVisibleString = "kOTCfgModemAdminPasswordPref";
            break;
        case kOTCfgModemApplicationPref:
            *userVisibleString = "kOTCfgModemApplicationPref";
            break;
            
        // Remote Access
 
        case kOTCfgRemoteARAPPref:
            *userVisibleString = "kOTCfgRemoteARAPPref";
            break;
        case kOTCfgRemoteAddressPref:
            *userVisibleString = "kOTCfgRemoteAddressPref";
            break;
        case kOTCfgRemoteChatPref:
            *userVisibleString = "kOTCfgRemoteChatPref";
            break;
        case kOTCfgRemoteDialingPref:
            *userVisibleString = "kOTCfgRemoteDialingPref";
            break;
        case kOTCfgRemoteAlternateAddressPref:
            *userVisibleString = "kOTCfgRemoteAlternateAddressPref";
            break;
        case kOTCfgRemoteClientLocksPref:
            *userVisibleString = "kOTCfgRemoteClientLocksPref";
            break;
        case kOTCfgRemoteClientMiscPref:
            *userVisibleString = "kOTCfgRemoteClientMiscPref";
            break;
        case kOTCfgRemoteConnectPref:
            *userVisibleString = "kOTCfgRemoteConnectPref";
            break;
        case kOTCfgRemoteUserPref:
            *userVisibleString = "kOTCfgRemoteUserPref";
            break;
        case kOTCfgRemoteDialAssistPref:
            *userVisibleString = "kOTCfgRemoteDialAssistPref";
            break;
        case kOTCfgRemoteIPCPPref:
            *userVisibleString = "kOTCfgRemoteIPCPPref";
            break;
        case kOTCfgRemoteLCPPref:
            *userVisibleString = "kOTCfgRemoteLCPPref";
            break;
        case kOTCfgRemoteLogOptionsPref:
            *userVisibleString = "kOTCfgRemoteLogOptionsPref";
            break;
        case kOTCfgRemotePasswordPref:
            *userVisibleString = "kOTCfgRemotePasswordPref";
            break;
        case kOTCfgRemoteServerPref:
            *userVisibleString = "kOTCfgRemoteServerPref";
            break;
        case kOTCfgRemoteUserModePref:
            *userVisibleString = "kOTCfgRemoteUserModePref";
            break;
        case kOTCfgRemoteX25Pref:
            *userVisibleString = "kOTCfgRemoteX25Pref";
            break;
        case kOTCfgRemoteApplicationPref:
            *userVisibleString = "kOTCfgRemoteApplicationPref";
            break;
 
        default:
            // do nothing
            break;
    }
}
 
/////////////////////////////////////////////////////////////////
#pragma mark ----- Core Implementation -----
 
static OSStatus DumpPref(CfgEntityAccessID prefsRefNum, OSType prefType, PrinterProc printerProc, void *printerCookie)
{
    OSStatus err;
    ByteCount prefSize;
    UInt8 *prefData;
    
    prefData = nil;
    
    err = OTCfgGetPrefsSize(prefsRefNum, prefType, &prefSize);
    if (err == noErr && prefSize != 0) {
        prefData = (UInt8*) NewPtr(prefSize);
        err = MemError();
        if (err == noErr) {
            MoreAssertQ(prefData != nil);
            err = OTCfgGetPrefs(prefsRefNum, prefType, prefData, prefSize);
        }
        if (err == noErr) {
            printerProc(prefData, prefSize, printerCookie);
        }
    }
    
    if (prefData != nil) {
        DisposePtr( (Ptr) prefData );
        MoreAssertQ(MemError() == noErr);
    }
 
    return err;
}
 
// static CfgPrefsHeader gPrefsTOCs[40];
 
static OSStatus DumpEntity(CfgDatabaseRef ref, CfgEntityRef entity)
{
    OSStatus err;
    OSStatus err2;
    CfgEntityAccessID accessID;
    ItemCount prefsTOCCount;
    ItemCount i;
    char *userVisibleString;
    PrinterProc printerProc;
    void *printerCookie;
    CfgPrefsHeader *prefsTOCs;
    
    prefsTOCs = nil;
    
    err = OTCfgOpenPrefs(ref, &entity, false, &accessID);
    if (err == noErr) {
        err = OTCfgGetPrefsTOCCount(accessID, &prefsTOCCount);
        if (err == noErr) {
            prefsTOCs = (CfgPrefsHeader *) NewPtr( prefsTOCCount * sizeof(CfgPrefsHeader));
            err = MemError();
        }
        if (err == noErr) {
            err = OTCfgGetPrefsTOC(accessID, &prefsTOCCount, prefsTOCs);
        }
        if (err == noErr) { 
            for (i = 0; i < prefsTOCCount; i++) {
                GetPrefTypeInfo(prefsTOCs[i].fType, &userVisibleString, &printerProc, &printerCookie);
                fprintf(gOutput, "    Preference\n");
                fprintf(gOutput, "      fSize = %hd\n", prefsTOCs[i].fSize);
                fprintf(gOutput, "      fVersion = %hd\n", prefsTOCs[i].fVersion);
                fprintf(gOutput, "      fType = '%4.4s' Ò%sÓ\n", &prefsTOCs[i].fType, userVisibleString);
                err = DumpPref(accessID, prefsTOCs[i].fType, printerProc, printerCookie);
                if (err != noErr) {
                    break;
                }
            }
        }
        
        err2 = OTCfgClosePrefs(accessID);
        if (err == noErr) {
            err = err2;
        }
    }
    if (prefsTOCs != nil) {
        DisposePtr( (Ptr) prefsTOCs );
        MoreAssertQ(MemError() == noErr);
    }
    return err;
}
 
// static CfgEntityRef gEntityRefs[20];
// static CfgEntityInfo gEntityInfos[20];
 
static OSStatus DumpArea(CfgDatabaseRef ref, CfgAreaID thisArea)
{
    OSStatus err;
    OSStatus err2;
    ItemCount entityCount;
    Str255 entityName;
    ItemCount i;
    CfgEntityRef *entityRefs;
    CfgEntityInfo *entityInfos;
    
    entityRefs = nil;
    entityInfos = nil;
    
    err = OTCfgOpenArea(ref, thisArea);
    if (err == noErr) {
        err = OTCfgGetEntitiesCount(ref, thisArea, kCfgClassAnyEntity, kCfgTypeAnyEntity, &entityCount);
        if (err == noErr) {
            entityRefs = (CfgEntityRef *) NewPtr( entityCount * sizeof(CfgEntityRef));
            err = MemError();
        }
        if (err == noErr) {
            entityInfos = (CfgEntityInfo *) NewPtr( entityCount * sizeof(CfgEntityInfo));
            err = MemError();
        }
        err = OTCfgGetEntitiesList(ref, thisArea,
                                 kCfgClassAnyEntity,
                                 kCfgTypeAnyEntity,
                                 &entityCount,
                                 entityRefs,
                                 entityInfos);
        if (err == noErr) {
            for (i = 0; i < entityCount; i++) {
                OTCfgGetEntityName(&entityRefs[i], entityName);
                fprintf(gOutput, "  Dumping entity Ò%#sÓ\n", entityName);
                fprintf(gOutput, "    CfgEntityRef\n");
                fprintf(gOutput, "      fLoc = %ld\n", entityRefs[i].fLoc);
                fprintf(gOutput, "      fReserved = %ld\n", entityRefs[i].fReserved);
                fprintf(gOutput, "      fID = %#s\n", entityRefs[i].fID);
                fprintf(gOutput, "    CfgEntityInfo\n");
                fprintf(gOutput, "      fClass = '%4.4s' Ò%sÓ\n", &entityInfos[i].fClass, ClassToString(entityInfos[i].fClass));
                fprintf(gOutput, "      fType  = '%4.4s' Ò%sÓ\n", &entityInfos[i].fType,  TypeToString(entityInfos[i].fType));
                fprintf(gOutput, "      fIcon\n");
                fprintf(gOutput, "        fFile\n");
                fprintf(gOutput, "          vRefNum = %hd\n", entityInfos[i].fIcon.fFile.vRefNum);
                fprintf(gOutput, "          parID   = %ld\n", entityInfos[i].fIcon.fFile.parID);
                fprintf(gOutput, "          name    = %#s\n", entityInfos[i].fIcon.fFile.name);
                fprintf(gOutput, "        fResID  = %hd\n", entityInfos[i].fIcon.fResID);
                
                err = DumpEntity(ref, entityRefs[i]);
                if (err != noErr) {
                    break;
                }
            }
        }
        
        err2 = OTCfgCloseArea(ref, thisArea);
        if (err == noErr) {
            err = err2;
        }
    }
 
    if (entityRefs != nil) {
        DisposePtr( (Ptr) entityRefs);
        MoreAssertQ(MemError() == noErr);
    }
    if (entityInfos != nil) {
        DisposePtr( (Ptr) entityInfos);
        MoreAssertQ(MemError() == noErr);
    }
    return err;
}
 
static OSStatus DumpDatabaseToFile(void)
{
    OSStatus err;
    OSStatus err2;
    CfgDatabaseRef ref;
    ItemCount areaCount;
    CfgAreaID currentArea;
    ItemCount i;
    CfgAreaID *areas;
    Str255 *areaNames;
    
    areas = nil;
    areaNames = nil;
    
    err = OTCfgOpenDatabase(&ref);
    if (err == noErr) {
        err = OTCfgGetAreasCount(ref, &areaCount);
        if (err == noErr) {
            areas = (CfgAreaID *) NewPtr( areaCount * sizeof(CfgAreaID) );
            err = MemError();
        }
        if (err == noErr) {
            areaNames = (Str255 *) NewPtr( areaCount * sizeof(Str255) );
            err = MemError();
        }
        if (err == noErr) {
            err = OTCfgGetAreasList(ref, &areaCount, areas, areaNames);
        }
        
        if (err == noErr) {
            err = OTCfgGetCurrentArea(ref, &currentArea);
        }
        
        if (err == noErr) {
            for (i = 0; i < areaCount; i++) {
                fprintf(gOutput, "Dumping area %ld Ò%#sÓ\n", areas[i], areaNames[i]);
                if ( OTCfgIsSameAreaID(currentArea, areas[i]) ) {
                    fprintf(gOutput, "  <current area>\n");
                }
                err = DumpArea(ref, areas[i]);
                if (err != noErr) {
                    break;
                }
            }
        }
    
        err2 = OTCfgCloseDatabase(&ref);
        if (err == noErr) {
            err = err2;
        }
    }
    if (areas != nil) {
        DisposePtr( (Ptr) areas);
        MoreAssertQ(MemError() == noErr);
    }
    if (areaNames != nil) {
        DisposePtr( (Ptr) areaNames);
        MoreAssertQ(MemError() == noErr);
    }
    return err;
}
 
static void InitToolbox(void)
{
    InitGraf(&qd.thePort);
    InitFonts();
    InitWindows();
    InitMenus();
    TEInit();
    InitDialogs(nil);
    MaxApplZone();
    MoreMasters();
    MoreMasters();
    MoreMasters();
}
 
extern void main(void)
{
    OSStatus err = noErr;
    StandardFileReply reply;
 
    InitToolbox();
 
    StandardPutFile("\pSave Network Setup database as text:", "\pNetworkSetup.txt", &reply);
    if (reply.sfGood) {
        (void) FSpDelete(&reply.sfFile);
        gOutput = FSp_fopen(&reply.sfFile, "w");
        if (gOutput == nil) {
            err = -1;
        }
        if (err == noErr) {
            err = DumpDatabaseToFile();
 
            (void) fclose(gOutput);
        }
        if (err != noErr) {
            printf("Failed with error %ld.\n", err);
        }
        
    }
}