ftp.nice.ch/pub/next/connectivity/infosystems/Archie.2.18.s.tar.gz#/Archie/ArchieSession.m

This is ArchieSession.m in view mode; [Download] [Up]

{\rtf0\ansi{\fonttbl\f1\fswiss Helvetica;\f0\fmodern Courier;\f3\ftech Symbol;}
\paperw11760
\paperh7800
\margl120
\margr120
{\colortbl;\red0\green0\blue0;}
\pard\tx520\tx1060\tx1600\tx2120\tx2660\tx3200\tx3720\tx4260\tx4800\tx5320\f1\b\i0\ulnone\fs24\fc0\cf0 #import <appkit/appkit.h>\
#import "ArchieSession.h"\
#import "ArchieApp.h"\
#import "FileWellView.h"\
#import "FTPObject.h"\
#import "MyBrowserCell.h"\
#import "Preferences.h"\
#import "Query.h"\
#import <ClockView.h>\
#import <CalendarView.h>\
#import <List_Archival.h>\
\
#import <objc/NXStringTable.h>\
#import <objc/Storage.h>\
\

\b0\i /* Class untitled document count variable */
\b\i0 \
static int gUntitledCount = 0;\
\

\b0\i\fc1\cf1 /* Class document extension list */
\b\i0\fc0\cf0 \
static const char *gDocTypes[] = \{"archie", NULL\};\
\

\b0\i\fc1\cf1 /* Pasteboard types we can do */
\b\i0\fc0\cf0 \
static NXAtom gPBoardTypes[2];\
static int gNumPBoardTypes = 2;\
/* The minimimum usable size of a session windo */\
static NXSize minWinSize = \{575, 450\};\
\

\pard\tx480\tx960\tx1440\tx1920\tx2400\tx2880\tx3360\tx3840\tx4320\tx4800\b0\i\fc1\cf1 /* The query mutex defined in ArchieSession.m. This is a temporary item required\
	until the source in libArchie.subproj is thread-safe. */
\b\i0\fc0\cf0 \
mutex_t query_thread_mutex;\

\pard\tx520\tx1060\tx1600\tx2120\tx2660\tx3200\tx3720\tx4260\tx4800\tx5320\fc0\cf0 \
@implementation ArchieSession\
\
/*\\ ---------------------- Initialization Methods ---------------------- \\*/\
+ initialize\
\{\

\pard\tx180\tx360\tx540\tx720\tx2660\tx3200\tx3720\tx4260\tx4800\tx5320\f0\b0\i\fc0\cf0 /*
{{\NeXTHelpMarker965 \markername initialize;}
¬}\pard\tx180\tx360\tx540\tx720\tx2660\tx3200\tx3720\tx4260\tx4800\tx5320\f0\b0\i\ulnone\fs24\fc0\cf0  --- 
\ul MethodDescription
\ulnone \
	
\i0\ul\fc1\cf1 ReturnValue:
\i\ulnone\fc0\cf0  self;\
	
\i0\ul\fc1\cf1 Description:
\i\ulnone\fc0\cf0  Register an error reporter for the exceptions raised\
		by the ObjectArchival methods and initialize our pasteboard types;\
*/\

\pard\tx520\tx1060\tx1600\tx2120\tx2660\tx3200\tx3720\tx4260\tx4800\tx5320\f1\b\i0\fc0\cf0 	/* Register the ObjectArchival protocol exeception reporter */\
	NXRegisterErrorReporter(NX_APPBASE, END_ObjectArchival_EXCEPTIONS,\
		ObjectArchivalError);\
	gPBoardTypes[0] = 
\fc1\cf1 NXRTFPboardType;\
	gPBoardTypes[1] = NXAsciiPboardType;\
\

\fc0\cf0 	/* Allocate the query thread mutex */\
	query_thread_mutex 
\fc1\cf1 = mutex_alloc();\

\fc0\cf0 \
	return self;\
\} 
\b0\i // End initialize
\b\i0 \
\
+ alloc\
\{\

\pard\tx180\tx360\tx540\tx720\tx2660\tx3200\tx3720\tx4260\tx4800\tx5320\f0\b0\i\fc1\cf1 /*
{{\NeXTHelpMarker1503 \markername alloc;}
¬}\pard\tx180\tx360\tx540\tx720\tx2660\tx3200\tx3720\tx4260\tx4800\tx5320\f0\b0\i\ulnone\fs24\fc1\cf1  --- 
\ul MethodDescription
\ulnone \
	
\i0\ul ReturnValue:
\i\ulnone  self;\
	
\i0\ul Description:
\i\ulnone  Allocates memory for the class inside of a new\
		zone using 
\b NXCreateZone
\b0 ().  Memory is actually allocated\
		using our super's 
\b allocFromZone:
\b0 .;\
*/\

\pard\tx520\tx1060\tx1600\tx2120\tx2660\tx3200\tx3720\tx4260\tx4800\tx5320\f1\b\i0\fc0\cf0 NXZone *zone;\
\
	/* Allocate ourselves in a new zone */\
	zone = NXCreateZone(vm_page_size, vm_page_size, YES);\
	self = [super allocFromZone: zone];\
\
	return self;\
\} 
\b0\i // End alloc
\b\i0 \
\
+ new\
\{\

\pard\tx180\tx360\tx540\tx720\tx2660\tx3200\tx3720\tx4260\tx4800\tx5320\f0\b0\i\fc1\cf1 /*
{{\NeXTHelpMarker1895 \markername new;}
¬}\pard\tx180\tx360\tx540\tx720\tx2660\tx3200\tx3720\tx4260\tx4800\tx5320\f0\b0\i\ulnone\fs24\fc1\cf1  --- 
\ul MethodDescription
\ulnone \
	
\i0\ul ReturnValue:
\i\ulnone  A new ArchieSession if successful, nil if not;\
	
\i0\ul Description:
\i\ulnone  Allocates a new class instance contained within\
		a new zone and initializes an untitled document;\
*/\

\pard\tx520\tx1060\tx1600\tx2120\tx2660\tx3200\tx3720\tx4260\tx4800\tx5320\f1\b\i0\fc0\cf0 char name[MAXPATHLEN];\
const char *directory;\
ArchieSession *session;\
\
	
\b0\i /* Allocate and init ourselves */
\b\i0 \
	session = [[self alloc] init];\
	if( session == nil )\
		return nil;\
\
	
\b0\i /* Set window title */
\b\i0 \
	directory = [session lastOpenPath];\
	sprintf(name, "%s/Untitled%d", directory, gUntitledCount ++);\
	[session->windowID setTitleAsFilename: name];\
	[session->windowID makeKeyAndOrderFront: session];\
\
	
\b0\i /* Set document variables */
\b\i0 \
	[session stringAlloc: name copyTo: &session->documentPath];\
	session->documentName = rindex(session->documentPath, '/');\
	session->documentName ++;\
	session->isUntitled = YES;\
\
    return session;\
\} 
\b0\i // End new
\b\i0 \
\
+ newFromFile\
\{\

\pard\tx180\tx360\tx540\tx720\tx2660\tx3200\tx3720\tx4260\tx4800\tx5320\f0\b0\i\fc0\cf0 /*
{{\NeXTHelpMarker2755 \markername newFromFile;}
¬}\pard\tx180\tx360\tx540\tx720\tx2660\tx3200\tx3720\tx4260\tx4800\tx5320\f0\b0\i\ulnone\fs24\fc0\cf0  --- 
\ul MethodDescription
\ulnone \
	
\i0\ul\fc1\cf1 ReturnValue:
\i\ulnone\fc0\cf0  value returned by our 
\b newFromFile:
\b0  method;\
	
\i0\ul\fc1\cf1 Description:
\i\ulnone\fc0\cf0  A cover for our 
\b newFromFile:
\b0  method.  It passes\
		a NULL filename argument to 
\b newFromFile:
\b0  to signal that\
		an OpenPanel should be displayed to select the archive.;\
*/\

\pard\tx520\tx1060\tx1600\tx2120\tx2660\tx3200\tx3720\tx4260\tx4800\tx5320\f1\b\i0\fc0\cf0 	return [self newFromFile: NULL];\
\} 
\b0\i // End newFromFile
\b\i0 \
\
+ newFromFile: (const char *) filename;\
\{\

\pard\tx180\tx360\tx540\tx720\tx2660\tx3200\tx3720\tx4260\tx4800\tx5320\f0\b0\i\fc1\cf1 /*
{{\NeXTHelpMarker3118 \markername newFromFile:;}
¬}\pard\tx180\tx360\tx540\tx720\tx2660\tx3200\tx3720\tx4260\tx4800\tx5320\f0\b0\i\ulnone\fs24\fc1\cf1  --- 
\ul MethodDescription
\ulnone \
	
\i0\ul ReturnValue:
\i\ulnone  A new ArchieSession if successful, nil if not;\
	
\i0\ul Description:
\i\ulnone  Allocates a new class instance contained within\
		a new zone. The method first opens a typed stream for the\
		specified filename.  This is accomplished using the\
		Object(Document) 
\b readStreamForDoc:
\b0  method. If filename is\
		NULL, an OpenPanel is displayed so that the user may select\
		the archive file. Once the stream is open, we unarchive our\
		instance variables using our 
\b readFromTStream:
\b0  method.  If\
		we fail to init from the archive, we free ourselves and\
		return nil;\
	
\i0\ul Args:
\i\ulnone \
		filename: The fully qualified path of the archive file to open;\
*/\

\pard\tx520\tx1060\tx1600\tx2120\tx2660\tx3200\tx3720\tx4260\tx4800\tx5320\f1\b\i0\fc0\cf0 NXTypedStream *fileStream;\
BOOL useOpenPanel;\
ArchieSession *session;\
\
	
\b0\i /* Allocate and init ourselves */
\b\i0 \
	session = [[self alloc] init];\
	if( session == nil )\
		return nil;\
\
	
\b0\i /* Open a typed stream of the document given by path */
\b\i0 \
	useOpenPanel = (filename == NULL ? YES : NO);\
	fileStream = [session readStreamForDoc: gDocTypes directory: NULL\
		file: filename prompt: useOpenPanel];\
	if( useOpenPanel == YES )\
		filename = [session lastFilename];\

\f0\b0\fs20 [session debug: MAX_DEBUG method: _cmd, "opened = %s, %p\\n", filename, fileStream];
\f1\b\fs24 \
\
	if( fileStream == NULL && errno != 0 )\
	\{	
\b0\i /* Try to report an informative error */
\b\i0 \
		[session systemErr: "Archie failed to open: %s" method: _cmd, filename];\
		[session free];\
		return nil;\
	\}\
	else if( fileStream == NULL )\
	\{	
\b0\i /* A NULL stream with a zero errno indicates the user canceled\
			the open operation from the OpenPanel */
\b\i0 \
		return [session free];\
	\}\
\

\f0\b0\fs20 [session debug: MAX_DEBUG method: _cmd, "Unarchiving..."];
\f1\b\fs24 \
	
\b0\i /* Read archived instance variables */
\b\i0 \
	if( [session readFromTStream: fileStream] == nil )\
	\{	
\b0\i /* We failed to init from the archive.  This should have\
			raised an exception msg panel informing the user */
\b\i0 \
		NXCloseTypedStream(fileStream);\
		return [session free];\
	\}\
	NXCloseTypedStream(fileStream);\

\f0\b0\fs20 [session debug: MAX_DEBUG method: _cmd, "File unarchived\\n"];
\f1\b\fs24 \
\
	
\b0\i /* Set window title */
\b\i0 \
	[session->windowID setTitleAsFilename: filename];\
	[session->windowID makeKeyAndOrderFront: session];\
\
	
\b0\i /* Set document variables */
\b\i0 \
	[session stringAlloc:(char *) filename copyTo: &session->documentPath];\
	session->documentName = rindex(session->documentPath, '/');\
	if( session->documentName == NULL )\
		session->documentName = session->documentPath;\
	else\
		session->documentName ++;\
	session->isUntitled = NO;\
\
	return session;\
\} 
\b0\i // End newFromFile
\b\i0 :\
\
- init\
\{\

\pard\tx180\tx360\tx540\tx720\tx2660\tx3200\tx3720\tx4260\tx4800\tx5320\f0\b0\i\fc1\cf1 /*
{{\NeXTHelpMarker5585 \markername init;}
¬}\pard\tx180\tx360\tx540\tx720\tx2660\tx3200\tx3720\tx4260\tx4800\tx5320\f0\b0\i\ulnone\fs24\fc1\cf1  --- 
\ul MethodDescription
\ulnone \
	
\i0\ul ReturnValue:
\i\ulnone  self if successful, nil if not;\
	
\i0\ul Description:
\i\ulnone  Initializes a newly allocated class instance.\
		This is the designated initialization routine that is\
		invoked by every method capable of creating ArchieSessions.\
		The method first loads its window interface contained\
		in the Session.nib file.  It also allocates an empty\
		List for our queryList instance variable.  It init\
		fails to load the window interface, it frees self\
		and returns nil.;\
*/\

\pard\tx520\tx1060\tx1600\tx2120\tx2660\tx3200\tx3720\tx4260\tx4800\tx5320\f1\b\i0\fc0\cf0 	[super init];\
\
	
\b0\i /* Load the session nib containing the window interface */
\b\i0 \
	if( [NXApp loadNibSection: "Session.nib" owner: self withNames: NO\
		fromZone: [self zone]] == nil )\
	\{	/* Without our interface we are in bad shape.  All we can do is\
			inform the user and quit */\
		[self error: INTERNAL_ERROR method: _cmd key: SESSION_NIB_FAILED];\
		return nil;\
	\}\
	[windowID setMinSize: &minWinSize];\
\
	/* Alloc and int the query list and set the active\
		query index to 0 */\
	queryList = [[List allocFromZone: [self zone]] initCount: 0];\
	viewQueryIndex = 0;\
	activeQueryCount = 0;\
\
	/* Get a reference to the application Preferences object */\
	preferences = [NXApp preferences];\
\
	return self;\
\} 
\b0\i // End init
\b\i0 \
\
- awakeFromNib\
\{\

\pard\tx180\tx360\tx540\tx720\tx2660\tx3200\tx3720\tx4260\tx4800\tx5320\f0\b0\i\fc1\cf1 /*
{{\NeXTHelpMarker6800 \markername awakeFromNib;}
¬}\pard\tx180\tx360\tx540\tx720\tx2660\tx3200\tx3720\tx4260\tx4800\tx5320\f0\b0\i\ulnone\fs24\fc1\cf1  --- 
\ul MethodDescription
\ulnone \
	
\i0\ul ReturnValue:
\i\ulnone  self;\
	
\i0\ul Description:
\i\ulnone  This method performs further initialization\
		for some of the instance variables which are outlets\
		to objects in the window interface;\
*/\

\pard\tx520\tx1060\tx1600\tx2120\tx2660\tx3200\tx3720\tx4260\tx4800\tx5320\f1\b\i0\fc0\cf0 	
\b0\i /* Set the class of the browser cells */
\b\i0 \
	[fileBrowserID setCellClass: [MyBrowserCell class]];\
	[fileBrowserID acceptArrowKeys: YES andSendActionMessages: YES];\
\
	
\b0\i /* Have the miniturized icon be the same as the document icon */
\b\i0 \
	[win
\fc1\cf1 dowID setMiniwindowIcon: "AppDoc"];\
	
\b0\i // Set the auto frame save name
\b\i0 \
	[windowID setFrameAutosaveName: "ArchieSessionFrame"];\
	
\b0\i // Restore the last saved frame size
\b\i0 \
	[windowID setFrameUsingName: "ArchieSessionFrame"];\
\

\fc0\cf0 	return self;\
\} 
\b0\i // End awakeFromNib
\b\i0 \
\
- free\
\{\

\pard\tx180\tx360\tx540\tx720\tx2660\tx3200\tx3720\tx4260\tx4800\tx5320\f0\b0\i\fc1\cf1 /*
{{\NeXTHelpMarker7497 \markername free;}
¬}\pard\tx180\tx360\tx540\tx720\tx2660\tx3200\tx3720\tx4260\tx4800\tx5320\f0\b0\i\ulnone\fs24\fc1\cf1  --- 
\ul MethodDescription
\ulnone \
	
\i0\ul ReturnValue:
\i\ulnone  [super free];\
	
\i0\ul Description:
\i\ulnone  This method frees all instance variables declared\
		by the class and messages super's 
\b free
\b0  method;\
*/\

\pard\tx520\tx1060\tx1600\tx2120\tx2660\tx3200\tx3720\tx4260\tx4800\tx5320\f1\b\i0\fc0\cf0 	if( documentPath != NULL )\
		[self free: documentPath];\
	[windowID free];\
	[ftpObject free];\
	[queryList free];\
\
	return [super free];\
\} 
\b0\i // End free
\b\i0 \
\

\b0\i\fs28 /*\\ ---------------------- Document Methods ---------------------- \\*/
\b\i0\fs24 \
+ (BOOL) canOpenFileType:(const char *) aType\
\{\

\pard\tx180\tx360\tx540\tx720\tx2660\tx3200\tx3720\tx4260\tx4800\tx5320\f0\b0\i\fc1\cf1 /*
{{\NeXTHelpMarker7937 \markername canOpenFileType:;}
¬}\pard\tx180\tx360\tx540\tx720\tx2660\tx3200\tx3720\tx4260\tx4800\tx5320\f0\b0\i\ulnone\fs24\fc1\cf1  --- 
\ul MethodDescription
\ulnone \
	
\i0\ul ReturnValue:
\i\ulnone  YES if we can open aType of doc, NO otherwise;\
	
\i0\ul Description:
\i\ulnone  This method compares the file extension aType\
		to the types of documents in our gDocTypes class variable.\
		A match indicates we known how to open the indicated file\
		type.;\
	
\i0\ul Args:
\i\ulnone \
		aType: the name of a file extension;\
*/\

\pard\tx520\tx1060\tx1600\tx2120\tx2660\tx3200\tx3720\tx4260\tx4800\tx5320\f1\b\i0\fc0\cf0 	if( strcmp(aType, gDocTypes[0]) == 0 )\
		return YES;\
\
	return NO;\
\} 
\b0\i // End canOpenFileType:
\b\i0 \
\
- save: sender\
\{\

\pard\tx180\tx360\tx540\tx720\tx2660\tx3200\tx3720\tx4260\tx4800\tx5320\f0\b0\i\fc1\cf1 /*
{{\NeXTHelpMarker8374 \markername save:;}
¬}\pard\tx180\tx360\tx540\tx720\tx2660\tx3200\tx3720\tx4260\tx4800\tx5320\f0\b0\i\ulnone\fs24\fc1\cf1  --- 
\ul MethodDescription
\ulnone \
	
\i0\ul ReturnValue:
\i\ulnone  The value return by our 
\b saveAs:
\b0  method;\
	
\i0\ul Description:
\i\ulnone  This method invokes our 
\b saveAs:
\b0  method with a\
		nil sender argument.  This indicates that a SavePanel should\
		not be brought up unless the document is marked as untitled.;\
	
\i0\ul Args:
\i\ulnone \
		sender: the Matrix of the Document submenu;\
*/\

\pard\tx520\tx1060\tx1600\tx2120\tx2660\tx3200\tx3720\tx4260\tx4800\tx5320\f1\b\i0\fc0\cf0 	[self saveAs: nil];\
\
	return self;\
\} 
\b0\i // End save:
\b\i0 \
\
- saveAs: sender\
\{\

\pard\tx180\tx360\tx540\tx720\tx2660\tx3200\tx3720\tx4260\tx4800\tx5320\f0\b0\i\fc1\cf1 /*
{{\NeXTHelpMarker8768 \markername saveAs:;}
¬}\pard\tx180\tx360\tx540\tx720\tx2660\tx3200\tx3720\tx4260\tx4800\tx5320\f0\b0\i\ulnone\fs24\fc1\cf1  --- 
\ul MethodDescription
\ulnone \
	
\i0\ul ReturnValue:
\i\ulnone  self if successful, nil otherwise;\
	
\i0\ul Description:
\i\ulnone  This method opens saves the ArchieSession document\
		to a typed stream using the writeToTStream: method.  A typed\
		stream is opened using the Object(Document) writeStreamForDoc:\
		method. If sender is not nil, a SavePanel is displayed so\
		that the user can select the new name. A nil value for sender\
		indicates that a SavePanel should not be brought up unless the\
		document isUntitled flag is YES.;\
	
\i0\ul Args:
\i\ulnone \
		sender: the Matrix of the Document submenu, or nil to indicate\
			that the current document name should be used;\
*/\

\pard\tx520\tx1060\tx1600\tx2120\tx2660\tx3200\tx3720\tx4260\tx4800\tx5320\f1\b\i0\fc0\cf0 NXTypedStream *fileStream;\
const char *filename = documentPath;\
BOOL useSavePanel = YES;\
\
	if( sender == nil && isUntitled == NO )\
	\{	/* Save document using current name */\
		useSavePanel = NO;\
	\}\
\
	
\b0\i\fc1\cf1 /* Open a typed stream for the document */
\b\i0\fc0\cf0 \
	fileStream = [self writeStreamForDoc: gDocTypes[0] directory: NULL\
			file: filename prompt: useSavePanel];\
	if( useSavePanel == YES )\
		filename = [self lastFilename];\

\f0\b0\fs20 [self debug: MAX_DEBUG method: _cmd, "opened = %s, %p\\n", filename, fileStream];
\f1\b\fs24 \
\
	if( fileStream == NULL && errno != 0 )\
	\{\
		[self systemErr: "Archie failed to open: %s" method: _cmd, filename];\
		return [self free];\
	\}\
	else if( fileStream == NULL )\
	\{	
\b0\i /* A NULL stream with a zero errno indicates the user canceled\
			the open operation from the OpenPanel */
\b\i0 \
		return [self free];\
	\}\
\
	
\b0\i /* Write the session to the stream */
\b\i0 \
	if( [self writeToTStream: fileStream] == nil )\
	\{	
\b0\i /* We failed to init from the archive.  This should have\
			raised an exception msg panel informing the user */
\b\i0 \
		NXCloseTypedStream(fileStream);\
		return [self free];\
	\}\
	NXCloseTypedStream(fileStream);\
\
	if( useSavePanel == YES )\
	\{	
\b0\i /* Update document title */
\b\i0 \
		[self stringAlloc:(char *) filename copyTo: &documentPath];\
		[windowID setTitleAsFilename: documentPath];\
		documentName = rindex(documentPath, '/');\
		if( documentName == NULL )\
			documentName = documentPath;\
		else\
			documentName ++;\
	\}\
	[windowID setDocEdited: NO];\
\
	return self;\
\} 
\b0\i // End saveAs:
\b\i0 \
\
- close: sender\
\{\

\pard\tx180\tx360\tx540\tx720\tx900\tx3200\tx3720\tx4260\tx4800\tx5320\f0\b0\i\fc1\cf1 /*
{{\NeXTHelpMarker10865 \markername close:;}
¬}\pard\tx180\tx360\tx540\tx720\tx900\tx3200\tx3720\tx4260\tx4800\tx5320\f0\b0\i\ulnone\fs24\fc1\cf1  --- 
\ul MethodDescription
\ulnone \
	
\i0\ul ReturnValue:
\i\ulnone  self if the session window will close, nil if will not;\
	
\i0\ul Description
\i\ulnone : This method tests if the session document is edited\
		and if it is, asks the user if changes should be saved.  If\
		the user says yes, it messages 
\b saveAs:
\b0  with a nil sender arg.;\
	
\i0\ul Args:
\i\ulnone \
		sender: can be a couple of different sources.  If our doc is edited,\
			and sender is:\
				NXApp - we display a save changes panel with a "Review Unsaved"\
					title.\
				other - we display a save changes panel with a "Close"\
					title.;\
*/\

\pard\tx520\tx1060\tx1600\tx2120\tx2660\tx3200\tx3720\tx4260\tx4800\tx5320\f1\b\i0\fc0\cf0 	if( [windowID isDocEdited] == YES )\
	\{	
\b0\i /* Ask user if the doc should be saved */
\b\i0 \
	int btn;\
	char *title = "Close";\
		if( sender == NXApp )\
			title = "Review Unsaved";\
		btn = [self alert: title msg: "Save changes to %s?"\
			btn1: "Save" btn2: "Don't Save" btn3: "Cancel", documentName];\
		switch( btn )\
		\{\
			case NX_ALERTDEFAULT:\
				if( [self saveAs: nil] == nil )\
					return nil;	
\b0\i\fc1\cf1 // User canceled
\b\i0\fc0\cf0 \
				break;\
			case NX_ALERTALTERNATE:\
				break;\
			case NX_ALERTOTHER:\
				return nil;\
				break;\
		\}\
	\}\
	if( sender == NXApp )\
		[windowID orderOut: self];\
	
\b0\i /* Free ourselves after completion of the current event handling.\
		If we don't do a delayed free, we get a bunch of error messages\
		that result from NXApp trying to send messages to our window. */
\b\i0 \
	[NXApp delayedFree: self];\
\
	return self;\
\} 
\b0\i // End close:
\b\i0 \
\
- (BOOL) isEdited\
\{\

\pard\tx180\tx360\tx540\tx720\tx900\tx3200\tx3720\tx4260\tx4800\tx5320\f0\b0\i\fc1\cf1 /*
{{\NeXTHelpMarker12247 \markername isEdited;}
¬}\pard\tx180\tx360\tx540\tx720\tx900\tx3200\tx3720\tx4260\tx4800\tx5320\f0\b0\i\ulnone\fs24\fc1\cf1  --- 
\ul MethodDescription
\ulnone \
	
\i0\ul ReturnValue:
\i\ulnone  The value of our Window's 
\b isDocEdited
\b0  method;\

\pard\tx520\tx1060\tx1600\tx2120\tx2660\tx3200\tx3720\tx4260\tx4800\tx5320\fc1\cf1 */
\f1\b\i0\fc0\cf0 \
	return [windowID isDocEdited];\
\} 
\b0\i\fc1\cf1 // End isEdited
\b\i0\fc0\cf0 \
\

\b0\i\fs28 /*\\ ---------------------- Query Methods ---------------------- \\*/
\b\i0\fs24 \
- archieRequest: sender\
\{\

\pard\tx180\tx360\tx540\tx720\tx900\tx3200\tx3720\tx4260\tx4800\tx5320\f0\b0\i\fc1\cf1 /*
{{\NeXTHelpMarker12481 \markername archieRequest:;}
¬}\pard\tx180\tx360\tx540\tx720\tx900\tx3200\tx3720\tx4260\tx4800\tx5320\f0\b0\i\ulnone\fs24\fc1\cf1  --- 
\ul MethodDescription
\ulnone \
	
\i0\ul ReturnValue:
\i\ulnone  self;\
	
\i0\ul Description
\i\ulnone : This method is invoked when the user types a return\
		or enter in the interface query field or selects the "Query" btn.\
		It creates a new Query object that is responsible for forwarding\
		the query request to an Archie server and handling the server\
		response.  The Query is appended to the query list at the\
		current viewQueryIndex.  The query is not accessible from the\
		window interface until it indicates it has received the server\
		response and has informed us of this through our 
\b displayQuery:
\b0 \
		method.;\
	
\i0\ul Args:
\i\ulnone \
		sender: The "Query" button in the interface;\
*/\

\pard\tx520\tx1060\tx1600\tx2120\tx2660\tx3200\tx3720\tx4260\tx4800\tx5320\f1\b\i0\fc0\cf0 Query *query;\
const char *queryString, *hostname;\
char type;\
int flags, maxReplies, (*cmpProc)();\
\
	
\b0\i /* Currently only allow one thread to be actively querying the\
		server because the prospero / archie code is not thread proof.\
		We check for an active thread by trying to lock the\
		query_thread_mutex. */
\b\i0 \
	if( mutex_try_lock(query_thread_mutex) == 0 )\

\pard\tx480\tx960\tx1440\tx1920\tx2400\tx2880\tx3360\tx3840\tx4320\tx4800\fc0\cf0 	\{\
		[self alertOk: "Only one query thread is currently allowed" quit: NO];\
		return self;\
	\}\

\pard\tx520\tx1060\tx1600\tx2120\tx2660\tx3200\tx3720\tx4260\tx4800\tx5320\fc0\cf0 \
	
\b0\i /* Get the current Arc
\fc1\cf1 hie preferences *
\fc0\cf0 /
\b\i0 \
	flags = [preferences sortFlag];\
	cmpProc = [preferences cmpProc];\
	hostname = [preferences serverHost];\
	maxReplies = [preferences maxReplies];\
	type = [preferences queryType];\
	if( [preferences exactMode] == YES )\
		type = NXToLower(type);\
\
	
\b0\i /* Get the search string from the interface */
\b\i0 \
	queryString = [queryFieldID stringValue];\
\
	
\b0\i /* Create a new Query object and begin the request */
\b\i0 \
	query = [[Query allocFromZone: [self zone]] init];\
	[query setDelegate: self];\
	[query performRequest: hostname query: queryString maxRep: maxReplies\
		queryType: type sortProc: cmpProc queryFlags: flags];\
\
	
\b0\i /* Append this Query object to the query list. */
\b\i0 \
	[queryList addObject: query];\
	activeQueryCount ++;\
\
	return self;\
\} 
\b0\i // End archieRequest:
\b\i0 \
\
- displayQuery: sender\
\{\

\pard\tx180\tx360\tx540\tx720\tx900\tx3200\tx3720\tx4260\tx4800\tx5320\f0\b0\i\fc1\cf1 /*
{{\NeXTHelpMarker14372 \markername displayQuery:;}
¬}\pard\tx180\tx360\tx540\tx720\tx900\tx3200\tx3720\tx4260\tx4800\tx5320\f0\b0\i\ulnone\fs24\fc1\cf1  --- 
\ul MethodDescription
\ulnone \
	
\i0\ul ReturnValue:
\i\ulnone  self;\
	
\i0\ul Description
\i\ulnone : This method is invoked to display the server\
		response contained by the Query sender.  If the index of\
		the sender object in the queryList is a newly received\
		response (one of the last activeQueryCount objects), the\
		response is only displayed if the showNewQueries preferences\
		option is set.;\
	
\i0\ul Args:
\i\ulnone \
		sender: The Query object in need of display;\
*/\

\pard\tx520\tx1060\tx1600\tx2120\tx2660\tx3200\tx3720\tx4260\tx4800\tx5320\f1\b\i0\fc0\cf0 int queryIndex, queryCount;\
BOOL displayQueryResponse = YES, audioNotification;\
Sound *notifySnd;\
id theResponder;\
\
	
\b0\i\fc1\cf1 /* Find the query in the list */
\b\i0\fc0\cf0 \
	queryIndex = [queryList indexOf: sender];\
	if( queryIndex == NX_NOT_IN_LIST )\
	\{	// An internal error\
		[self error: INTERNAL_ERROR method:_cmd key: QUERY_NOT_IN_LIST];\
		return nil;\
	\}\
	
\b0\i\fc1\cf1 /* The number of queries available for display */
\b\i0\fc0\cf0 \
	queryCount = [queryList count] - activeQueryCount;\

\f0\b0\fs20 [self debug: MAX_DEBUG method:_cmd, "qc = %d; qi = %d", queryCount, queryIndex];
\f1\b\fs24 \
	if( queryIndex >= queryCount )\
	\{	
\b0\i\fc1\cf1 /* This is a new query response.  Only display it if\
			the showNewQueries option is yes, or this is the\
			first query response -- viewQuery == nil */
\b\i0\fc0\cf0 \
		
\b0\i\fc1\cf1 /* Play a notification sound if it is desired */
\b\i0\fc0\cf0 \
		audioNotification = [preferences audioNotification];\
		if( audioNotification == YES )\
		\{\
			notifySnd = [preferences notificationSnd: QueryReceived];\

\fc1\cf1 			[notifySnd play];
\fc0\cf0 \
		\}\
		activeQueryCount --;\
		displayQueryResponse = [preferences showNewQueries];\
		displayQueryResponse |= (viewQuery == nil);\
	\}\
\
	
\b0\i\fc1\cf1 /* If there are active queries ahead of this one in the queryList,\
		insert this query before them.  We need to do this since\
		only the first [queryList count] - activeQueryCount Query\
		objects can be accessed by the user. */\

\b\i0\fc0\cf0 	[queryCountID setIntValue: [queryList count]];\
	if( queryIndex > queryCount )\
	\{\
		[query
\fc1\cf1 List removeObjectAt: queryIndex
\fc0\cf0 ];\
		[queryList insertObject: sender at: queryCount];\
		queryIndex = queryCount;\
	\}\
\
	
\b0\i\fc1\cf1 /* This is all we do is displayQueryResponse is NO */
\b\i0\fc0\cf0 \
	if( displayQueryResponse == NO )\
		return self;\
\
	
\b0\i\fc1\cf1 /* Clear the interface */
\b\i0\fc0\cf0 \
	[self clearFields];\
\
	
\b0\i\fc1\cf1 /* Set the active query index to that corresponding to the sender,\
		make the sender the files NXBrowser delegate, make the sender\
		the file selection FileWellView delegate, and display\
		the query */
\b\i0\fc0\cf0 \
	viewQuery = sender;\
	viewQueryIndex = queryIndex;\
	[fileBrowserID setDelegate: sender];\
	theResponder = [fileBrowserID nextResponder];\
	while( [theResponder isKindOf: [Query class]] == YES )\
	\{	
\b0\i\fc1\cf1 /* Find the first non Query responder. With out this we can\
			introduce a responder circle between Query objects. */
\b\i0\fc0\cf0 \
		theResponder = [theResponder nextResponder];\
	\} \
	[sender setNextResponder: theResponder];\
	[fileBrowserID setNextResponder: sender];\
	[fileBrowserID setTarget: sender];\
	[fileBrowserID setAction: @selec
\fc1\cf1 tor(fileAttributes:)];\
	[fileBrowserID setDoubleAction: @selector(openInWorkspace:)];\
	[fileBrowserID loadColumnZero];\

\fc0\cf0 	[selectionViewID setDelegate: sender];\
	[selectionViewID clear];\
	
\b0\i /* Make the file browser the first reponder if it is not already */
\b\i0 \
	if( [windowID firstResponder] != 
\fc1\cf1 fileBrowserID )\
		[windowID makeFirstResponder: fileBrowserID];\

\fc0\cf0 \
	
\b0\i\fc1\cf1 /* Set the match count & query no. fields, as well as the query string field */
\b\i0\fc0\cf0 \
	[queryNoID setIntValue: queryIndex+1];\
	[matchCountID setIntValue: [viewQuery matchCount]];\
	[queryFieldID setStringValue: [viewQuery queryString]];\
\
	return self;\
\} 
\b0\i // End displayQuery:
\b\i0 \
\
- clearFields\
\{\

\pard\tx180\tx360\tx540\tx720\tx900\tx3200\tx3720\tx4260\tx4800\tx5320\f0\b0\i\fc1\cf1 /*
{{\NeXTHelpMarker17804 \markername clearFields;}
¬}\pard\tx180\tx360\tx540\tx720\tx900\tx3200\tx3720\tx4260\tx4800\tx5320\f0\b0\i\ulnone\fs24\fc1\cf1  --- 
\ul MethodDescription
\ulnone \
	
\i0\ul ReturnValue:
\i\ulnone  self;\
	
\i0\ul Description
\i\ulnone : This method clears the file information fields;\
*/\

\pard\tx520\tx1060\tx1600\tx2120\tx2660\tx3200\tx3720\tx4260\tx4800\tx5320\f1\b\i0\fc0\cf0 	
\b0\i\fc1\cf1 /* Reset date to now */
\b\i0\fc0\cf0 \
	[clockID now];\
	[calendarID today];\
\
	
\b0\i\fc1\cf1 /* Reset the file info Form */
\b\i0\fc0\cf0 \
	[fileInfoID setStringValue: NULL at: 0];\
	[fileInfoID setStringValue: NULL at: 1];\
	[fileInfoID setStringValue: NULL at: 2];\
	[fileInfoID setStringValue: NULL at: 3];\
	[fileInfoID setStringValue: NULL at: 4];\
\
	
\b0\i\fc1\cf1 /* Rest permissions */
\b\i0\fc0\cf0 \
	[readMatrixID setState: YES at: 0 : 0];\
	[readMatrixID setState: YES at: 0 : 1];\
	[readMatrixID setState: YES at: 0 : 2];\
	[writeMatrixID setState: YES at: 0 : 0];\
	[writeMatrixID setState: YES at: 0 : 1];\
	[writeMatrixID setState: YES at: 0 : 2];\
	[execMatrixID setState: YES at: 0 : 0];\
	[execMatrixID setState: YES at: 0 : 1];\
	[execMatrixID setState: YES at: 0 : 2];\
\
	return self;\
\} 
\b0\i // End clearFields
\b\i0 \
\
- nextQuery:(Button *) sender\
\{\

\pard\tx180\tx360\tx540\tx720\tx900\tx3200\tx3720\tx4260\tx4800\tx5320\f0\b0\i\fc1\cf1 /*
{{\NeXTHelpMarker18686 \markername nextQuery:;}
¬}\pard\tx180\tx360\tx540\tx720\tx900\tx3200\tx3720\tx4260\tx4800\tx5320\f0\b0\i\ulnone\fs24\fc1\cf1  --- 
\ul MethodDescription
\ulnone \
	
\i0\ul ReturnValue:
\i\ulnone  self;\
	
\i0\ul Description
\i\ulnone : This method displays the next available Query\
		object in our queryList;\
	
\i0\ul Args:
\i\ulnone \
		sender: The 
\f3\i0 ­
\f0\i  button in the interface;\
*/\

\pard\tx520\tx1060\tx1600\tx2120\tx2660\tx3200\tx3720\tx4260\tx4800\tx5320\f1\b\i0\fc0\cf0 id newQuery;\
int maxIndex;\
\
	
\b0\i /* The last available Query object is equal to the queryList count\
		minus the number of outstanding query requests */
\b\i0 \
	maxIndex = [queryList count] - activeQueryCount - 1;\
	if( viewQueryIndex >= maxIndex )\
		return nil;\
\
	
\b0\i /* Get the next query object to display */
\b\i0 \
	newQuery = [queryList objectAt: viewQueryIndex+1];\
	if( newQuery == nil )\
		[self error: INTERNAL_ERROR method:_cmd key: NO_QUERY_FOR_INDEX];\
\
	
\b0\i /* Update the browser interface */
\b\i0 \
	[self displayQuery: newQuery];\
\
	return self;\
\} 
\b0\i // End nextQuery:
\b\i0 \
\
- prevQuery:(Button *) sender\
\{\

\pard\tx180\tx360\tx540\tx720\tx900\tx3200\tx3720\tx4260\tx4800\tx5320\f0\b0\i\fc1\cf1 /*
{{\NeXTHelpMarker19445 \markername prevQuery:;}
¬}\pard\tx180\tx360\tx540\tx720\tx900\tx3200\tx3720\tx4260\tx4800\tx5320\f0\b0\i\ulnone\fs24\fc1\cf1  --- 
\ul MethodDescription
\ulnone \
	
\i0\ul ReturnValue:
\i\ulnone  self;\
	
\i0\ul Description
\i\ulnone : This method displays the previous available Query\
		object in our queryList;\
	
\i0\ul Args:
\i\ulnone \
		sender: The 
\f3\i0 ¯
\f0\i  button in the interface;\
*/\

\pard\tx520\tx1060\tx1600\tx2120\tx2660\tx3200\tx3720\tx4260\tx4800\tx5320\f1\b\i0\fc0\cf0 id newQuery;\
\
	
\b0\i /* Check the query list bounds */
\b\i0 \
	if( viewQueryIndex <= 0 )\
		return nil;\
\
	
\b0\i /* Get the previous query object */
\b\i0 \
	newQuery = [queryList objectAt: viewQueryIndex-1];\
	if( newQuery == nil )\
		[self error: INTERNAL_ERROR method:_cmd key: NO_QUERY_FOR_INDEX];\
\
	
\b0\i /* Update the browser interface */
\b\i0 \
	[self displayQuery: newQuery];\
\
	return self;\
\} 
\b0\i // End prevQuery:
\b\i0 \
\

\b0\i\fs28 /*\\ ---------------------------- MainWindow Object Access ---------------------------- \\*/
\b\i0\fs24 \

\b0\i /* The following routines allow Query objects to gain access to the interface\
	objects they update according to the file selected in the files browser */
\b\i0 \
- getMainWindowID\
\{
\b0\i //
{{\NeXTHelpMarker20273 \markername getMainWindowID;}
¬}\pard\tx520\tx1060\tx1600\tx2120\tx2660\tx3200\tx3720\tx4260\tx4800\tx5320\f1\b\i0\ulnone\fs24\fc0\cf0 \
	return windowID;\
\}\
- getFileBrowserID\
\{
\b0\i //
{\b\i0{\NeXTHelpMarker20317 \markername getFileBrowserID;}
¬}\pard\tx520\tx1060\tx1600\tx2120\tx2660\tx3200\tx3720\tx4260\tx4800\tx5320\f1\b\i0\ulnone\fs24\fc0\cf0 \
	return fileBrowserID;\
\}\
- getQueryFieldID\
\{
\b0\i //
{\b\i0{\NeXTHelpMarker20365 \markername getQueryFieldID;}
¬}\pard\tx520\tx1060\tx1600\tx2120\tx2660\tx3200\tx3720\tx4260\tx4800\tx5320\f1\b\i0\ulnone\fs24\fc0\cf0 \
	return queryFieldID;\
\}\
- getFileInfoID\
\{
\b0\i //
{\b\i0{\NeXTHelpMarker20410 \markername getFileInfoID;}
¬}\pard\tx520\tx1060\tx1600\tx2120\tx2660\tx3200\tx3720\tx4260\tx4800\tx5320\f1\b\i0\ulnone\fs24\fc0\cf0 \
	return fileInfoID;\
\}\
- getReadMatrixID\
\{
\b0\i //
{\b\i0{\NeXTHelpMarker20455 \markername getReadMatrixID;}
¬}\pard\tx520\tx1060\tx1600\tx2120\tx2660\tx3200\tx3720\tx4260\tx4800\tx5320\f1\b\i0\ulnone\fs24\fc0\cf0 \
	return readMatrixID;\
\}\
- getWriteMatrixID\
\{
\b0\i //
{\b\i0{\NeXTHelpMarker20503 \markername getWriteMatrixID;}
¬}\pard\tx520\tx1060\tx1600\tx2120\tx2660\tx3200\tx3720\tx4260\tx4800\tx5320\f1\b\i0\ulnone\fs24\fc0\cf0 \
	return writeMatrixID;\
\}\
- getExecMatrixID\
\{
\b0\i //
{\b\i0{\NeXTHelpMarker20551 \markername getExecMatrixID;}
¬}\pard\tx520\tx1060\tx1600\tx2120\tx2660\tx3200\tx3720\tx4260\tx4800\tx5320\f1\b\i0\ulnone\fs24\fc0\cf0 \
	return execMatrixID;\
\}\
- getCalendarID\
\{
\b0\i //
{\b\i0{\NeXTHelpMarker20596 \markername getCalendarID;}
¬}\pard\tx520\tx1060\tx1600\tx2120\tx2660\tx3200\tx3720\tx4260\tx4800\tx5320\f1\b\i0\ulnone\fs24\fc0\cf0 \
	return calendarID;\
\}\
- getClockID\
\{
\b0\i //
{\b\i0{\NeXTHelpMarker20636 \markername getClockID;}
¬}\pard\tx520\tx1060\tx1600\tx2120\tx2660\tx3200\tx3720\tx4260\tx4800\tx5320\f1\b\i0\ulnone\fs24\fc0\cf0 \
	return clockID;\
\}\
- getSelectionViewID\
\{//
{{\NeXTHelpMarker20681 \markername getSelectionViewID;}
¬}\pard\tx520\tx1060\tx1600\tx2120\tx2660\tx3200\tx3720\tx4260\tx4800\tx5320\f1\b\i0\ulnone\fs24\fc0\cf0 \
	return selectionViewID;\
\}\
- getSmallMsgID\
\{//
{{\NeXTHelpMarker20729 \markername getSmallMsgID;}
¬}\pard\tx520\tx1060\tx1600\tx2120\tx2660\tx3200\tx3720\tx4260\tx4800\tx5320\f1\b\i0\ulnone\fs24\fc0\cf0 \
	return smallMsgID;\
\}\
\
- appWillTerminate: sender\
\{\

\pard\tx180\tx360\tx540\tx720\tx900\tx3200\tx3720\tx4260\tx4800\tx5320\f0\b0\i\fc1\cf1 /*
{{\NeXTHelpMarker20785 \markername appWillTerminate:;}
¬}\pard\tx180\tx360\tx540\tx720\tx900\tx3200\tx3720\tx4260\tx4800\tx5320\f0\b0\i\ulnone\fs24\fc1\cf1  --- 
\ul MethodDescription
\ulnone \
	
\i0\ul ReturnValue:
\i\ulnone  self if we are willing to close the session,\
		nil otherwise;\
	
\i0\ul Description
\i\ulnone : This method checks for outstanding active queries\
		and the edit status of the document. If there are active\
		queries, the user is asked if they still want to quit. If\
		the document is edited we send ourselves a 
\b close:
\b0  message\
		to handle saving of the document.;\
	
\i0\ul Args:
\i\ulnone \
		sender: The application object;\
*/\

\pard\tx520\tx1060\tx1600\tx2120\tx2660\tx3200\tx3720\tx4260\tx4800\tx5320\f1\b\i0\fc0\cf0 const char *format;\
int userAction;\
id close = self;\
\
	
\b0\i /* Check to see if there are active queries */
\b\i0 \
	if( activeQueryCount > 0 )\
	\{	
\b0\i /* Ask user if the want to cancel. Msg is like:\
			"There are active queries. Do you want to quit?" */
\b\i0 \
		format = [[NXApp msgTable] valueForStringKey:\
			QUIT_ACTIVE_QUERY_FORMAT];\
		userAction = [self askYesNo: format cancel: NO];\
		if( userAction == NX_ALERTALTERNATE )\
			return nil;		
\b0\i\fc1\cf1 // No selected
\b\i0\fc0\cf0 \
	\}\
\
	
\b0\i /* Notify user if doc is not saved */
\b\i0 \
	if( [windowID isDocEdited] == YES )\
		close = [self close: sender];\
\
	return close;\
\} 
\b0\i // End appWillTerminate:
\b\i0 \
\

\b0\i\fs28\fc1\cf1 /*\\ ------------------------------- Window Delegate Methods ------------------------------- \\*/
\b\i0\fs24\fc0\cf0 \
- windowDidBecomeKey: sender\
\{\

\pard\tx180\tx360\tx540\tx720\tx900\tx3200\tx3720\tx4260\tx4800\tx5320\f0\b0\i\fc1\cf1 /*
{{\NeXTHelpMarker21930 \markername windowDidBecomeKey:;}
¬}\pard\tx180\tx360\tx540\tx720\tx900\tx3200\tx3720\tx4260\tx4800\tx5320\f0\b0\i\ulnone\fs24\fc1\cf1  --- 
\ul MethodDescription
\ulnone \
	
\i0\ul ReturnValue:
\i\ulnone  self;\
	
\i0\ul Description
\i\ulnone : This method requests the the files browser be\
		made the first responder.  We do this so that arrow key\
		events are sent to the browser.;\
	
\i0\ul Args:
\i\ulnone \
		sender: Our windowID object;\
*/
\pard\tx520\tx1060\tx1600\tx2120\tx2660\tx3200\tx3720\tx4260\tx4800\tx5320\f1\b\i0\fc0\cf0 \
	[sender makeFirstResponder: fileBrowserID];\
\
	return self;\
\} 
\b0\i // End windowDidBecomeKey:
\b\i0 \
\
- windowWillClose: sender\
\{\

\pard\tx180\tx360\tx540\tx720\tx900\tx3200\tx3720\tx4260\tx4800\tx5320\f0\b0\i\fc1\cf1 /*
{{\NeXTHelpMarker22288 \markername windowDidBecomeKey:;}
¬}\pard\tx180\tx360\tx540\tx720\tx900\tx3200\tx3720\tx4260\tx4800\tx5320\f0\b0\i\ulnone\fs24\fc1\cf1  --- 
\ul MethodDescription
\ulnone \
	
\i0\ul ReturnValue:
\i\ulnone  The value of our 
\b close:
\b0  method;\
	
\i0\ul Description
\i\ulnone : This method is called when the user clicks\
		the window's close button.  We forward it to our 
\b close:
\b0 \
		method and return its value.;\
	
\i0\ul Args:
\i\ulnone \
		sender: Our windowID object;\
*/
\pard\tx520\tx1060\tx1600\tx2120\tx2660\tx3200\tx3720\tx4260\tx4800\tx5320\f1\b\i0\fc0\cf0 \
id close;\
\
	close = [self close: sender];\
\
	return close;\
\} 
\b0\i // End windowWillClose:
\b\i0 \
\

\b0\i\fs28\fc1\cf1 /*\\ ---------------------- Menu Update Methods ---------------------- \\*/
\b\i0\fs24\fc0\cf0 \
- (BOOL) validateCommand:(MenuCell *) menuCell\
\{\

\pard\tx180\tx360\tx540\tx720\tx900\tx3200\tx3720\tx4260\tx4800\tx5320\f0\b0\i\fc1\cf1 /*
{{\NeXTHelpMarker22756 \markername validateCommand:;}
¬}\pard\tx180\tx360\tx540\tx720\tx900\tx3200\tx3720\tx4260\tx4800\tx5320\f0\b0\i\ulnone\fs24\fc1\cf1  --- 
\ul MethodDescription
\ulnone \
	
\i0\ul ReturnValue:
\i\ulnone  YES if the menuCell should be redrawn, NO otherwise;\
	
\i0\ul Description:
\i\ulnone  This method determines the enabled state of its argument\
		MenuCell based on the current value of the application items\
		which the item can affect;\
	
\i0\ul Args:
\i\ulnone  \
		menuCell: the MenuCell whose status is being checked;\
*/\

\pard\tx520\tx1060\tx1600\tx2120\tx2660\tx3200\tx3720\tx4260\tx4800\tx5320\f1\b\i0\fc0\cf0 SEL action = [menuCell action];\
BOOL enable = YES;\
\
	
\b0\i /* Determine which menu item the cell represents by its\
		action method and set its state.  Menu item actions that\
		are sent to us but are not caught in the if statements\
		are always enabled because of the default YES return. */
\b\i0 \
	if ( action == @selector(ftpRetrieve:) || action == @selector(ftpOpen:) )\
		enable = ([viewQuery selectedFile] == nil ? NO : YES);\
	else if( action == @selector(save:) )\
		enable = [windowID isDocEdited];\
	else if( action == @selector(saveAs:) )\
	\{\
		enable = ! isUntitled;\
		enable |= [windowID isDocEdited];\
	\}\
	else if( action == @selector(copy:) || action == @selector(cut:) ||\
			action == @selector(delete:) )\
		enable = (viewQuery != nil);\
	else if( action == @selector(undelete:) )\
		enable = (lastDeletedQuery != nil);\
\
	return enable;\
\} 
\b0\i // End validateCommand:
\b\i0 \
\

\b0\i\fs28 /*\\ ---------------------- ObjectArchival Protocol Methods ---------------------- \\*/
\b\i0\fs24 \

\b0\i /* Inline functions which return the name & version of the archive format */
\b\i0 \
static inline char *ClassName() \{ return "ArchieSession"; \} 
\b0\i //
{{\NeXTHelpMarker24159 \markername ClassName;}
¬}\pard\tx520\tx1060\tx1600\tx2120\tx2660\tx3200\tx3720\tx4260\tx4800\tx5320\f1\b\i0\ulnone\fs24\fc0\cf0 \
static inline long ArchiveVersion()\
\{
\b0\i //
{{\NeXTHelpMarker24200 \markername ArchiveVersion;}
¬}\pard\tx520\tx1060\tx1600\tx2120\tx2660\tx3200\tx3720\tx4260\tx4800\tx5320\f1\b\i0\ulnone\fs24\fc0\cf0 \
long version;\
	version = 1000 * ARCHIESESSION_VERS + 10 * ARCHIESESSION_SUBVERS\
		+ ARCHIESESSION_TYPE;\
	return version;\
\}\
\
- initFromTStream:(NXTypedStream *) stream\
\{\

\pard\tx180\tx360\tx540\tx720\tx900\tx3200\tx3720\tx4260\tx4800\tx5320\f0\b0\i\fc1\cf1 /*
{{\NeXTHelpMarker24373 \markername initFromTStream:;}
¬}\pard\tx180\tx360\tx540\tx720\tx900\tx3200\tx3720\tx4260\tx4800\tx5320\f0\b0\i\ulnone\fs24\fc1\cf1  --- 
\ul MethodDescription
\ulnone \
	
\i0\ul ReturnValue:
\i\ulnone  self if we successfully unarchive an instance\
		from the stream, nil if not;\
	
\i0\ul Description:
\i\ulnone  This method initializes a newly allocated\
		ArchieSession using our 
\b init
\b0  and 
\b readFromTStream:
\b0  methods.\
		If either 
\b init
\b0  or 
\b readFromTStream:
\b0  fail, we free ourseleves\
		and return nil.;\
	
\i0\ul Args:
\i\ulnone  \
		stream: The typed stream from which to unarchive the instance;\
*/\

\pard\tx520\tx1060\tx1600\tx2120\tx2660\tx3200\tx3720\tx4260\tx4800\tx5320\f1\b\i0\fc0\cf0 	if( [self init] == nil )\
		return [self free];\
	if( [self readFromTStream: stream] == nil )\
		return nil;	
\b0\i // 
\b readFromTStream:
\b0  invokes 
\b free
\i0 \
\
	return self;\
\} 
\b0\i // End initFromTStream:
\b\i0 \
\
- readFromTStream:(NXTypedStream *) stream\
\{\

\pard\tx180\tx360\tx540\tx720\tx900\tx3200\tx3720\tx4260\tx4800\tx5320\f0\b0\i\fc1\cf1 /*
{{\NeXTHelpMarker24991 \markername readFromTStream:;}
¬}\pard\tx180\tx360\tx540\tx720\tx900\tx3200\tx3720\tx4260\tx4800\tx5320\f0\b0\i\ulnone\fs24\fc1\cf1  --- 
\ul MethodDescription
\ulnone \
	
\i0\ul ReturnValue:
\i\ulnone  self if we successfully unarchive an instance\
		from the stream, nil if not;\
	
\i0\ul Description:
\i\ulnone  This method attempts to unarchive an ArchieSession\
		instance that was previously written using a 
\b writeToTStream:
\b0 \
		format. We must have been previously allocated and inited.\
		It does an initial check of the archived object's\
		class name and archive version to make sure it can deal\
		with it. This method is the top level handler for all of\
		the ObjectArchival exceptions defined in ObjectArchival.h.\
		It simply forwards them to the registered error reporter\
		by calling 
\b NXReportError
\b0 (). If an exception occurs, we\
		call free and return nil.;\
	
\i0\ul Args:
\i\ulnone  \
		stream: The typed stream from which to unarchive the instance;\
*/\

\pard\tx520\tx1060\tx1600\tx2120\tx2660\tx3200\tx3720\tx4260\tx4800\tx5320\f1\b\i0\fc0\cf0 const char *className;\
long version;\
void *data1 = NULL, *data2 = NULL;\
\
NX_DURING\

\f0\b0\fs20 [self debug: SUPER_DEBUG method: _cmd, "class = %s; superclass = %s\\n",\
	[[self class] name], [[self superclass] name]];
\f1\b\fs24 \
\
	
\b0\i /* First read the class name & archive version info */
\b\i0 \
	NXReadTypes(stream, "*i", &className, &version);\
	if( strcmp(className, ClassName()) != 0 )\
	\{	
\b0\i /* Not and ArchieSession class instance */
\b\i0 \
		NXAllocErrorData(strlen(className)+1, &data1);\
		NXAllocErrorData(strlen(ClassName())+1, &data2);\
		strcpy(data1, className);\
		strcpy(data2, ClassName());\
		NX_RAISE(eWrongClassName, data1, data2);\
	\}\
\
	switch( version )\
	\{\
		case ARCHIESESSION_VERSION_0:\
			/* Read in the query list */\
			queryList = [[List allocFromZone: [self zone]]\
				initFromTStream: stream];\
			[queryList makeObjectsPerform:@selector(setDelegate:)\
				with: self];\
			break;\
		default:\
			
\b0\i /* This is a version we don't know about */
\b\i0 \
			NXAllocErrorData(strlen([[self class] name])+1, &data1);\
			NXAllocErrorData(sizeof(long), &data2);\
			strcpy(data1, [[self class] name]);\
			*((long *) data2) = version;\
			NX_RAISE(eBadObjVersion, data1, data2);\
			break;\
	\}\
NX_HANDLER\
	
\b0\i /* Invoke the ObjectArchivalError() error reporter. It displays the\
		exception information. */
\b\i0 \
	NXReportError(&NXLocalHandler);\
	[self free];\
	NX_VALRETURN(nil);\
NX_ENDHANDLER\
\
	
\b0\i\fc1\cf1 /* Finish setting up instance variables */
\b\i0\fc0\cf0 \
	viewQuery = [queryList objectAt: viewQueryIndex];\
	[windowID makeKeyAndOrderFront: self];\
	[self displayQuery: viewQuery];\
\
	return self;\
\} 
\b0\i // End readFromTStream:
\b\i0 \
\
- writeToTStream:(NXTypedStream *) stream\
\{\

\pard\tx180\tx360\tx540\tx720\tx900\tx3200\tx3720\tx4260\tx4800\tx5320\f0\b0\i\fc1\cf1 /*
{{\NeXTHelpMarker27335 \markername writeToTStream:;}
¬}\pard\tx180\tx360\tx540\tx720\tx900\tx3200\tx3720\tx4260\tx4800\tx5320\f0\b0\i\ulnone\fs24\fc1\cf1  --- 
\ul MethodDescription
\ulnone \
	
\i0\ul ReturnValue:
\i\ulnone  self if we successfully unarchive an instance\
		from the stream, nil if not;\
	
\i0\ul Description:
\i\ulnone  This method attempts to archive an ArchieSession\
		instance. It writes out the class name and archive version to\
		aide the unarhival process. This method is the top level handler\
		for all of the ObjectArchival exceptions defined in ObjectArchival.h.\
		It simply forwards them to the registered error reporter\
		by calling 
\b NXReportError
\b0 (). If an exception occurs, we return nil.;\
	
\i0\ul Args:
\i\ulnone  \
		stream: The typed stream to archive the instance to;\
*/\

\pard\tx520\tx1060\tx1600\tx2120\tx2660\tx3200\tx3720\tx4260\tx4800\tx5320\f1\b\i0\fc0\cf0 const char *className;\
long version;\
\
NX_DURING\

\f0\b0\fs20 [self debug: MAX_DEBUG method: _cmd, "class = %s; superclass = %s\\n",\
	[[self class] name], [[self superclass] name]];
\f1\b\fs24 \
\
	
\b0\i /* First write the class name & archive version info */
\b\i0 \
	className = ClassName();\
	version = ArchiveVersion();\
	NXWriteTypes(stream, "*i", &className, &version);\
\
	
\b0\i /* Write our query list */
\b\i0 \
	[queryList writeToTStream: stream];\
\
NX_HANDLER\
	NXReportError(&NXLocalHandler);\
	NX_VALRETURN(nil);\
NX_ENDHANDLER\
\
	return self;\
\} 
\b0\i // End writeToTStream:
\b\i0 \
\

\b0\i\fs28 /*\\ ---------------------- Edit Menu Actions ---------------------- \\*/
\b\i0\fs24 \
- copy: sender\
\{\

\pard\tx180\tx360\tx540\tx720\tx900\tx3200\tx3720\tx4260\tx4800\tx5320\f0\b0\i\fc1\cf1 /*
{{\NeXTHelpMarker28519 \markername copy:;}
¬}\pard\tx180\tx360\tx540\tx720\tx900\tx3200\tx3720\tx4260\tx4800\tx5320\f0\b0\i\ulnone\fs24\fc1\cf1  --- 
\ul MethodDescription
\ulnone \
	
\i0\ul ReturnValue:
\i\ulnone  self;\
	
\i0\ul Description:
\i\ulnone  This method copies ASCII and RTF versions of the\
		query response currently displayed in the interface.  It also\
		sets the pbQuery instance variable to allow for 
\b copy:
\b0 , 
\b cut:
\b0 \
		and 
\b paste:
\b0  operations of Query objects within a given window.\
		I haven't provided a mechanism by which Query objects or their\
		responses could be transferred between ArchieSession windows\
		because I did not think it was necessary.  Later I suppose.;\
	
\i0\ul Args:
\i\ulnone  \
		sender: The Matrix of the Edit submenu;\
*/\

\pard\tx520\tx1060\tx1600\tx2120\tx2660\tx3200\tx3720\tx4260\tx4800\tx5320\f1\b\i0\fc0\cf0 Pasteboard *pboard;\
NXStream *pbData;\
int type;\
\

\f0\b0\fs20 [self debug: MAX_DEBUG method: _cmd, "viewQuery = %p\\n", viewQuery];
\f1\b\fs24 \
	
\b0\i /* Prepare the general Pasteboard for the copy operation and save the\
		current change count.  We use this to determine if the current\
		pasteboard data was provided by the pbQuery object.*/
\b\i0 \
	pboard = [Pasteboard new];\
	if( pbChangeCount == [pboard changeCount] && pbQuery == viewQuery )\
		return self;	
\b0\i // We already put this data on the pasteboard
\b\i0 \
\
	pbChangeCount = [pboard declareTypes: gPBoardTypes\
		num: gNumPBoardTypes owner: nil];\
	pbQuery = viewQuery;\
\
	pbData = NXOpenMemory(
\fc1\cf1 NULL, 0, NX_READWRITE);\
	if( pbData == NULL )\
		[self error: INTERNAL_ALERT method: _cmd\
			key: "Failed to open memory for operation"];\
\
	
\b0\i /* Place every format we can do on the pasteboard.  We accomplish\
		this by messaging viewQuery with 
\b copyTo: type:
\b0 . */
\b\i0 \
	for( type = 0; type < gNumPBoardTypes; type ++)\
	\{\
		if( [viewQuery copyTo: pbData type: gPBoardTypes[type]] != nil )\
		\{	
\b0\i /* Rewind the stream and write it to the Pasteboard */
\b\i0 \
			NXSeek(pbData, 0, NX_FROMSTART);\
			if( [pboard writeType: gPBoardTypes[type] fromStream: pbData] == nil )\
			\{\
				[self alertOk: "Copy operation failed!" quit: NO];\
				break;\
			\}\
		\}\
	\}\

\f0\b0\fs20\fc0\cf0 [self debug: MAX_DEBUG method: _cmd, "copy done\\n"];
\f1\b\fs24\fc1\cf1 \
	NXCloseMemory(pbData, NX_FREEBUFFER);\
\
	return self;\

\fc0\cf0 \} 
\b0\i // End copy:
\b\i0 \
\
- cut: sender\
\{\

\pard\tx180\tx360\tx540\tx720\tx900\tx3200\tx3720\tx4260\tx4800\tx5320\f0\b0\i\fc1\cf1 /*
{{\NeXTHelpMarker30433 \markername copy:;}
¬}\pard\tx180\tx360\tx540\tx720\tx900\tx3200\tx3720\tx4260\tx4800\tx5320\f0\b0\i\ulnone\fs24\fc1\cf1  --- 
\ul MethodDescription
\ulnone \
	
\i0\ul ReturnValue:
\i\ulnone  self;\
	
\i0\ul Description:
\i\ulnone  This method invokes copy: to write the\
		date to the pasteboard and removes the currently displayed\
		Query from the queryList.  Either the previous or next\
		query response is displayed depending on viewQueryIndex.;\
	
\i0\ul Args:
\i\ulnone  \
		sender: The Matrix of the Edit submenu;\
*/\

\pard\tx520\tx1060\tx1600\tx2120\tx2660\tx3200\tx3720\tx4260\tx4800\tx5320\f1\b\i0\fc0\cf0 id newQuery;\
\

\f0\b0\fs20 [self debug: MAX_DEBUG method: _cmd, "viewQuery = %p\\n", viewQuery];
\f1\b\fs24 \
	
\b0\i /* If the last pbQuery object is not in the queryList, it was\
		removed with a cut operation.  Our cut and copy stack is\
		only 1 deep so we free the object */
\b\i0 \
	if( pbQuery != nil )\
		if( [queryList indexOf: pbQuery] == NX_NOT_IN_LIST )\
			[pbQuery free];\
\
	
\b0\i /* Write the data to the pasteboard */
\b\i0 \
	[self copy: sender];\
	[queryList removeObjectAt: viewQueryIndex];\
\
	if( [queryList count] == 0 )\
	\{	
\b0\i /* Deleted the last query, clear the interface */
\b\i0 \
		[self clearFields];\
		[queryNoID setIntValue: 0];\
		[queryCountID setIntValue: 0];\
		[matchCountID setIntValue: 0];\
		[fileBrowserID setDelegate: nil];\
		[fileBrowserID loadColumnZero];\
		viewQuery = nil;\
		viewQueryIndex = 0;\
	\}\
	else\
	\{	
\b0\i /* Display the previous query, or if we were already at the front\
			of the queryList, the next query */
\b\i0 \
		if( viewQueryIndex > 0 )\
			viewQueryIndex --;\
		newQuery = [queryList objectAt: viewQueryIndex];\
		if( newQuery == nil )\
		\{	
\b0\i /* Internal error */
\b\i0 \
			[self error: INTERNAL_ALERT method:_cmd key: QUERY_NOT_IN_LIST];\
			return self;\
		\}\
		[self displayQuery: newQuery];\
	\}\
\
	return self;\
\} 
\b0\i // End cut:
\b\i0 \
\
- paste: sender\
\{\

\pard\tx180\tx360\tx540\tx720\tx900\tx3200\tx3720\tx4260\tx4800\tx5320\f0\b0\i\fc1\cf1 /*
{{\NeXTHelpMarker31962 \markername paste:;}
¬}\pard\tx180\tx360\tx540\tx720\tx900\tx3200\tx3720\tx4260\tx4800\tx5320\f0\b0\i\ulnone\fs24\fc1\cf1  --- 
\ul MethodDescription
\ulnone \
	
\i0\ul ReturnValue:
\i\ulnone  self;\
	
\i0\ul Description:
\i\ulnone  This method attempts to paste the last copyied\
		or cut Query object into the queryList at the current\
		viewQueryIndex. It will only suceed if the current\
		change count is equal to pbChangeCount.;\
	
\i0\ul Args:
\i\ulnone  \
		sender: The Matrix of the Edit submenu;\
*/\

\pard\tx520\tx1060\tx1600\tx2120\tx2660\tx3200\tx3720\tx4260\tx4800\tx5320\f1\b\i0\fc0\cf0 Pasteboard *pboard;\
const char *msg;\
\

\f0\b0\fs20 [self debug: MAX_DEBUG method: _cmd, "pasting %p\\n", pbQuery];
\f1\b\fs24 \
	pboard = [Pasteboard new];\
	if( [pboard changeCount] != pbChangeCount )\
	\{\
		msg = [[NXApp msgTable] valueForStringKey: QUERY_NOT_ON_PB];\
		[self alertOk: msg quit: NO];\
		return nil;\
	\}\
\
	
\b0\i\fc1\cf1 /* Add the pbQuery into the queryList */
\b\i0\fc0\cf0 \
	[queryList insertObject: pbQuery at: viewQueryIndex];\
	[self displayQuery: pbQuery];\

\f0\b0\fs20 [self debug: MAX_DEBUG method: _cmd, "paste done, qlc = %d\\n", [queryList count]];
\f1\b\fs24 \
\
	return self;\
\} 
\b0\i // End paste:
\b\i0 \
\
- delete: sender\
\{\

\pard\tx180\tx360\tx540\tx720\tx900\tx3200\tx3720\tx4260\tx4800\tx5320\f0\b0\i\fc1\cf1 /*
{{\NeXTHelpMarker32826 \markername delete:;}
¬}\pard\tx180\tx360\tx540\tx720\tx900\tx3200\tx3720\tx4260\tx4800\tx5320\f0\b0\i\ulnone\fs24\fc1\cf1  --- 
\ul MethodDescription
\ulnone \
	
\i0\ul ReturnValue:
\i\ulnone  self;\
	
\i0\ul Description:
\i\ulnone  This method removes the current Query object from\
		our queryList and assigns it to lastDeletedQuery.  The 
\b copy:
\b0 ,\
		
\b cut:
\b0 , and 
\b paste:
\b0  methods are independent of the 
\b delete:
\b0  and\
		
\b undelete:
\b0  methods.  For example, you cannot 
\b delete:
\b0  an object\
		and then 
\b paste:
\b0  it back. This method is also invoked by Query\
		objects to remove an aborted query.;\
	
\i0\ul Args:
\i\ulnone  \
		sender: The Matrix of the Edit submenu or the aborted Query;\
*/\

\pard\tx520\tx1060\tx1600\tx2120\tx2660\tx3200\tx3720\tx4260\tx4800\tx5320\f1\b\i0\fc0\cf0 id newQuery;\
\

\f0\b0\fs20 [self debug: MAX_DEBUG method: _cmd, 
\fc1\cf1 "viewQuery = %p; sender = %s\\n", viewQuery,\
	[sender name]]
\fc0\cf0 ;
\f1\b\fs24 \
	
\b0\i\fc1\cf1 /* First check for aborted queries */
\b\i0\fc0\cf0 \
	if( [sender isKindOf: [Query class]] == YES )\
	\{\
		newQuery = [quer
\fc1\cf1 yList removeObject: sender];\

\fc0\cf0 		activeQueryCount --;\

\fc1\cf1 		if( newQuery == nil )\
			[self error: INTERNAL_ERROR method:_cmd\
				key: "Failed to remove aborted query: %p", sender];\
		return self;\
	\}\

\fc0\cf0 \
	
\b0\i /* Delete stack has a depth of 1 */
\b\i0 \
	if( lastDeletedQuery != nil )\
		[lastDeletedQuery free];\
\
	lastDeletedQuery = viewQuery;\
	[queryList removeObjectAt: viewQueryIndex];\
	if( [queryList count] == 0 )\
	\{	
\b0\i /* Deleted the last query, clear the interface */
\b\i0 \
		[self clearFields];\
		[queryNoID setIntValue: 0];\
		[queryCountID setIntValue: 0];\
		[matchCountID setIntValue: 0];\
		[fileBrowserID setDelegate: nil];\
		[fileBrowserID loadColumnZero];\
		viewQuery = nil;\
		viewQueryIndex = 0;\
	\}\
	else\
	\{	
\b0\i /* Display the previous query, or if we were already at the front\
			of the queryList, the next query */
\b\i0 \
		if( viewQueryIndex > 0 )\
			viewQueryIndex --;\
		newQuery = [queryList objectAt: viewQueryIndex];\
		if( newQuery == nil )\
		\{	
\b0\i\fc1\cf1 /* Internal error */
\b\i0\fc0\cf0 \
			[self error: INTERNAL_ALERT method:_cmd key: QUERY_NOT_IN_LIST];\
			return nil;\
		\}\
		[self displayQuery: newQuery];\
	\}\
\
	return self;\
\} 
\b0\i // End delete:
\b\i0 \
\
- undelete: sender\
\{\

\pard\tx180\tx360\tx540\tx720\tx900\tx3200\tx3720\tx4260\tx4800\tx5320\f0\b0\i\fc1\cf1 /*
{{\NeXTHelpMarker34643 \markername undelete:;}
¬}\pard\tx180\tx360\tx540\tx720\tx900\tx3200\tx3720\tx4260\tx4800\tx5320\f0\b0\i\ulnone\fs24\fc1\cf1  --- 
\ul MethodDescription
\ulnone \
	
\i0\ul ReturnValue:
\i\ulnone  self;\
	
\i0\ul Description:
\i\ulnone  This method inserts and displays the deleted\
		query stored in lastDeletedQuery at the current viewQueryIndex.;\
	
\i0\ul Args:
\i\ulnone  \
		sender: The Matrix of the Edit submenu;\
*/
\pard\tx520\tx1060\tx1600\tx2120\tx2660\tx3200\tx3720\tx4260\tx4800\tx5320\f1\b\i0\fc0\cf0 \

\f0\b0\fs20 [self debug: MAX_DEBUG method: _cmd, 
\fc1\cf1 "lastDeletedQuery = %p\\n", lastDeletedQuery]
\fc0\cf0 ;
\f1\b\fs24 \
	if( [queryList insertObject: lastDeletedQuery at: viewQueryIndex] == nil )\
		[self error: INTERNAL_ALERT method:_cmd key: INSERT_QUERY_FAILURE];\
	[self displayQuery: lastDeletedQuery];\
	lastDeletedQuery = nil;\
\
	return self;\
\} 
\b0\i // End undelete:
\b\i0 \
\
/*\\ ---------------------------------- Service Methods ---------------------------------- \\*/\
- serviceArchieQuery: pasteboard userData:(const char *) serviceInfo\
	error:(char **) errorMsg\
\{\

\pard\tx180\tx360\tx540\tx720\tx2660\tx3200\tx3720\tx4260\tx4800\tx5320\f0\b0\i\fc0\cf0 /*
{{\NeXTHelpMarker35388 \markername serviceFtpToHost:userData:error:;}
¬}\pard\tx180\tx360\tx540\tx720\tx2660\tx3200\tx3720\tx4260\tx4800\tx5320\f0\b0\i\ulnone\fs24\fc0\cf0  --- 
\ul MethodDescription
\ulnone \
	
\i0\ul\fc1\cf1 ReturnValue:
\i\ulnone\fc0\cf0  self if successful, nil otherwise;\
	
\i0\ul\fc1\cf1 Description:
\i\ulnone\fc0\cf0  This method initiates a general or anonymous ftp\
		session with the host whose hostname is on the pasteboard.\
		If we fail to connect we return a message indicating this in\
		the errorMsg buffer;\
	
\i0\ul\fc1\cf1 Args:
\i\ulnone\fc0\cf0  \
		pasteboard: the Pasteboard object containing the hostname;\
		serviceInfo: additional info not currently used;\
		errorMsg: the pointer to update should an error occur;\
*/
\f1\b\i0 \

\pard\tx520\tx1060\tx1600\tx2120\tx2660\tx3200\tx3720\tx4260\tx4800\tx5320\fc1\cf1 const NXAtom *types;\
char *data, *queryString;\
int queryStringLength;\
\
	
\b0\i /* Check the pasteboard types.  This is probably uneccessary. */
\b\i0 \
	types = [pasteboard types];\
	while( *types != NULL && *types != NXAsciiPboardType )\
		types ++;\
	if( *types == NULL )\
	\{	
\b0\i /* Just not my type */
\b\i0 \
		*errorMsg = "Archie cannot handle the type of data sent";\

\f0\b0\fs20\fc0\cf0 [self debug: LOW_DEBUG method:_cmd, "errMsg = %s", errorMsg];
\f1\b\fs24 \

\fc1\cf1 		return nil;\
	\}\
\
	
\b0\i\fc0\cf0 /* Retrie
\fc1\cf1 ve the hostname from the pasteboard */
\b\i0 \
	if( [pasteboard readType: NXAsciiPboardType data: &data\
		length: &queryStringLength] == nil )\
	\{	/* Pasteboard contents must have changed */\
		*errorMsg = "Pasteboard contents appear to have changed to an invalid type";\

\f0\b0\fs20\fc0\cf0 [self debug: LOW_DEBUG method:_cmd, "errMsg = %s", errorMsg];
\f1\b\fs24 \

\fc1\cf1 		return self;\
	\}\

\f0\b0\fs20\fc0\cf0 [self debug: MAX_DEBUG method:_cmd, "service = %s; data = %.*s", serviceInfo, queryStringLength, data];\

\f1\b\fs24 \

\fc1\cf1 	
\b0\i /* Create a NIL terminated string and start the query */
\b\i0 \
	queryString = [self malloc: queryStringLength+1];\
	strncpy(queryString, data, queryStringLength);\
	queryString[queryStringLength] = '\\0';\
	[pasteboard deallocatePasteboardData: data length: queryStringLength];\

\fc0\cf0 	[queryFieldID setStringValue: queryString];\
	[queryBtnID performClick: self];\
	[self free: 
\fc1\cf1 queryString
\fc0\cf0 ];\
\
	return self;\
\}\

\pard\tx480\tx960\tx1440\tx1920\tx2400\tx2880\tx3360\tx3840\tx4320\tx4800\fc0\cf0 \

\pard\tx520\tx1060\tx1600\tx2120\tx2660\tx3200\tx3720\tx4260\tx4800\tx5320\fc0\cf0 @end\

\b0\i\fc1\cf1 /* RCS Information:\
	$Author: me $;\
	$Date: 94/01/08 14:39:59 $;\
	$Source: /usr1/me/NeXTSrc/Archie/RCS/ArchieSession.m,v $;\
	$Revision: 1.1 $;\
	$Log:	ArchieSession.m,v $Revision 1.1  94/01/08  14:39:59  meCheck point of 2.09a version.Revision 1.4  93/03/02  16:02:03  meAdded service method for archie query.\
Revision 1.3  93/02/26  03:15:41  meAdded RCS Log keyword.\
Revision 1.2 93/02/26 03:11:14 me Updated to make sure the file browser was the first responder in the displayQuery: method.  This ensures the the FTP menu items get validated correctly by the browser's delegate Query.\
Revision 1.1 93/02/23 02:09:47 me Version 2.01a of the project.\
*/\

}

These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.