Talk.c

#include <Stdio.h>
#include <Memory.h>
#include <Types.h>
#include <CursorCtl.h>
#include <AppleTalk.h>
#include <Packages.h>
#include <Events.h>
#include <SysEqu.h>
#include <Desk.h>
#include <Devices.h>
#include <Errors.h>
 
/*
                    © Copyright 1989 Apple Computer, Inc.
 
    This is an MPW 3.0 tool to demonstrate how AppleTalk calls are implemented in MPW C 3.0
    and assembler 3.0.
    AppleTalk protocols shown are:
    
        NBP
        DDP
        Echo
        ATP
        ZIP
    
        
    The functions we provide here are:
    
        Register a name in the network, the user provides an object name and a type,
        the tool provides a dummy socket listener so the socket does not get reused
        by another process.
        
        Lookup names in the network, the user can optionally give as parameters an
        object name, a type name, a zone or a combination of the three as search
        criteria.  Initial buffer allocated is for 200 names.
        
        Write a DDP packet.  The user provides a destination network number,
        destination node, socket, ddpType and optional data.  Before sending
        a ddp packet a socket is opened and a socket listener installed in case
        we receive a response, then the packet is sent out and we wait 30
        seconds for a response.  If a response is received then we display the
        data we got.
        The socket and its listener are then disposed of.
        
        Write an ATP packet.  The user provides a destination network number,
        destination node, socket, atpUserData and optional data.  The packet
        is sent out as a transaction request and we wait 30 seconds for a response.
        If a response is received then we display the data we got back.
        
        Write an Echo packet.  The user provides a destination network number,
        destination node, and optional data.  To send an Echo packet we first
        create a ddp socket and a socket listener to receive the echo reply.
        The packet is sent out and we wait 30 seconds for the echo reply.
        If a reply is received then we display the data we got.
        The ddp socket and its listener are then disposed of.
    
        Set SelfSend flag.  This enables or disables the capability to send
        and receive packets from our own machine.
        
        Zone names can be requested from the network, and the zone to which
        this machine belongs is pointed out to the user.
        
        
        NOTE:  THIS TOOL IS NOT FULLY COMMENTED BECAUSE A NEW VERSION WILL BE
        IMPLEMENTED IN C++
        
        
    Written by Ricardo Batista. 1/12/89
*/
 
#define Buf 20000
#define     TRUE        -1
#define     FALSE       0
 
 
#define     GetZoneList     0x8000000
#define     GetMyZone       0x7000000
 
 
pascal void InitDDPListener(ATDDPRec *ddp);
pascal void DDPListener(void);
 
 
 
 
typedef struct {
    short moveq0_d3;
    long jmp2_a4;
} dumb_listener;
 
 
 
 
void DoDDP(int argc, char* argv[], Boolean echo);
Boolean Abort(void);
void SetSelf(char* argv[]);
void Usage(char* argv[]);
void Names(int argc, char* argv[]);
void DoATP(int argc, char* argv[]);
void DoRegName(int argc, char* argv[]);
void DoZones(char* argv[]);
 
short mpp;
 
 
int main(int argc, char* argv[])
{
    short err;
    char *copyright = {"© 1989 Apple Computer, Inc.  By Ricardo Batista"};
    // short counter;
    
    // fprintf(stdout,"argc = %d\n",argc);
    // for (counter = 0; counter < argc; counter++)
        // fprintf(stdout,"argv[%d] = %s\n",counter,argv[counter]);
    // fflush(stdout);
    if (argc < 2) {
        Usage(argv);
        return(1);
    }
    InitCursorCtl(0L);
    SpinCursor(1);
    err = OpenDriver("\p.MPP",&mpp);
    if (err) {
        fprintf(stderr,"## %s: Error opening AppleTalk %d\n",argv[0],err);
        return(1);
    }
    SpinCursor(1);
    if ((argv[1][0] == '-') && ((argv[1][1] == 'n') || (argv[1][1] == 'N'))) {
        Names(argc, argv);
    }
    if ((argv[1][0] == '-') && ((argv[1][1] == 'r') || (argv[1][1] == 'R'))) {
        if (argc != 6) {
            Usage(argv);
            return(1);
        }
        DoRegName(argc, argv);
    }
    if ((argv[1][0] == '-') && ((argv[1][1] == 's') || (argv[1][1] == 'S'))) {
        if (argc != 3) {
            Usage(argv);
            return(1);
        }
        SetSelf(argv);
    }
    if ((argv[1][0] == '-') && ((argv[1][1] == 'd') || (argv[1][1] == 'D'))) {
        if (argc < 6) {
            Usage(argv);
            return(1);
        }
        DoDDP(argc, argv, false);
    }
    if ((argv[1][0] == '-') && ((argv[1][1] == 'e') || (argv[1][1] == 'E'))) {
        if (argc < 3) {
            Usage(argv);
            return(1);
        }
        DoDDP(argc, argv, true);
    }
    if ((argv[1][0] == '-') && ((argv[1][1] == 'a') || (argv[1][1] == 'A'))) {
        if (argc < 6) {
            Usage(argv);
            return(1);
        }
        DoATP(argc, argv);
    }
    if ((argv[1][0] == '-') && ((argv[1][1] == 'z') || (argv[1][1] == 'Z'))) {
        if (argc < 1) {
            Usage(argv);
            return(1);
        }
        DoZones(argv);
    }
    return(0);
}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
void DoRegName(int argc, char* argv[])
{
    EntityName name;
    short err, counter, len;
    THz zone;
    MPPParamBlock p;
    NamesTableEntry *NTPtr;
    short index;
    unsigned char socket;
    dumb_listener *listener;
    
    SpinCursor(1);
    zone = GetZone();
    SetZone(SystemZone());
    listener = (dumb_listener*) NewPtr(sizeof(dumb_listener));
    SetZone(zone);
    if (!listener) {
        fprintf(stderr,"## %s: Error getting space for socket listener\n\n",argv[0]);
        return;
    }
    listener->moveq0_d3 = 0x7600;
    listener->jmp2_a4 = 0x4EEC0002;
    p.MPPioCompletion = 0L;
    p.MPPioRefNum = mpp;
    p.DDPsocket = 0;
    p.DDPlistener = (Ptr) listener;
    err = POpenSkt(&p,FALSE);
    socket = p.DDPsocket;
    if (err) {
        fprintf(stderr,"## %s: Error opening socket %d\n\n",argv[0],err);
        return;
    }
    if (!socket) {
        fprintf(stderr,"## %s: Could not open socket, socket = %d, err = %d\n",argv[0],(short) socket,err);
        return;
    }
    name.objStr[1] = 0;
    name.typeStr[1] = 0;
    name.zoneStr[1] = 0;
    name.objStr[0] = '=';
    name.typeStr[0] = '=';
    name.zoneStr[0] = '*';
    for (counter = 2; counter < argc; counter++) {
        if (argv[counter][0] == '-') {
            if ((argv[counter][1] == 'o') || (argv[counter][1] == 'O')) {
                BlockMove(argv[counter + 1],name.objStr,33L);
            }
            if ((argv[counter][1] == 't') || (argv[counter][1] == 'T')) {
                BlockMove(argv[counter + 1],name.typeStr,33L);
            }
        }
    }
    len = sizeof(NamesTableEntry);
    if ((name.typeStr[0] == '=') || (name.objStr[0] == '=')) {
        fprintf(stderr,"## %s: Object and type names must not be any of '@ * = :'\n",argv[0]);
        return;
    }
    zone = GetZone();
    SetZone(SystemZone());
    NTPtr = (NamesTableEntry*) NewPtr(len);
    SetZone(zone);
    if (!NTPtr) {
        fprintf(stderr,"## %s: Not enough memory.\n",argv[0]);
        return;
    }
    NTPtr->nt.nteAddress.aSocket = socket;
    p.NBPinterval = 3;
    p.NBPcount = 3;
    p.NBPverifyFlag = TRUE;
    p.NBPntQElPtr = (Ptr) NTPtr;
    fprintf(stdout,"## %s: Registering: '%s:%s@*'\n\n",argv[0],name.objStr,name.typeStr);
    fflush(stdout);
    c2pstr(name.objStr);
    c2pstr(name.typeStr);
    c2pstr(name.zoneStr);
    BlockMove(name.objStr,&(NTPtr->nt.entityData[0]),33L);
    index = name.objStr[0] + 1;
    BlockMove(name.typeStr,&(NTPtr->nt.entityData[index]),33L);
    index += name.typeStr[0] + 1;
    BlockMove(name.zoneStr,&(NTPtr->nt.entityData[index]),33L);
    err = PRegisterName(&p,TRUE);
    while ((p.MPPioResult > 0) && !Abort())
            SpinCursor(1);
    err = p.MPPioResult;
    while (err == nbpDuplicate) {
        fprintf(stdout,"## %s: Duplicate name being modified\n",argv[0]);
        fflush(stdout);
        name.objStr[0]++;
        name.objStr[name.objStr[0]] = '1';
        BlockMove(name.objStr,&(NTPtr->nt.entityData[0]),33L);
        index = name.objStr[0] + 1;
        BlockMove(name.typeStr,&(NTPtr->nt.entityData[index]),33L);
        index += name.typeStr[0] + 1;
        BlockMove(name.zoneStr,&(NTPtr->nt.entityData[index]),33L);
        err = PRegisterName(&p,TRUE);
        while ((p.MPPioResult > 0) && !Abort())
            SpinCursor(1);
        err = p.MPPioResult;
    }
    if (err)
        fprintf(stderr,"## %s: err = %d\n",argv[0],err);
    else
        fprintf(stdout,"## %s: Socket %d\n\n",argv[0],(short) socket);
}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
void DoATP(int argc, char* argv[])
{
    ATPParamBlock a;
    short err = 0, counter, newline;
    long num;
    Str255 st;
    short len;
    char buffer[578],smallBuffer[5];
    BDSElement bds;
    
    a.ATPioCompletion = 0L;
    a.ATPatpSocket = 0;
    BlockMove(argv[2],st,33L);
    c2pstr(st);
    StringToNum(st,&num);
    a.ATPaddrBlock.aNet = (short) num;
    BlockMove(argv[3],st,33L);
    c2pstr(st);
    StringToNum(st,&num);
    a.ATPaddrBlock.aNode = (short) num;
    BlockMove(argv[4],st,33L);
    c2pstr(st);
    StringToNum(st,&num);
    a.ATPaddrBlock.aSocket = (short) num;
    BlockMove(argv[5],st,33L);
    c2pstr(st);
    StringToNum(st,&num);
    a.ATPuserData = num;
    a.ATPatpFlags = 0;
    a.ATPreqLength = 0;
    a.ATPreqPointer = 0L;
    a.ATPnumOfBuffs = 1;
    a.ATPtimeOutVal = 4;
    a.ATPretryCount = 3;
    a.ATPbdsPointer = (Ptr) &bds;
    bds.buffSize = 600;
    bds.buffPtr = &buffer[0];
    bds.dataSize = 0;
    bds.userBytes = 0L;
    buffer[0] = 0;
    len = 0;
    if (argc > 6) {
        a.ATPreqPointer = argv[6];
        len = strlen(argv[6]);
        fprintf(stdout,"## %s: ATPData to write is %d bytes\n",argv[0],len);
        a.ATPreqLength = len;
    }
    fflush(stdout);
    err = PSendRequest(&a,TRUE);
    while ((a.ATPioResult > 0) && !Abort())
        SpinCursor(1);
    err = a.ATPioResult;
    if (err) {
        if (err == 1)
            PKillSendReq(&a,false);
    }
    if (err)
        fprintf(stderr,"## %s: Error doing ATPRequest %d\n",argv[0],err);
    else {
        fprintf(stdout,"## %s: ATP packet sent, %d ATPData bytes sent.\n",argv[0],len);
        fprintf(stdout,"## %s: Response user data is %ld = '",argv[0],bds.userBytes);
        BlockMove((Ptr) &(bds.userBytes),(Ptr) &smallBuffer[0],4L);
        smallBuffer[4] = 0;
        fprintf(stdout,"%s'\n\n",smallBuffer);
        len = bds.dataSize;
        fprintf(stdout,"## %s: Actual response bytes: %d\n",argv[0],len);
        if (len) {
            for (counter = 0; counter < len; counter++, newline++) {
                fprintf(stdout,"%c",buffer[counter]);
                if (buffer[counter] == '\n')
                    newline = 0;
                if ((newline % 70) == 0)
                    fprintf(stdout,"\n");
            }
        }
    }
    fprintf(stdout,"\n\n");
}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
void DoDDP(int argc, char* argv[], Boolean echo)
{
    MPPParamBlock p;
    short err = 0;
    unsigned char socket = 0;
    long num;
    Str255 st;
    short len, type;
    char buffer[600];
    long ticks;
    int counter;
    WDSElement wds[4];
    AddrBlock address;
    unsigned char header[20];
    ATDDPRec ddp;
    char echoRequest = 1;
    
    ddp.abResult = 1;
    ddp.ddpActCount = 0;
    ddp.ddpReqCount = 586;
    ddp.ddpDataPtr = buffer;
    p.MPPioCompletion = 0L;
    p.MPPioRefNum = mpp;
    p.DDPsocket = 0;
    p.DDPlistener = (Ptr) (ProcPtr) DDPListener;
    err = POpenSkt(&p,FALSE);
    socket = p.DDPsocket;
    if (err) {
        fprintf(stderr,"## %s: Error opening socket %d\n\n",argv[0],err);
        return;
    }
    if (!socket) {
        fprintf(stderr,"## %s: Could not open socket, socket = %d, err = %d\n",argv[0],(short) socket,err);
        return;
    }
    InitDDPListener(&ddp);
    fprintf(stdout,"## %s: Temporary Socket is %d\n",argv[0],(short) socket);
    fflush(stdout);
    BlockMove(argv[2],st,33L);
    c2pstr(st);
    StringToNum(st,&num);
    address.aNet = (short) num;
    BlockMove(argv[3],st,33L);
    c2pstr(st);
    StringToNum(st,&num);
    address.aNode = (short) num;
    len = 0;
    wds[2].entryLength = 0;
    wds[2].entryPtr = 0L;
    wds[3].entryLength = 0;
    wds[3].entryPtr = 0L;
    if (!echo) {
        BlockMove(argv[4],st,33L);
        c2pstr(st);
        StringToNum(st,&num);
        address.aSocket = (short) num;
        BlockMove(argv[5],st,33L);
        c2pstr(st);
        StringToNum(st,&num);
        type = num;             // ddpType to use
        if (argc > 6) {
            len = strlen(argv[6]);
            fprintf(stdout,"## %s: DDPData to write is %d bytes\n",argv[0],len);
        }
        wds[1].entryPtr = argv[6];
        wds[1].entryLength = len;
    }
    else {
        address.aSocket = 4;
        type = 4;
        len = strlen(argv[4]);
        fprintf(stdout,"## %s: Echo protocol data to write is %d bytes\n",argv[0],len);
        wds[1].entryLength = 1;
        wds[1].entryPtr = &echoRequest;
        wds[2].entryLength = len;
        wds[2].entryPtr = argv[4];
    }
    p.MPPioResult = 1;
    p.MPPioCompletion = 0L;
    p.MPPioRefNum = mpp;
    p.DDPchecksumFlag = FALSE;
    p.DDPsocket = socket;
    p.DDPwdsPointer = (Ptr) wds;
    fflush(stdout);
    wds[0].entryPtr = &header[1];
    wds[0].entryLength = 16;
    BlockMove((Ptr) &address.aNet,&header[8],2L);
    header[12] = address.aNode;
    header[14] = address.aSocket;
    header[16] = type;
    err = PWriteDDP(&p,TRUE);
    while ((p.MPPioResult > 0) && !Abort())
        SpinCursor(1);
    if (!err)
        err = p.MPPioResult;
    if (err)
        fprintf(stderr,"## %s: Error doing DDPWrite %d\n",argv[0],err);
    else {
        ticks = TickCount() + 1800;
        fprintf(stdout,"## %s: DDP packet type %d sent, %d DDPData bytes sent.\n",argv[0],type,len);
        fprintf(stdout,"## %s: waiting for a response (30 seconds)...\n",argv[0]);
        fflush(stdout);
        while ((ticks > TickCount()) && (ddp.abResult == 1) && !Abort())
            SpinCursor(1);
        if (ddp.abResult == 0) {
            len = ddp.ddpActCount;
            fprintf(stdout,"## %s: Response received... %d bytes\n",argv[0],len);
            for (counter = 0; counter < len; counter++)
                fprintf(stdout,"%c",buffer[counter]);
            fprintf(stdout,"\n\n");
        }
        if (ddp.abResult > 0) {
            fprintf(stdout,"## %s: No response...\n",argv[0]);
        }
        if (ddp.abResult < 0)
            fprintf(stdout,"## %s: Error reading a packet id %d...\n",argv[0],ddp.abResult);
    }
    err = PCloseSkt(&p,FALSE);
    if (err)
        fprintf(stderr,"## %s: Error disposing of socket %d\n",argv[0],err);
}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
Boolean Abort(void)
{
    EventRecord myEvent;
    char theChar;
    
    if (EventAvail(keyDownMask,&myEvent)) {
        GetNextEvent(keyDownMask,&myEvent);
        theChar = myEvent.message & charCodeMask;
        if (theChar == '.') {
            if (myEvent.modifiers & cmdKey)
                return(true);
        }
    }
    return(false);
}
 
 
 
 
 
 
 
 
 
 
void SetSelf(char* argv[])
{
    MPPParamBlock p;
    short err;
    
    p.MPPioCompletion = 0L;
    p.MPPioRefNum = mpp;
    p.SETSELF.newSelfFlag = argv[2][0] - '0';
    err = PSetSelfSend(&p,false);
    if (err)
        fprintf(stderr,"## %s: Error setting SelfSend flag %d",argv[0],err);
    else
        fprintf(stdout,"## %s: Old SelfSend flag is %d\n",argv[0],(short) p.SETSELF.oldSelfFlag);
}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
void Usage(char* argv[])
{
    fprintf(stderr,"## %s: No parameters specified.\n## Usage :\n",argv[0]);
    fprintf(stderr,"## -n -o ObjectName -t TypeName -z zoneName ## Shows network names\n");
    fprintf(stderr,"## -s 1 | 0                                 ## Sets Self send flag\n");
    fprintf(stderr,"## -d Net Node Socket ddpType [data]        ## Sends DDP packet\n");
    fprintf(stderr,"## -e Net Node [Echo data]                  ## Sends Echo packet\n");
    fprintf(stderr,"## -a Net Node Socket [UData] [data]        ## Sends ATPRequest\n");
    fprintf(stderr,"## -r -o ObjectName -t TypeName             ## Registers Name\n");
    fprintf(stderr,"## -z                                       ## Display zone names\n");
    fprintf(stderr,"## © 1989 Apple Computer, Inc. by Ricardo Batista\n## Version 1.1\n\n");
}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
void Names(int argc, char* argv[])
{
    AddrBlock address;
    EntityName name;
    short err, counter;
    Handle buffer = 0L;
    short found;
    MPPParamBlock p;
    char Entity[100];
    
    p.MPPioCompletion = 0L;
    p.MPPioRefNum = mpp;
    SpinCursor(1);
    buffer = NewHandle(Buf);
    if (!buffer) {
        fprintf(stderr,"## %s: Not enough memory.\n",argv[0]);
        return;
    }
    HLock(buffer);
    name.objStr[1] = 0;
    name.typeStr[1] = 0;
    name.zoneStr[1] = 0;
    name.objStr[0] = '=';
    name.typeStr[0] = '=';
    name.zoneStr[0] = '*';
    for (counter = 2; counter < argc; counter++) {
        if (argv[counter][0] == '-') {
            if ((argv[counter][1] == 'o') || (argv[counter][1] == 'O')) {
                BlockMove(argv[counter + 1],name.objStr,33L);
            }
            if ((argv[counter][1] == 't') || (argv[counter][1] == 'T')) {
                BlockMove(argv[counter + 1],name.typeStr,33L);
            }
            if ((argv[counter][1] == 'z') || (argv[counter][1] == 'Z')) {
                BlockMove(argv[counter + 1],name.zoneStr,33L);
            }
        }
    }
    fprintf(stdout,"## %s: Network search for: '%s' '%s' '%s'\n\n\n",argv[0],name.objStr,name.typeStr,name.zoneStr);
    fflush(stdout);
    c2pstr(name.objStr);
    c2pstr(name.typeStr);
    c2pstr(name.zoneStr);
    BlockMove(name.objStr,Entity,33L);
    counter = Entity[0] + 1;
    BlockMove(name.typeStr,&Entity[counter],33L);
    counter += name.typeStr[0] + 1;
    BlockMove(name.zoneStr,&Entity[counter],33L);
    p.NBPinterval = 5;
    p.NBPcount = 4;
    p.NBPentityPtr = Entity;
    p.NBPretBuffPtr = *buffer;
    p.NBPretBuffSize = Buf;
    p.NBPmaxToGet = Buf / 110;
    err = PLookupName(&p,FALSE);
    if (!err) {
        while ((p.MPPioResult > 0) && !Abort())
            SpinCursor(1);
    }
    err = p.MPPioResult;
    if (!err) {
        found = p.NBPnumGotten;
        if (found > 1)
            fprintf(stdout,"## %s: %d matches\n",argv[0],found);
        if (found == 1)
            fprintf(stdout,"## %s: %d match\n",argv[0],found);
        if (found == 0)
            fprintf(stdout,"## %s: No matches\n",argv[0]);
        if (found) {
            fprintf(stdout,"Object                    Type                      Zone                ");
            fprintf(stdout,"Net    Node  Socket\n\n");
        }
        for (counter = 0; counter < found; counter++) {
            address.aNet = 0;
            err = myNBPExtract(*buffer,found,counter + 1,&name, &address);
            p2cstr(name.objStr);
            p2cstr(name.typeStr);
            p2cstr(name.zoneStr);
            fprintf(stdout,"%-25s %-25s %-20s",name.objStr,name.typeStr,name.zoneStr);
            fprintf(stdout,"%-5u   %-5u %-5u\n",(unsigned short) address.aNet,address.aNode,address.aSocket);
        }
    }
    fflush(stdout);
    if (err)
        fprintf(stderr,"err = %d\n",err);
    if (buffer)
        DisposHandle(buffer);
    buffer = 0L;
}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
int myNBPExtract(buffer,howMany,which,Name,Addr)
char *buffer;
int howMany;
int which;
EntityName *Name;
AddrBlock *Addr;
{
    char *p;
    register int index = 1, nameCounter = 0;
    
    p = buffer;
    while ((index < which) && (index < howMany)) {
        p += 5; /* skip addr and enumerator */
        p += (*p) + 1;  /* skip name */
        p += (*p) + 1;  /* skip type */
        p += (*p) + 1;  /* skip zone */
        index++;
    }
    BlockMove(p,(Ptr) Addr,4L);
    p += 5;
    BlockMove(p,Name->objStr,33L);
    p += (*p) + 1;
    BlockMove(p,Name->typeStr,33L);
    p += (*p) + 1;
    BlockMove(p,Name->zoneStr,33L);
    return(0);
}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
void DoZones(char* argv[])
{
    ATPParamBlock a;
    short err = 0, counter;
    short len;
    char buffer[578];
    BDSElement bds;
    short abridge, node, net;
    short howMany = 0, zones = 0;
    char dummy[4];
    long ourData;
    Boolean done = FALSE;
    short index;
    char st[100];
    
    abridge = GetBridgeAddress();
    if (!abridge) {
        fprintf(stdout,"## %s: No zones in the network.\n\n",argv[0]);
        return;
    }
    net = node = 0;
    GetNodeAddress(&node,&net);
    a.ATPioCompletion = 0L;
    a.ATPatpSocket = 0;
    a.ATPaddrBlock.aNet = net;
    a.ATPaddrBlock.aNode = abridge;
    a.ATPaddrBlock.aSocket = 6;
    a.ATPuserData = GetZoneList;
    a.ATPatpFlags = 0;
    a.ATPreqLength = 0;
    a.ATPreqPointer = 0L;
    a.ATPnumOfBuffs = 1;
    a.ATPtimeOutVal = 4;
    a.ATPretryCount = 3;
    a.ATPbdsPointer = (Ptr) &bds;
    bds.buffSize = 600;
    bds.buffPtr = &buffer[0];
    bds.dataSize = 0;
    bds.userBytes = 0L;
    buffer[0] = 0;
    ourData = 1;
    fprintf(stdout,"\n## %s: Getting the zone names from a router....\n\n",argv[0]);
    fflush(stdout);
    while (!done) {
        ourData |= GetZoneList;
        a.ATPuserData = ourData;
        err = PSendRequest(&a,TRUE);
        while ((a.ATPioResult > 0) && !Abort())
            SpinCursor(1);
        err = a.ATPioResult;
        if (err) {
            fprintf(stderr,"## %s: Error requesting for zones %d\n",argv[0],err);
            done = TRUE;
            zones = 0;
            if (err == 1)
                PKillSendReq(&a,false);
        }
        else {
            BlockMove((Ptr) &(bds.userBytes),dummy,4L);
            BlockMove(&dummy[2],(Ptr) &howMany,2L);
            zones += howMany;
            ourData = zones;
            if (!done) {
                for (counter = 0, index = 0; counter < howMany; counter++) {
                    len = buffer[index] + 1;
                    BlockMove(&buffer[index],st,(long) len);
                    p2cstr(st);
                    fprintf(stdout,"## '%s'\n",st);
                    index += len;
                }
                done = dummy[0];
                fflush(stdout);
            }
        }
    }
    if (zones) {
        buffer[0] = 0;
        a.ATPuserData = GetMyZone;
        err = PSendRequest(&a,TRUE);
        while ((a.ATPioResult > 0) && !Abort())
            SpinCursor(1);
        err = a.ATPioResult;
        if (!err) {
            p2cstr(buffer);
            fprintf(stdout,"\n## %s: My zone is '%s'\n",argv[0],buffer);
        }
    }
    fprintf(stdout,"\n\n");
}