home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Otherware
/
Otherware_1_SB_Development.iso
/
mac
/
developm
/
scnote
/
gzonelst.011
/
GetZoneList.c
< prev
next >
Wrap
Text File
|
1989-10-01
|
22KB
|
811 lines
/* ------------------------------------------------------------------------------
#
# Apple Macintosh Developer Technical Support
#
# AppleTalk GetZoneList Sample Application
#
# GetZoneList
#
# GetZoneList.c - C Source
#
# Copyright ⌐ 1989 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. Since C does not allow nested procedures
# a la Pascal, a few modifications were made to incorporate
# the failure handling and keep this sample fairly close in
# design to the Pascal sample.
# (Gee, thanks a lot M2 for using nested procs. - pvh)
#
# GetZoneList is based on MACDTS Sample.c. For more
# description and explanation of the non-example
# specific areas of this application, please refer to
# either Sample.p or TESample.c.
#
------------------------------------------------------------------------------ */
#include <Values.h>
#include <Types.h>
#include <QuickDraw.h>
#include <Fonts.h>
#include <Events.h>
#include <Controls.h>
#include <Windows.h>
#include <Menus.h>
#include <TextEdit.h>
#include <Dialogs.h>
#include <Packages.h>
#include <Desk.h>
#include <Scrap.h>
#include <Lists.h>
#include <ToolUtils.h>
#include <Memory.h>
#include <SegLoad.h>
#include <Errors.h>
#include <Files.h>
#include <OSUtils.h>
#include <AppleTalk.h>
#include <Traps.h>
#include <DiskInit.h>
#include <Script.h>
#include <UFailure.h>
#define kSysEnvironsVersion 1
#define kOSEvent app4Evt /* event used by Multifinder */
#define kSuspendResumeMessage 1 /* high byte of suspend/resume event message */
#define kResumeMask 1 /* bit of message field for resume vs. suspend */
#define kCR 13 /* carriage return character */
#define kENTER 3 /* enter character */
#define kScrollBarWidth 15 /* the width of the scrollbar in the list */
#define kListInset -1 /* adjustment for list frame */
#define kATPTimeOutVal 3 /* re-try ATP SendRequest every 3 seconds */
#define kATPRetryCount 5 /* for five times */
#define kZonesSize 578 /* size of buffer for zone names */
#define kGZLCall 0x08000000 /* GetZoneList indicator */
#define kZIPSocket 6 /* the Zone Information Protocol socket */
#define kMoreZones 0xFF000000 /* mask to see if more zones to come */
#define kZoneCount 0x0000FFFF /* mask to count zones in buffer */
#define kHilite 1 /* hilite value for button control */
#define kDeHilite 0 /* dehilite value for button control */
#define kHiliteDelay 5 /* time in ticks to leave button hilited */
#define kMinHeap 0
#define kMinSpace 0
#define sErrStrings 128 /* error string STR# */
#define eStandardErr 1
#define eWrongMachine 2
#define eSmallSize 3
#define eNoMemory 4
#define eAppleTalk 5
#define eNoZones 6
#define rAboutAlert 128 /* about alert */
#define rZoneDialog 129 /* zone list dialog */
#define dZoneList 2 /* user item that is zone list */
#define dDefault 3 /* user item that is default indicator */
#define rUserAlert 130 /* error alert */
#define rMenuBar 128 /* application's menu bar */
#define mApple 128 /* Apple menu */
#define iAbout 1
#define mFile 129 /* File menu */
#define iNew 1
#define iClose 4
#define iQuit 12
#define mEdit 130 /* Edit menu */
#define iUndo 1
#define iCut 3
#define iCopy 4
#define iPaste 5
#define iClear 6
/* kDITop and kDILeft are used to locate the Disk Initialization dialogs. */
#define kDITop 0x0050
#define kDILeft 0x0070
/* Globs */
SysEnvRec gMac; /* set up by Initialize */
Boolean gHasWaitNextEvent; /* set up by Initialize */
Boolean gInBackground; /* maintained by Initialize and DoEvent */
ListHandle gList; /* the list to be filled with zone names */
extern void _DataInit();
/* globals added for C sample use as the Pascal
example used those horrid :-) nested procedures! */
ATPPBPtr gATPPBPtr; /* the parameter block for GetZoneList call */
Ptr gZones; /* the data buffer for GetZoneList call */
DialogPtr gErrDlg; /* Dialog used for displaying zone list */
#pragma segment Initialize
Boolean TrapAvailable(tNumber, tType)
short tNumber;
TrapType tType;
{
return( NGetTrapAddress(tNumber, tType) != GetTrapAddress(_Unimplemented) );
} /* TrapAvailable */
#pragma segment Main
void FailOSErrMsg(result, message)
short result;
short message;
{
if (result != noErr)
Failure(result, message);
} /* SignalOSErrMsg */
#pragma segment Main
void FailnilMsg(p, message)
Ptr p;
short message;
{
if (p == nil)
Failure(memFullErr, message);
} /* FailNILMsg */
#pragma segment Main
void AlertUser(error, message)
/* 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. */
short error;
long message;
{
Str255 msg1, msg2;
short itemHit;
if (message == 0L) message = eStandardErr;
GetIndString(msg1, sErrStrings, message);
if (error == noErr)
msg2[0] = '';
else
NumToString(error, msg2);
ParamText(msg1, msg2, "\p", "\p");
itemHit = Alert(rUserAlert, nil);
} /* AlertUser */
#pragma segment Main
Boolean IsDAWindow(window)
WindowPtr window;
{
if (window == nil)
return (false);
else /* DA windows have negative windowKinds */
return ((WindowPeek) window)->windowKind < 0;
} /* IsDAWindow */
#pragma segment Main
Boolean IsAppWindow(window)
WindowPtr window;
{
short windowKind;
if ( window == nil )
return false;
else { /* application windows have windowKinds >= userKind (8) or dialogKind (2) */
windowKind = ((WindowPeek) window)->windowKind;
return (windowKind >= userKind) || (windowKind == dialogKind);
}
} /* IsAppWindow */
#pragma segment Main
void ZoneListCleanUp()
{
if (gATPPBPtr != nil)
DisposPtr((Ptr)gATPPBPtr); /* get rid of pb block */
if (gZones != nil)
DisposPtr(gZones); /* and buffer */
} /* ZoneListCleanUp */
#pragma segment Main
pascal void HandleZoneListErr(short error, long message)
{
#pragma unused (error, message)
ZoneListCleanUp(); /* get rid of allocated junk */
} /* HandleZoneListErr */
#pragma segment Main
void 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. */
{
BDSElement dBDS; /* the BDS for GetZoneList call */
Ptr dCurr; /* the data buffer for GetZoneList call */
short dIndex, dCount;
short ignore;
Cell cSize;
FailInfo fi;
gATPPBPtr = nil; /* init some important variables*/
gZones = nil;
CatchCFailures(&fi, HandleZoneListErr);
gATPPBPtr = (ATPPBPtr)NewPtr(sizeof(ATPParamBlock));
FailnilMsg(gATPPBPtr, eNoMemory);
gZones = NewPtr(kZonesSize);
FailnilMsg(gZones, eNoMemory);
dBDS.buffSize = kZonesSize; /* set up BDS */
dBDS.buffPtr = gZones;
gATPPBPtr->ATPatpFlags = 0;
FailOSErrMsg(GetNodeAddress(&ignore, &gATPPBPtr->ATPaddrBlock.aNet), eAppleTalk); /* get net of bridge */
if (gATPPBPtr->ATPaddrBlock.aNet == 0)
Failure(0, eNoZones); /* bail if no zones present */
gATPPBPtr->ATPaddrBlock.aNode = GetBridgeAddress(); /* get node of bridge */
gATPPBPtr->ATPaddrBlock.aSocket = kZIPSocket; /* the socket we want */
gATPPBPtr->ATPreqLength = 0;
gATPPBPtr->ATPreqPointer = nil;
gATPPBPtr->ATPbdsPointer = (Ptr) &dBDS;
gATPPBPtr->ATPnumOfBuffs = 1;
gATPPBPtr->ATPtimeOutVal = kATPTimeOutVal;
gATPPBPtr->ATPretryCount = kATPRetryCount;
dIndex = 1;
dCount = 0;
SetPt(&cSize, 0, 0); /* we always stuff into first */
do {
gATPPBPtr->ATPuserData = kGZLCall + dIndex; /* indicate GetZoneList request */
FailOSErrMsg(PSendRequest(gATPPBPtr, false), eAppleTalk); /* send sync request */
dCount = dCount + dBDS.userBytes & kZoneCount; /* find out how many returned */
dCurr = gZones; /* put current pointer at start */
do { /* get each zone */
ignore = LAddRow(1, 0, gList); /* create new cell at start */
LSetCell((Ptr)dCurr + 1L, (short) *dCurr, cSize, gList); /* stuff in zone */
dCurr = (Ptr)(dCurr + *dCurr + 1 ); /* bump up current pointer */
dIndex = dIndex + 1; /* increment which zone */
} while(! (dIndex > dCount));
} while ((dBDS.userBytes & kMoreZones) == 0); /* keep going until none left */
ZoneListCleanUp();
Success(&fi);
} /* BuildZoneList */
#pragma segment Main
pascal void ZoneListDraw(dlg, item)
DialogPtr dlg;
short item;
{
/* The user item void 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 */
GrafPtr port;
short kind;
Handle h;
Rect r;
PenState ps;
GetPort(&port); /* save old port */
SetPort(dlg); /* make dialog port */
switch (item) {
case dZoneList:
LUpdate(dlg->visRgn, gList); /* re-draw list */
GetDItem(dlg, dZoneList, &kind, &h, &r);
InsetRect(&r, kListInset, kListInset);
FrameRect(&r); /* re-draw frame */
break;
case dDefault:
GetDItem(dlg, dDefault, &kind, &h, &r);
GetPenState(&ps);
PenSize(3, 3);
InsetRect(&r, -4, -4);
FrameRoundRect(&r, 16, 16); /* draw default box */
SetPenState(&ps);
break;
}
SetPort(port); /* restore old port */
} /* ZoneListDraw */
#pragma segment Main
pascal Boolean ListFilter (dlg, event, item)
DialogPtr dlg;
EventRecord *event;
short *item;
{
/* 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. */
GrafPtr port;
Point loc;
short kind;
Handle h;
Rect r;
Boolean ignore;
char key;
long finalTicks;
Boolean returnValue;
returnValue = false; /* always default false */
switch (event->what) {
case keyDown: /* check for <cr> or <enter> */
case autoKey:
key = (char) event->message;
if (key == kCR || key == kENTER) { /* it was a <cr> or <enter> */
GetDItem(dlg, ok, &kind, &h, &r);
HiliteControl((ControlHandle)h, kHilite);
Delay(kHiliteDelay, &finalTicks);
HiliteControl((ControlHandle)h, kDeHilite);
returnValue = true; /* so we handle it */
*item = 1; /* and make the first item hit */
}
break;
case mouseDown: /* 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)) { /* if clicked inside╔ */
returnValue = true; /* we take care of it */
ignore = LClick(loc, event->modifiers, gList); /* by passing click to list */
}
SetPort(port);
break;
}
return (returnValue);
} /* ListFilter */
#pragma segment Main
void CleanUp_DoZoneList()
{
if (gList != nil)
LDispose(gList); /* get rid of list */
if (gErrDlg != nil)
DisposDialog(gErrDlg); /* get rid of dialog */
} /* CleanUp_DoZoneList */
#pragma segment Main
pascal void HandleErr_DoZoneList(short error, long message)
{
#pragma unused (error, message)
CleanUp_DoZoneList(); /* release junk */
} /* HandleErr_DoZoneList */
#pragma segment Main
void 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. */
{
DialogPtr dlg;
short item, kind;
Handle h;
Rect r, rView, dataBounds;
Cell cSize;
FailInfo fi;
short hor, ver;
gList = nil; /* init some important variables */
dlg = nil;
CatchCFailures(&fi, HandleErr_DoZoneList);
dlg = GetNewDialog(rZoneDialog, nil, (WindowPtr)-1); /* create dialog */
gErrDlg = dlg;
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. */
hor = dlg->portRect.right - dlg->portRect.left;
hor = ((qd.screenBits.bounds.right - qd.screenBits.bounds.left) - hor) / 2;
ver = ((qd.screenBits.bounds.bottom - qd.screenBits.bounds.top) - GetMBarHeight()) / 3;
MoveWindow(dlg, hor, ver, false);
GetDItem(dlg, dDefault, &kind, &h, &r);
SetDItem(dlg, dDefault, kind, (Handle) ZoneListDraw, &r);
GetDItem(dlg, dZoneList, &kind, &h, &r);
SetDItem(dlg, dZoneList, kind, (Handle) ZoneListDraw, &r); /* connect drawing void */
rView = r;
rView.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 */
do {
ModalDialog((ModalFilterProcPtr) ListFilter, &item); /* accept events */
} while (item != ok); /* until he presses 'ok' */
CleanUp_DoZoneList();
Success(&fi);
} /* DoZoneList */
#pragma segment Main
Boolean DoCloseWindow(window)
WindowPtr window;
{
Boolean functionValue = true;
if (IsDAWindow(window))
CloseDeskAcc((short) ((WindowPeek)window)->windowKind);
else
if (IsAppWindow(window))
CloseWindow(window);
return(functionValue);
} /* DoCloseWindow */
#pragma segment Initialize
pascal void HandleErr_Initialize(error, message)
short error;
long message;
{
if (error > 0)
AlertUser(0, error);
else
AlertUser(error, message);
ExitToShell();
} /* HandleErr_Initialize */
#pragma segment Initialize
void Initialize()
{
Handle menuBar;
OSErr ignoreError;
long total, contig;
Boolean ignoreResult;
EventRecord event;
short count;
FailInfo fi;
gHasWaitNextEvent = TrapAvailable(_WaitNextEvent, ToolTrap);
gInBackground = false;
InitGraf(&qd.thePort);
InitFonts();
InitWindows();
InitMenus();
TEInit();
InitDialogs(nil);
InitCursor();
/* get MultiFinder started */
for (count=1;count<3;count++)
ignoreResult = EventAvail(everyEvent, &event);
CatchCFailures(&fi, HandleErr_Initialize);
FailOSErrMsg(MPPOpen(), eAppleTalk);
FailOSErrMsg(ATPLoad(), eAppleTalk);
ignoreError = SysEnvirons(kSysEnvironsVersion, &gMac);
if (gMac.machineType < 0)
Failure(0, eWrongMachine);
if (GetApplLimit() - ApplicZone() < kMinHeap)
Failure(0, eSmallSize);
PurgeSpace(&total, &contig);
if (total < kMinSpace)
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);
} /* Initialize */
#pragma segment Main
void Terminate()
{
WindowPtr aWindow;
Boolean closed;
closed = true;
do {
aWindow = FrontWindow(); /* get the current front window */
if (aWindow != nil)
closed = DoCloseWindow(aWindow); /* close this window */
} while ((closed) && (aWindow != nil)); /* do all windows */
if (closed)
ExitToShell(); /* exit if no cancellation */
} /* Terminate */
#pragma segment Main
void AdjustMenus()
{
WindowPtr window;
MenuHandle menu;
window = FrontWindow();
menu = GetMHandle(mFile);
if (IsDAWindow(window)) /* 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)) { /* a desk accessory might need the edit menu */
EnableItem(menu, iUndo);
EnableItem(menu, iCut);
EnableItem(menu, iCopy);
EnableItem(menu, iPaste);
EnableItem(menu, iClear);
}
else { /* but we know we do not */
DisableItem(menu, iUndo);
DisableItem(menu, iCut);
DisableItem(menu, iCopy);
DisableItem(menu, iClear);
DisableItem(menu, iPaste);
}
} /* AdjustMenus */
pascal void HandleMenu(short error, long message)
{
#pragma unused (error, message)
HiliteMenu(0); /* unhighlight what MenuSelect (or MenuKey) hilited */
} /* HandleMenu */
#pragma segment Main
void DoMenuCommand(menuResult)
long menuResult;
{
short menuID; /* the resource ID of the selected menu */
short menuItem; /* the item number of the selected menu */
short itemHit;
Str255 daName;
short daRefNum;
Boolean handledByDA ;
Boolean ignore;
FailInfo fi;
CatchCFailures(&fi, (HandlerFuncPtr) HandleMenu);
menuID = HiWord(menuResult); /* use built-ins (for efficiency)... */
menuItem = LoWord(menuResult); /* to get menu item number and menu number */
switch (menuID) {
case mApple:
switch (menuItem) {
case iAbout: /* bring up alert for About */
itemHit = Alert(rAboutAlert, nil);
break;
default: /* all non-About items in this menu are DAs */
GetItem(GetMHandle(mApple), menuItem, daName);
daRefNum = OpenDeskAcc(daName);
break;
}
break;
case mFile:
switch (menuItem) {
case iNew:
DoZoneList();
break;
case iClose:
ignore = DoCloseWindow(FrontWindow());
break;
case iQuit:
Terminate();
break;
}
break;
case mEdit: /* call SystemEdit for DA editing & Multifinder */
handledByDA = SystemEdit(menuItem-1); /* since we don't do any editing */
break;
}
HiliteMenu(0); /* cleanup */
Success(&fi);
} /* DoMenuCommand */
#pragma segment Main
void AdjustCursor(Point mouse, RgnHandle region)
{
#pragma unused (mouse, region)
} /* AdjustCursor */
#pragma segment Main
pascal void HandleErr_DoEvent(error, message)
short error;
long message;
{
if (error > 0)
AlertUser(0, error);
else
AlertUser(error, message);
ExitToShell();
} /* HandleErr_DoEvent */
#pragma segment Main
void DoEvent(event)
EventRecord event;
{
short part;
WindowPtr window;
char key;
FailInfo fi;
Point aPoint;
OSErr err;
CatchCFailures(&fi, (HandlerFuncPtr) HandleErr_DoEvent);
switch (event.what) {
case mouseDown:
part = FindWindow(event.where, &window);
switch (part) {
case inMenuBar: /* process the menu command */
AdjustMenus();
DoMenuCommand(MenuSelect(event.where));
break;
case inSysWindow: /* let the system handle the mouseDown */
SystemClick(&event, window);
break;
case inContent:
break;
case inDrag:
break;
case inGrow:
break;
case inZoomIn:
case inZoomOut:
break;
}
break;
case keyDown: /* check for menukey equivalents */
case autoKey:
key = event.message & charCodeMask;
if (event.modifiers & cmdKey) { /* Command key down */
if (event.what == keyDown) {
AdjustMenus(); /* enable/disable/check menu items properly */
DoMenuCommand(MenuKey(key));
}
}
break;
/* call DoActivate with the window and... */
case activateEvt:
break;
case updateEvt:
break;
/* It is not a bad idea to at least call DIBadMount in response
to a diskEvt, so that the user can format a floppy. */
case diskEvt:
if (HiWord(event.message) != noErr) {
SetPt(&aPoint, kDILeft, kDITop);
err = DIBadMount(aPoint, event.message);
}
case kOSEvent:
switch ((event.message >> 24) & 0x0FF) { /* high byte of message */
case kSuspendResumeMessage:
gInBackground = event.message & kResumeMask;
break;
}
break;
}
Success(&fi);
} /* DoEvent */
#pragma segment Main
void EventLoop()
{
RgnHandle cursorRgn;
Boolean gotEvent;
EventRecord event;
cursorRgn = NewRgn(); /* we╒ll pass WNE an empty region the 1st time thru */
do {
if (gHasWaitNextEvent) /* put us 'asleep' forever under Multifinder */
gotEvent = WaitNextEvent(everyEvent, &event, MAXLONG, cursorRgn);
else {
SystemTask(); /* must be called if using GetNextEvent */
gotEvent = GetNextEvent(everyEvent, &event);
}
if (gotEvent) {
AdjustCursor(event.where, cursorRgn); /* make sure we have the right cursor */
DoEvent(event);
}
AdjustCursor(event.where, cursorRgn);
} while (true); /* loop forever; we quit through an ExitToShell */
} /* EventLoop */
#pragma segment Main
void main()
{
UnloadSeg(_DataInit); /* note that _DataInit must not be in Main! */
MaxApplZone(); /* expand the heap so code segments load at the top */
InitUFailure();
Initialize(); /* initialize the program */
UnloadSeg(Initialize); /* note that Initialize must not be in Main! */
EventLoop(); /* call the main event loop */
} /* main */