home *** CD-ROM | disk | FTP | other *** search
- {------------------------------------------------------------------------------
- #
- # Apple Macintosh Developer Technical Support
- #
- # AppleTalk GetZoneList Sample Application
- #
- # GetZoneList
- #
- # GetZoneList.p - Pascal Source
- #
- # Copyright ⌐ 1988 Apple Computer, Inc.
- # All rights reserved.
- #
- # Versions: 1.0 11/88
- # 1.1 10/89
- #
- # Components: GetZoneList.p October 1, 1989
- # GetZoneList.c October 1, 1989
- # GetZoneList.r October 1, 1989
- # PGetZoneList.make October 1, 1989
- # CGetZoneList.make October 1, 1989
- #
- # Requirements:
- # UFailure.p November 1, 1988
- # UFailure.inc1.p November 1, 1988
- # UFailure.a November 1, 1988
- #
- # GetZoneList is a sample application that uses
- # AppleTalk ATP and ZIP to obtain a list of zones
- # on an AppleTalk internet.
- #
- # GetZoneList also demonstrates using a signal, or
- # failure-catching mechanism to recover from error
- # situations.
- #
- # GetZoneList is based on MACDTS Sample.p. For more
- # description and explanantion of the non-example
- # specific areas of this application, please refer to
- # either Sample.p or TESample.p.
- #
- ------------------------------------------------------------------------------}
-
- PROGRAM GetZoneList;
-
- USES
- MemTypes, QuickDraw, OSIntf, ToolIntf, AppleTalk, PackIntf, FixMath, Script, UFailure, Traps;
-
- CONST
- kSysEnvironsVersion = 1;
- kOSEvent = app4Evt; {event used by MultiFinder}
- kSuspendResumeMessage = 1; {high byte of suspend/resume event message}
- kResumeMask = 1; {bit of message field for resume vs. suspend}
-
- kCR = 13; {carriage return character}
- kENTER = 3; {enter character}
- kScrollBarWidth = 15; {the width of the scrollbar in the list}
- kListInset = -1; {adjustment for list frame}
- kATPTimeOutVal = 3; {re-try ATP SendRequest every 3 seconds}
- kATPRetryCount = 5; {for five times}
- kZonesSize = 578; {size of buffer for zone names}
- kGZLCall = $08000000; {GetZoneList indicator}
- kZIPSocket = 6; {the Zone Information Protocol socket}
- kMoreZones = $FF000000; {mask to see if more zones to come}
- kZoneCount = $0000FFFF; {mask to count zones in buffer}
- kHilite = 1; {hilite value for button control}
- kDeHilite = 0; {dehilite value for button control}
- kHiliteDelay = 5; {time in ticks to leave button hilited}
-
- kMinHeap = 0;
- kMinSpace = 0;
-
- sErrStrings = 128; {error string STR#}
- eStandardErr = 1;
- eWrongMachine = 2;
- eSmallSize = 3;
- eNoMemory = 4;
- eAppleTalk = 5;
- eNoZones = 6;
-
- rAboutAlert = 128; {about alert}
- rZoneDialog = 129; {zone list dialog}
- dZoneList = 2; {user item that is zone list}
- dDefault = 3; {user item that is default indicator}
- rUserAlert = 130; {error alert}
-
- rMenuBar = 128; {application's menu bar}
-
- mApple = 128; {Apple menu}
- iAbout = 1;
-
- mFile = 129; {File menu}
- iNew = 1;
- iClose = 4;
- iQuit = 12;
-
- mEdit = 130; {Edit menu}
- iUndo = 1;
- iCut = 3;
- iCopy = 4;
- iPaste = 5;
- iClear = 6;
-
- {1.01 - kDITop and kDILeft are used to locate the Disk Initialization dialogs.}
- kDITop = $0050;
- kDILeft = $0070;
-
-
- VAR
- gMac : SysEnvRec; {set up by Initialize}
- gHasWaitNextEvent : BOOLEAN; {set up by Initialize}
- gInBackground : BOOLEAN; {maintained by Initialize and DoEvent}
-
- gList : ListHandle; {the list to be filled with zone names}
-
- {$S Initialize}
- FUNCTION TrapAvailable(tNumber: INTEGER; tType: TrapType): BOOLEAN;
- BEGIN
- TrapAvailable := NGetTrapAddress(tNumber, tType) <> GetTrapAddress(_Unimplemented);
- END; {TrapAvailable}
-
-
- {$S Main}
- PROCEDURE FailOSErrMsg(result, message: INTEGER);
- BEGIN
- IF result <> noErr THEN
- Failure(result, message);
- END; {SignalOSErrMsg}
-
-
- {$S Main}
- PROCEDURE FailNILMsg(p: UNIV Ptr; message: INTEGER);
- BEGIN
- IF p = NIL THEN
- Failure(memFullErr, message);
- END; {FailNILMsg}
-
-
- {$S Main}
- PROCEDURE AlertUser(error: INTEGER; message: LongInt);
-
- {Display an alert to inform the user of an error. Message acts as an
- index into a STR# resource of error messages. If no message is given,
- i.e. = 0, then use a standard message. If error is not noErr then
- display it as well.}
-
- VAR
- msg1, msg2 : Str255;
- itemHit : INTEGER;
- BEGIN
- IF message = 0 THEN message := eStandardErr;
- GetIndString(msg1, sErrStrings, message);
- IF error = noErr THEN
- msg2 := ''
- ELSE
- NumToString(error, msg2);
- ParamText(msg1, msg2, '', '');
- itemHit := Alert(rUserAlert, NIL);
- END; {AlertUser}
-
-
- {$S Main}
- FUNCTION IsDAWindow(window: WindowPtr): BOOLEAN;
- BEGIN
- IF window = NIL THEN
- IsDAWindow := FALSE
- ELSE {DA windows have negative windowKinds}
- IsDAWindow := WindowPeek(window)^.windowKind < 0;
- END; {IsDAWindow}
-
-
- {$S Main}
- FUNCTION IsAppWindow(window: WindowPtr): BOOLEAN;
- BEGIN
- IF window = NIL THEN
- IsAppWindow := FALSE
- ELSE {application windows have windowKinds >= userKind (8) or dialogKind (2)}
- WITH WindowPeek(window)^ DO
- IsAppWindow := (windowKind >= userKind) | (windowKind = dialogKind);
- END; {IsAppWindow}
-
-
- {$S Main}
- PROCEDURE BuildZoneList;
-
- {Create the list of zones on the network. Find a bridge to talk to , if one is
- present, then ask it for zone names. Add the names to the list in the dialog.}
-
- VAR
- dATPPBptr : ATPPBptr; {the parameter block for GetZoneList call}
- dBDS : BDSElement; {the BDS for GetZoneList call}
- dZones, dCurr : Ptr; {the data buffer for GetZoneList call}
- dIndex, dCount, dNode, dNet : INTEGER;
- ignore : INTEGER;
- cSize : Point;
- fi : FailInfo;
-
- PROCEDURE CleanUp;
- BEGIN
- IF dATPPBptr <> NIL THEN
- DisposPtr(Ptr(dATPPBptr)); {get rid of pb block}
- IF dZones <> NIL THEN
- DisposPtr(dZones); {and buffer}
- END; {CleanUp}
-
- PROCEDURE HandleErr(error: INTEGER; message: LongInt);
- BEGIN
- CleanUp; {get rid of allocated junk}
- END;
-
- BEGIN
- dATPPBptr := NIL; {init some important variables}
- dZones := NIL;
- CatchFailures(fi, HandleErr);
-
- dATPPBptr := ATPPBptr(NewPtr(SIZEOF(ATPParamBlock)));
- FailNILMsg(dATPPBptr, eNoMemory);
- dZones := NewPtr(kZonesSize);
- FailNILMsg(dZones, eNoMemory);
- WITH dBDS DO BEGIN {set up BDS}
- buffSize := kZonesSize;
- buffPtr := dZones;
- END;
- WITH dATPPBptr^ DO BEGIN {set up pb block}
- atpFlags := 0;
- FailOSErrMsg(GetNodeAddress(ignore,
- addrBlock.aNet), eAppleTalk); {get net of bridge}
- IF addrBlock.aNet = 0 THEN
- Failure(0, eNoZones); {bail if no zones present}
- addrBlock.aNode := GetBridgeAddress; {get node of bridge}
- addrBlock.aSocket := kZIPSocket; {the socket we want}
- reqLength := 0;
- reqPointer := NIL;
- bdsPointer := @dBDS;
- numOfBuffs := 1;
- timeOutVal := kATPTimeOutVal;
- retryCount := kATPRetryCount;
- END;
- dIndex := 1;
- dCount := 0;
- SetPt(cSize, 0, 0); {we always stuff into first}
- REPEAT
- dATPPBptr^.userData := kGZLCall + dIndex; {indicate GetZoneList request}
- FailOSErrMsg(PSendRequest(dATPPBptr,
- FALSE), eAppleTalk); {send sync request}
- dCount := dCount + BAND(dBDS.userBytes,
- kZoneCount); {find out how many returned}
- dCurr := dZones; {put current pointer at start}
- REPEAT {get each zone}
- ignore := LAddRow(1, 0, gList); {create new cell at start}
- LSetCell(POINTER(ORD4(dCurr) + 1), dCurr^,
- cSize, gList); {stuff in zone}
- dCurr := POINTER(ORD4(dCurr) + dCurr^+1); {bump up current pointer}
- dIndex := dIndex + 1; {increment which zone}
- UNTIL dIndex > dCount;
- UNTIL (BAND(dBDS.userBytes, kMoreZones) <> 0); {keep going until none left}
- CleanUp;
-
- Success(fi);
- END; {BuildZoneList}
-
-
- {$S Main}
- PROCEDURE ZoneListDraw(dlg: DialogPtr; item: INTEGER);
-
- {The user item procedure for the zone list user item and default
- box user item in the dialog. Draw the list and the frame that goes with it.
- Draw the default box around the OK button.}
-
- VAR
- port : GrafPtr;
- kind : INTEGER;
- h : Handle;
- r : Rect;
- ps : PenState;
-
- BEGIN
- GetPort(port); {save old port}
- SetPort(dlg); {make dialog port}
- CASE item OF
- dZoneList: BEGIN
- LUpdate(dlg^.visRgn, gList); {re-draw list}
- GetDItem(dlg, dZoneList, kind, h, r);
- InsetRect(r, kListInset, kListInset);
- FrameRect(r); {re-draw frame}
- END;
- dDefault: BEGIN
- GetDItem(dlg, dDefault, kind, h, r);
- GetPenState(ps);
- PenSize(3, 3);
- InsetRect(r, -4, -4);
- FrameRoundRect(r, 16, 16); {draw default box}
- SetPenState(ps);
- END;
- END;
- SetPort(port); {restore old port}
- END; {ZoneListDraw}
-
-
- {$S Main}
- FUNCTION ListFilter (dlg: DialogPtr; VAR event: EventRecord;
- VAR item: INTEGER) : BOOLEAN;
-
- {Passed as parameter to ModalDialog. Handle key presses and mouse clicks
- from the user. Do all the right default actions since we override them
- by virtue of our existence.}
-
- VAR
- port : GrafPtr;
- loc : Point;
- kind : INTEGER;
- h : Handle;
- r : Rect;
- ignore : BOOLEAN;
- key : SignedByte;
- finalTicks : LongInt;
- BEGIN
- ListFilter := FALSE; {always default FALSE}
- CASE event.what OF
- keyDown, autoKey: BEGIN {check for <cr> or <enter>}
- key := SignedByte(event.message);
- IF key IN [kCR, kENTER] THEN BEGIN {it was a <cr> or <enter>}
- GetDItem(dlg, ok, kind, h, r);
- HiliteControl(ControlHandle(h), kHilite);
- Delay(kHiliteDelay, finalTicks);
- HiliteControl(ControlHandle(h), kDeHilite);
- ListFilter := TRUE; {so we handle it}
- item := 1; {and make the first item hit}
- END;
- END;
- mouseDown: BEGIN {we want mouseDowns}
- GetPort(port);
- SetPort(dlg);
- loc := event.where;
- GlobalToLocal(loc); {find where clicked}
- GetDItem(dlg, dZoneList, kind, h, r); {get rect for list}
- IF PtInRect(loc, r) THEN BEGIN {if clicked inside╔}
- ListFilter := TRUE; {we take care of it}
- ignore := LClick(loc, event.modifiers,
- gList); {by passing click to list}
- END;
- SetPort(port);
- END;
- END;
- END; {ListFilter}
-
-
- {$S Main}
- PROCEDURE DoZoneList;
-
- {Put up a modal dialog that shows a list of the zones on the net. Create the dialog
- and list, call BuildZoneList to fill it, then wait for the user to click OK.}
-
- VAR
- dlg : DialogPtr;
- item, kind : INTEGER;
- h : Handle;
- r, rView, dataBounds : Rect;
- cSize : Point;
- fi : FailInfo;
- hor, ver : INTEGER;
-
- PROCEDURE CleanUp;
- BEGIN
- IF gList <> NIL THEN
- LDispose(gList); {get rid of list}
- IF dlg <> NIL THEN
- DisposDialog(dlg); {get rid of dialog}
- END; {CleanUp}
-
- PROCEDURE HandleErr(error: INTEGER; message: LongInt);
- BEGIN
- CleanUp; {release junk}
- END;
-
- BEGIN
- gList := NIL; {init some important variables}
- dlg := NIL;
- CatchFailures(fi, HandleErr);
-
- dlg := GetNewDialog(rZoneDialog, NIL, POINTER(-1)); {create dialog}
- FailNILMsg(dlg, eNoMemory);
-
- {We center the dialog horizontally and position it vertically one-third the
- distance from the menu bar to the bottom of the main device. We do not
- check for the dialog extending past the bottom of the device because we
- know the dialog is not that big. You may wish to make that check.}
- WITH dlg^.portRect DO
- hor := right - left;
- WITH screenBits.bounds DO BEGIN
- hor := ((right - left) - hor) DIV 2;
- ver := ((bottom - top) - GetMBarHeight) DIV 3;
- END;
- MoveWindow(dlg, hor, ver, FALSE);
-
- GetDItem(dlg, dDefault, kind, h, r);
- h := @ZoneListDraw; {connect drawing procedure}
- SetDItem(dlg, dDefault, kind, h, r);
- GetDItem(dlg, dZoneList, kind, h, r);
- h := @ZoneListDraw; {connect drawing procedure}
- SetDItem(dlg, dZoneList, kind, h, r);
- rView := r;
- WITH rView DO
- right := right - kScrollBarWidth; {adjust rectangle for scroll}
- SetRect(dataBounds, 0, 0, 1, 0); {init to one-wide list}
- SetPt(cSize, 0, 0);
- gList := LNew(rView, dataBounds, cSize, 0, WindowPtr(dlg),
- FALSE, FALSE, FALSE, TRUE); {create with vertical scroll}
- FailNILMsg(gList, eNoMemory);
- BuildZoneList; {put the stuff into the list}
- SetPt(cSize, 0, 0);
- LSetSelect(TRUE, cSize, gList); {select the first guy}
- LDoDraw(TRUE, gList); {turn on the list}
- ShowWindow(dlg); {turn on the dialog}
- REPEAT
- ModalDialog(@ListFilter, item); {accept events}
- UNTIL item = ok; {until he presses 'ok'}
- CleanUp;
-
- Success(fi);
- END; {DoZoneList}
-
-
- {$S Main}
- FUNCTION DoCloseWindow(window: WindowPtr) : BOOLEAN;
- BEGIN
- DoCloseWindow := TRUE;
- IF IsDAWindow(window) THEN
- CloseDeskAcc(WindowPeek(window)^.windowKind)
- ELSE
- IF IsAppWindow(window) THEN
- CloseWindow(window);
- END; {DoCloseWindow}
-
-
- {$S Initialize}
- PROCEDURE Initialize;
- VAR
- menuBar : Handle;
- window : WindowPtr;
- ignoreError : OSErr;
- total, contig : LongInt;
- ignoreResult : BOOLEAN;
- event : EventRecord;
- count : INTEGER;
- fi : FailInfo;
-
- PROCEDURE HandleErr(error: INTEGER; message: LongInt);
- BEGIN
- IF error > 0 THEN
- AlertUser(0, error)
- ELSE
- AlertUser(error, message);
- ExitToShell;
- END; {HandleErr}
-
- BEGIN
- gHasWaitNextEvent := TrapAvailable(_WaitNextEvent, ToolTrap);
- gInBackground := FALSE;
-
- InitGraf(@thePort);
- InitFonts;
- InitWindows;
- InitMenus;
- TEInit;
- InitDialogs(NIL);
- InitCursor;
-
- FOR count := 1 TO 3 DO
- ignoreResult := EventAvail(everyEvent, event);
-
- CatchFailures(fi, HandleErr);
-
- FailOSErrMsg(MPPOpen, eAppleTalk);
- FailOSErrMsg(ATPLoad, eAppleTalk);
-
- ignoreError := SysEnvirons(kSysEnvironsVersion, gMac);
- IF gMac.machineType < 0 THEN
- Failure(0, eWrongMachine);
-
- IF ORD(GetApplLimit) - ORD(ApplicZone) < kMinHeap THEN
- Failure(0, eSmallSize);
-
- PurgeSpace(total, contig);
- IF total < kMinSpace THEN
- Failure(0, eNoMemory);
-
- menuBar := GetNewMBar(rMenuBar); {read menus into menu bar}
- FailNILMsg(menuBar, eNoMemory);
- SetMenuBar(menuBar); {install menus}
- DisposHandle(menuBar);
- AddResMenu(GetMHandle(mApple), 'DRVR'); {add DA names to Apple menu}
- DrawMenuBar;
-
- Success(fi);
- END; {Initialize}
-
-
- {$S Main}
- PROCEDURE Terminate;
- VAR
- aWindow : WindowPtr;
- closed : BOOLEAN;
-
- BEGIN
- closed := TRUE;
- REPEAT
- aWindow := FrontWindow; {get the current front window}
- IF aWindow <> NIL THEN
- closed := DoCloseWindow(aWindow); {close this window}
- UNTIL (NOT closed) | (aWindow = NIL); {do all windows}
- IF closed THEN
- ExitToShell; {exit if no cancellation}
- END; {Terminate}
-
-
- {$S Main}
- PROCEDURE AdjustMenus;
- VAR
- window : WindowPtr;
- menu : MenuHandle;
-
- BEGIN
- window := FrontWindow;
-
- menu := GetMHandle(mFile);
- IF IsDAWindow(window) THEN {we can allow desk accessories to be closed from the menu}
- EnableItem(menu, iClose)
- ELSE
- DisableItem(menu, iClose); {but not our traffic light window}
-
- menu := GetMHandle(mEdit);
- IF IsDAWindow(window) THEN BEGIN {a desk accessory might need the edit menu}
- EnableItem(menu, iUndo);
- EnableItem(menu, iCut);
- EnableItem(menu, iCopy);
- EnableItem(menu, iPaste);
- EnableItem(menu, iClear);
- END ELSE BEGIN {but we know we do not}
- DisableItem(menu, iUndo);
- DisableItem(menu, iCut);
- DisableItem(menu, iCopy);
- DisableItem(menu, iClear);
- DisableItem(menu, iPaste);
- END;
-
- END; {AdjustMenus}
-
-
- {$S Main}
- PROCEDURE DoMenuCommand(menuResult: LONGINT);
- VAR
- menuID : INTEGER; {the resource ID of the selected menu}
- menuItem : INTEGER; {the item number of the selected menu}
- itemHit : INTEGER;
- daName : Str255;
- daRefNum : INTEGER;
- handledByDA : BOOLEAN;
- ignore : BOOLEAN;
- fi : FailInfo;
-
- PROCEDURE HandleMenu(error: INTEGER; message: LongInt);
- BEGIN
- HiliteMenu(0); {unhighlight what MenuSelect (or MenuKey) hilited}
- END;
-
- BEGIN
- CatchFailures(fi, HandleMenu);
- menuID := HiWrd(menuResult); {use built-ins (for efficiency)...}
- menuItem := LoWrd(menuResult); {to get menu item number and menu number}
- CASE menuID OF
- mApple:
- CASE menuItem OF
- iAbout: {bring up alert for About}
- itemHit := Alert(rAboutAlert, NIL);
- OTHERWISE BEGIN {all non-About items in this menu are DAs}
- GetItem(GetMHandle(mApple), menuItem, daName);
- daRefNum := OpenDeskAcc(daName);
- END;
- END;
- mFile:
- CASE menuItem OF
- iNew:
- DoZoneList;
- iClose:
- ignore := DoCloseWindow(FrontWindow);
- iQuit:
- Terminate;
- END;
- mEdit: {call SystemEdit for DA editing & MultiFinder}
- handledByDA := SystemEdit(menuItem-1); {since we don't do any editing}
- END;
- Success(fi);
- HiliteMenu(0); {cleanup}
- END; {DoMenuCommand}
-
-
- {$S Main}
- PROCEDURE AdjustCursor(mouse: Point; region: RgnHandle);
- BEGIN
- END; {AdjustCursor}
-
-
- {$S Main}
- PROCEDURE DoEvent(event: EventRecord);
- VAR
- part, err : INTEGER;
- window : WindowPtr;
- hit : BOOLEAN;
- key : CHAR;
- fi : FailInfo;
- aPoint : Point;
-
- PROCEDURE HandleErr(error: INTEGER; message: LongInt);
- BEGIN
- IF error > 0 THEN
- AlertUser(0, error)
- ELSE
- AlertUser(error, message);
- EXIT(DoEvent);
- END; {HandleErr}
-
- BEGIN
- CatchFailures(fi, HandleErr);
-
- CASE event.what OF
- mouseDown: BEGIN
- part := FindWindow(event.where, window);
- CASE part OF
- inMenuBar: BEGIN {process the menu command}
- AdjustMenus;
- DoMenuCommand(MenuSelect(event.where));
- END;
- inSysWindow: {let the system handle the mouseDown}
- SystemClick(event, window);
- inContent:;
- inDrag:;
- inGrow:;
- inZoomIn, inZoomOut:;
- END;
- END;
- keyDown, autoKey: BEGIN {check for menukey equivalents}
- key := CHR(BAnd(event.message, charCodeMask));
- IF BAnd(event.modifiers, cmdKey) <> 0 THEN {Command key down}
- IF event.what = keyDown THEN BEGIN
- AdjustMenus; {enable/disable/check menu items properly}
- DoMenuCommand(MenuKey(key));
- END;
- END; {call DoActivate with the window and...}
- activateEvt:;
- updateEvt:;
- {1.01 - It is not a bad idea to at least call DIBadMount in response
- to a diskEvt, so that the user can format a floppy.}
- diskEvt:
- IF HiWrd(event.message) <> noErr THEN BEGIN
- SetPt(aPoint, kDILeft, kDITop);
- err := DIBadMount(aPoint, event.message);
- END;
- kOSEvent:
- CASE BAnd(BRotL(event.message, 8), 255) OF {high byte of message}
- kSuspendResumeMessage: BEGIN
- gInBackground := BAnd(event.message, kResumeMask) = 0;
- END;
- END;
- END;
-
- Success(fi);
- END; {DoEvent}
-
-
- {$S Main}
- PROCEDURE EventLoop;
- VAR
- cursorRgn : RgnHandle;
- gotEvent : BOOLEAN;
- event : EventRecord;
-
- BEGIN
- cursorRgn := NewRgn; {we╒ll pass WNE an empty region the 1st time thru}
-
- REPEAT
- IF gHasWaitNextEvent THEN {put us 'asleep' forever under MultiFinder}
- gotEvent := WaitNextEvent(everyEvent, event, MAXLONGINT, cursorRgn)
- ELSE BEGIN
- SystemTask; {must be called if using GetNextEvent}
- gotEvent := GetNextEvent(everyEvent, event);
- END;
- IF gotEvent THEN BEGIN
- AdjustCursor(event.where, cursorRgn); {make sure we have the right cursor}
- DoEvent(event);
- END;
- AdjustCursor(event.where, cursorRgn);
- UNTIL FALSE; {loop forever; we quit through an ExitToShell}
- END; {EventLoop}
-
-
- PROCEDURE _DataInit; EXTERNAL;
-
-
- {$S Main}
- BEGIN
- UnloadSeg(@_DataInit); {note that _DataInit must not be in Main!}
- MaxApplZone; {expand the heap so code segments load at the top}
-
- InitSignals;
- Initialize; {initialize the program}
- UnloadSeg(@Initialize); {note that Initialize must not be in Main!}
-
- EventLoop; {call the main event loop}
- END.
-