Talker.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>
#include <Fonts.h>
#include <Menus.h>
#include <ToolUtils.h>
#include <Events.h>
#include <Resources.h>
#include <OSEvents.h>
#include <Scrap.h>
 
 
 
/*
                    © Copyright 1991 Apple Computer, By Ricardo Batista
 
    This is a quick and dirty application to chat over the network using
    
        
        
    Written by Ricardo Batista. 1/31/91
*/
 
 
#define     appleMenu           128
#define     fileMenu            129
#define     editMenu            130
#define     setupMenu           131
 
 
#define     quitItem            1
 
#define     undoItem            1
#define     cutItem             3
#define     copyItem            4
#define     pasteItem           5
#define     clearItem           6
 
#define     configureItem       1
 
#define     okItem          1
#define     cancelItem      2
 
#define     MAXADDRBLOCKS       100
 
#define     LOOKUPBUFSIZE       20000
 
pascal void InitDDPListener(ATDDPRec *ddp);
pascal void DDPListener(void);
 
void DoAbout(void);
void NewMessage(void);
void SetMenus(void);
void AnalizeKeys(void);
Boolean Working(void);
Boolean DoCommand(long mResult);
Boolean HandleMouseDowns(void);
void Configure(void);
void ShowStatus(void);
void CleanUp(void);
void AdjustTextScrollBar();
void Message(char *mess);
short DoDDP(char *st);
short DoRegName(void);
void CleanTalk(void);
Boolean Setup(void);
void Names(void);
short myNBPExtract(char *buffer,int howMany,int which,EntityName *Name,AddrBlock *Addr);
 
 
char ourName[60];
EventRecord myEvent;
Boolean commandK, shiftK, optionK;
Boolean inFront;
short err;
MenuHandle myMenu[5];
WindowPtr textWindow = 0L;
TEHandle textTE = 0L;
ControlHandle textScrollBar = 0L;
WindowRecord wRec;
 
short mpp = 0, socket = 0;
NamesTableEntry *NTPtr = 0L;
MPPParamBlock p;
ATDDPRec ddp;
char buffer[1000];
AddrBlock *users;
 
 
 
void main()
{
    short err, len;
    char *copyright = {"© 1991 Apple Computer, Inc.  By Ricardo Batista"};
    char st[256];
    
    if (!Setup())
        return;
    err = OpenDriver("\p.MPP",&mpp);
    if (err) {
        Message("\pAppleTalk is not available");
        return;
    }
    err = DoRegName();
    Names();
    BlockMove("\pEntering the network...",st,30L);
    len = ourName[0];
    BlockMove(&ourName[1], &st[st[0] + 1], (long) len);
    st[0] += len;
    err = DoDDP(st);
    if (err)
        Message("\pError writing to network.");
    while (Working())
        ;
    BlockMove("\pLeaving the network...",st,30L);
    len = ourName[0];
    BlockMove(&ourName[1], &st[st[0] + 1], (long) len);
    st[0] += len;
    err = DoDDP(st);
    CleanTalk();
}
 
 
 
 
 
Boolean Setup(void)
{
    short counter;
    Rect box, bounds;
    
    for (counter = 0; counter < 10; counter++)
        MoreMasters();
    InitGraf(&qd.thePort);
    InitFonts();
    InitWindows();
    TEInit();
    InitMenus();
    InitDialogs(0L);
    DrawMenuBar();
    FlushEvents(everyEvent,0L);
    InitCursor();
    MaxApplZone();
    SetCursor(*GetCursor(watchCursor));
    InitAllPacks();
    SetMenus();
    box.top = 40;
    box.left = 10;
    box.right = 500;
    box.bottom = 300;
    textWindow = NewWindow((Ptr) &wRec,&box,"\pNeighborhood Watch  by Ricardo Batista",1,documentProc,
                    (WindowPtr) -1L,0,0L);
    if (!textWindow)
        return(false);
    SetPort(textWindow);
    TextSize(9);
    TextFont(1);
    box = textWindow->portRect;
    box.left = 5;
    box.bottom -= 16;
    box.right -= 16;
    bounds.top = box.top;
    bounds.left = 5;
    bounds.right = box.right;
    bounds.bottom = 2000;
    textTE = TENew(&bounds,&box);
    if (!textTE)
        return(false);
    box = textWindow->portRect;
    box.top--;
    box.right -= 15;
    bounds.top = box.top;
    bounds.left = box.right;
    bounds.right = bounds.left + 16;
    bounds.bottom = box.bottom - 14;
    textScrollBar = NewControl(textWindow,&bounds,"\p",1,1,1,1,scrollBarProc,(long) textTE);
    BeginUpdate(textWindow);
    EndUpdate(textWindow);
    DrawGrowIcon(textWindow);
    TEActivate(textTE);
    AdjustTextScrollBar();
    inFront = true;
    ddp.abResult = 1;
    ddp.ddpActCount = 0;
    ddp.ddpReqCount = 586;
    ddp.ddpDataPtr = buffer;
    users = (AddrBlock*) NewPtrClear(sizeof(AddrBlock) * MAXADDRBLOCKS);
    return(true);
}
 
 
 
 
 
 
void CleanTalk()
{
    if (socket && NTPtr) {
        p.NBPntQElPtr = (Ptr) &(NTPtr->nt.entityData[0]);
        err = PRemoveName(&p,false);
        DisposPtr((Ptr) NTPtr);
        p.DDPsocket = (unsigned char) socket;
        err = PCloseSkt(&p,false);
        if (err)
            Message("\pCould not close socket.");
    }
    if (textWindow)
        CloseWindow(textWindow);
    if (textTE)
        TEDispose(textTE);
}
 
 
 
 
 
void SetMenus()
{
    char appleStr[2];
    
    appleStr[0] = 1;
    appleStr[1] = 0x14;
    myMenu[appleMenu - 128] = NewMenu(appleMenu,appleStr);
    myMenu[fileMenu - 128] = NewMenu(fileMenu,"\pFile");
    myMenu[editMenu - 128] = NewMenu(editMenu,"\pEdit");
    myMenu[setupMenu - 128] = NewMenu(setupMenu,"\pTalk");
    
    AppendMenu(myMenu[appleMenu - 128],"\pAbout Neighborhood Watch...;(-");
    AddResMenu(myMenu[appleMenu - 128],'DRVR');
    
    AppendMenu(myMenu[fileMenu - 128],"\pQuit/Q");
    AppendMenu(myMenu[editMenu - 128],"\pUndo;(-;Cut/X;Copy/C;Paste/V;Clear");
    AppendMenu(myMenu[setupMenu - 128],"\pSend A Message/M");
    InsertMenu(myMenu[appleMenu - 128],0);
    InsertMenu(myMenu[fileMenu - 128],0);
    InsertMenu(myMenu[editMenu - 128],0);
    InsertMenu(myMenu[setupMenu - 128],0);
    DrawMenuBar();
}
 
 
 
 
 
 
 
 
short DoRegName()
{
    EntityName name;
    short err, len;
    short index;
    StringHandle H;
    
    H = GetString(-16096);
    if (H) {
        LoadResource((Handle) H);
        HLock((Handle) H);
        BlockMove((Ptr) *H, ourName, 40L);
        HUnlock((Handle) H);
        ReleaseResource((Handle) H);
    }
    else {
        ourName[0] = 1;
        ourName[1] = '?';
    }
    p.MPPioCompletion = 0L;
    p.MPPioRefNum = mpp;
    p.DDPsocket = 0;
    p.DDPlistener = (Ptr) StripAddress((Ptr) (ProcPtr) DDPListener);
    err = POpenSkt(&p,true);
    while (p.MPPioResult == 1)
        ;
    if (err) {
        Message("\pCould not open AppleTalk socket !!!");
        return(err);
    }
    socket = p.DDPsocket;
    name.zoneStr[0] = 1;
    name.zoneStr[1] = '*';
    BlockMove("\pNeighborhood Watch",name.typeStr, 20L);
    len = sizeof(NamesTableEntry);
    
    NTPtr = (NamesTableEntry*) NewPtrClear(len);
    if (!NTPtr)
        return(MemErr);
    NTPtr->nt.nteAddress.aSocket = socket;
    p.NBPinterval = 3;
    p.NBPcount = 3;
    p.NBPverifyFlag = true;
    p.NBPntQElPtr = (Ptr) NTPtr;
    BlockMove(ourName,&(NTPtr->nt.entityData[0]),33L);
    index = ourName[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 == 1)
        ;
    err = p.MPPioResult;
    while (err == nbpDuplicate) {
        ourName[0]++;
        ourName[ourName[0]] = '1';
        BlockMove(ourName,&(NTPtr->nt.entityData[0]),33L);
        index = ourName[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 == 1)
            ;
        err = p.MPPioResult;
    }
    if (err)
        Message("\pCould not register name in network.");
    InitDDPListener(&ddp);
    return(noErr);
}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
// I tried making network wide broadcasts, but seems like the FX didn't like opening static sockets,
// there was no problem with the SE30 and Portable, but the FX was a problem...
 
 
 
short DoDDP(char *st)
{
    MPPParamBlock p;
    short err = 0;
    WDSElement wds[4];
    unsigned char header[20];
    register short counter;
    
    wds[2].entryLength = 0;
    wds[2].entryPtr = 0L;
    wds[3].entryLength = 0;
    wds[3].entryPtr = 0L;
    wds[1].entryPtr = st;
    wds[1].entryLength = st[0] + 1;
    p.MPPioResult = 1;
    p.MPPioCompletion = 0L;
    p.MPPioRefNum = mpp;
    p.DDPchecksumFlag = false;
    p.DDPsocket = socket;
    p.DDPwdsPointer = (Ptr) wds;
    wds[0].entryPtr = &header[1];
    wds[0].entryLength = 16;
    
    header[16] = 44;        // Type;
    for (counter = 0; counter < MAXADDRBLOCKS;) {
        BlockMove((Ptr) &(users[counter].aNet),&header[8],2L);
        header[14] = users[counter].aSocket;    //  Socket;
        header[12] = users[counter].aNode;      // Node
        err = PWriteDDP(&p,true);
        while (p.MPPioResult == 1)
            ;
        counter++;
        if (users[counter].aNet == 0)
            counter = MAXADDRBLOCKS + 1;
    }
    if (!err)
        err = p.MPPioResult;
    return(err);
}
 
 
 
 
 
 
 
 
 
 
 
 
void UpdateTextWindow()
{
    GrafPtr savePort;
    Rect box;
    
    GetPort(&savePort);
    SetPort(textWindow);
    BeginUpdate(textWindow);
    box = textWindow->portRect;
    TEUpdate(&box,textTE);
    EndUpdate(textWindow);
    DrawGrowIcon(textWindow);
    SetPort(savePort);
}
 
 
 
 
 
 
void AnalizeKeys()
{
    if (myEvent.modifiers & cmdKey)
        commandK = true;
    else
        commandK = false;
    if (myEvent.modifiers & shiftKey)
        shiftK = true;
    else
        shiftK = false;
    if (myEvent.modifiers & optionKey)
        optionK = true;
    else
        optionK = false;
}
 
 
 
 
 
Boolean Working()
{
    register char theChar;
    register Boolean event;
    WindowPtr w;
    GrafPtr savePort;
    Rect box;
    Point mouse;
    short lines;
    register long counter;
    
    if (ddp.abResult == 0) {
        Message(buffer);
        ddp.abResult = 1;
        for (counter = 0; counter < MAXADDRBLOCKS; counter++) {
            if ((users[counter].aNet == 0) && (users[counter].aNode == 0)) {
                users[counter] = ddp.ddpAddress;
                counter = MAXADDRBLOCKS + 1;
                Message("\pA new user has been recorded.");
            }
            else {
                if ((ddp.ddpAddress.aNet == users[counter].aNet) && 
                                (ddp.ddpAddress.aNode == users[counter].aNode))
                        counter = MAXADDRBLOCKS + 1;
            }
        }
    }
    event = GetNextEvent(everyEvent,&myEvent);
    AnalizeKeys();
    w = FrontWindow();
    if ((w == textWindow) && inFront && textTE) {
        GetPort(&savePort);
        SetPort(textWindow);
        TEIdle(textTE);
        box = w->portRect;
        GetMouse(&mouse);
        box.right -= 16;
        box.bottom -= 16;
        if (PtInRect(mouse,&box))
            SetCursor(*(GetCursor(iBeamCursor)));
        else
            InitCursor();
        SetPort(savePort);
    }
    if (event) {
        switch (myEvent.what) {
            case app4Evt:
                if (myEvent.modifiers & 128)
                    inFront = true;
                else
                    inFront = false;
                break;
            case activateEvt:
                w = (WindowPtr) myEvent.message;
                if (myEvent.modifiers & activeFlag) {
                    if (w == textWindow)
                        TEActivate(textTE);
                }
                else {
                    if (w == textWindow)
                        TEDeactivate(textTE);
                }
                break;
            case keyDown:
            case autoKey:
                theChar =  myEvent.message & charCodeMask;
                if (commandK) {
                    if (!DoCommand(MenuKey(theChar)))
                        return(false);
                }
                else {
                    w = FrontWindow();
                    if (w == textWindow) {
                        lines = (**textTE).nLines;
                        TEKey(theChar,textTE);
                        if (lines != (**textTE).nLines)
                            AdjustTextScrollBar();
                    }
                }
                break;
            case updateEvt:
                w = (WindowPtr) myEvent.message;
                if (w == textWindow)
                    UpdateTextWindow();
                break;
            case mouseDown:
                if (!HandleMouseDowns())
                    return(false);
                break;
            default:
                break;
        }
    }
    return(true);
}
 
 
 
 
 
 
 
 
 
 
pascal void CtlAction(theControl, part)
ControlHandle theControl;
short part;
{
    TEHandle TE;
    short newValue, value, v, max;
    
    TE = (TEHandle) GetCRefCon(theControl);
    max = GetCtlMax(theControl);
    v = (**TE).lineHeight;
    newValue = value = GetCtlValue(theControl);
    if (part == inPageUp) {
        newValue -= 12;
        if (newValue < 1)
            newValue = 1;
        SetCtlValue(theControl,newValue);
    }
    if (part == inPageDown) {
        newValue += 12;
        if (newValue > max)
            newValue = max;
        SetCtlValue(theControl,newValue);
    }
    if (part == inUpButton) {
        newValue--;
        if (newValue < 1)
            newValue = 1;
        SetCtlValue(theControl,newValue);
    }
    if (part == inDownButton) {
        newValue++;
        if (newValue > max)
            newValue = max;
        SetCtlValue(theControl,newValue);
    }
    if (value != newValue)
        TEScroll(0,(value - newValue) * v,TE);
}
 
 
 
 
 
 
 
 
void HandleMouseInText()
{
    short where;
    ControlHandle whichControl;
    short value, oldValue;
    short v;
    Rect box;
    
    SetPort(textWindow);
    GlobalToLocal(&myEvent.where);
    where = FindControl(myEvent.where,textWindow,&whichControl);
    switch (where) {
        case inUpButton:
        case inDownButton:
        case inPageUp:
        case inPageDown:
            TrackControl(whichControl,myEvent.where,(ProcPtr) CtlAction);
            break;
        case inThumb:
            v = (**(textTE)).lineHeight;
            oldValue = GetCtlValue(whichControl);
            if (TrackControl(whichControl,myEvent.where,0L)) {
                value = GetCtlValue(whichControl);
                if (value != oldValue) {
                    TEScroll(0,(oldValue - value) * v,textTE);
                }
            }
            break;
        case 0:
            box = (**(textTE)).viewRect;
            if (PtInRect(myEvent.where,&box))
                TEClick(myEvent.where,shiftK,textTE);
            break;
        default:
            break;
    }
}
 
 
 
 
 
 
void AdjustTextScrollBar()
{
    short lines;
    short v;
    short top, bottom;
    
    lines = (**textTE).nLines;
    v = (**textTE).lineHeight;
    top = (**textTE).viewRect.top;
    bottom = (**textTE).viewRect.bottom;
    bottom -= top + 10;
    lines -= bottom / v;
    if (lines < 1)
        lines = 1;
    if (lines > 1)
        lines++;
    SetCtlMax(textScrollBar,lines);
    if (lines > 1)
        HiliteControl(textScrollBar,0);
    else
        HiliteControl(textScrollBar,255);
}
 
 
 
 
 
Boolean DoCommand(mResult)
long mResult;
{
    register short theItem;
    char st[250];
    
    theItem = LoWord(mResult);
    switch (HiWord(mResult)) {
        case appleMenu:
                GetItem(myMenu[0],theItem,st);
                if (theItem > 2)
                    OpenDeskAcc(st);
                else
                    DoAbout();
                break;
        case fileMenu:
                switch (theItem) {
                    case quitItem:
                        return(false);
                        break;
                    default:
                        break;
                }
                break;
        case editMenu:
                if (!SystemEdit(theItem -1)) {
                    switch (theItem) {
                        case undoItem:
                            break;
                        case cutItem:
                            if (textTE) {
                                TECut(textTE);
                                AdjustTextScrollBar();
                            }
                            ZeroScrap();
                            TEToScrap();
                            break;
                        case copyItem:
                            if (textTE)
                                TECopy(textTE);
                            ZeroScrap();
                            TEToScrap();
                            break;
                        case pasteItem:
                            TEFromScrap();
                            if (textTE) {
                                TEPaste(textTE);
                                AdjustTextScrollBar();
                            }
                            break;
                        case clearItem:
                            if (textTE) {
                                TEDelete(textTE);
                                AdjustTextScrollBar();
                            }
                            break;
                        default:
                            break;
                    }
                }
                break;
        case setupMenu:
                if (theItem == configureItem)
                    NewMessage();
                break;
            default:
                break;
    }
    HiliteMenu(0);
    return(true);
}
 
 
 
 
 
 
 
 
 
Boolean HandleMouseDowns()
{
    WindowPtr whichWindow;
    Rect box;
    long new;
    short v, h;
    
    switch (FindWindow(myEvent.where,&whichWindow)) {
        case inSysWindow:
            SystemClick(&myEvent,whichWindow);
            break;
        case inMenuBar:
            return(DoCommand(MenuSelect(myEvent.where)));
            break;
        case inGrow:
            SetRect(&box,160,100,600,600);
            new = GrowWindow(whichWindow,myEvent.where,&box);
            if (new) {
                v = HiWord(new);
                h = LoWord(new);
                SetPort(whichWindow);
                SizeWindow(whichWindow,h,v,true);
                EraseRect(&(whichWindow->portRect));
                InvalRect(&(whichWindow->portRect));
                if (whichWindow == textWindow) {
                    MoveControl(textScrollBar,h - 15,0);
                    SizeControl(textScrollBar,16,v - 15);
                    HLock((Handle) textTE);
                    (**textTE).viewRect.right = h - 15;
                    (**textTE).viewRect.bottom = v - 15;
                    (**textTE).destRect.right = h - 15;
                    HUnlock((Handle) textTE);
                    TECalText(textTE);
                    AdjustTextScrollBar();
                }
            }
            break;
        case inGoAway:
            if (!TrackGoAway(whichWindow,myEvent.where))
                break;
            break;
        case inDrag:
            if (commandK || (FrontWindow() == whichWindow))
                DragWindow(whichWindow,myEvent.where,&qd.screenBits.bounds);
            else {
                SelectWindow(whichWindow);
                SetPort(whichWindow);
            }
            break;
        case inContent:
             if (whichWindow != FrontWindow()) {
                SelectWindow(whichWindow);
                SetPort(whichWindow);
            }
            else {
                if (whichWindow == textWindow)
                    HandleMouseInText();
            }
            break;
        default:
            break;
    }
    return(true);
}
 
 
 
 
 
 
void NewMessage(void)
{
    short err;
    char st[256], mess[256];
    GrafPtr savePort;
    DialogPtr aDialog;
    short item;
    Handle H;
    Rect box;
    DialogRecord d;
    
    mess[0] = 0;
    BlockMove(ourName, st, 40L);
    st[0]++;
    st[st[0]] = ':';
    st[0]++;
    st[st[0]] = 'Ê';
    GetPort(&savePort);
    aDialog = GetNewDialog(128, (Ptr) &d, (WindowPtr) -1L);
    if (aDialog) {
        SetPort(aDialog);
        GetDItem(aDialog, okItem, &item, &H, &box);
        PenSize(3,3);
        InsetRect(&box, -5, -5);
        FrameRoundRect(&box, 16, 16);
        PenNormal();
        item = 0;
        while ((item != okItem) && (item != cancelItem))
            ModalDialog(0L, &item);
        if (item == okItem) {
            GetDItem(aDialog, 3, &item, &H, &box);
            GetIText(H, mess);
            item = okItem;
        }
        CloseDialog(aDialog);
    }
    SetPort(savePort);
    if (item == okItem) {
        BlockMove(&mess[1], &st[st[0] + 1], (long) ((short) mess[0]));
        st[0] += mess[0];
        err = DoDDP(st);
        if (err)
            Message("\pError sending packet. Destination not found.");
    }
}
 
 
 
 
void DoAbout()
{
    Message("\pThis is a quick and dirty application by Ricardo Batista.");
    Message("\pAnyone in the network with this same application is able to");
    Message("\preceive messages by others using this application.");
    Message("\p© Copyright 1991 Apple Computer, Inc.  All Rights Reserved.");
    Message("\p");
}
 
 
 
 
 
 
 
 
void Message(char *mess)
{
    long len;
    GrafPtr savePort;
    char st[40];
    unsigned long t;
    
    GetDateTime(&t);
    GetPort(&savePort);
    SetPort(textWindow);
    IUTimeString((long) t, true,st);
    while (st[0] < 14) {
        st[0]++;
        st[st[0]] = ' ';
    }
    len = st[0];
    TEInsert(&st[1],len,textTE);
    IUDateString((long) t, shortDate ,st);
    while (st[0] < 14) {
        st[0]++;
        st[st[0]] = ' ';
    }
    len = st[0];
    TEInsert(&st[1],len,textTE);
    len = mess[0];
    TEInsert(&mess[1],len,textTE);
    TEKey(13,textTE);
    TECalText(textTE);
    AdjustTextScrollBar();
    SetPort(savePort);
}
 
 
 
 
 
void Names()
{
    EntityName name;
    short err, counter;
    Handle buffer = 0L;
    short found;
    MPPParamBlock p;
    char Entity[110];
    
    p.MPPioCompletion = 0L;
    p.MPPioRefNum = mpp;
    buffer = NewHandle(LOOKUPBUFSIZE);
    if (!buffer) {
        return;
    }
    Message("\pFindind Neighbors...");
    HLock(buffer);
    BlockMove("\pNeighborhood Watch",name.typeStr, 20L);
    name.objStr[0] = 1;
    name.objStr[1] = '=';
    name.zoneStr[0] = 1;
    name.zoneStr[1] = '*';
    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 = LOOKUPBUFSIZE;
    p.NBPmaxToGet = LOOKUPBUFSIZE / 110;
    p.NBPnumGotten = 0;
    err = PLookupName(&p,false);
    err = p.MPPioResult;
    if (!err) {
        found = p.NBPnumGotten;
        for (counter = 0; counter < found; counter++)
            err = myNBPExtract(*buffer,found,counter + 1,&name, &(users[counter]));
            Message(name.objStr);
    }
    if (buffer)
        DisposHandle(buffer);
    buffer = 0L;
}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
short myNBPExtract(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);
}