AppleShare IP Additions
Volume Number: 15
Issue Number: 2
Column Tag: ExplainIt
Crafting AppleShare IP Web and File Server
Additions
by Erik Sea
Edited by Peter N Lewis
Using the AppleShare IP Web & File Server Control
API
Server Additions - AppleShare IP Web & File
You're probably quite familiar with Mac OS APIs, functions, and controls. You've
probably also run across AppleShare, and you've likely also used an AppleShare IP File
Server. But I'll bet you didn't know that key pieces of AppleShare functionality are
accessible to developers through a number of APIs. In this article, we'll only talk
about the Web & File Server, but you can find out about other APIs, such as the
AppleShare Registry and User Authentication Modules, by perusing the AppleShare IP
SDK.
In this article, I'll go through the process of writing a simple little application (called
a "server addition") that allows the user to control the W&F Server, and displays some
server statistics. As I proceed, I'll pursue the occasional diversion that may inspire
you but isn't directly related to the server addition I'm concocting here.
To use the code presented in this article, you'll need an AppleShare IP Web & File
Server, and a copy of the latest version of the AppleShare IP SDK, which is available
on the Mac OS SDK CD and on the Apple Developer web pages. While a few of these calls
work with Macintosh File Sharing, the basic peer-to-peer version of AppleShare that
ships with Mac OS (sometimes called Personal File Sharing), this article is focussed
on the much more extensive developer API suite that is available under the full W&F
Server.
Give Me Server Control
Although it is technically correct to view the Web & File Server as an application, in
reality, when the server is installed on a machine it alters and extends the behavior of
several parts of Mac OS. Once W&F is on a machine, you can control and monitor the
server using API calls, just as you can make Mac OS API calls, whether the server is
"serving" or not (although most calls are not useful when the server is not running
and will simply return errors). In ASIP 6.1, there are roughly 29 API calls you can
make, ranging from starting the server, to sending messages to connected users. You
can also ask the server to tell you when things happen, such as when a user has
connected or disconnected. The AppleShare Web & File Server also supports WebStar
plugins.
The Server Control API consists of various parameter blocks used to set and retrieve
information from the server. While it would take a lot of space to detail each of the
various calls and parameters in this article, I've provided a brief summary in Table 1.
If you want to know more on any of these, see the AppleShare IP SDK.
Table 1: Server Control Calls & Command Constants
SCStartServer = 0 // Start the server
SCShutDown = 2 // Shut down the server
SCCancelShutDown = 3 // Stop a shut down in progress
SCDisconnect = 4 // Disconnect a list of users
SCPollServer = 5 // Status:
starting/running/shutting down
SCGetExpFldr = 6 // Info about a shared folder or
SCGetSetupInfo = 7 // Get configuration info
SCSetSetupInfo = 8 // Change configuration info
SCSendMessage = 9 // Send message to user or users
SCGetServerStatus = 10 // Time of last server change
SCInstallServerEventProc = 11 // Installs a server event handler
SCRemoveServerEventProc = 12 // Removes a server event handler
SCGetServerEventProc = 13 // Retrieve a server event handler
SCServerVersion = 14 // Version of AppleShare
SCSetCopyProtect = 16 // Make file copy protected
SCClrCopyProtect = 17 // Make file unprotected
SCDisconnectVolUsers = 18 // Disconnect users from volumes
SCGetUserNameRec = 19 // Retrieve connected user
information
SCGetUserMountInfo = 20 // How a user is using a volume
SCWakeServer = 21 // Starts a server that has been
paused
SCSleepServer = 22 // Pauses the server
SCGetCacheStats = 23 // Cache size, utilization,
hitcount
SCResetCache = 31 // Empty the file cache
SCGetExtUserNameRec = 35 // Additional user information
SCServiceStateInfo = 38 // Individual service states (FTP,
etc.)
SCGetPlugInInfo = 41 // Info about user's installed
plugins
SCGetPlugInMimeType = 42 // MIME type associated with a
plugin
SCSetHistorySampleTime = 43 // Time slice for server load
monitoring
SCGetServerActivityHistory = 44 // Server load percentages
Interestingly, the W&F Server's user interface is actually a separate application from
the server, and it communicates with the server using these very same calls. Not all of
the information available from these calls is exposed in the current user interface,
and the possibilities for writing a server addition that displays additional information
to the user are fairly wide-ranging - you could even replace the server's user
interface entirely if you choose!
The application I'll be presenting is necessarily simplistic - just a modal dialog with a
few bits of information and controls in it - but it provides a good foundation on which
you could write a more advanced application, with more information and control
organized as you see fit. And I hope you'll make it pretty and modeless!
ServerControl Demo Application
The user interface of the finished application is as seen in Figure 1. There's a button to
flush the file server's data cache, some status text, and some counters. At the bottom of
the screen, we have a histogram of server activity (gathered over a one day period),
which shows maximum, minimum, or average usage levels, depending on what the user
chooses.
Figure 1. ServerControl Demo main window.
We'll be using a modal dialog, in order to simplify the code (so I don't fill space with
UI handling that's not directly related to the task at hand).
Determining if the Server is Installed
The first thing we need to do when our addition starts, after initializing all the
appropriate toolbox routines, is ensure that an AppleShare IP W&F Server is
installed. The easy method is to make a gestalt call, which will return an error if W&F
is not installed, and the version number if it is (actually, this technique only works
with 6.0 or later, but we're going to require 6.0 anyway so this is not a limitation).
The source for this is in Listing 1.
Listing 1: Checking for Server and Version
extern Boolean
AppleShareIsInstalled (void) {
Boolean isInstalled = true;
SInt32 asipVersion;
OSErr err;
err = Gestalt (gestaltASIPFSVersion, &asipVersion);
if ((err != noErr) ||
(asipVersion < kMinimumAppleShareVersion)) {
isInstalled = false;
} // if
return isInstalled;
} // AppleShareIsInstalled
Setting up the Window
Once we know that the server is there, and it's a suitable version, we can bring in the
window, and handle it until closed. There's actually a bit more to it, of course. In order
to count logins and file accesses, we need a server event handler (actually, we'll be
counting each open of a file fork, so, if a file has both a data fork and a resource fork, a
single open could be counted twice). We also need to set up the user item that draws the
histogram and to ask the server to record history information using an appropriate
time slice. The recommended time slice value is one sample every 84 seconds, so that
with 1024 data points the server retains a full day's information. Changing the value
may interfere with other programs that expect the value to be 84 seconds, so don't
deviate without cause.
For the most part, we'll use global variables for communication between the server
event handler, the dialog user item, and the modal dialog filter. Since AppleShare IP is
PowerPC-only, we can write the addition as a PowerPC application, which means that
we don't have to do anything special to use global variables.
Listing 2 shows these basic elements. We'll talk more about server event handlers and
the server control calls we use in a bit.
Listing 2: Main.c
#define kAllocateStorage NULL
#define kPlaceInFront ((WindowPtr) (-1L))
// Global variables...
SInt16 gActivityType = kWindowAvgRadioButtonIdx;
// We map the radio group state to the current on value...
SInt32 gActiveUserCount = 0;
// Number of users currently logged on...
SInt32 gLoginCount = 0;
// Cumulative counter of login events...
SInt32 gAccessCount = 0;
// Cumulative counter of access events...
UInt16 gServerState = kStateNotRunningIdx;
// Map the server state to the string we'll display...
Boolean gResetEnabled = false;
// The Reset button should be drawn enabled...
UInt32 gLastTimeServerPolled = 0;
// TimeStamp of the last time the server was called...
ServerHistoryRec gHistoryData;
// Historical data last returned by the server...
ServerEventQEntry gServerEventQEntry;
// Event handler queue entry...
// Support routines...
static void
// Initialize the managers we need...
InitGraf (&qd.thePort);
InitFonts ();
InitWindows ();
InitMenus ();
TEInit ();
InitDialogs (NULL);
InitCursor ();
// Initialize the data structures we'll use...
gHistoryData.numDataPoints = 0;
gHistoryData.historyLastSample = 0;
} // Initialize
// Main routine...
extern int
DialogPtr additionWindow;
// Initialize the toolbox, then check for AppleShare.
// If AppleShare is installed, go get the window, set default
control
// and data structure values, install server event handler, and
install
// a dialog user item to draw the histogram.
Initialize ();
if (AppleShareIsInstalled ()) {
additionWindow = GetNewDialog (kAdditionWindowRsrcID,
kAllocateStorage, kPlaceInFront);
if (additionWindow != NULL) {
InstallServerEventHandler ();