home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Otherware
/
Otherware_1_SB_Development.iso
/
mac
/
developm
/
scnote
/
gzonelst.011
/
GetZoneList.p
< prev
next >
Wrap
Text File
|
1989-10-01
|
19KB
|
710 lines
{------------------------------------------------------------------------------
#
# 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.