TweetFollow Us on Twitter

AppleTalk Client
Volume Number:1
Issue Number:10
Column Tag:Pascal Procedures

"Dial a Fortune Apple Talk Client"

By Alan Wootton, President, Top-Notch Productions, MacTutor Contributing Editor

Fig. 1 Phone type network

AppleTalk and Macintosh Pascal

This month's topic is AppleTalk. In collaboration with Bob Denny (see the column 'C Workshop' in this issue), I present a pair of programs that form 'Dial-A-Fortune'. The names of the two programs presented below are Get_Fortune and Send_Fortune. These are fully conversational with Bob Denny's server version, which performs the task of Send_Fortune. Of course, to try them, you will need two Macs. Either my Pascal Send_Fortune or Bob's server program run in one Mac while my Pascal Get_Fortune runs in the other Mac as the "requestor". Get_Fortune will request fortunes from either of the C or Pascal Send_Fortune servers which respond by sending back a fortune cookie! In this way, all the concepts of AppleTalk are illustrated. (Note: due to space limitations, the C version of Bob's requestor program was not included in the C column. Use my Get_Fortune requestor instead. A C requestor program to compliment Bob's server will be published in the C workshop next month.) If you are using Pascal, everything you need is here in this column for two way AppleTalk communications.

Appletalk

I started this project with only a passing knowledge of networks. Networks are for hooking computers together, right? So, I went to the store and bought one -- actually, two -- one for each computer. After paying $50 retail for each, I hurried home to try it out. Shock! What you get are merely cables to wire your machines together, and a short pamphlet on how this is done. A child could do it but having the wires in place does not a network make. You need software.

I referred immediately to Inside Macintosh. After careful study I identified two types of software that are needed. There are some drivers that you install in your system like a desk accessory, or like a new printer driver, and there are Macintosh Programs that use the drivers. Searching through the billions of disks sent to the Apple Certified Developers uncovered the drivers (presumably you can get them at the store too), and I installed them. Still, no network. Actually, it was like having telephones but not knowing how to talk.

I could have gone to the store to look for software to use my network, but I decided to write my own (actually, Bob Denny gave me Dial-A-Fortune first). So, back to the Bible -- excuse me -- Inside Macintosh.

What I found are many programs sending many messages at many levels of organization. The drivers send and receive data over the net at the drop of a hat. On the top of them all seemed to be a thing called AppleTalk Transaction Protocol, ATP for short. What this is, are some routines you can call to send and receive data (up to 512 bytes at a time). ATP is pretty clever. It will wait until it is its turn to talk, it will retransmit requests if no reply is received, and more. In the descriptions of the routines, I found numbers to set to indicate what data to send, and how persistent I wanted ATP to be about delivery. I found something else, too.

To use a network to 'hook computers together' you have to know something about the rules and conventions. Just as you cannot mail a letter without understanding about countries, cities, streets, addresses, and names, you also cannot make a phone call without knowing when you need an area code, or when you need a prefix, or when you can just dial 8 and then an extension. As I found, you must tell ATP three things to have a message delivered (refer now to the diagrams of networks in action).

Fig. 2. AppleTalk type network

First is the network number or zone (an integer). This is for situations where your network is connected to other networks. For me this is like an area code in a world with two telephones -- Not real useful. After ATP knows which network you're calling, it wants to know which node you want (a byte). I had two nodes. Each computer with a serial port, running the drivers, is a node. This is as if each of my computers were a whole town, each meriting it's own prefix, even though there may be only one phone in each town. Simple so far, but now my misconceptions begin to show. This network is for connecting programs together, not computers. The final destination of any message is a socket. For this ATP requires a socket number (a byte. Personally, I think that 'socket' is a poor choice of words for this; it brings the image of a connecter to mind, not a software process). This is analagous to the last four digits of a phone number. Even though there is only one 'phone' in each of two 'towns' you still must 'dial' an 'area code' (net number), a 'prefix' (node number), and the 'last four' (socket number) for a 'call' to go through. So, lets send some messages!

What is the number for the place we wish to call? Telephones are considered mostly permanent installations and are given permanent numbers (a very IBM type of mentality). Area codes especially won't change (even though this just happened to L.A. when they split the city into two areas where there was previously one). For AppleTalk the designers decided that numbers might change a lot and this would become a drag (it would be). So they decided that they would make it so that numbers could change all the time. This is a lot like a system where every time you plug your phone in the wall you call the phone company with your name and they give you a brand new number. Makes it pretty hard for some one to call you! But wait -- as the lazy ones among us have already guessed, all you have to do is call directory assistance before every call (a very Apple type of mentality). This way it doesn't matter what your friend's number is this week; you can always call him. AppleTalk works exactly this way, except directory assistance is called Name Binding Protocol, NBP for short.

When you call directory assistance the first thing they want to know is "Which city, please". NBP will search all the cities, or nodes, for the name you want, but you must provide a string for the zone (area code) you want. If you are calling directory assistance in another state you probably called first to get the area code and then called (area code) 555-1212 for the number. NBP will do this all in one inquiry. So, before every call you ask NPB for the number of the entity with a particular name, in a particular zone. NBP, unlike the phone company, will also look in the yellow pages. You see, there is another string you pass to NBP which is meant to be an identifier for the 'type' of party you wish to reach. This is really a superior system (are you listening Ma Bell?). All parties on the system are identified by their zone, their name, and their type. You can ask NBP for all the numbers in any combination of these. Think how nice it would be to dial national directory assistance and ask for all the Smiths in L.A. that are in the computer business. Only the names are used. The numbers are only a necessary evil to be ignored as much as possible.

Now that we know how to deal with the authorities involved lets get down to the nitty gritty and see if we can establish communication. Everyone get out your copies of Inside Mac, boot your Macs, and follow along.

Inside Inside Appletalk

It will be necessary to refer to the AppleTalk programmers guide. This is the 'Programmer's Guide' section in Inside Appletalk and the 'AppleTalk' section of Inside MacIntosh (regular or phone book version). They are all the same (first draft 1/31/85). Inside AppleTalk contains chapters describing in detail the many philosophies and protocols involved. The only routines needed are the Name-Binding protocol and the AppleTalk Transaction protocol.

The Appletalk section begins with brief descriptions of the various levels of service involved. You can ignore references to link access protocol (LAP) and datagram delivery protocol (DDP). On page 16 a description of how to call AppleTalk from Pascal begins. This is all for the Lisa-Pascal Workshop and is therefore completely worthless. Skim to page 66. Also ignore the AbusRecord type in the summary. The data types we will use are all in the programs that follow and I present a diagram for easy reference. Don't worry about assembly language. We will simply use the parameter block lists presented after each routine name. The method of access to AppleTalk will be to make device manager control calls directly to the drivers involved. This is simply illustrated in the code that follows. Following NPB are instructions on page 78 for making your own handlers. We definitely don't need this so skip to the summary on page 86. Again, watch out for the 'Pascal' interface; we are using the assembly language information.

ATP

The AppleTalk Transaction Protocol (ATP) is the main purpose behind the other, lower level, routines. ATP is used to send and receive messages on the system.

Although messages can be sent anonymously, every receiver has an address. The address (sometimes called the internet address) consists of a network number, a node number and a socket number. We will worry how to find an address later, so for now assume this is taken care of. The network number is to specify which of several individual appletalk networks the reciever is on. This is presently not used. The node number specifies which Mac (or other processor) the message is to go to. The socket number specifies which of several entities (desk accessories for instance) the message is to go to.

To send a message somewhere on the network use the function SendRequest. Note that not only is a message sent but a reply is secured also. To use SendRequest you must know the address of the receiver. In our example the mesage sent is ignored and the reply contains a Pascal-style string which is a fortune.

In order to receive messages (not merely replies) you (meaning your program) must declare yourself as an address capable of receiving requests. To do this call OpenATPSkt. When you are done call CloseATPSkt. Once you have an open socket you may then ask to receive messages. To do this call GetRequest. You may use asynhcronous device manager calls in order to not tie up the system but in this example we will simply wait (hang) for a message. When a request is received call SendResponse to send the reply.

Fig. 3 Appletalk Data structures

Name-Binding Protocol

Whenever a program opens a socket, ATP assigns an address to it. The address could be any valid address so it would be very hard for anyone to already know your address. To receive messages it is necessary to supply a name for that socket. Then another entity can call NBP with your name and NBP will find your address.

To do this call RegisterName. Each name is made of three strings. The strings are called the object string, the type string, and the zone string. The zone string is used to name which network one is on, and since multiple networks are not in common use '*' is usually used for the zone string. The type string is to declare the purpose of this particular socket. Sockets could be used for receiving mail or for providing file access. Each function should use a unique type string. Our example uses 'Dial-A-Fortune' as the type. The name string is to differentiate between several sockets that all offer the same service. For example, my Dial-A-Fortune socket has an object name of 'MacPascal Fortunes', and Bob Denny's Dial-A-Fortune socket has the object name of 'Confuscious'. It might be wise to add a unique identifier, like the disk name, or the users name, on the end of this string (for instance 'Confuscious-Bobs disk').

Once you have called RegisterName it is much more likely that someone will send a message to your GetRequest. After you don't want anymore messages you should call RemoveName and then you may close the socket.

If you want to send a message and you don't know the address to use you can call LookUpName. You supply a name and LookUpName will find the address. As a matter of fact, you can look up many names. LookUpName will take wild card characters in the object, type, and zone fields. Pass an array to hold the resulting addresses and pass the maximum number of addresses that you want and LookUpName will try to fill it for you. Unfortunately, the 'array' of addresses also contains the names that go with them and the whole affair is packed together so that it is harder to access the individual elements in Pascal. Not that it couldn't be done, but for our example we only look up one name to avoid this problem.

AppleTalk from MacPascal

As usual, the first task is to declare the types we will need. Our method of passing data to the various routines is to use a parameter block. This is the same block used by the file manager and the device manager. However, AppleTalk uses the fields in many new ways, and the various routines will re-use a particular field for up to four different purposes. To accomodate this we define a parameter block with variant fields. A bad problem remains. MacPascal refuses to correctly lay out byte sized fields. Observing that MacPascal will do packed arrays of char in the correct manner, and that byte sized fields always occur in pairs, we will declare them in pairs and use an array index to choose the one we want. For example, to access ATPsocket, use ATPsocket_ATPflags[0], and to access ATPflags, use ATPsocket_ATPflags[1]. A record of many variant fields is sometimes hard to refer to so I have provided a diagram of all the records we will use and the positions of the fields therein in fig. 2.

The NamesTableEntry is another problem. The lower part of this record is three strings that have been packed together. The procedure Pack3str is used to accomplish this.

As I mentioned before, our access to the AppleTalk routines will be through device manager control calls. The routines presented set the csCode correctly, then call the correct driver interface. The driver interface then sets ioRefNum correctly and requests filecall to make a control call. Filecall was presented in previous columns in this magazine. Look in the past issues, or better yet, just use it the way I do and forget how it works.

Before you can try to get the examples running you must install AppleTalk into your system file. Apple supplies an installer that will do this (but it won't work on my HyperDrive!). The Appletalk installer moves these resources into the file 'System': DRVR 9 .MPP, DRVR 10 .ATP, INIT 6, and two of type NBPC. The INIT opens the MPP driver. The NBPC types are code used for NBP.

Get_Fortune

To Get_Fortune we first must check that the drivers are opened. This is the function of ATPLoad. I adapted this from the example on page 54. Its purpose is to open both drivers if they are not already open and if the serial port is free. I wish this were not necessary. It would be better if it were just a trap in ROM that you call which returns an OS error code. Obscure system globals are checked and PBopen calls are made. Let's just assume that it works and let the hot-shots analyze its code for extra credit.

Next, we stuff Nblock in preparation for a LookUpName call. Interval and count are the time between retries and the number of times to try, respectively. Pack3str is used to set the strings in myNtable and entityPtr is set to point at the string part of myNtable (not at the beginning). RetBuffPtr and retBuffsize specify where we want a ntTuple returned, and maxToGet asks for only one to be returned. If you are following along in the book on page 76 you will note that I set the parameters in the order they are listed. Then LookUpName is called to return the first Dial-A-Fortune type it finds.

Now, myTuple will have an address in it's upper part. After we set ATPflags for once-only-mode we transfer the three part address into Sblock. There will be no message so we set reqLength and reqPointer to nothing. Moving along, we set BDSpointer to our numOfBuffs:=1 buffers. Timeoutval is the number of seconds that SendRequest will wait for a response before trying again, and retryCount is the number of times it will try before giving up. The parameter block is now filled but we first must set myBDS.buffPtr and buffSize to the address of the string reply which is where we want the fortune to be returned. After the SendRequest we examine reply and see that it does indeed contain a fortune transmitted from a Dial-A-Fortune somewhere on the network.

Send_Fortune

Send_Fortune follows Get_Fortune below but, since the upper portion of code is exactly the same as in Get_Fortune, it is not repeated. Please make note of this! The addrBlock of Sblock, when cleared, indicates to OpenATPSkt that we want it to assign a new address to us (I can't think of a situation where we would already know a valid address).

After OpenATPSocket we transfer the new address into the top (excluding the nextEntry pointer) of myNtable. Then we pack3str to fill the rest of myNtable. Ablock.ntQElPtr points to myNtable and after we specify an interval, a count, and set the verifyFlag we call RegisterName. Now, myNtable is the exclusive property of NBP, and it must not be disturbed before we RemoveName.

To prepare for GetRequest it is not necessary to set ATPsocket because it remains set from OpenATPsocket. Even though we don't expect a message in our message (it's existence is enough) we set Sblock.reqPointer and reqLength for the string buffer. Then we call GetRequest.

Three of the items that are listed on page 70 as being required for SendResponse are already set by GetRequest so those of you following along, don't be alarmed when we skip them. They are atpSocket, addrBlock, and transID. It is necessary to set the EOM bit of the ATPflags since this will be our last (and only) response. BdsPointer is set to myBDS. NumOfBuffs and bdsSize are set to one because our reply string will easily fit into one packet and one BDSelement. MyBDS is set for the string reply and then we SendResponse.

The GetRequest - SendResponse loop is repeated until the mouse button is held down after a response. After that we RemoveName and CloseATPSkt. Note that unlike Bob Denny's version, this returns the same fortune every time. We leave it to you to jazz it up with a more varied response.

So, now we have our network. Happy talking!

Get_Fortune listing:
program Apple_talk_Access;{by Alan Wootton 7/85 }
 type
  ptr = ^integer;
  strptr = ^str255;

  Bsplit = packed array[0..1] of char;

  AddrBlockRec = record
    aNet : integer;
    aNode_aSocket : Bsplit
   end;

  BDSElement = record
    buffSize : integer;
    buffPtr : ptr;
    datasize : integer;
    userbytes : longint
   end;

  BDSType = array[0..7] of BDSElement;

  NtTuple = record
    NetworkNumber : integer;
    NodeID_SocketNumber : Bsplit;
    none_ObjectName : Bsplit;
    entityname : array[0..42] of integer;
   end;

  NamesTableEntry = record
    nextEntry : ^NamesTableEntry;
    NetworkNumber : integer;
    NodeID_SocketNumber : Bsplit;
    none_ObjectName : Bsplit;
    entityname : array[0..42] of integer;
   end;

{ Parameter Block information, heavily modified for Appletalk}

  ParamBlkPtr = ^ParamBlockRec;
  ParamBlockRec = record
    qLink : Ptr;
    qType : integer;
    ioTrap : integer;
    ioCmdAddr : ptr;
    ioCompletion : ptr;
    reqTid : integer;
    ioNamePtr : ^str255;{ also UserData }
    ioVrefnum : integer;
    ioRefNum : integer;
    csCode : integer;
    case integer of
     0 : (
       ATPSocket_ATPFlags : Bsplit;
       AddrBlock : AddrBlockrec;
       ReqLength : integer;
       Reqpointer : ptr;
       BDSpointer : ^BDSelement;
       numofBuffs_timeoutVal : Bsplit;
       numofResps_retrycount : Bsplit
     );
     1 : (
       curRBitmap_ATPflags : Bsplit;
       dummy1 : longint;
       confirmAddr : ptr;
       dummy2 : array[0..2] of integer;
       bitMap_BDSsize : Bsplit;
       transID : integer
     );
     2 : (
       interval_count : Bsplit;
       ntQElPtr : ^namesTableEntry;
       verifyFlag_none : Bsplit;
       dummy3 : integer;
       newSocket_none : Bsplit;
       dummy4 : longint;
       rspNum_none : Bsplit
     );
     3 : (
       dummy5 : integer;
       entityPtr : ^char;{ actually three packed str's }
       retBuffPtr : ptr;
       retbuffsize : integer;
       maxtoget : integer;
       numgotten : integer
     )
   end;

{common OS trap code}
{This nasty little piece is used to make the PBxx calls}
{described in the File Manager and the Device Manager}
{chapters of Inside Mac.  This is covered in detail in }
{MacTutor vol.1 no. 6, and also no.7 }  
 function filecall (Pb : ParamBlkPtr;
         trap : integer) : integer;{ OSError }
  var
   d0, a0 : longint;
   access : array[0..12] of integer;
 begin
  stuffHex(@access, '2848548C41FA000C309F245F265F20522013FFFF224826804ED4');
  a0 := ord(pb);
  inlineP($4E75, @d0, @a0, trap, @access);
  filecall := loword(d0);
 end;

{Given a pointer and three strings, pack them }
{end to end starting at the pointer }
 procedure pack3str (strP : strptr;
         s1, s2, s3 : str255);
 begin
  strP^ := s1;
  strP := pointer(ord(strP) + length(strP^) + 1);
  strP^ := s2;
  strP := pointer(ord(strP) + length(strP^) + 1);
  strP^ := s3;
 end;

{Open the drivers '.MPP', and '.ATP' if they are }
{not already open, and if the serial port is free. } 
{To understand this search high and low for } 
{descriptions of PortBUse, and SPConfig, which }
{are system globals (I'm still not totally sure how }
{these work).  }

function ATPLoad : integer;{ OSError }
  type
   r = record
     use : char;
    end;
  var
   pblock : ParamBlockRec;
   Tstr : str255;
   PortBUseP : ^r;
   SPConfigP : ^char;
   err : integer;
 begin
  pBlock.ioNamePtr := @Tstr;
  pBlock.dummy5 := 0;{ ioPermssn }
  PortBUseP := pointer($291);
  SPConfigP := pointer($1FB);
  with PortBUseP^ do
   begin
    writeln(' PortBuse is ', ord(use));
    if ord(use) > 127 then
     begin
      err := -98;{ assume portNotCf }
      if (ord(SPConfigP^) mod 16) < 2 then
       begin
        Tstr := '.MPP';
        err := filecall(@pBlock, $A000);{ open }
       end
     end
    else if (ord(use) mod 16) <> 1 then
     err := -97;{  PortInUse }
    if (not odd((ord(use) div 16))) and (err = 0) then
     begin
      Tstr := '.ATP';
      err := filecall(@pBlock, $A000);{ open }
     end;
   end;{ of with }
  ATPLoad := err;
 end;{ of function }

 function ATPcall (Pb : ParamBlkPtr) : integer;
 begin
  Pb^.ioRefNum := -11;
  ATPcall := filecall(Pb, $A004);{ control }
 end;

 function OpenATPSkt (Pb : ParamBlkPtr) : integer;
 begin
  Pb^.csCode := 254;
  OpenATPSkt := ATPcall(Pb);
 end;

 function CloseATPSkt (Pb : ParamBlkPtr) : integer;
 begin
  Pb^.csCode := 250;
  CloseATPSkt := ATPcall(Pb);
 end;

 function SendRequest (Pb : ParamBlkPtr) : integer;
 begin
  Pb^.csCode := 255;
  SendRequest := ATPcall(Pb);
 end;

 function GetRequest (Pb : ParamBlkPtr) : integer;
 begin
  Pb^.csCode := 253;
  GetRequest := ATPcall(Pb);
 end;

 function SendResponse (Pb : ParamBlkPtr) : integer;
 begin
  Pb^.csCode := 252;
  SendResponse := ATPcall(Pb);
 end;

 function MPPcall (Pb : ParamBlkPtr) : integer;
 begin
  Pb^.ioRefNum := -10;
  MPPcall := filecall(Pb, $A004);{ control }
 end;

 function RegisterName (Pb : ParamBlkPtr) : integer;
 begin
  Pb^.csCode := 253;
  RegisterName := MPPcall(Pb);
 end;

 function LookupName (Pb : ParamBlkPtr) : integer;
 begin
  Pb^.csCode := 251;
  LookupName := MPPcall(Pb);
 end;

 function RemoveName (Pb : ParamBlkPtr) : integer;
 begin
  Pb^.csCode := 252;
  RemoveName := MPPcall(Pb);
 end;
{ Above portion should be copied to Send_Fortune also.}

 procedure Get_Fortune;
  var
   Nblock, Sblock : ParamBlockRec;
   myNtable : NamesTableEntry;
   myTuple : ntTuple;
   myBDS : BDStype;
   strP : strptr;
   err : integer;
   reply : str255;
 begin
  if ATPLoad = 0 then
   begin
    with Nblock do
     begin
      interval_count[0] := chr(1);
      interval_count[1] := chr(32);
      strP := pointer(ord(           
                              @myNtable.none_ObjectName[1]));
      pack3str(strP, '=', 'Dial-A-Fortune', '=');
      entityPtr := pointer(ord(
                              @myNtable.none_ObjectName[1]));
      retBuffptr := pointer(ord(@myTuple));
      retBuffsize := sizeof(myTuple);
      maxToGet := 1;{ if larger use array of tuples}
      err := LookupName(@Nblock);
      writeln('lookup err', err);
     end;{ of with Nblock }
    if err = 0 then
     with Sblock do
      with myTuple do
       begin
        ATPsocket_ATPFlags[1] := chr(32);{atpXObit}
        addrBlock.aNet := networkNumber;
        addrBlock.aNode_Asocket[0] := 
                                            nodeID_SocketNumber[0];
        addrBlock.aNode_Asocket[1] := 
                                            nodeID_SocketNumber[1];
        reqLength := 0;{no request data}
        reqPointer := nil;
        bdsPointer := @myBDS;
        numOfBuffs_timeoutval[0] := chr(1);{buffers}
        numOfBuffs_timeoutval[1] := chr(2);{ seconds }
        numOfResps_retryCount[1] := chr(3);{ tries }
        myBDS[0].buffsize := 256;
        myBDS[0].buffPtr := pointer(ord(@reply));
        err := SendRequest(@Sblock);
        writeln('request err', err);
        writeln('fortune returned is - ', reply);
       end;
   end
  else
   writeln('Appletalk open error ', ATPLoad);
 end;

begin { main main main main main main }
 showtext;
 Get_Fortune;
end.
Send_Fortune listing:
note:upper portion is the same as Get_Fortune.
Copy and attach that portion to this.

 procedure Send_Fortune;
  var
   Ablock, Sblock : ParamBlockRec;
   myNtable : NamesTableEntry;
   myBDS : BDStype;
   strP : strptr;
   err : integer;
   buffer, reply : str255;
 begin
  reply := 'You will live long and prosper';
  if ATPLoad = 0 then
   begin
    Sblock.addrBlock.Anet := 0;
    Sblock.addrBlock.Anode_Asocket[0] := chr(0);
    Sblock.addrBlock.Anode_Asocket[1] := chr(0);
    Sblock.atpSocket_atpFlags[0] := chr(0);
    err := OpenATPSkt(@Sblock);
    writeln('open skt err', err);
    writeln('socket',      
                            ord(Sblock.atpSocket_atpFlags[0]));
    myNtable.nodeID_SocketNumber[1] := 
                                     Sblock.atpSocket_atpFlags[0];
    strP := 
            pointer(ord(@myNtable.none_ObjectName[1]));
    pack3str(strP, 
               'MacPascal Fortunes', 'Dial-A-Fortune', '*');
    Ablock.ntQElPtr := @myNtable;
    Ablock.interval_count[0] := chr(1);
    Ablock.interval_count[1] := chr(32);
    Ablock.verifyFlag_none[0] := chr(255);
    err := RegisterName(@Ablock);
    writeln('register err', err);
    if err = 0 then
     begin
      writeln('Sending fortunes, press mouse to quit');
      repeat{ send fortunes }
       begin
        Sblock.reqPointer := pointer(ord(@buffer));
        Sblock.reqLength := 256;
        err := GetRequest(@Sblock);
        writeln('get err', err);

        
        Sblock.ATPsocket_ATPflags[1] := chr(16);
           {ATPEomBit}
        Sblock.bdsPointer := @myBDS;
        Sblock.numofbuffs_timeoutval[0] := chr(1);
        Sblock.bitmap_bdssize[1] := chr(1);
        myBDS[0].buffPtr := pointer(ord(@reply));
        myBDS[0].dataSize := length(reply);
        myBDS[0].buffsize := 256;
        err := SendResponse(@Sblock);
        writeln('send err', err);
       end
      until button;
      Ablock.entityPtr := 
            pointer(ord(@myNtable.none_ObjectName[1]));
      err := RemoveName(@Ablock);
      writeln('remve err', err);
      err := CloseATPSkt(@Sblock);
      writeln('close SKT err', err);
     end;
   end
  else
   writeln('Appletalk open error ', ATPLoad);
 end;

begin { main main main main }
 showtext;
 Send_Fortune;
end.
 
AAPL
$524.94
Apple Inc.
+5.93
MSFT
$40.01
Microsoft Corpora
-0.39
GOOG
$536.10
Google Inc.
-20.44

MacTech Search:
Community Search:

Software Updates via MacUpdate

VMware Fusion 6.0.3 - Run Windows apps a...
VMware Fusion allows you to create a Virtual Machine on your Mac and run Windows (including Windows 8.1) and Windows software on your Mac. Run your favorite Windows applications alongside Mac... Read more
Tweetbot 1.5.1 - Popular iOS twitter cli...
Tweetbot is a full-featured OS X Twitter client with a lot of personality. Whether it's the meticulously-crafted interface, sounds and animation, or features like multiple timelines and column views... Read more
Mac DVDRipper Pro 4.1.7 - Copy, backup,...
Mac DVDRipper Pro is the DVD backup solution that lets you protect your DVDs from scratches, save your batteries by reading your movies from your hard disk, manage your collection with just a few... Read more
PDFpenPro 6.2 - Advanced PDF toolkit for...
PDFpenPro allows users to edit PDF's easily. Add text, images and signatures. Fill out PDF forms. Merge or split PDF documents. Reorder and delete pages. Even correct text and edit graphics! Create... Read more
PDFpen 6.2 - Edit and annotate PDFs with...
PDFpen allows users to easily edit PDF's. Add text, images and signatures. Fill out PDF forms. Merge or split PDF documents. Reorder and delete pages. Even correct text and edit graphics! Features... Read more
Monolingual 1.5.9 - Remove unwanted OS X...
Monolingual is a program for removing unnecesary language resources from OS X, in order to reclaim several hundred megabytes of disk space. It requires a 64-bit capable Intel-based Mac and at least... Read more
Maya 2015 - Professional 3D modeling and...
Maya is an award-winning software and powerful, integrated 3D modeling, animation, visual effects, and rendering solution. Because Maya is based on an open architecture, all your work can be scripted... Read more
Starcraft II: Wings of Liberty 1.1.1.180...
Download the patch by launching the Starcraft II game and downloading it through the Battle.net connection within the app. Starcraft II: Wings of Liberty is a strategy game played in real-time. You... Read more
Sibelius 7.5.0 - Music notation solution...
Sibelius is the world's best-selling music notation software for Mac. It is as intuitive to use as a pen, yet so powerful that it does most things in less than the blink of an eye. The demo includes... Read more
Typinator 5.9 - Speedy and reliable text...
Typinator turbo-charges your typing productivity. Type a little. Typinator does the rest. We've all faced projects that require repetitive typing tasks. With Typinator, you can store commonly used... Read more

Latest Forum Discussions

See All

Have a Special Dead Trigger 2 Easter Bas...
Have a Special Dead Trigger 2 Easter Basket Full of Goodies, Courtesy of Madfinger Games Posted by Rob Rich on April 18th, 2014 [ permalink ] Dead Trigger 2 | Read more »
Almost All of Playdek’s Library is on Sa...
Almost All of Playdek’s Library is on Sale Right Now, and You Should Check it Out Posted by Rob Rich on April 18th, 2014 [ permalink ] Playdek has released quite a few great iOS ports of board and card games over the years, and now most of them... | Read more »
Zynga Launches Brand New Farmville Exper...
Zynga Launches Brand New Farmville Experience with Farmville 2: Country Escape Posted by Tre Lawrence on April 18th, 2014 [ permalink ] | Read more »
David. Review
David. Review By Cata Modorcea on April 18th, 2014 Our Rating: :: MINIMALISTIC IN A DIFFERENT WAYUniversal App - Designed for iPhone and iPad David is a minimalistic game wrapped inside of a soothing atmosphere in which the hero... | Read more »
Eyefi Unveils New Eyefi Cloud Service Th...
Eyefi Unveils New Eyefi Cloud Service That Allows Users to Share Media Across Personal Devices Posted by Tre Lawrence on April 18th, 2014 [ permalink ] | Read more »
Tales from the Dragon Mountain: The Lair...
Tales from the Dragon Mountain: The Lair Review By Jennifer Allen on April 18th, 2014 Our Rating: :: STEADY ADVENTURINGiPad Only App - Designed for the iPad Treading a safe path, Tales from the Dragon Mountain: The Lair is a... | Read more »
Yahoo Updates Flickr App with Advanced E...
Yahoo Updates Flickr App with Advanced Editing Features and More Posted by Tre Lawrence on April 18th, 2014 [ permalink ] | Read more »
My Incredible Body - A Kid's App to...
My Incredible Body - A Kid's App to Learn about the Human Body 1.1.00 Device: iOS Universal Category: Education Price: $2.99, Version: 1.1.00 (iTunes) Description: Wouldn’t it be cool to look inside yourself and see what was going on... | Read more »
Trials Frontier Review
Trials Frontier Review By Carter Dotson on April 18th, 2014 Our Rating: :: A ROUGH LANDINGUniversal App - Designed for iPhone and iPad Trials Frontier finally brings the famed stunt racing franchise to mobile, but how much does its... | Read more »
Evernote Business Notebook by Moleskin I...
Evernote Business Notebook by Moleskin Introduced – Support Available in Evernote for iOS Posted by Tre Lawrence on April 18th, 2014 [ permalink ] | Read more »

Price Scanner via MacPrices.net

Free HopTo 2.2 Helps Enhance Your Productivit...
The HopTo app helps you do more on your iPad by providing more and easier adaccess to files and documents. Version 2.2 adds Egnyte and HopTo’s Mac OSX File Connector. If you already have the hopTo... Read more
National Distracted Driving Awareness Month:...
As the country recognizes National Distracted Driving Awareness Month, Sprint is reminding wireless consumers to focus on driving while behind the wheel, to not text or email while driving, and to... Read more
13-inch 2.4GHz Retina MacBook Pro available f...
Abt has the 13″ 2.4GHz 128GB Retina MacBook Pro available for $1229 including free shipping. Their price is $70 off MSRP. Read more
iMacs on sale for up to $160 off MSRP this we...
Best Buy has iMacs on sale for up to $160 off MSRP for a limited time. Choose free home shipping or free instant local store pickup (if available). Prices are valid for online orders only, in-store... Read more
iPad Airs on sale this weekend for up to $100...
Best Buy has WiFi iPad Airs on sale for $50 off MSRP and WiFi + Cellular iPad Airs on sale for $100 off MSRP on their online store for a limited time, with prices now starting at $449. Choose free... Read more
Apple restocks refurbished Mac minis starting...
The Apple Store has restocked Apple Certified Refurbished Mac minis for up to $150 off the cost of new models. Apple’s one-year warranty is included with each mini, and shipping is free: - 2.5GHz Mac... Read more
Hyundai Brings Apple CarPlay To The 2015 Sona...
Hyundai Motor America has announced it will bring Apple CarPlay functionality to the 2015 Sonata. CarPlay is pitched as a smarter, safer and easier way to use iPhone in the car and gives iPhone users... Read more
Updated iPads Coming Sooner Than We Had Thoug...
MacRumors, cites KGI securities analyst Ming Chi Kuo, well-respected as an Apple product prognisticator, saying that Apple will introduce an upgraded iPad Air and iPad mini in 2014/Q3, meaning the... Read more
Toshiba Unveils New High And Low End Laptop M...
Toshiba has announced new laptop models covering both the high-end and low-end of the notebook computer spectrum. Toshiba 4K Ultra HD Laptop Toshiba’s new Satellite P55t features one of the world’s... Read more
Save up to $270 with Apple refurbished 13-inc...
The Apple Store has Apple Certified Refurbished October 2013 13″ Retina MacBook Pros available starting at $1099, with models up to $270 off MSRP. Apple’s one-year warranty is standard, and shipping... Read more

Jobs Board

*Apple* Automotive Parts Department position...
Apple Automotive is one of the fastest growing dealer…and it shows. Consider making the switch to the Apple Automotive Group today! At Apple Automotive, we Read more
*Apple* Solutions Consultant (ASC) - Apple (...
**Job Summary** The ASC is an Apple employee who serves as an Apple brand ambassador and influencer in a Reseller's store. The ASC's role is to grow Apple Read more
*Apple* Retail - Manager - Holyoke - Apple I...
Job Summary Keeping an Apple Store thriving requires a diverse set of leadership skills, and as a Manager, you’re a master of them all. In the store’s fast-paced, Read more
*Apple* Retail - Manager - Apple (United Sta...
Job SummaryKeeping an Apple Store thriving requires a diverse set of leadership skills, and as a Manager, you're a master of them all. In the store's fast-paced, dynamic Read more
*Apple* Solutions Consultant (ASC) - Apple (...
**Job Summary** The ASC is an Apple employee who serves as an Apple brand ambassador and influencer in a Reseller's store. The ASC's role is to grow Apple Read more
All contents are Copyright 1984-2011 by Xplain Corporation. All rights reserved. Theme designed by Icreon.