OTCheckNetForNBPName.c

/*
 *  
 *  File: OTCheckNetForNBPName.c
 *          Sample code to demonstrate how to check for an AppleTalk NBPName on a
 *          network. The sample works by first determining the number of zones that
 *          will be searched.
 */
 
//#define DEBUG 1
//#define TARGET_API_MAC_CARBON 1
 
#include <Types.h>
#include <Events.h>
#include <Windows.h>
#include <Memory.h>
#include <Resources.h>
#include <Errors.h>
#include <OSUtils.h>
#include <String.h>
#include <Gestalt.h>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <OpenTransport.h>
#include <OpenTptAppleTalk.h>
#include "OTCheckNetForNBPName.h"
 
// static globals here
static ATSvcRef         gOTSvcRef   = nil;
static MapperRef        gOTMapper   = nil;
static UInt32           gNumZones   = 0;
static UInt32           gMatchesFound = 0;
static UInt32           gNextLookup = 0;
static UInt32           gNumLookupsCompleted = 0;
static OTNameID         gMyNameID   = 0;
static TLookupRequest   *gLookupReqPtr = nil;
static MyLookupReply    *gLookupReplyPtr = nil;
static ZoneBufPtr       gZoneBufPtr  = nil;
static NBPEntity        *gNBPEntityPtr;
static Boolean          gDone = false;
static Boolean          gTriggerAction = false;
static Boolean          gNameRegistered = false;
static OTNotifyUPP      gNotifier = nil;
 
static UInt8            gNameToSearchFor[33] = "MyName";
static UInt8            gTypeToSearchFor[33] = "MyEntity";
static UInt8            gNameToRegister[33] = "MyName";
static UInt8            gTypeToRegister[33] = "MyEntity";
static UInt8            gNameBuf[100];
 
 
 
//
//  Prototypes here
//
 
extern      OSStatus DoNegotiateSelfSendOption(EndpointRef ep, long enableSelfSend);
OSStatus    ActivateCheckNetStuff(void);
void        CleanupNetStuff(void);
void        CleanupLookupStuff(void);
UInt32      GetNumZonesToCheckFor(void);
UInt32      CountZonesFromUnpackedBuffer(UInt8 *buffer, long len);
UInt32      MoveZonesToUnpackedBuffer(UInt8 *packedBuffer, ZoneBufPtr zoneBufPtr, long len);
OSStatus    DoOTGetZoneList(void);
OSStatus    SetNameMatchString(Str32 *matchString);
OSStatus    SetTypeMatchString(Str32 *matchString);
OSStatus    SetNameRegisterString(Str32 *registerString);
OSStatus    SetTypeRegisterString(Str32 *registerString);
UInt32      GetNumberOfActiveLookups(void);
UInt32      GetNumberOfEntitiesPerZone(void);
UInt32      GetLookupTimeout(void);
UInt32      GetEntitySize(Str32 *nameString, Str32 *typeString);
OSStatus    InitiateLookupStuff(Str32 *nameString, Str32 *typeString);
OSStatus    MakeOTLookupCall(UInt32 indx, UInt32 lindx, Str32 *nameString, Str32 *typeString);
OSStatus    OTRegisterMyName (void);
void        OTDeleteMyName (void);
OSStatus    DoLookupTest(void);
short       clen(char *cptr);
void        c2p(char *cptr);
UInt16      OTMySetNBPEntity(char *buffer, Ptr nbpObject, Ptr nbpType, Ptr nbpZone);
pascal void MyNBPHandler(void* contextPtr, OTEventCode event, OTResult result, void* cookie);
void        DoEvent(EventRecord *event);
 
 
OSStatus ActivateCheckNetStuff(void)
{
    OSStatus        err = noErr;
    
    if (gOTSvcRef == nil)
    {
            // open the appletalk services provider
        gOTSvcRef = OTOpenAppleTalkServicesInContext(OTCreateConfiguration(kZIPName), 0, &err, nil);
    }
    if (err)
        fprintf(stdout, "error %d occurred on call to OTOpenAppleTalkServicesInContext\n", err);
    else
        fprintf(stdout, "OTOpenAppleTalkServicesInContext worked \n");
 
    if ((err == noErr) && (gOTMapper == nil))
    {
        
            // open an NBP Mapper service provider
        gOTMapper = OTOpenMapperInContext(OTCreateConfiguration(kNBPName), 0, &err, nil);
 
        
        if (err == noErr) 
        {
            if (gNotifier == nil)
            {
                gNotifier = NewOTNotifyUPP(MyNBPHandler);
                if (gNotifier == nil)
                {
                    err = memFullErr;
                    fprintf(stdout, "NewOTNotifyUPP failed \n");
                }
            }
            
            if (gNotifier)
            {
                    // install notifier for the mapper
                    // note that since OpenTransport sets the A5 world for a 68K handler,
                    // we don't need to mess with saving/setting/restoring A5 - yea!!
                err = OTInstallNotifier(gOTMapper, gNotifier, nil);
            }
        }
        else
        {
            fprintf(stdout, "error %d occurred on call to OTOpenMapperInContext\n", err);
        }
 
    }
    
    fflush(stdout);
    return err;
 
}
 
/*
    Cleanup what we opened in the ActivateCheckNetStuff routine - this routine also frees up the 
    memory associated with the zone list. It also checks whether an entity has been registered and
    deletes it.
*/
void CleanupNetStuff(void)
{
    if (gZoneBufPtr)
    {
        OTFreeMem(gZoneBufPtr);
        gZoneBufPtr = nil;
    }
 
    if (gOTSvcRef)
    {
        OTCloseProvider(gOTSvcRef);
        gOTSvcRef = nil;
    }
    
    if (gOTMapper)
    {
        if (gNameRegistered == true)
        {
            OTDeleteMyName();
            gNameRegistered = false;
        }
            
        OTCloseProvider(gOTMapper);
        gOTMapper = nil;
    }
    
    if (gNotifier)
    {
        DisposeOTNotifyUPP(gNotifier);
        gNotifier = nil;
    }
}
 
/*
    Cleanup what we opened in the InitiateLookup routine 
*/
void CleanupLookupStuff(void)
{
    if (gLookupReqPtr)
    {
        OTFreeMem(gLookupReqPtr);
        gLookupReqPtr= nil;
    }
 
    if (gLookupReplyPtr)
    {
        OTFreeMem(gLookupReplyPtr);
        gLookupReplyPtr = nil;
    }
 
    if (gNBPEntityPtr)
    {
        OTFreeMem(gNBPEntityPtr);
        gNBPEntityPtr = nil;
    }
}
 
/*
    CountZonesFromUnpackedBuffer takes a input the zone name buffer and the valid length of the
    buffer contents and returns the number of zone names in the buffer
*/
UInt32 CountZonesFromUnpackedBuffer(UInt8 *buffer, long len)
{
    long    index = 0L;
    short   i = 0;
    
    while (index < len) 
    {
        index += (char)((Ptr)buffer+index)[0]+1L;
        i++;
    }
    return i;
}
 
/*
    MoveZonesToUnpackedBuffer takes as input the zone name buffer and the valid length of the
    buffer contents and moves the zones names into the ZoneBufPtr array elements.
    the zoneBufPtr will be an array of Pascal strings
*/
UInt32 MoveZonesToUnpackedBuffer(UInt8 *packedBuffer, ZoneBufPtr zoneBufPtr, long len)
{
    long    index = 0L;
    short   i = 0;
    
    while (index < len) 
    {
        BlockMoveData((Ptr)packedBuffer+index, (Ptr)&zoneBufPtr[i].zoneName, zoneNameSize);
        index += (char)((Ptr)packedBuffer+index)[0]+1L;
        i++;
    }
    return i;
}
 
/*
    GetNumZonesToCheckFor returns the number of zones to start checking for. The smaller the number the more you may have to 
    search until all of the zones are read
*/
UInt32  GetNumZonesToCheckFor(void)
{
        // could store this in a resource and obtain the value here.
    return kNumZonesToCheckFor;
}
 
/*
    DoOTGetZoneList repeatedly calls OTAtalkGetZoneList until kOTBufferOverflowErr is no longer
    returned, which indicates that the provided buffer was too small for the number of AppleTalk zones present.
    Note that the global gZoneBufPtr is allocated here and is not de-allocated until the CleanupNetStuff call.
*/
OSStatus DoOTGetZoneList(void)
{
    TNetbuf     reply;
    OSStatus    err = noErr;
    UInt8       *packedzonebuffptr = nil;
    UInt32      numZonesToCheckFor;
    short       increment = 0;
    Boolean     done = false;
    
    numZonesToCheckFor = GetNumZonesToCheckFor();
        // set up to loop until we have a buffer big enough to hold all of the returned zones
    while (done == false)
    {
        numZonesToCheckFor += increment;
        
        if (packedzonebuffptr != nil)
            OTFreeMem(packedzonebuffptr);
            
        packedzonebuffptr = OTAllocMemInContext(numZonesToCheckFor * zoneNameSize, nil);
 
        if (packedzonebuffptr != nil)
        {
            reply.buf = packedzonebuffptr;
            reply.maxlen = numZonesToCheckFor * zoneNameSize;
                // by default, the AtalkServiceProvider is in synchronous mode
            err = OTATalkGetZoneList(gOTSvcRef, &reply);
            if (err == kOTBufferOverflowErr)
            {
                fprintf(stdout, "Buffer Overflow error occurred with numZonesToCheckFor = %d\n", numZonesToCheckFor);
                    // reset the err to noErr
                err = noErr;
                increment = numZonesIncrement;
            }
            else if( err == noErr)
            {
                done = true;
            }
            else
            {
                done = true;
                fprintf(stdout, "error %d occurred on call to OTATalkGetZoneList\n", err);
                
            }
                
        }
        else
        {
            done = true;
            fprintf(stdout, "mem error occurred while allocating packedzonebuffptr for %d zones\n", numZonesToCheckFor);
            err = memFullErr;
        }
    }
    
    if (err == noErr)
    {
        gNumZones = CountZonesFromUnpackedBuffer(packedzonebuffptr, reply.len);
        fprintf(stdout, "There are %d zones detected\n", gNumZones);
            // allocate the memory for the zone list structure
            // check first if any zones were found
        if (gNumZones == 0)
            gZoneBufPtr = (ZoneBufPtr)OTAllocMemInContext(sizeof(ZoneBuffer), nil);
        else
            gZoneBufPtr = (ZoneBufPtr)OTAllocMemInContext(gNumZones * sizeof(ZoneBuffer), nil);
            
        if (gZoneBufPtr == nil)
        {
            fprintf(stdout, "mem error occurred while allocating ZoneBuffer array for %d zones\n", numZonesToCheckFor);
            err = memFullErr;
        }
        else
        {
            if (gNumZones == 0)
            {
                gZoneBufPtr->zoneName[0] = 1;
                gZoneBufPtr->zoneName[1] = '*';
                gZoneBufPtr->zoneName[2] = 0;
                gNumZones = 1;
            }
            else
                MoveZonesToUnpackedBuffer(packedzonebuffptr, gZoneBufPtr, reply.len);
        }
    }
    
        // we're done with the packedzonebuffptr, so lets get rid of it.
    if (packedzonebuffptr != nil)
        OTFreeMem(packedzonebuffptr);
    
    return err;
}
 
/*
    SetNameMatchString is where you set the name string that the program will search for among the zones.
    replace this code with that where you define the NBP name string to search for
*/
OSStatus SetNameMatchString(Str32 *matchString)
{
    BlockMoveData((Ptr)gNameToSearchFor, (Ptr)matchString, clen((char*)gNameToSearchFor)+1);
    c2p((char*)matchString);
    return noErr;
}
 
/*
    SetTypeMatchString is where you set the type string that the program will search for among the zones.
    replace this code with that where you define the NBP type string to search for
 
*/
OSStatus SetTypeMatchString(Str32 *matchString)
{
    BlockMoveData((Ptr)gTypeToSearchFor, (Ptr)matchString, clen((char*)gTypeToSearchFor)+1);
    c2p((char*)matchString);
    return noErr;
}
 
/*
    SetNameRegisterString is where you set the name string that the program will register with NBP
*/
OSStatus SetNameRegisterString(Str32 *registerString)
{
    BlockMoveData((Ptr)gNameToRegister, (Ptr)registerString, clen((char*)gNameToRegister)+1);
    c2p((char*)registerString);
    return noErr;
}
 
/*
    SetTypeMatchString is where you set the type string that the program will search for among the zones.
 
*/
OSStatus SetTypeRegisterString(Str32 *registerString)
{
    BlockMoveData((Ptr)gTypeToRegister, (Ptr)registerString, clen((char*)gTypeToRegister)+1);
    c2p((char*)registerString);
    return noErr;
}
 
/*
    GetNumberOfActiveLookups returns the number of simultaneous lookups that are active at one time.  The more you do at
    one time, the faster you get the search done.  On the other hand, doing to many lookups at once may flood the
    network.  GetNumberOfActiveLookups allows you to define how many lookups are active at the same time.
 
*/
UInt32 GetNumberOfActiveLookups(void)
{
    if (gNumZones <= kMaxActiveLookups)
    {
        // if there are no zones
        if (gNumZones == 0)
            return 1;
        else
            return gNumZones;
    }
    else return kMaxActiveLookups;
}
 
/*
    GetNumberOfEntitiesPerZone returns the maximum number of matches that I want to look for in a zone.  If multiple matches are
    permitted, then you have to face the possibility that the maximum number of matches might exist in the same zone.
*/
UInt32 GetNumberOfEntitiesPerZone(void)
{
    return 1;
}
 
/*
    return the lookup timeout value that the program will use
*/
UInt32 GetLookupTimeout(void)
{
    return kDefaultTimeout;
}
 
/*
    GetEntitySize returns the entity size to use
    Note that we have only allocated a "minimum" size entity array rather than a full 
    size array, in order to reduce the memory allocation requirement.  Since we do this
    we can't treat the entity array as a simple array.  In order to access each element
    we have to take the size of each element, multiply that value against the array index
    for the element and add the result to the base pointer to get each array element.
*/
UInt32 GetEntitySize(Str32 *nameString, Str32 *typeString)
{
    UInt8   *c1, *c2;
    
    c1 = (UInt8*)nameString;
    c2 = (UInt8*)typeString;
            
//  return (c1[0] + c2[0] + 16);
    return (kNBPEntityBufferSize + 8);
}
 
/*
    Set up the lookup arrays that we will need for the NBP lookups.  The request, reply and
    entity structures cannot go away while the lookup is active since we are making them asynchronously
    
*/
OSStatus InitiateLookupStuff(Str32 *nameString, Str32 *typeString)
{
    UInt32      numLookupsActive;
    UInt32      entitySize;
    UInt32      numEntitiesPerZone;
    OSStatus    err;
    short       i;
    
    numLookupsActive = GetNumberOfActiveLookups();
    
#ifdef DEBUG
    DebugStr("\p about to allocate memory");
#endif
 
    gLookupReqPtr = (TLookupRequest*) OTAllocMemInContext(numLookupsActive * sizeof(TLookupRequest), nil);
    gLookupReplyPtr = (MyLookupReply*) OTAllocMemInContext(numLookupsActive * sizeof(MyLookupReply), nil);
    
    if ((gLookupReqPtr != nil) && (gLookupReplyPtr != nil))
    {
        err = noErr;
        
            // figure out the max number of entities we want to match on in a zone.  If we want to find any
            // duplicate of a name, then return 1.  But if we allow more than one entity at all, then plan on
            // that maximum number existing in the same zone.
        numEntitiesPerZone = GetNumberOfEntitiesPerZone();
 
            // figure out how much memory to allocate for the entity buffer.
            // since we know the name and type strings, we can figure their length and add the max zone string
            // length instead of allocating the full max entity length string
            // make sure to also add space for the address, plus the 4 bytes at the beginning of each response
            // which is for the 2 length values - total of 8 bytes.
        entitySize = GetEntitySize(nameString, typeString);
        
            // allocate the entityptr array.  Note that we will use the same entity structure for input and 
            // potential output
        gNBPEntityPtr = (NBPEntity*) OTAllocMemInContext(numLookupsActive * entitySize * numEntitiesPerZone, nil);
        if (gNBPEntityPtr == nil)
            err = memFullErr;
    }
    else
        err = memFullErr;
        
    
    if (err == noErr)
    {
        for (i = 0; i < numLookupsActive;)
        {
            gLookupReplyPtr[i].index = i;
            i++;
        }
        
            // we initiate all of the lookups in the following loop, however, if there are more lookups than
            // we have lookuprequests in the array, then set the gNextLookup indice to numLookupsActive
            // so that this will be where we begin other lookups if the entity is not found.
        gNextLookup = numLookupsActive;
        
            // set the gOTMapper endpoint to operate asynchronously
        OTSetAsynchronous(gOTMapper);
        
        for (i = 0; (gDone == false) && (i < numLookupsActive);)
        {
            err = MakeOTLookupCall(i, i, nameString, typeString);
            i++;
        }
    }
    return err;
    
}
 
/*
    MakeOTLookupCall is where we make the zone specific Lookup call.
    input parameters
        indx - index into the gLookupReqPtr, gNBPEntityPtr, and the gLookupReplyPtr arrays
        lindx - index into the gZoneBufPtr where we get the zone where we will perform the next lookup
        nameString - pascal name string
        typeString - pascal type string
*/
 
OSStatus MakeOTLookupCall(UInt32 indx, UInt32 lindx, Str32 *nameString, Str32 *typeString)
{
    OSStatus    err;
    UInt32      entitySize;
    UInt32      numEntitiesPerZone;
    char*       entityPtrToUse;
 
    
        // figure out the max number of entities we want to match on in a zone.  If we want to find any
        // duplicate of a name, then return 1.  But if we allow more than one entity at all, then plan on
        // that maximum number existing in the same zone.
    numEntitiesPerZone = GetNumberOfEntitiesPerZone();
    
        // figure out how much memory to allocate for the entity buffer.
        // since we know the name and type strings, we can figure their length and add the max zone string
        // length instead of allocating the full max entity length string
    entitySize = GetEntitySize(nameString, typeString);
    
    OTMemset(&gLookupReqPtr[indx], 0, sizeof(TLookupRequest));
        // set up the lookup request record
    gLookupReqPtr[indx].maxcnt = numEntitiesPerZone;
    gLookupReqPtr[indx].timeout = GetLookupTimeout();
        // figure out where the the pointer is in the array to use.
    entityPtrToUse = (char*) ((UInt32) gNBPEntityPtr + indx * entitySize * numEntitiesPerZone);
    
    gLookupReqPtr[indx].name.len = (size_t)OTMySetNBPEntity(entityPtrToUse, 
                                (char*)nameString, (char*)typeString, (char*)&gZoneBufPtr[lindx].zoneName);
    gLookupReqPtr[indx].name.buf = (unsigned char*)entityPtrToUse;
    
    gLookupReqPtr[indx].addr.len = 0;
    gLookupReqPtr[indx].addr.buf = nil;
    gLookupReqPtr[indx].addr.maxlen = 0;
    
        // set up the lookup reply record
    gLookupReplyPtr[indx].lkReply.names.maxlen = numEntitiesPerZone * entitySize;
    gLookupReplyPtr[indx].lkReply.names.len = 0;
    gLookupReplyPtr[indx].lkReply.names.buf = (unsigned char*)entityPtrToUse;
    gLookupReplyPtr[indx].lkReply.rspcount = 0;
 
    gLookupReplyPtr[indx].lindex = lindx;
    
        // make the lookup call
    err = OTLookupName(gOTMapper, &gLookupReqPtr[indx], (TLookupReply*)&gLookupReplyPtr[indx]);
    if (err != noErr)
    {
#ifdef DEBUG
            // this call can be made at deferred task time, so we can't make a call that
            // might allocate memory
        DebugStr("\p Error occurred making OTLookupName call");
#endif
    }
    return err;
}
 
/*******************************************************************************
** Register my name using Open Transport
********************************************************************************/
OSStatus OTRegisterMyName (void)
{
    TRegisterRequest regreq;
    TRegisterReply  regreply;
    OSErr           err;
    Str32           nameString;
    Str32           typeString;
        
    err = SetNameRegisterString(&nameString);
 
    if (err == noErr)
    {
        err = SetTypeRegisterString(&typeString);   
    }
        // create the NBP name string and set the len field for the string
        // and register in the local zone
    regreq.name.len = OTMySetNBPEntity((char*)gNameBuf, (Ptr)&nameString, (Ptr)&typeString, (Ptr)"\p*");
    regreq.name.buf = gNameBuf;
    
        // let the system define the network address for this name
    regreq.addr.len = regreq.addr.maxlen = 0;
    regreq.addr.buf = NULL;
    
        // set up regreply
    regreply.addr.maxlen = 0;
    regreply.addr.buf = nil;
        
    OTSetSynchronous(gOTMapper);
    err = OTRegisterName(gOTMapper, &regreq, &regreply);
    if (err == noErr)
    {
        gMyNameID = regreply.nameid;
        gNameRegistered = true;
    }
    
    return err;
}
 
/*******************************************************************************
** Delete my name using Open Transport
********************************************************************************/
void OTDeleteMyName (void)
{   
    OTSetSynchronous(gOTMapper);
    OTDeleteNameByID(gOTMapper, gMyNameID);
    gNameRegistered = false;    
}
 
OSStatus DoLookupTest(void)
{
    EventRecord     theEvent;
    OSStatus        err;
    Str32           nameString;
    Str32           typeString;
    long            ticks;
    Boolean         watchTrigger = true;
 
        // we start the lookup test here by getting the NBP name and type to look for
    err = SetNameMatchString(&nameString);
    
    if (err == noErr)
    {
        err = SetTypeMatchString(&typeString);
    }
 
        // we start the asynch lookup process here.
    if (err == noErr)
    {
        err = InitiateLookupStuff(&nameString, &typeString);
    }
    
        // we sit in a WNE (WaitNextEvent) loop for the search to complete.
    if (err == noErr)
    {
        ticks = TickCount() + 300;
        printf("Use Command-Q to quit.\n");
        
        while (gDone == false)
        {
            ticks++;
            if (!WaitNextEvent(everyEvent, &theEvent, 15, nil))
                theEvent.what = nullEvent;
                
            DoEvent(&theEvent);
 
            if (ticks < TickCount())
            {
                ticks = TickCount() + 300;
                fprintf(stdout, "%d/%d ", gMatchesFound, gNumLookupsCompleted);
                fflush(stdout);
            }
            
            if (watchTrigger == true)
            {
                if (gTriggerAction == true)
                {
                    fprintf(stdout, "\n Too many matches were found \n");
                    fflush(stdout);
                    watchTrigger = false;
                }
            }
            
            if (gNumLookupsCompleted >= gNumZones)
            {
                gDone = true;
                fprintf(stdout, "\nThere were %d matches found in %d zones\n\n", gMatchesFound, gNumLookupsCompleted);
                fflush(stdout);
            }
            
        }
        CleanupLookupStuff();
    }
    return err;
}
 
int main(void)
{
    OSStatus        err;
            
    printf ("Sample Program: OTCheckNetForNBPName!\n\n");
    
    err = InitOpenTransportInContext(kInitOTForApplicationMask, nil);
 
    if (err != noErr)
    {
        printf ("InitOpenTransport failed with error %d\n", err);
        return err;
    }
    else
        printf ("InitOpenTransportInContext worked!\n\n");
    
    err = ActivateCheckNetStuff();
    if (err != noErr)
    {
        fprintf(stdout, "ActivateCheckNetStuff returned error %d.\n", err);
    }
    fflush(stdout);
    
    if (err == noErr)
    {
        fprintf(stdout, "Checking for the number of zones present.\n");
        fflush(stdout);
        err = DoOTGetZoneList();
        if (err != noErr)
        {
            fprintf(stdout, "DoOTGetZoneList returned error %d.\n", err);
        }
    }
    
        if (err == noErr)
        {
            fprintf(stdout, "Beginning the lookup test.\n");
            fflush(stdout);
            err = DoLookupTest();
        }
    
    if ((err == noErr) && (gNumLookupsCompleted < gNumZones))
    {
        fprintf(stdout, "\nYou stopped the lookup test before all of the lookups were complete!\n");
        fprintf(stdout, "Am closing the mapper endpoint to clear all outstanding lookups.\n");
            // close the mapper endpoint and reopen it
        OTCloseProvider(gOTMapper);
        gOTMapper = nil;
        fprintf(stdout, "Am reopening the mapper endpoint.\n");
        err = ActivateCheckNetStuff();
    }
    
    if (err == noErr)
    {
        fprintf(stdout, "Am registering a new NBP entity\n");
        fflush(stdout);
 
        err = OTRegisterMyName();
        if (err)
            fprintf(stdout, "Error occurred registering the name %d\n", err);
        else
        {
            fprintf(stdout, "\nEntity successfully registered\n");
            // the following code will enable SelfSend mode globally on the machine
            // otherwise it is only enabled for this process
            OTSetSynchronous(gOTMapper);
            err = DoNegotiateSelfSendOption(gOTMapper, 1);
            if (err == 1)
            {
                fprintf(stdout, "self send previously enable\n");
                    // reset err
                err = noErr;
            }
            else
            {
                fprintf(stdout, "Error occurred negotiating self send %d\n", err);
                fprintf(stdout, "Quitting program\n");
            }
        }
    }
    fflush(stdout);
        
    if (err == noErr)
    {
        fprintf(stdout, "\nPerforming the next lookup for the new entity\n");
        fflush(stdout);
            // reset gDone and try the lookup test again
        gDone = false;
        gNumLookupsCompleted = 0;
        err = DoLookupTest();
    }
    
    CleanupLookupStuff();
    
    CleanupNetStuff();
 
    CloseOpenTransportInContext(nil);
        
    fprintf(stdout, "\nTest ended\n");
    return 0;
}
 
/*****************************************************************************/
/* Convert a c-string to a pascal-string. */
short   clen(char *cptr)
{
    short   i;
 
    for (i = 0; cptr[i]; ++i) {};
    return(i);
}
 
/*****************************************************************************/
void    c2p(char *cptr)
{
    char    len;
 
    BlockMove(cptr, cptr + 1, len = clen(cptr));
    *cptr = len;
}
 
/*
    OTMySetNBPEntity is used to set up an NBP lookup query buffer.
    All input strings are assumed to be pascal strings
*/
UInt16 OTMySetNBPEntity(char *buffer, Ptr nbpObject, Ptr nbpType, Ptr nbpZone)
{
    char*   bufPtr;
    UInt16  len;
    
    bufPtr = buffer;
 
    BlockMove((Ptr)&nbpObject[1], bufPtr, nbpObject[0]);
    bufPtr += nbpObject[0];     // point buffer to end of current string
    len = nbpObject[0];         // collect number of chars moved to buffer
 
        // add the ":" character between the object and type strings
    *bufPtr = ':';
    bufPtr++;
    len++;
 
    BlockMove((Ptr)&nbpType[1], bufPtr, nbpType[0]);
    bufPtr += nbpType[0];       // point buffer to end of current string
    len += nbpType[0];          // collect number of chars moved to buffer
    
        // add the "@" character between the type and zone strings
    *bufPtr = '@';
    bufPtr++;
    len++;
 
    BlockMove((Ptr)&nbpZone[1], bufPtr, nbpZone[0]);
    len += nbpZone[0];          // collect number of chars moved to buffer
    return len; 
}
 
 
/*******************************************************************************
** HandleMapperEvents TMapper (NBP) Event Handling
********************************************************************************/
 
 
pascal void MyNBPHandler(void* contextPtr, OTEventCode event, OTResult result, void* cookie)
{
#pragma unused (contextPtr)
 
    MyLookupReplyPtr    myReplyPtr;
    OSStatus            err;
    UInt32              indx;
    Boolean             dolookup = false;
    Str32               nameString;
    Str32               typeString;
    
    switch (event)
    {
        case T_LKUPNAMERESULT:      // intermediate result notification
            break;
            
        case T_LKUPNAMECOMPLETE:
#ifdef DEBUG
            DebugStr("\p about to set gNumLookupsCompleted");
#endif
            gNumLookupsCompleted++;
                // in a lookupcomplete event, the cookie is a OTLookupReply ptr.
            myReplyPtr = (MyLookupReplyPtr)cookie;
            
            if ((result == kOTBufferOverflowErr) ||
                (result == noErr))
            {
                gMatchesFound += myReplyPtr->lkReply.rspcount;
                dolookup = true;
                if (gMatchesFound > GetNumberOfEntitiesPerZone())
                    gTriggerAction = true;
            }
            
            if (result == kOTNoDataErr)
                dolookup = true;
            
            if (dolookup == true)
            {
                if (gNextLookup < gNumZones)
                {
                    indx = myReplyPtr->index;
                    if (indx >= kMaxActiveLookups)
                    {
#ifdef DEBUG
                        DebugStr("\p about to set gNumLookupsCompleted");
#endif
                    }
                    else
                    {
                        SetNameMatchString(&nameString);
                        SetTypeMatchString(&typeString);
                        err = MakeOTLookupCall(indx, gNextLookup, &nameString, &typeString);
                            // increment the lookup index in to the zone array for the next
                            // zone to look into.
                        gNextLookup++;
                    }
                }
            }
            else
            {
#ifdef DEBUG
                DebugStr("\p T_LKUPNAMECOMPLETE: Unexpected error");
#endif
            }
 
            break;
            
        case T_REGNAMECOMPLETE:
            break;
            
        case T_DELNAMECOMPLETE:
            break;
            
        default:
#ifdef DEBUG
            DebugStr("\pHandleMapperEvents: Unexpected Event!;g");
#endif
            break;
    }
}
 
void    DoEvent(EventRecord *event)
{
    char    key;
 
    switch(event->what) 
    {
 
        case nullEvent:
        case mouseDown:
        case activateEvt:
        case updateEvt:
        case kHighLevelEvent:
        case osEvt:
        case diskEvt:
            break;
 
        case autoKey:
        case keyDown:
            key = event->message & charCodeMask;
            switch (key)
            {
                case 'q':
                case 'Q':
                    if (event->modifiers & cmdKey)
                    gDone = true;
                    break;
            }
            break;
 
    }
 
}