/***************************************************************** Program: < ADSP Chat > File: < Atalk.c > Written by Pete Helm, Scott Kuechle of modified by Scott Kuechle 10/92 SRK Converted from Pascal to C 8/94 SRK Modified to use a queue of parameter blocks. Copyright © 1992, 1994 Apple Computer, Inc. All rights reserved. *****************************************************************/ /*****************************************************************/ /* I N C L U D E S /*****************************************************************/ #include "ADSP Chat.h" /******************************************************************** /* G L O B A L V A R I A B L E D E C L A R A T I O N S /********************************************************************/ ATPPBPtr gATPPBPtr; /* the parameter block for GetZoneList call */ XPPParmBlkPtr gXPBPBPtr; /* structure for Phase 2 NBP lookups */ short xppDriverRefNum; Str255 gZoneString, gObjStr, gTypeStr; Str32 myName; NamesTableEntry myNTE; AddrBlock theBridgeAddress, ourNetworkAddress; /*****************************************************************/ /* /* E X T E R N A L S /* /*****************************************************************/ extern SysEnvRec gMac; /* set up by Initialize */ extern char myLocalSocket; extern void ShowError(short index); extern void CopyPstr(Ptr pSource, Ptr pDest); extern void Terminate(); extern void Exit(short message); extern qsort (Ptr base, long n, long size, ProcPtr compare); /*****************************************************************/ /* /* R O U T I N E S /* /*****************************************************************/ Boolean registerMyName(); void removeMyName(); long myCompare (Str255 aStr, Str255 bStr); void letsSort (Ptr theBuffPtr, long numZonesGot); void addZonesToBuffer (Ptr LkUpBuffer, Ptr BufferForZoneMenu, short NumZonesGot, short CurrentTotal); void parseItemsAddToMenu (Ptr theBuffPtr, MenuHandle zoneMenu, short NumZonesGot);; Boolean zonesPresent(); void parseLkupBuffAddToMenu (Ptr theBuffPtr, Ptr bigBuffer, MenuHandle lookupMenu, short NumGot, Boolean doObjects); void LookupNames (MenuHandle lookupMenu, Boolean doObjects); void BuildZoneListPhase1(MenuHandle zoneMenu); void BuildZoneListPhase2(MenuHandle zoneMenu); void GetZones(MenuHandle ZoneMenu); void getOurZonePhase2(); void getOurZonePhase1(); OSErr InitAppleTalk(); void GetOurZone(); #pragma segment Main // ***************************************************************** // * registerMyName // * // * registers our nbp name on the network so we can find other // * machines that are running our application. // ***************************************************************** Boolean registerMyName() { MPPParamBlock pb; StringHandle userName; userName = GetString(-16096); myName[0] = 0; if (userName != nil) { if (*userName[0] != 0) BlockMove(*userName,&myName,*userName[0]+1); } NBPSetNTE((Ptr)&myNTE, &myName, "\pMoof", "\p*", myLocalSocket); pb.NBP.interval = 2; pb.NBP.count = 3; pb.NBP.NBPPtrs.entityPtr = (Ptr)&myNTE; pb.NBP.parm.verifyFlag = 1; if (PRegisterName(&pb,false) != noErr) { ShowError(nbpErr); return false; } return true; } // ***************************************************************** // * removeMyName // * // * removes our nbp name from the network. // ***************************************************************** void removeMyName() { MPPParamBlock pb; OSErr err; pb.NBP.NBPPtrs.entityPtr = (Ptr)&myNTE.nt.entityData; err = PRemoveName(&pb, false); } // ***************************************************************** // * myCompare // * // * this uses stand International Utilites package for sorting // ***************************************************************** long myCompare (Str255 aStr, Str255 bStr) { return ((long)IUCompString(bStr, aStr)); } // ***************************************************************** // * letsSort // * // * calls a standard C qSort routine compiled with Pascal calling // * conventions the 33 is the standard size of a Str32 type, which // * is the standard size of an AppleTalk NBP object. // ***************************************************************** void letsSort (Ptr theBuffPtr, long numZonesGot) { qsort(theBuffPtr, numZonesGot, 33, &myCompare); } // ***************************************************************** // * addZonesToBuffer // * // * // ***************************************************************** void addZonesToBuffer (Ptr LkUpBuffer, Ptr BufferForZoneMenu, short NumZonesGot, short CurrentTotal) { char curLength; long index; short i; index = 0; curLength = 0; for (i=CurrentTotal;i<=(NumZonesGot + CurrentTotal) && (i < maxZones);++i) { curLength = *(LkUpBuffer + index); BlockMove((LkUpBuffer + index), (BufferForZoneMenu + (i * 33)), 33); index = index + curLength + 1; } } // ***************************************************************** // * parseItemsAddToMenu // * // * this routine adds zone name items to our zones popup menu // ***************************************************************** void parseItemsAddToMenu (Ptr theBuffPtr, MenuHandle zoneMenu, short NumZonesGot) { long index; Str255 tempString; short i; letsSort(theBuffPtr, NumZonesGot); index = 0; for (i=0; i<=(NumZonesGot - 1); ++i) { BlockMove((theBuffPtr + i * 33), &tempString, 33); /* initially insert a blank item so meta-characters aren't used */ AppendMenu(zoneMenu, "\p "); /* use SetItem so we can display meta-chars in zone names */ SetItem(zoneMenu, i + 1, tempString); } } // ***************************************************************** // * zonesPresent // * // * this checks to see if there is a local bridge available // ***************************************************************** Boolean zonesPresent() { short myNode,ignore; theBridgeAddress.aNode = 0; theBridgeAddress.aNode = GetBridgeAddress(); ignore = GetNodeAddress(&myNode, &ourNetworkAddress.aNet); ourNetworkAddress.aNode = myNode; theBridgeAddress.aNet = ourNetworkAddress.aNet; if (ourNetworkAddress.aNode != 0) { theBridgeAddress.aSocket = theBridgeSocket; return true; } else { CopyPstr("\p*", &gZoneString); return false; } } // ***************************************************************** // * parseLkupBuffAddToMenu // * // * this routine takes all the names returned from the nbp lookup // * and checks to see if the item is already in the list. If not, // * the item is added to the appropriate popup menu. // ***************************************************************** void parseLkupBuffAddToMenu (Ptr NamesReturnedBuffer, /* lookup buffer where names were returned */ Ptr NonDuplicateNamesBuffer, /* check for duplicates then store all names here */ MenuHandle lookupMenu, short NumGot, /* number of items returned in this lookup */ Boolean doObjects) /* flag - are we saving nbp type or object items? */ { Str255 menuString, str; short i, j, k; EntityName abEntity; AddrBlock address; OSErr resultCode; Boolean weHaveDupe; k = 1; for (i=1; i<=NumGot; ++i) { /* get an item from the list */ resultCode = NBPExtract(NamesReturnedBuffer, NumGot, i, &abEntity, &address); /* save off current item */ if (doObjects) /* do object strings */ BlockMove(&abEntity.objStr,&menuString,abEntity.objStr[0]+1); else /* do type strings */ BlockMove(&abEntity.typeStr,&menuString,abEntity.typeStr[0]+1); /* check for duplicates here */ weHaveDupe = false; j = 0; do { j = j + 1; BlockMove((NonDuplicateNamesBuffer + (j - 1) * 33), &str, 33); /* do we already have this item in the list? */ if (EqualString(str, menuString, false, true)) weHaveDupe = true; } while ((j <= k) && (weHaveDupe == false)); /* if we dont have a duplicate item and if the item is not our own node (we dont support self-send) then add it to our list */ if ((weHaveDupe == false) && (address != ourNetworkAddress)) { BlockMove(&menuString, (NonDuplicateNamesBuffer + (k - 1) * 33), 33); k = k + 1; } } /* now put all our new items into the actual menu */ parseItemsAddToMenu(NonDuplicateNamesBuffer, lookupMenu, k - 1); } // ***************************************************************** // * LookupNames // * // * issues an nbp lookup for the desired object, type and zone // * the user has specified with the target machine popup menus. // ***************************************************************** void LookupNames (MenuHandle lookupMenu, Boolean doObjects) /* flag - do we want nbp type or object items? */ { Str32 NBPObject, NBPType, NBPZone; NamesTableEntry lookupEntity; Ptr NBPLookupBuffer; /* totally gross mondo buffer for returned names */ Ptr NonDuplicateNamesBuffer; /* put all non-duplicate into this buffer */ MPPParamBlock pbLKP; NBPLookupBuffer = nil; NonDuplicateNamesBuffer = nil; NBPLookupBuffer = NewPtr(BigLookupBuffer); if (NBPLookupBuffer == nil) return; NonDuplicateNamesBuffer = NewPtr(NameBufSize); if (NonDuplicateNamesBuffer == nil) goto Exit; CopyPstr("\p=", NBPObject); if (!doObjects) CopyPstr("\p=", NBPType); else BlockMove(&gTypeStr,&NBPType,gTypeStr[0]+1); if (zonesPresent()) BlockMove(&gZoneString,&NBPZone,gZoneString[0]+1); else CopyPstr("\p*", NBPZone); NBPSetEntity((Ptr)&lookupEntity.nt.entityData, NBPObject, NBPType, NBPZone); pbLKP.NBP.ioCompletion = nil; pbLKP.NBP.interval = 3; pbLKP.NBP.count = 3; pbLKP.NBPentityPtr = &lookupEntity.nt.entityData; pbLKP.NBPretBuffSize = BigLookupBuffer; pbLKP.NBPretBuffPtr = NBPLookupBuffer; pbLKP.NBPmaxToGet = (BigLookupBuffer/sizeof(NTElement)); if (PLookupName(&pbLKP, false) == noErr) if (pbLKP.NBPnumGotten > 0) parseLkupBuffAddToMenu(NBPLookupBuffer, NonDuplicateNamesBuffer, lookupMenu, pbLKP.NBPnumGotten, doObjects); Exit: if (NBPLookupBuffer != nil) DisposPtr(NBPLookupBuffer); if (NonDuplicateNamesBuffer != nil) DisposPtr(NonDuplicateNamesBuffer); } // ***************************************************************** // * BuildZoneListPhase1 // * // * Create the list of zones on the network. Find a bridge to talk to , if one is // * present, then ask it for zone names. Add the names to the list in the dialog. // ***************************************************************** void BuildZoneListPhase1(MenuHandle zoneMenu) { BDSElement dBDS; /* the BDS for GetZoneList call */ ATPPBPtr gATPPBPtr; Ptr gZones,sortBuffer; long tempUserData; short zIndex,zoneCallType; Boolean DontGetMoreZones; short NumZonesGot, totalZones; gATPPBPtr = nil; /* init some important variables*/ gZones = nil; sortBuffer = nil; if (zonesPresent() == false) return; gATPPBPtr = (ATPPBPtr)NewPtr(sizeof(ATPParamBlock)); if (gATPPBPtr == nil) return; gZones = NewPtr(kZonesSize); if (gZones == nil) goto Exit; sortBuffer = NewPtr(ZoneBufSize); if (sortBuffer == nil) goto Exit; zoneCallType = kGetZoneList; zIndex = 1; dBDS.buffSize = kZonesSize; /* set up BDS */ dBDS.buffPtr = gZones; dBDS.dataSize = 0; dBDS.userBytes = 0; gATPPBPtr->ATPatpFlags = 0; gATPPBPtr->ATPaddrBlock.aNet = theBridgeAddress.aNet; gATPPBPtr->ATPaddrBlock.aNode = theBridgeAddress.aNode; /* get node of bridge */ gATPPBPtr->ATPaddrBlock.aSocket = kZIPSocket; /* the socket we want */ gATPPBPtr->ATPreqLength = 0; gATPPBPtr->ATPreqPointer = nil; gATPPBPtr->ATPbdsPointer = (Ptr) &dBDS; gATPPBPtr->ATPnumOfBuffs = 1; gATPPBPtr->ATPtimeOutVal = kATPTimeOutVal; gATPPBPtr->ATPretryCount = kATPRetryCount; NumZonesGot = 0; totalZones = 0; DontGetMoreZones = false; /* keep going until none left (and we haven't exceeded our buffer size) */ while (!DontGetMoreZones && (totalZones <= maxZones)) { zIndex += NumZonesGot; /* index count. 1 for start */ BlockMove((Ptr) &zoneCallType + 1, (Ptr) &tempUserData, 1L); BlockMove((Ptr) &zIndex, (Ptr)&tempUserData + 2, 2L); gATPPBPtr->ATPuserData = tempUserData; /* indicate GetZoneList request */ if (PSendRequest(gATPPBPtr, false) != noErr) /* send sync request */ Exit(DrvrErr); tempUserData = dBDS.userBytes; BlockMove((Ptr) &tempUserData, (Ptr) &DontGetMoreZones, 1); /* the highbyte will be nonzero if its the last packet of zones */ BlockMove((Ptr)&tempUserData + 2, (Ptr) &NumZonesGot, 2); addZonesToBuffer(dBDS.buffPtr,sortBuffer,NumZonesGot,totalZones); totalZones += NumZonesGot; } totalZones = (totalZones <= maxZones) ? totalZones : maxZones; parseItemsAddToMenu(sortBuffer,zoneMenu,totalZones); Exit: if (gATPPBPtr != nil) DisposePtr((Ptr)gATPPBPtr); if (gZones != nil) DisposePtr(gZones); if (sortBuffer != nil) DisposePtr(sortBuffer); } /* BuildZoneList */ // ***************************************************************** // * BuildZoneListPhase2 // * // * Create the list of zones on the network. Find a bridge to talk to , if one is // * present, then ask it for zone names. Add the names to the list in the dialog. // ***************************************************************** void BuildZoneListPhase2(MenuHandle zoneMenu) { Ptr bigBuffer; short TotalZones; Ptr gZones; /* the data buffer for GetZoneList call */ gXPBPBPtr = nil; /* init some important variables*/ gZones = nil; bigBuffer = nil; if (zonesPresent() == false) return; gXPBPBPtr = (XPPParmBlkPtr)NewPtr(sizeof(XCallParam)); if (gXPBPBPtr == nil) return; gZones = NewPtr(kZonesSize); if (gZones == nil) goto Exit; /* big, ugly mondo buffer to hold complete zone list so we can sort them */ bigBuffer = NewPtr(ZoneBufSize); if (bigBuffer == nil) goto Exit; gXPBPBPtr->XCALL.zipInfoField[0] = 0; /* ALWAYS 0 on first call. has state info on subsequent calls */ gXPBPBPtr->XCALL.zipInfoField[1] = 0; /* ALWAYS 0 on first call. has state info on subsequent calls */ gXPBPBPtr->XCALL.zipLastFlag = 0; gXPBPBPtr->XCALL.ioRefNum = xppDriverRefNum; gXPBPBPtr->XCALL.csCode = xCall; gXPBPBPtr->XCALL.xppSubCode = zipGetZoneList; gXPBPBPtr->XCALL.xppTimeout = kATPTimeOutVal; gXPBPBPtr->XCALL.xppRetry = kATPRetryCount; gXPBPBPtr->XCALL.zipBuffPtr = (Ptr) gZones; TotalZones = 0; do { if (PBControl((ParmBlkPtr) gXPBPBPtr, false) != noErr) Exit(DrvrErr); addZonesToBuffer(gZones,bigBuffer,gXPBPBPtr->XCALL.zipNumZones,TotalZones); TotalZones = TotalZones + gXPBPBPtr->XCALL.zipNumZones; /* find out how many returned */ } while ((gXPBPBPtr->XCALL.zipLastFlag == 0) && (TotalZones <= maxZones)); /* keep going until none left */ TotalZones = (TotalZones <= maxZones) ? TotalZones : maxZones; parseItemsAddToMenu(bigBuffer,zoneMenu,TotalZones); Exit: if (gXPBPBPtr != nil) DisposPtr((Ptr)gXPBPBPtr); /* get rid of pb block */ if (gZones != nil) DisposPtr(gZones); /* and buffer */ if (bigBuffer != nil) DisposPtr(bigBuffer); /* and buffer */ } /* BuildZoneList */ // ***************************************************************** // * GetZones // * // * checks which version of AppleTalk we are using and then calls // * the appropriate routine for building the zone list. // ***************************************************************** void GetZones(MenuHandle ZoneMenu) { /* are we using AppleTalk Phase 1 or 2 ? */ if(gMac.atDrvrVersNum > 52) BuildZoneListPhase2(ZoneMenu); /* put the stuff into the list */ else BuildZoneListPhase1(ZoneMenu); /* put the stuff into the list */ } #pragma segment Initialize // ***************************************************************** // * getOurZonePhase2 // * // * gets our local zone using AppleTalk Phase 2 calls // ***************************************************************** void getOurZonePhase2() { gXPBPBPtr = nil; /* init some important variables*/ gZoneString[0] = 0; if (zonesPresent() == false) return; gXPBPBPtr = (XPPParmBlkPtr)NewPtr(sizeof(XCallParam)); if (gXPBPBPtr == nil) return; gXPBPBPtr->XCALL.zipInfoField[0] = 0; /* ALWAYS 0 on first call. has state info on subsequent calls */ gXPBPBPtr->XCALL.zipInfoField[1] = 0; /* ALWAYS 0 on first call. has state info on subsequent calls */ gXPBPBPtr->XCALL.zipLastFlag = 0; gXPBPBPtr->XCALL.ioRefNum = xppDriverRefNum; gXPBPBPtr->XCALL.csCode = xCall; gXPBPBPtr->XCALL.xppSubCode = zipGetMyZone; gXPBPBPtr->XCALL.xppTimeout = kATPTimeOutVal; gXPBPBPtr->XCALL.xppRetry = kATPRetryCount; gXPBPBPtr->XCALL.zipBuffPtr = (Ptr)&gZoneString; if (PBControl((ParmBlkPtr) gXPBPBPtr, false) != noErr) /* send sync control call */ Exit(DrvrErr); DisposPtr((Ptr)gXPBPBPtr); /* get rid of pb block */ } // ***************************************************************** // * getOurZonePhase1 // * // * gets our local zone using AppleTalk Phase 1 calls // ***************************************************************** void getOurZonePhase1() { BDSElement myZoneBDS; ATPParamBlock ZonePB; long tempUserData; Ptr theBufferPtr; char zoneCallType; zoneCallType = 7; /*8 for zone list 7 returns my zone */ theBufferPtr = nil; gZoneString[0] = 0; if (zonesPresent() == true) { theBufferPtr = NewPtr(33); if (theBufferPtr != nil) { myZoneBDS.buffSize = 33; myZoneBDS.buffPtr = theBufferPtr; myZoneBDS.dataSize = 0; myZoneBDS.userBytes = 0; ZonePB.ATP.atpFlags = 0; ZonePB.ATP.ioCompletion = nil; ZonePB.ATP.userData = 0;/* ATP user data */ ZonePB.ATP.addrBlock = theBridgeAddress; ZonePB.ATP.reqLength = 0; ZonePB.ATP.reqPointer = nil; ZonePB.ATP.bdsPointer = (Ptr)&myZoneBDS; ZonePB.ATPnumOfBuffs = 1; ZonePB.ATPtimeOutVal = 2; ZonePB.ATPretryCount = 3; /* 0 this out so bottom three bytes are 0 */ tempUserData = 0; BlockMove(&zoneCallType, (Ptr)&tempUserData, 1); ZonePB.ATP.userData = tempUserData; gZoneString[0] = 0; if (PSendRequest(&ZonePB, false) == noErr) { BlockMove(myZoneBDS.buffPtr, &gZoneString, 33); } DisposPtr(theBufferPtr); } } } // ***************************************************************** // * InitAppleTalk // * // * opens the appropriate AppleTalk drivers // ***************************************************************** OSErr InitAppleTalk() { OSErr err; short ref; if (gMac.atDrvrVersNum > 52) { err = OpenDriver("\p.MPP",&ref); if (err != noErr) return err; err = OpenDriver("\p.XPP",&xppDriverRefNum); } else err = MPPOpen(); return err; } // ***************************************************************** // * GetOurZone // * // * checks which version of AppleTalk we are using and then calls // * the appropriate phase 1 or phase 2 call to get the local zone. // ***************************************************************** void GetOurZone() { if(gMac.atDrvrVersNum > 52) getOurZonePhase2(); /* put the stuff into the list */ else getOurZonePhase1(); /* put the stuff into the list */ }