TweetFollow Us on Twitter

HyperAppleTalk 1
Volume Number:5
Issue Number:1
Column Tag:HyperChat™

Related Info: AppleTalk Mgr

XCMD Cookbook: HyperAppleTalk

By Donald Koscheka, Arthur Young & Company, MacTutor Contributing Editor

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

HyperCard Networking

One of the areas where XCMDs can dramatically alter the capabilities of HyperCard is networking. HyperCard 1.2 introduced the concept of shared stacks by implementing an interface to AppleShare. Unfortunately, too many people have come to believe that AppleShare is all the networking that you need in HyperCard or in any other application on the Macintosh.

Networking can offer a lot more than simple file access to the user. Imagine sending messages or data between stacks interactively. While I was still at Apple, we implemented two stacks that better explain this concept. Imagine that one Mac on the network acted as the stock exchange. Each successive stack that logged in becomes a stock broker and can immediately begin buying and selling stocks and competing against other brokers on the network. This was a fun little project that took on a wonderful new dimension when we added the network interface. There is no truth to the rumor that we began beta testing this stack on October 19, 1987!

A second stack that we wrote provided the capability of an interactive chalkboard. Everybody who logs in can see the chalkboard as well as pick a paint tool and actually draw something on the board. Every other user would see these changes. An interesting exercise in cooperative work area applications.

HyperAppleTalk

The code that I used to implement these sample stacks is a set of XCMDs called “HyperAppleTalk”. These XCMDs implemented the AppleTalk Transaction Protocol (ATP) and the Name Binding Protocol (NBP). ATP is a network protocol that implements the server/client model. One entity on the network acts as an information provider or server while subsequent systems act as information requestors or clients. Although this is a very flexible model, the particular implementation of ATP is a little too limiting. Client requests must be less the 578 bytes in length and server responses must be less than 4624 bytes. If a client made a request to the user for a file that is greater than 4600 bytes, the ATP protocol would need help from another protocol layered on top of ATP. I chose not to implement this protocol because ATP as it stands is more than adequate for sharing messages between stacks. You can obtain a copy of these XCMDs, written in MPW C, from the Apple Programmers and Developers Association (APDA).

The second protocol that I implemented in HyperAppleTalk is the Name Binding Protocol. This is the mechanism by which user names are associated with network addresses on AppleTalk. The name binding protocol allows you to register a name with the network. This is an important feature since network addresses tend to resemble phone numbers. Imagine how much trouble you would have using the phone if you knew only a party’s number and not their name!

Over the next several months I will be providing you with network access in HyperCard. This month I will introduce the concept of “connecting” to the network, that is, establishing the address and record structures required to maintain communication with the network. Next month, I will provide a complete set of routines for access to the Name Binding Protocol. The third installment will feature an important new protocol, the AppleTalk Data Stream Protocol. Finally, we’ll add some embellishments such as access to multiple networks across bridges and file transfer across the network. The result will be complete set of protocols that will allow you to interactively send messages, data and even entire files between stacks running on different systems.

“Connecting” to the Network

To help us get started, we need to examine network basics. Because network programming carries the aura of being difficult, I will keep this introduction simple. You can obtain more information from Inside Macintosh, Inside AppleTalk or from back issues of MacTutor (April ’87, Vol. 3 No. 4) which is where I first learned how to program for the network.

A network consists of a number of entities that are connected by some common transport mechanism. Foremost of us, this transport mechanism is LocalTalk. A node is any device that can be connected to the network and share information with other devices. For sake of illustration, think of each device on the network as a single node.

The set of software protocols that control the traffic and communications on the network is called “AppleTalk”. These protocols are quite independent of the cabling between entities which is why Apple went to such pains to divorce LocalTalk from AppleTalk. This separation pays dividends to the programmer. We can think of AppleTalk as a software mechanism and not worry a whit about what wires are connected.

AppleTalk functions at a variety of levels. At the lowest level, AppleTalk coordinates the transmission and reception of discrete packets of information between entities. To ensure that two entities don’t “hog up the wire” each communication is sent as packets of about 600 bytes of information. A 6K file will require about 10 packets to be sent in its entirety. We call the complete communication of all packets a transaction. The completion of a transaction is guaranteed for you by AppleTalk via the Dynamic DataLink Protocol (DDP), and we need not concern ourselves with it at this time (there are lower-level protocols than DDP, but we don’t need to know them to do serious programming on the network. Think of the lower layers as the network’s “assembly language”).

Nodes address each other on the network by their network addresses. As we said, Network Addresses are similar to phone numbers. If you know the network address of any entity, you can communicate with that entity. The network address consists of three objects: the network number, the node and the socket. For now, we’ll assume that all entities are on the same network so that the network number is always 0 (we’ll relax this constraint later when we introduce the concept of internet addressing with the Zone Information Protocol). The second part of the address is the node id which uniquely identifies an entity within a given network.

The most important concept in the network address is the concept of a socket. A network address is a 16-bit object (a pascal INTEGER) that remains constant for as long as that network remains active. The node id is an 8-byte entity that remains valid for as long as an given node in the network stays up. Sockets, unlike network and node id’s, come and go as needed. Sockets are associated with individual transactions on the network and provide a vital way for the network to properly route transactions between nodes on the network.

Socket Flavors

For our purposes, sockets come in two flavors, listening sockets and transaction sockets. Each node on the network needs at least one “semi-permanent” listening socket whose sole job is to react to incoming requests from other nodes. Listening sockets are like the “ringer” on your telephone. They don’t do much more than let you know that someone is trying to get a hold of you. Listening sockets are said to be semi-permanent because they are assigned to a single node for as long as that node remains connected to the appropriate protocol. In ATP, a listening socket is equivalent to a server. In ADSP, as we shall see, a listening socket is also called a connection listener.

The second class of sockets are “dynamic” sockets which I refer to as transaction sockets. Once a connection is established between any two nodes, a transaction socket is assigned to those two nodes for the duration of that transaction. Once the transaction is completed, the dynamic socket is returned to the “socket” pool. This is important because a socket is an 8-bit entity. With only 256 possible combinations, the need to conserve and reuse socket numbers becomes important.

The neat thing about dynamic sockets is that they uniquely identify a given transaction. One node can easily carry on multiple conversations simultaneously because each conversation is identified by its unique socket id. Dynamic sockets are assigned and de-assigned automatically. We won’t have to concern ourselves with the intricate underworkings of this mechanism in this discussion. All we need to remember is that when we establish a connection with another entity on the network, that connection will receive a unique socket id. When we “tear down” the connection, that socket will be made available for a future connection.

Name Calling

Keeping track of nodes on the network by their network address is not particularly user friendly; it would be roughly similar to calling people by their social security numbers. And we know that’s not user friendly because only government agencies and the DMV would think of doing that!

We need a way of identifying a given node on a given network with a particular user. In other words, we need a way of binding a user-selectable name with a given network address. This is accomplished using AppleTalk’s name binding protocol (NBP). To bind a name to a network address, we need both a name and an address. Choosing a name is a matter of taste. You can use the name that the user entered in the chooser, or you can ask the user for a name. We’ll present both techniques since not every user types a name in the chooser dialog. Next we’ll need to know what address to bind that name to. We can’t bind a name to a dynamically assigned address for an obviously subtle reason. That is, a node can have a name, a transaction takes on the name of whichever node the transaction is taking place on. As far as why this is true, it should become obvious as you read through the code (i.e. it is left as an exercise for the student).

The binding of a name to a network address can only be done once we establish an address for the listening socket. The listening socket is protocol-sensitive - we don’t want to open a listening socket for ATP if we’re going to be using ADSP as our communications protocol. Thus, we’ll need to open up access to ADSP first to establish the socket address. Once we have this address, we can pass it to the Name Binding Protocol (NBP) along with a name to establish a link. We refer to the association of a name with a network address as an “entity”. An entity is said to be network visible if any other entity on the network can see the address of that entity.

To gain access to the network, we first check to see if AppleTalk is installed with the call to MPPOpen in ADSPOpen (see listing 4). Next, we open up the ADSP protocol driver, intialize some global variables and then establish an ADSP listening socket. We use the setglobal callback to set the values of the globals “HyperADSPData and “mySocketListener”. These globals must be declared before they are used or you may find that earlier versions of HyperCard will bomb out (alas, a bug in HyperCard).

We don’t need to open the Name Binding Protocol (NBP) driver since it is automatically opened for us if AppleTalk is running. The XFCN NBPOpen ( see listing 5 ) initializes the fields in the NBPBlock record. Don’t worry about what those fields do, they’ll be the topic of next month’s article.

Listing 1a is a sample HyperTalk script for opening both ADSP and NBP. Note that if ADSP doesn’t open, there is no need to open NBP; we didn’t get access to the network (the most likely reason for this is that the ADSP driver was not installed at boot time).

If ADSP opens ok, it sets the globaladspdata and mysocketlistener global containers. NBP will need access to the latter container, while globaladspdata is used solely by our ADSP xcmds. Don’t worry about the individual fields in all the records yet, we’ll cover them in sufficient detail in upcoming issues.

The important actions to point out right now is the opening of the “.dsp” (aka ADSP) driver and the assigning of a listening socket. Also, three globals will be used for storage. GlobalNBPData stores a pointer to our NBPBlock. Note that the pointer is stored as a numeric string. This is just to keep compatible with HyperCard’s wanting to use containers to store strings. Similarly, GlobalADSPData stores a pointer to the ADSPBlock and mySocketListener stores the value of the connection listening socket (to be discussed in gory detail in an upcoming issue). Changing any of these values will result in the untimely death of your stack. Make sure your users don’t have access to these containers.

Listings 2-3 contain some global constant and type declarations for ADSP and NBP respectively. Again, there is a lot more there than I can cover in one issue of this magazine, let alone a single column. We will cover all of this information in more detail so stay tuned.

Because we should never leave something undone in HyperCard, a pair of complementary XFCNs are provided in listings 6 and 7. ADSPClose and NBPClose check to see that their global data is allocated. If not, they assume that the drivers are already closed and just return. Otherwise, shut down the communications and clear out the global data. We don’t actually close either AppleTalk or ADSP because some other application may have opened them after we did. This is an important exception to the “If you opened, you close it rule”. In general, if you open an AppleTalk driver, you can leave it open because another application may already be using it. Listing 1b shows one way to access these XFCNs.

Listing 1

on openstack
 global globalNBPData, myRegisteredType, myRegisteredName
 global globaladspData, mySocketListener
  
 put adspOpen() into it
 if it is empty then
 -- have access to adsp and a valid socket in
 -- mySocketListener, okay to continue
        put nbpOpen() into it
        if it is not empty then
        answer “Could Not gain access to NBP” with “OK”
 else
 answer “Welcome to AppleTalk” with “OK”
        end if
   else
        answer “ADSP Driver Not installed” with “OK”
 end if
end openstack

Listing 1a. A sample Script to Open access to the network
on closeStack
 global globalNBPData, myRegisteredType, myRegisteredName
 global globaladspData, mySocketListener

 put adspClose() into some_sort_of_error
 put nbpclose() into yet_another_result
end closeStack

Listing 1b. A sample Script for closing down the network 
Listing 2. Constant and Type declarations for ADSP connections

(******************************)
(* file: ADSPxcmd.p*)
(* *)
(* Interface stuff for adsp *)
(* *)
(* ------------------------ *)
(* By:  Donald Koscheka *)
(* Date:10-Oct-88*)
(* ------------------------ *)
(******************************)

UNIT adspxcmd;

INTERFACE

USES  Memtypes, QuickDraw, OSIntf,
 ToolIntf, AppleTalk, ADSP;

CONST

ASYNC   = TRUE;
SYNC    = FALSE;

{*** connection mode status ***}
NOP= 0;
REQ= 1;
ACK= 2;
EST= 3;

NBPLSIZE= 120;
ATPBSIZE= 578;{standard size of transaction}

INTERVAL= 20;{ default retry interval}
RETRY = 3;{ retry count =3 (3*60=30 secs)}

CLOSE_OK= 0;
RECEIVING = 1;
CLOSE_NOW = 2;

(************************************)
(* The following data blocks      *)
(* reference memory pointers      *)
(* rather than handles. This      *)
(* is to insure that all of the   *)
(* data in the connection  block    *)
(* is non-relocatable since       *)
(* ADSP runs asynchronously       *)
(************************************)

TYPE

LIntPtr = ^LongInt;
IntPtr  = ^INTEGER;

{******** A connection block    **************}
CBPtr = ^Connection;
Connection  = Packed Record
next  : CBPtr;   { pointer to next connection      }
last  : CBPtr;   { pointer to last connection      }
ccbRef: Integer; { connection reference #          }
mode  : Integer; { set if connection is open }
adr: AddrBlock;  { address of remote end           }
msg: Handle;{ callback  for incoming dat     }
sendQ: Ptr; { send buffer to remote end      }
recvQ: Ptr; { input buf from remote end}
attn  : Ptr;{ attention messages buffer}
outBuf: Handle;  { where outgoing data goes  }
inBuf: Handle;   { where the input data goes }
attnBuf: Handle; { where attention data goes }
remName: Handle; { entity name of  remote end      }
ccb: TRCCB; { pointer to ccb}
attnPB: DSPParamBlock;  { attntion message pb      }
dspPB: DSPParamBlock;{ connection pb }
user  : Handle;  { place for user data }
End;

{ This is the listening connection }
ADSPPtr = ^ADSPBlock;
ADSPBlock = Packed Record{ ADSP protocol data}
 dspRefNum: Integer; { driver refnum }
 ccbref : Integer; { listener ccbRefNum}
 addr   : AddrBlock; { listener socket }
 ends   : CBPtr; { connections list}
 ccb    : TRCCB; { listener ccb    }
 pb: DSPParamBlock;{ pb for listener }
 chkPoint : Integer; { set if in callback}
 oldSelf: Byte;  {old  self-send flag}
 pad    : Byte;  { keep em even    }
End;

Str31 = String[31];

End.
Listing 3. Constant and Type declarations for NBP access


(******************************)
(* file:  NBPXCMD.p*)
(* *)
(* Constant and type *)
(* decalarations for nbp  *)
(* xcmds*)
(* ------------------------ *)
(* © Donald Koscheka *)
(* 6-October, 1988 *)
(* All Rights Reserved    *)
(* *)
(* ------------------------ *)
(*  Date    |   Description*)
(* ------------------------ *)
(* 06-Oct-88| file created*)
(* ------------------------ *)
(******************************)

UNIT  NBPXCMD;

(******************************)
 INTERFACE
(******************************)

USES  Memtypes, QuickDraw, OSIntf, ToolIntf, AppleTalk;

CONST

ASYNC   = TRUE;
SYNC    = FALSE;
NODE_NAME = -16096;(* name in chooser (STR )*)
MAXNODES= 100; (* maximum nodes for zone*)
NBPLSIZE= 120; (* size local buf for NBP*)
NN = 30;(* #names in lookup table*)
ENTITYSIZE= 110; (* size of entity *)
CLOSE_OK= 0;(* not “CLOSE” critical*)
CLOSE_NOW = 2;   (* close down when done     *)

TYPE

Str31   = String[31];

NBPBlkPtr = ^NBPBlock;
NBPBlock  = RECORD
 Registered: BOOLEAN;(* true = registered    *)
 EntCount : INTEGER;(* # of entities visible *)
LookUpBuffer: Handle;(* lookup buffer*)
 NTEntry: NamesTableEntry;(* entry in names table*)
 NBPLocal : array[1..NBPLSIZE] of Char;(* used by NBP*)
END;

END.
Listing 4. ADSPOpen() XFCN

(******************************)
(* file:  ADSPOpen.p *)
(* *)
(* Open the “.DSP” driver *)
(* and establish memory for *)
(* the ADSPBlock.Creates the*)
(*connection listener*)
(* *)
(* Requires these Globals *)
(* GLOBALADSPDATA*)
(* mySocketListener*)
(* *)
(* DEFINE THE GLOBALS BEFORE*)
(* USING THEM    *)
(* ------------------------ *)
(* By:   Donald Koscheka  *)
(* Date:10-Oct-88*)
(******************************)
(****************************
 Build Sequence

pascal “{adsp}”ADSPOpen.p -o “{hato}”ADSPOpen.p.o 
link -m ENTRYPOINT  -rt XFCN=1300 -sn Main=ADSPOpen
 “{hato}”ADSPOpen.p.o
 “{libraries}”Interface.o 
 -o “{hat}”SwitchBoard
  
*****************************)

{$R-}
{$S ADSPOpen}
UNIT Koscheka;

(****************************)
 INTERFACE
(****************************)

Uses  MemTypes, QuickDraw, OSIntf, ToolIntf, PackIntf, 
 HyperXCmd, AppleTalk, ADSP, adspxcmd;

Procedure EntryPoint( paramPtr : XCmdPtr );

(****************************)
 IMPLEMENTATION
(****************************)

PROCEDURE ADSPOpen( paramPtr: XCmdPtr ); FORWARD;


Procedure EntryPoint( paramPtr : XCmdPtr );
Begin
 ADSPOpen( paramPtr );
End;
 
Procedure ADSPOpen( paramPtr : XCmdPtr );
VAR
 refnum : integer;
 tempH  : Handle;
 adsp   : ADSPPtr;
 error  : OSErr;
 mppPB  : MPPParamBlock;
 longStr: Str255;
 
{$I XCmdGlue.inc }

BEGIN
 error  := noErr;
 adsp   := NIL; {*** assume not in yet***}
 
 {*** Retrieve pointer to our globals  ***}
 tempH := GetGlobal( ‘GLOBALADSPDATA’ );
 
 {*** If it in, convert it to a pointer***}
 IF (tempH <> NIL) AND (tempH^ <> NIL) THEN
 BEGIN
 HLock( tempH );
 ZeroToPas( tempH^, longStr );
 adsp := ADSPPtr( StrToLong( longStr ));
 HUnlock( tempH );
 END;
 
 IF adsp = NIL THEN
 BEGIN
 error := MPPOpen;
 
 IF error = noErr THEN
 BEGIN
 {*** Open the ADSP Driver  ***}
 {*** ADSP driver must be in***}
 {*** your system folder  ***}
 mppPB.newSelfFlag := 1;
 error := PSetSelfSend( @mppPB, SYNC );
 
 error := OpenDriver( ‘.DSP’, refnum );
 END;

 {*** set up connection listener ***}
 IF error = noErr THEN 
 BEGIN

 adsp := ADSPPtr( NewPtr( sizeOf( ADSPBLOCK ) ));
 
 IF adsp <> NIL THEN
 WITH adsp^ DO
 BEGIN
 addr.aNode := 0;
 addr.aNet  := 0;
 addr.aSocket  := 0;
 ends   := NIL;
 dspRefNum  := refnum;
 oldSelf:= mppPB.oldSelfFlag;
 ccbRef := 0;
 chkPoint := CLOSE_OK;
 
 WITH pb DO
 BEGIN
 { OKAY to open a listening socket }
 ioCRefNum  := refnum;
 csCode := dspCLInit;
 ioCompletion  := NIL;
 ccbPtr := @adsp^.ccb;
 localSocket:= 0;
 error  := PBControl( @adsp^.pb, SYNC );

 IF error = noErr THEN
 BEGIN
 { Listener is now all ears}
 ccbRef := ccbRefNum;
 addr.aSocket    := localSocket;
 csCode := dspCLListen;
 filterAddress.aNet  := 0;
 filterAddress.aNode := 0;
 filterAddress.aSocket:= 0;
 error := PBControl( @adsp^.pb, ASYNC );
 END;
 END;
 END;   {*** with adsp  ***}
 
 {*** If adsp opened ok, we have a socket    ***}
 {*** so put away the data and the socket    ***}
 IF error = noErr THEN 
 BEGIN
 SetGlobal(‘GLOBALADSPDATA’,
 PasToZero( NumToStr(LongInt(adsp))));

 SetGlobal( ‘mySocketListener’, 
 PasToZero( NumToStr(LongInt(adsp^.addr))));
 END
 ELSE
 DisposPtr( Ptr(adsp) );
 
 END
 END;
 
 IF error = noErr THEN
 paramPtr^.returnValue := PasToZero( ‘’ )
 ELSE
 paramPtr^.returnValue := PasToZero(numToStr(longint(error)));
END;

end.
Listing 5. NBPOpen() XFCN

(***********************************)
(* file:  NBPOPen.p*)
(* *)
(* Create the control block and  *)
(* initialize the data for  *)
(* the name binding protocol  *)
(* (nbp) stuff.  *)
(* *)
(* ----------------------------  *)
(* © Donald Koscheka *)
(* 6-October, 1988 *)
(* All Rights Reserved    *)
(* *)
(* -------------------------- *)
(*  Date    |   Description *)
(* ----------------------------  *)
(* 06-Oct-88| file created*)
(* ----------------------------  *)
(***********************************)

(***********************************
 MPW Build Sequence
 
pascal “{nbp}”NBPOpen.p -o “{hato}”NBPOpen.p.o
link -m ENTRYPOINT  -rt XFCN=2001 -sn Main=NBPOpen
 “{hato}”NBPOpen.p.o
 “{libraries}”Interface.o 
 -o “{hat}”SwitchBoard
***********************************)

{$R-}
{$S NBPOpen}

UNIT Donald_Koscheka;

(*******************************)
 INTERFACE
(*******************************)

Uses  MemTypes, QuickDraw, OSIntf,
 ToolIntf, PackIntf, HyperXCmd, 
 AppleTalk, nbpxcmd;

Procedure EntryPoint( paramPtr : XCmdPtr );

(*******************************)
 IMPLEMENTATION
(*******************************)

PROCEDURE NBPOpen( paramPtr: XCmdPtr ); FORWARD;

Procedure EntryPoint( paramPtr : XCmdPtr );
Begin
 NBPOpen( paramPtr );
End;
 
Procedure NBPOpen( paramPtr : XCmdPtr );
(**********************************
* This routine initializes some common 
* memory for use by the Name Binding
* Protocol (NBP) Driver and the XCMDs that
* will use it.  
*
* YOU MUST CALL THIS ROUTINE BEFORE
* ANY OF THE OTHER XCMDs/XFCNs in the
* AppleTalk suite.  Failure to do so 
* will result in wildly unpredicatable
* and possibly fatal performance by
* hypercard.
*
* IMPORTANT: 
*THE HYPERCARD VARIABLE 
*  “GLOBALNBPDATA” MUST BE
*DECLARED IN YOUR SCRIPT
*BEFORE CALLING NBPOPEN
*
* Out: Error Result is returned to hypercard
*  or empty if no error
**********************************)
VAR
 i : INTEGER;  {*** just a loop counter***}
 tempH: Handle;  {*** Used to get global     ***}
 nbp  : NBPBlkPtr; {*** MUST NOT MOVE  ***}
 error: OSerr;   {*** allocate as pointer    ***}
 longStr: Str255;{*** for  ZeroToPas call    ***}

{$I XCMDGlue.Inc }
BEGIN
 error := noErr; 
 nbp := NIL; {*** assume no data yet ***}
 
 {*** Retrieve the pointer that’s stored           ***}
 tempH := GetGlobal( ‘GLOBALNBPDATA’ );
 
 {*** If it’s defined, convert it to a pointer***}
 IF (tempH <> NIL) AND (tempH^ <> NIL) THEN
 BEGIN
 HLock( tempH );
 ZeroToPas( tempH^, longStr );
 nbp := NBPBlkPtr( StrToLong( longStr ));
 HUnlock( tempH );
 END;
 
 IF  nbp = NIL THEN
 BEGIN  

 {*** Allocate nbp, initialize its fields***}
 nbp := NBPBlkPtr(NewPtr( sizeof( NBPBlock )));
 
 IF nbp <> NIL THEN
 WITH nbp^ DO
 BEGIN
 WITH NTEntry DO
 BEGIN
 nteAddress.aSocket:= 0;
 nteAddress.aNode := 0;
 nteAddress.aNet:= 0;
 
 For i := 1 TO 100 DO
 nteData[i]:= chr(0);
 END;
 {*** Clear at the lookup stuff  ***}
 {*** (signifies no lookup yet)  ***}
 LookUpBuffer  := nil;
 EntCount := 0;
 Registered := FALSE;
 
 SetGlobal(‘GLOBALNBPDATA’,PasToZero( NumToStr(LongInt(nbp))));
 
 END
 ELSE
 error := -1;  {*** some sort of error occured ***}
 END; 

 {*** Note that no error is reported ***}
 {*** as ‘empty’, rather than 0.  This ***}
 {*** is in keeping with HyperCard ***}
 IF error = noErr THEN
 paramPtr^.returnValue := PasToZero( ‘’ )
 ELSE
 paramPtr^.returnValue := PasToZero(numToStr(longint(error)));
 
END;

END.
Listing 6. ADSPClose() XFCN

(******************************)
(* file:  ADSPClose.p*)
(* *)
(* Close down the connection*)
(* listener and all open  *)
(* connections.  *)
(* Set the globals to empty *)
(* *)
(* Requires these Globals *)
(* GLOBALADSPDATA*)
(* mySocketListener*)
(* *)
(* DEFINE THE GLOBALS BEFORE*)
(* USING THEM    *)
(* ------------------------ *)
(* By:  Donald Koscheka *)
(* Date:10-Oct-88*)
(******************************)
(*******************************
 Build Sequence

pascal “{adsp}”ADSPClose.p -o “{hato}”ADSPClose.p.o 
link -m ENTRYPOINT  -rt XFCN=1301 -sn Main=ADSPClose
 “{hato}”ADSPClose.p.o
 “{libraries}”Interface.o 
 -o “{hat}”SwitchBoard     
********************************)

{$R-}
{$S ADSPClose}
UNIT Koscheka;

(*******************************)
 INTERFACE
(*******************************)

Uses  MemTypes, QuickDraw, OSIntf, ToolIntf, PackIntf, 
 HyperXCmd, AppleTalk, ADSP, adspxcmd;

Procedure EntryPoint( paramPtr : XCmdPtr );

(*******************************)
 IMPLEMENTATION
(*******************************)

PROCEDURE ADSPClose( paramPtr: XCmdPtr ); FORWARD;

Procedure EntryPoint( paramPtr : XCmdPtr );
 Begin
 ADSPClose( paramPtr );
 End;
 
Procedure ADSPClose( paramPtr : XCmdPtr );
VAR
 tempH  : Handle;
 adsp   : ADSPPtr;
 error,err: OSErr;
 tpb    : DSPParamBlock;
 cb, nb : CBPtr;
 mppPB  : mppParamBlock;
 longStr: Str255;
 
{$I XCmdGlue.inc }

BEGIN
 error  := noErr;
 adsp   := NIL; 
 
 {*** Retrieve the pointer***}
 tempH  := GetGlobal( ‘GLOBALADSPDATA’ );
 
 IF (tempH <> NIL) AND (tempH^ <> NIL) THEN
 BEGIN
 HLock( tempH );
 ZeroToPas( tempH^, longStr );
 adsp := ADSPPtr( StrToLong( longStr ));
 HUnlock( tempH );
 END;
 
 {*** Only kill if allocated ***}
 IF  adsp <> NIL THEN
 WITH adsp^ DO
 BEGIN  
 (* 1 - Tear down connection listener*)
 IF pb.ioResult > 0 THEN
 WITH tpb DO
 BEGIN
 ioCRefNum:= dspRefNum;
 csCode := dspCLRemove;
 ccbRefnum  := adsp^.ccbref;
 abort  := 1;
 
 err := PBControl( @tpb, SYNC );
 IF err <> noErr THEN error := err;
 END;
 
 (* 2 - Restore old self send *)
 mppPB.newSelfFlag := adsp^.oldSelf;
 err := PSetSelfSend( @mppPB, SYNC );
 
 {* PSetSelfSend  not implemented on*}
 {* Mac+ (???), so ignore result   *}
 {* “driver can’t respond to this  *}
 {* control call”. *}
 
 
 (* 3 - Deallocate all ADSP memory *)
 DisposPtr( Ptr( adsp ) );
 
 (* 4 * Clear out the containers *)
 SetGlobal(‘GLOBALADSPDATA’,PasToZero(‘’));
 
 (* 5 - leave socket address valid *)
 (*   for now    *)
 END; {*** WITH adsp^ ***}
 
 IF error = noErr THEN
 paramPtr^.returnValue:=PasToZero(‘’)
 ELSE
 paramPtr^.returnValue:=PasToZero(numToStr(longint(error)));
END;

END.
Listing 7. NBPClose() XFCN

(******************************)
(* file:  nbpClose.p *)
(* *)
(* Create control block and *)
(* initialize the data for  *)
(* the name binding protocol  *)
(* (nbp) stuff.  *)
(* *)
(* -------------------------- *)
(* © Donald Koscheka *)
(* 6-October, 1988 *)
(* All Rights Reserved    *)
(* *)
(******************************)
(*******************************
 MPW Build Sequence

pascal “{nbp}”nbpClose.p -o “{hato}”nbpClose.p.o
link -m ENTRYPOINT  -rt XFCN=2002 -sn Main=nbpClose
 “{hato}”nbpClose.p.o
 “{libraries}”Interface.o 
 -o “{hat}”SwitchBoard
*******************************)

{$R-}
{$S nbpClose}
UNIT Donald_Koscheka;

(*******************************)
 INTERFACE
(*******************************)

Uses  MemTypes, QuickDraw, OSIntf,
 ToolIntf, PackIntf, HyperXCmd, 
 AppleTalk, nbpxcmd;

Procedure EntryPoint( paramPtr : XCmdPtr );

(*******************************)
 IMPLEMENTATION
(*******************************)

PROCEDURE nbpClose( paramPtr: XCmdPtr ); FORWARD;

Procedure EntryPoint( paramPtr : XCmdPtr );
Begin
 nbpClose( paramPtr );
End;
 
Procedure nbpClose(paramPtr : XCmdPtr);
(**********************************
* This routine shuts down access to 
* the NBP driver.  It also unregisters
* the entity if that hasn’t already been
* done.
*
* IMPORTANT: 
*
* THE HYPERCARD VARIABLE 
* “GLOBALNBPDATA” MUST BE
* DECLARED IN YOUR SCRIPT
* BEFORE CALLING nbpClose
*
* Does not report an error
**********************************)
VAR
error : OSErr;
longStr : Str255;
tempH : Handle;
nbp: NBPBlkPtr;{*** MUST NOT MOVE  ***}
pb : MPPParamBlock;

{$I XCMDGlue.Inc }

BEGIN
 error := noErr;
 nbp := NIL; {*** assume no data yet ***}
 
 {*** Retrieve the pointer that’s stored     ***}
 tempH := GetGlobal( ‘GLOBALNBPDATA’ );
 
 {*** If it’s there, convert  to pointer     ***}
 IF (tempH <> NIL) AND (tempH^ <> NIL) THEN
 BEGIN
 HLock( tempH );
 ZeroToPas( tempH^, longStr );
 nbp := NBPBlkPtr( StrToLong( longStr ));
 HUnlock( tempH );
 END;
 
 {*** If the data is still allocated, we     ***}
 {*** shut down NBP, otherwise, just quit***}
 IF  nbp <> NIL THEN
 WITH nbp^ DO
 BEGIN  
 {*** Unregister if still registered***}
 IF NTEntry.nteData[1] <> chr(0) THEN
 BEGIN
 pb.entityPtr := @NTEntry.nteData[1];
 error := PRemoveName( @pb, SYNC );
 END;
 
 {*** Remove the lookup buffer***}
 IF LookUpBuffer <> NIL THEN
 BEGIN
 HUnlock( LookUpBuffer );
 DisposHandle( LookUpBuffer );
 END;
 
 {*** Dump the NBP Master Block  ***}
 DisposPtr( Ptr(nbp) );
 SetGlobal( ‘GLOBALNBPDATA’, PasToZero( ‘’ ));
 END; 

 IF error = noErr THEN
 paramPtr^.returnValue := PasToZero( ‘’ )
 ELSE
 paramPtr^.returnValue := PasToZero(numToStr(longint(error)));
 
END;
END.

Next month: Accessing the Name Binding Protocol in HyperCard.

end HyperChat

 

Community Search:
MacTech Search:

Software Updates via MacUpdate

1Password 6.8.5 - Powerful password mana...
1Password is a password manager that uniquely brings you both security and convenience. It is the only program that provides anti-phishing protection and goes beyond password management by adding Web... Read more
BetterTouchTool 2.319 - Customize multi-...
BetterTouchTool adds many new, fully customizable gestures to the Magic Mouse, Multi-Touch MacBook trackpad, and Magic Trackpad. These gestures are customizable: Magic Mouse: Pinch in / out (zoom... Read more
iFFmpeg 6.6.3 - Convert multimedia files...
iFFmpeg is a comprehensive media tool to convert movie, audio and media files between formats. The FFmpeg command line instructions can be very hard to master/understand, so iFFmpeg does all the hard... Read more
Evernote 6.13.2 - Create searchable note...
Evernote allows you to easily capture information in any environment using whatever device or platform you find most convenient, and makes this information accessible and searchable at anytime, from... Read more
HoudahSpot 4.3.4 - Advanced file-search...
HoudahSpot is a versatile desktop search tool. Use HoudahSpot to locate hard-to-find files and keep frequently used files within reach. HoudahSpot will immediately feel familiar. It works just the... Read more
calibre 3.14.0 - Complete e-book library...
Calibre is a complete e-book library manager. Organize your collection, convert your books to multiple formats, and sync with all of your devices. Let Calibre be your multi-tasking digital librarian... Read more
Evernote 6.13.2 - Create searchable note...
Evernote allows you to easily capture information in any environment using whatever device or platform you find most convenient, and makes this information accessible and searchable at anytime, from... Read more
calibre 3.14.0 - Complete e-book library...
Calibre is a complete e-book library manager. Organize your collection, convert your books to multiple formats, and sync with all of your devices. Let Calibre be your multi-tasking digital librarian... Read more
HoudahSpot 4.3.4 - Advanced file-search...
HoudahSpot is a versatile desktop search tool. Use HoudahSpot to locate hard-to-find files and keep frequently used files within reach. HoudahSpot will immediately feel familiar. It works just the... Read more
Hopper Disassembler 4.3.10- - Binary dis...
Hopper Disassembler is a binary disassembler, decompiler, and debugger for 32- and 64-bit executables. It will let you disassemble any binary you want, and provide you all the information about its... Read more

Latest Forum Discussions

See All

Sweety Kitty is an epic adventure for sw...
Join Sweety the Kitty on his journey around the world in Sweety Kitty, an all new match-three adventure full of colorful lands and tasty treats, developed and self published by Integra Games Global OU. Available now on both the App Store and Google... | Read more »
The best deals on the App Store this wee...
A new week means new deals on the App Store, and it looks as though Christmas has arrived a bit early this Monday with a whole slew of new discount games, many of which have yet to be covered in this roundup series. Puzzle games, point and click... | Read more »
CUPHEAD (Games)
CUPHEAD 1.0 Device: iOS Universal Category: Games Price: $4.99, Version: 1.0 (iTunes) Description: Cuphead is a classic run and gun single player action game heavily focused on boss battles. Inspired by cartoons of the 1930s, the... | Read more »
Run Sausage Run! guide - tips and tricks...
Run Sausage Run! is a mildly sadistic endless runner in which you guide a sausage or any other variety of cured meat through a deadly meat factory full of sawblades and other hazards. Getting a high score in this game is no small feat, and will... | Read more »
WWE Mayhem guide - beginner tips and tri...
WWE Mayhem brings all of the familiar faces from your favorite wrestling league to mobile in this exciting new fighting game. Build up a team of your favorite WWE superstars and fight your way to the championship title, or battle against your... | Read more »
The best new games we played this week -...
We've made it through another week, so let's treat ourselves to some of the best new games to launch in the past few days. It was another exciting week with some long-awaited indie games making their debut, and some big console titles making the... | Read more »
Match blocks to pull off dance moves in...
Ferdinand: Unstoppabull is a brand new match three puzzler based on the animated movie of (almost) the same name. As you can expect, you have to match blocks together to complete a bunch of puzzling levels and earn a high score. [Read more] | Read more »
Lineage 2: Revolution’s end of year upda...
Now available in 54 countries worldwide, Lineage 2: Revolution is continuing its global quest to be the most popular mobile MMORPG by launching a jam-packed end of year update. Complete with many subtle tweaks to help improve users’ online... | Read more »
The 5 best Star Wars games on iOS
The time has almost come.Star Wars: The Last Jedifinally hits theaters in the cinematic event that might be bigger than Christmas. To celebrate, we're taking a look at the best--and only the best--Star Warsmobile games to date. [Read more] | Read more »
Life Is Strange (Games)
Life Is Strange 1.1 Device: iOS Universal Category: Games Price: $2.99, Version: 1.1 (iTunes) Description: Life Is Strange is a five part episodic game that sets out to revolutionize story-based choice and consequence games by... | Read more »

Price Scanner via MacPrices.net

Holiday deals on 9″ Apple iPads: Resellers of...
B&H Photo has 9.7″ 2017 iPads on sale for $10-$50 off MSRP as part of their Holiday sale. Overnight shipping is free, and pay sales tax in NY & NJ only: – 9″ 32GB iPad WiFi: $299, $30 off – 9... Read more
12″ and 10″ Apple iPad Pros on sale for up to...
B&H Photo has 10″ and 12″ iPad Pros on sale for up to $80 off MSRP as part of their Holiday sale. Overnight shipping is free in many cases, and B&H charges sales tax in NY & NJ only. Note... Read more
Sunday flash sale: Beats Solo3 Wireless On-Ea...
Amazon has Beats Solo3 Wireless On-Ear Headphones on sale for $199.99 including free shipping. Their price is $100 off MSRP, and it’s the lowest price available for Beats Solo3. Multiple colors are... Read more
B&H Holiday sale: MacBooks for up to $300...
B&H Photo has Apple MacBook Pros, MacBook Airs, and 12″ MacBooks on sale for up to $300 off MSRP as part of their Holiday sale. B&H charges sales tax in NY & NJ only, and overnight... Read more
The lowest prices on Apple 13″ MacBook Pros t...
Save $300-$300 on the purchase of a 2017 13″ MacBook Pro this weekend with Certified Refurbished models at Apple. In many cases, Apple’s refurbished prices are the lowest available for each model... Read more
Lowest prices of the Holiday season: 15″ Appl...
Save $360-$420 on the purchase of a 2017 15″ MacBook Pro with Certified Refurbished models at Apple. In many cases, Apple’s refurbished prices are the lowest available for each model from any... Read more
Apple discounts Beats products by up to 30% t...
Apple has Beats by Dr. Dre (BeatsX, Powerbeats3 Wireless, and Beats Solo3 Wireless) on sale for up to 30% off their retail price from now until December 26th: – BeatsX: Was $149.95, now $99 –... Read more
Updated Price Trackers: Macs, iPads, iPhones,...
Scan our Apple Price Trackers for the latest information on sales, bundles, and availability on systems from Apple’s authorized internet/catalog resellers. We update the trackers continuously: – 15″... Read more
How to preorder a new iMac Pro and pay zero s...
B&H Photo and Adorama are accepting preorders on multiple configurations of the new Apple iMac Pro. Both resellers charge sales tax for residents of NY & NJ only, and shipping is free.... Read more
Apple Macs back in stock at Amazon with model...
Amazon has MacBook Pros, MacBook Airs, MacBooks, and iMacs on sale for up to $200 off MSRP as part of their Holiday/Christmas sale. Shipping is free. Note that stock of some Macs may come and go (and... Read more

Jobs Board

*Apple* Retail - Multiple Positions - Apple,...
Job Description: Sales Specialist - Retail Customer Service and Sales Transform Apple Store visitors into loyal Apple customers. When customers enter the store, Read more
*Apple* Retail - Multiple Positions - Apple,...
Job Description: Sales Specialist - Retail Customer Service and Sales Transform Apple Store visitors into loyal Apple customers. When customers enter the store, Read more
*Apple* Retail - Multiple Positions - Apple,...
Job Description:SalesSpecialist - Retail Customer Service and SalesTransform Apple Store visitors into loyal Apple customers. When customers enter the store, Read more
*Apple* Retail - Multiple Positions - Apple,...
Job Description: Sales Specialist - Retail Customer Service and Sales Transform Apple Store visitors into loyal Apple customers. When customers enter the store, Read more
*Apple* Retail - Multiple Positions - Apple,...
Job Description:SalesSpecialist - Retail Customer Service and SalesTransform Apple Store visitors into loyal Apple customers. When customers enter the store, Read more
All contents are Copyright 1984-2011 by Xplain Corporation. All rights reserved. Theme designed by Icreon.