(FILECREATED "12-May-86 22:28:13" {ROSEBOWL}<FEUERMAN>LISP>NCSERVER.;40 70245  

      changes to:  (VARS NCSERVERCOMS)

      previous date: " 8-May-86 13:53:49" {ROSEBOWL}<FEUERMAN>LISP>NCSERVER.;39)


(PRETTYCOMPRINT NCSERVERCOMS)

(RPAQQ NCSERVERCOMS ((FNS NCSERVER.FILELOADEDP)
	(FILES (SOURCE)
	       NCSERVERLISTENER)
	(* Don't overwrite the Listener program with the caller program)
	(P (OR (NCSERVER.FILELOADEDP (QUOTE NCCLIENTLISTENER))
	       (FILESLOAD (SOURCE)
			  NCCLIENTCALLER)))
	(* * Functions that respond directly to commands.)
	(FNS NCSERVER.COURIERLISTNOTEFILES NCSERVER.COURIERCREATENOTEFILE 
	     NCSERVER.COURIERDELETENOTEFILE NCSERVER.COURIERSUBSCRIBETONOTEFILE 
	     NCSERVER.COURIERCANCELNOTEFILESUBSCRIPTION NCSERVER.COURIERLISTUIDS 
	     NCSERVER.COURIERLISTCLIENTS NCSERVER.COURIERCREATECARD NCSERVER.COURIERDELETECARD 
	     NCSERVER.COURIERGETCARDPART NCSERVER.COURIEROBTAINWRITELOCK NCSERVER.COURIERPUTCARDPART 
	     NCSERVER.COURIERRELEASEWRITELOCK NCSERVER.COURIERCANCELCARDPARTSUBSCRIPTION)
	(* * Both local and courier clients are routed to calling these functions.)
	(FNS NCSERVER.LISTNOTEFILES NCSERVER.CREATENOTEFILE NCSERVER.DELETENOTEFILE 
	     NCSERVER.SUBSCRIBETONOTEFILE NCSERVER.CANCELNOTEFILESUBSCRIPTION NCSERVER.LISTUIDS 
	     NCSERVER.LISTCLIENTS NCSERVER.CREATECARD NCSERVER.DELETECARD NCSERVER.GETCARDPART 
	     NCSERVER.OBTAINWRITELOCK NCSERVER.PUTCARDPART NCSERVER.RELEASEWRITELOCK 
	     NCSERVER.CANCELCARDPARTSUBSCRIPTION)
	(RECORDS NFTOPBOXES)
	(* * The Notification functions which are triggered by NoteFile changes. These perform calls 
	   to the Courier program NoteCardsClient.)
	(FNS NCSERVER.NOTIFYSUBSCRIBERS NCSERVER.NOTIFY.CARDCREATED NCSERVER.NOTIFY.CARDDELETED 
	     NCSERVER.NOTIFY.CARDPARTCHANGED NCSERVER.NOTIFY.WRITELOCKOBTAINED 
	     NCSERVER.NOTIFY.WRITELOCKRELEASED)
	(* * The "bit bucket" functions. These take care of your basic GetCardPartBits and 
	   PutCardPartBits functionality.)
	(FNS NCSERVER.GETCARDPARTBITS NCSERVER.GETPROPLISTBITS NCSERVER.GETSUBSTANCEBITS 
	     NCSERVER.GETTITLEBITS NCSERVER.GETFROMLINKSBITS NCSERVER.GETGLOBALTOLINKSBITS 
	     NCSERVER.GETTOLINKSBITS)
	(FNS NCSERVER.PUTCARDPARTBITS NCSERVER.PUTGLOBALTOLINKSBITS NCSERVER.PUTFROMLINKSBITS 
	     NCSERVER.PUTPROPLISTBITS NCSERVER.PUTSUBSTANCEBITS NCSERVER.PUTTITLEBITS 
	     NCSERVER.PUTTOLINKSBITS)
	(* These functions are necessary for splitting and combining links information at the server 
	   end.)
	(FNS NCSERVER.COPYCARDPARTHEADER NCSERVER.COLLECTOLDLINKS)
	(* * Functions to manipulate the checkout lists.)
	(FNS NCSERVER.ADDCLIENT NCSERVER.REMOVECLIENT)
	(FNS NCSERVER.MAKEWRITER NCSERVER.REMOVEWRITER NCSERVER.GETWRITER NCSERVER.ADDSUBSCRIBER 
	     NCSERVER.REMOVESUBSCRIBER NCSERVER.GETSUBSCRIBERS)
	(* Functions that make use of the Card-level checkout lists.)
	(FNS NCSERVER.GETCARDUSERS)
	(* Functions that access the Card-PART-level lists.)
	(FNS NCSERVER.GETCARDPARTUSERS)
	(RECORDS CardPartUsers CardUsers)
	(* * Card part Monitor functions.)
	(FNS NCSERVER.GETCARDPARTMONITOR NCSERVER.SETCARDPARTMONITOR)
	(RECORDS CardPartMonitor)
	(* * Miscellaneous and utility functions.)
	(FNS NCSERVER.SERVICENOTIMPLEMENTED NCSERVER.GETCLIENTCOURIERSTREAM 
	     NCSERVER.DELETECARDFROMNOTEFILE NC.NOTEFILEP NCSERVER.COLLECTHASHKEYS 
	     NCSERVER.REMOVECLIENTFROMCARD NCSERVER.GETNOTEFILENAME NCSERVER.CONSTRUCTFILELIST 
	     NCSERVER.GETTOPLEVELUIDS NCSERVER.NSEQUAL NCSERVER.REALLYOPENNOTEFILE 
	     NCSERVER.REMOVEHOST NCSERVER.REMOVEHOSTNAME)
	(FILES NCNOTEFILEPROP NCCOURIER (FROM VALUEOF LISPUSERSDIRECTORIES SYSLOAD)
	       COURIERSERVE)
	(GLOBALVARS NCSERVER.ALLOW.ONLY.NOTEFILES.DELETE NCSERVER.NCCARDPARTS 
		    NCSERVER.NOTIFYINSTIGATORP NCSERVER.CLIENTSTREAMS)
	[VARS (NCSERVER.NCCARDPARTS (QUOTE (SUBSTANCE TOLINKS FROMLINKS TITLE PROPLIST GLOBALTOLINKS]
	(INITVARS (NCSERVER.ALLOW.ONLY.NOTEFILES.DELETE T)
		  (NCSERVER.NOTIFYINSTIGATORP NIL)
		  (NCSERVER.CLIENTSTREAMS NIL))
	(DECLARE: DONTCOPY (RECORDS NSADDRESS))
	(P (COURIER.START.SERVER))))
(DEFINEQ

(NCSERVER.FILELOADEDP
  [LAMBDA (FILENAME)                                         (* Feuerman " 2-May-86 11:24")
    (GETPROP FILENAME (QUOTE FILEDATES])
)
(FILESLOAD (SOURCE)
	   NCSERVERLISTENER)



(* Don't overwrite the Listener program with the caller program)

(OR (NCSERVER.FILELOADEDP (QUOTE NCCLIENTLISTENER))
    (FILESLOAD (SOURCE)
	       NCCLIENTCALLER))
(* * Functions that respond directly to commands.)

(DEFINEQ

(NCSERVER.COURIERLISTNOTEFILES
  [LAMBDA (COURIERSTREAM PROGRAM PROCEDURE PATTERN)          (* Feuerman " 7-May-86 13:40")

          (* * Calls the file enumeration function and returns the values to the Courier stream.)


    (COURIER.RETURN COURIERSTREAM PROGRAM PROCEDURE (LIST (NCSERVER.LISTNOTEFILES PATTERN])

(NCSERVER.COURIERCREATENOTEFILE
  [LAMBDA (COURIERSTREAM PROGRAM PROCEDURE NOTEFILENAME)     (* Feuerman " 7-May-86 08:09")

          (* * Creates a new NoteFile on this server by this name. Note that it is NOT opened; the client must come along 
	  later and open it explicitely.)


    (PROG ((CREATEDNOTEFILENAME (NCSERVER.CREATENOTEFILE NOTEFILENAME)))
	    (COND
	      [CREATEDNOTEFILENAME (COURIER.RETURN COURIERSTREAM PROGRAM PROCEDURE
						     (LIST (MKSTRING CREATEDNOTEFILENAME]
	      (T (COURIER.ABORT COURIERSTREAM PROGRAM (QUOTE CreateNoteFileFailed)
				  (LIST (MKSTRING NOTEFILENAME])

(NCSERVER.COURIERDELETENOTEFILE
  [LAMBDA (COURIERSTREAM PROGRAM PROCEDURE NOTEFILENAME)     (* Feuerman " 7-May-86 08:19")

          (* * Tries to delete the notefile.)


    (PROG ((DELFILERESULT (NCSERVER.DELETENOTEFILE NOTEFILENAME)))
	    (COND
	      [DELFILERESULT (COURIER.RETURN COURIERSTREAM PROGRAM PROCEDURE (LIST (MKSTRING
											 
										    DELFILERESULT]
	      (T (COURIER.ABORT COURIERSTREAM PROGRAM (QUOTE NoteFileNotDeleted)
				  (LIST (MKSTRING NOTEFILENAME])

(NCSERVER.COURIERSUBSCRIBETONOTEFILE
  [LAMBDA (COURIERSTREAM PROGRAM PROCEDURE FILENAMEorUID CLIENTADDRESS)
                                                             (* Feuerman " 7-May-86 08:37")

          (* * Calls the subscribe to notefile routine, passing in the remote client address.)


    (PROG ((RESULTS (NCSERVER.SUBSCRIBETONOTEFILE FILENAMEorUID CLIENTADDRESS)))
	    (COND
	      (RESULTS (COURIER.RETURN COURIERSTREAM PROGRAM PROCEDURE (LIST RESULTS)))
	      (T (COURIER.ABORT COURIERSTREAM PROGRAM (QUOTE NoteFileNotOpened)
				  (LIST "Could not find a local file for FILENAMEorUID"])

(NCSERVER.COURIERCANCELNOTEFILESUBSCRIPTION
  [LAMBDA (COURIERSTREAM PROGRAM PROCEDURE NOTEFILEorUID CLIENTADDRESS)
                                                             (* Feuerman " 7-May-86 08:49")

          (* * Removes the remote client from the notefile subscription.)


    (COND
      [(NCSERVER.CANCELNOTEFILESUBSCRIPTION (SELECTQ (CAR NOTEFILEorUID)
							 [FILENAME (NC.NoteFileFromFileName
								     (PACK* (QUOTE {DSK})
									      (CADR NOTEFILEorUID]
							 (NOTEFILEUID (NC.NoteFileFromNoteFileUID
									(CADR NOTEFILEorUID)))
							 NIL)
					      CLIENTADDRESS)
	(COURIER.RETURN COURIERSTREAM PROGRAM PROCEDURE (QUOTE (T]
      (T (COURIER.ABORT COURIERSTREAM PROGRAM (QUOTE NoteFileNotClosed)
			  (LIST (MKSTRING NOTEFILEorUID])

(NCSERVER.COURIERLISTUIDS
  [LAMBDA (COURIERSTREAM PROGRAM PROCEDURE NOTEFILEUID)      (* Feuerman " 7-May-86 08:53")

          (* * Calls for the list of UIDs for a NoteFile.)


    (COURIER.RETURN COURIERSTREAM PROGRAM PROCEDURE (LIST (NCSERVER.LISTUIDS NOTEFILEUID])

(NCSERVER.COURIERLISTCLIENTS
  [LAMBDA (COURIERSTREAM PROGRAM PROCEDURE NOTEFILEUID)      (* Feuerman " 7-May-86 09:00")

          (* * Returns the list of client addresses to the remote client. Converts instances of (QUOTE SELF) to 
	  \MY.NSADDRESS.)


    (DECLARE (GLOBALVARS \MY.NSADDRESS))
    (COURIER.RETURN COURIERSTREAM PROGRAM PROCEDURE (LIST (SUBST \MY.NSADDRESS (QUOTE SELF)
								       (NCSERVER.LISTCLIENTS 
										      NOTEFILEUID])

(NCSERVER.COURIERCREATECARD
  [LAMBDA (COURIERSTREAM PROGRAM PROCEDURE NOTEFILEUID CLIENTADDRESS)
                                                             (* Feuerman " 7-May-86 09:04")

          (* * Performs the creation of a new card from a remote client.)


    (COURIER.RETURN COURIERSTREAM PROGRAM PROCEDURE (LIST (NCSERVER.CREATECARD NOTEFILEUID 
										    CLIENTADDRESS])

(NCSERVER.COURIERDELETECARD
  [LAMBDA (COURIERSTREAM PROGRAM PROCEDURE NOTEFILEUID NOTECARDUID CLIENTNETADDRESS)
                                                             (* Feuerman " 7-May-86 09:10")

          (* * The remote call to deleting a card. Right now, probably the only reason for the delete to fail would be if the
	  client doesn't own write locks on all card parts.)


    (COND
      [(NCSERVER.DELETECARD NOTEFILEUID NOTECARDUID CLIENTNETADDRESS)
	(COURIER.RETURN COURIERSTREAM PROGRAM PROCEDURE (QUOTE (T]
      (T (COURIER.ABORT COURIERSTREAM PROGRAM (QUOTE CardNotDeleted)
			  (LIST "Client probably needs to obtain write locks on all card parts."])

(NCSERVER.COURIERGETCARDPART
  [LAMBDA (COURIERSTREAM PROGRAM PROCEDURE NOTEFILEUID NOTECARDUID CARDPART CLIENTADDRESS 
			 BULK.DATA.SINK)                     (* Feuerman " 7-May-86 09:25")

          (* * This function calls the GETCARDPART function, which fills up the BULK.DATA.SINK with the data requested.
	  Next, we close the BULK.DATA.SINK, indicating to the remote client that we're finished with it, and then return.)


    (NCSERVER.GETCARDPART NOTEFILEUID NOTECARDUID CARDPART CLIENTADDRESS BULK.DATA.SINK)
    (CLOSE.BULK.DATA BULK.DATA.SINK)
    (COURIER.RETURN COURIERSTREAM PROGRAM PROCEDURE])

(NCSERVER.COURIEROBTAINWRITELOCK
  [LAMBDA (COURIERSTREAM PROGRAM PROCEDURE NOTEFILEUID NOTECARDUID CARDPART CLIENTADDRESS)
                                                             (* Feuerman " 7-May-86 09:34")

          (* * The remote courier call to obtain write lock.)


    (COURIER.RETURN COURIERSTREAM PROGRAM PROCEDURE (LIST (COND
								((NCSERVER.OBTAINWRITELOCK 
										      NOTEFILEUID 
										      NOTECARDUID 
											 CARDPART 
										    CLIENTADDRESS)
								  T)
								(T NIL])

(NCSERVER.COURIERPUTCARDPART
  [LAMBDA (COURIERSTREAM PROGRAM PROCEDURE NOTEFILEUID NOTECARDUID CARDPART BULK.DATA.SOURCE 
			 CLIENTADDRESS)                      (* Feuerman " 7-May-86 10:10")

          (* * Calls the PUTCARDPART function. That function will return T if successful, and NIL otherwise.
	  It is assumed at this point that the reason for a NIL return is the lack of ownership of the writelock.)


    (COND
      [(NCSERVER.PUTCARDPART NOTEFILEUID NOTECARDUID CARDPART BULK.DATA.SOURCE CLIENTADDRESS)
	(CLOSE.BULK.DATA BULK.DATA.SOURCE)
	(COURIER.RETURN COURIERSTREAM PROGRAM PROCEDURE (QUOTE (T]
      (T (CLOSE.BULK.DATA BULK.DATA.SOURCE)
	 (COURIER.ABORT COURIERSTREAM PROGRAM (QUOTE PutNotPerformed)
			  (LIST "Client does not own writelock for card part."])

(NCSERVER.COURIERRELEASEWRITELOCK
  [LAMBDA (COURIERSTREAM PROGRAM PROCEDURE NOTEFILEUID NOTECARDUID CARDPART CLIENTADDRESS)
                                                             (* Feuerman " 7-May-86 10:14")

          (* * If the call to RELEASEWRITELOCK fails, then probably the write lock isn't owned by the calling client.)


    (COND
      [(NCSERVER.RELEASEWRITELOCK NOTEFILEUID NOTECARDUID CARDPART CLIENTADDRESS)
	(COURIER.RETURN COURIERSTREAM PROGRAM PROCEDURE (QUOTE (T]
      (T (COURIER.ABORT COURIERSTREAM PROGRAM (QUOTE WriteLockNotReleased)
			  (LIST "Write lock not owned by calling client."])

(NCSERVER.COURIERCANCELCARDPARTSUBSCRIPTION
  [LAMBDA (COURIERSTREAM PROGRAM PROCEDURE NOTEFILEUID NOTECARDUID CARDPART CLIENTADDRESS)
                                                             (* Feuerman " 7-May-86 10:17")

          (* * If the call to CANCELCARDPARTSUBSCRIPTION fails, then chances are that the subscription was never held.)


    (COND
      [(NCSERVER.CANCELCARDPARTSUBSCRIPTION NOTEFILEUID NOTECARDUID CARDPART CLIENTADDRESS)
	(COURIER.RETURN COURIERSTREAM PROGRAM PROCEDURE (QUOTE (T]
      (T (COURIER.ABORT COURIERSTREAM PROGRAM (QUOTE SubscriptionNotCancelled)
			  (LIST "Client is not currently subscribed to card part."])
)
(* * Both local and courier clients are routed to calling these functions.)

(DEFINEQ

(NCSERVER.LISTNOTEFILES
  [LAMBDA (PATTERN)                                          (* Feuerman " 7-May-86 07:50")

          (* * The local entry into the list notefiles command.)


    (NCSERVER.CONSTRUCTFILELIST PATTERN])

(NCSERVER.CREATENOTEFILE
  [LAMBDA (NOTEFILENAME)                                     (* Feuerman " 7-May-86 08:09")

          (* * Creates a new NoteFile on this server by this name. Note that it is NOT opened; the client must come along 
	  later and open it explicitely.)


    (PROG ((NOTEFILE (NC.CreateDatabaseFile (PACK* (QUOTE {DSK})
							 NOTEFILENAME)
						NIL "Remote Client Creating NoteFile")))
	    (RETURN (AND (type? NoteFile NOTEFILE)
			     (NCSERVER.REMOVEHOST (ffetch (NoteFile FullFileName) of NOTEFILE])

(NCSERVER.DELETENOTEFILE
  [LAMBDA (NOTEFILENAME)                                     (* Feuerman " 7-May-86 13:44")

          (* * Performs the deletion of the local file by the NOTEFILENAME. Some rudimentary checks to see if the file is 
	  indeed a NoteFile, and if we're checking to delete only NoteFiles.)


    (PROG ((LOCALFILENAME (PACK* (QUOTE {DSK})
				     NOTEFILENAME))
	     DELFILERESULT)
	    (RETURN (COND
			((OR (NOT NCSERVER.ALLOW.ONLY.NOTEFILES.DELETE)
			       (NC.NOTEFILEP LOCALFILENAME))
                                                             (* That clause checked to see if we're only letting 
							     NoteFiles be deleted as opposed to any file.)
			  (SETQ DELFILERESULT (DELFILE LOCALFILENAME))
			  (AND DELFILERESULT (NCSERVER.REMOVEHOST DELFILERESULT])

(NCSERVER.SUBSCRIBETONOTEFILE
  [LAMBDA (FILENAMEorUID CLIENTADDRESS)                      (* Feuerman " 7-May-86 08:37")

          (* * Opens the NoteFile if necessary, then adds the Client as a subscriber to the NoteFile.
	  Returns the list of UIDs as a record of top level boxes.)


    (PROG ((LOCALFILENAME (NCSERVER.GETNOTEFILENAME FILENAMEorUID))
	     NOTEFILE)
	    (RETURN (COND
			(LOCALFILENAME (OR (OPENP LOCALFILENAME)
					     (NCSERVER.REALLYOPENNOTEFILE LOCALFILENAME))
				       (NCSERVER.ADDCLIENT CLIENTADDRESS (SETQ NOTEFILE
							       (NC.NoteFileFromFileName 
										    LOCALFILENAME)))
				       (NCSERVER.GETTOPLEVELUIDS NOTEFILE])

(NCSERVER.CANCELNOTEFILESUBSCRIPTION
  [LAMBDA (NOTEFILE CLIENTADDRESS)                           (* Feuerman " 7-May-86 08:49")

          (* * If CLIENTADDRESS is the last client on the client list, the NOTEFILE is really closed, thus flushing all 
	  information from the data object. Otherwise, CLIENTADDRESS is simply removed from the client list, and also removed
	  from all subscription lists and write locks on all card parts.)


    (PROG (CLIENT)
	    (RETURN (COND
			((SETQ CLIENT (find Client in (NCNOTEFILEPROP.NoteFileGetProp
							      NOTEFILE
							      (QUOTE CLIENTS))
					   suchthat (NCSERVER.NSEQUAL CLIENTADDRESS Client)))
			  (COND
			    ((EQLENGTH (NCNOTEFILEPROP.NoteFileGetProp NOTEFILE (QUOTE CLIENTS))
					 1)                  (* This was the last client, so simply close)
			      (NC.CloseDatabaseFile NOTEFILE))
			    (T (NCSERVER.REMOVECLIENT NOTEFILE CLIENTADDRESS)))
			  T])

(NCSERVER.LISTUIDS
  [LAMBDA (NOTEFILEUID)                                      (* Feuerman " 7-May-86 08:53")

          (* * Returns a list of CardObject UIDs contained in the NoteFile.)


    (NCSERVER.COLLECTHASHKEYS (ffetch (NoteFile HashArray) of (NC.NoteFileFromNoteFileUID
								      NOTEFILEUID])

(NCSERVER.LISTCLIENTS
  [LAMBDA (NOTEFILEUID)                                      (* Feuerman " 7-May-86 09:00")

          (* * Returns the list of clients that are currently subscribed to the NoteFile.)


    (NCNOTEFILEPROP.NoteFileGetProp (NC.NoteFileFromNoteFileUID NOTEFILEUID)
				      (QUOTE CLIENTS])

(NCSERVER.CREATECARD
  [LAMBDA (NOTEFILEUID CLIENTADDRESS)                        (* Feuerman " 8-May-86 09:28")

          (* * Creates a new NoteCard instance and installs it into the NoteFile. Assigns the creator all write-locks for the
	  card, and includes as a subscriber. Returns the UID for the card to the Client.)


    (PROG ((NoteFile (NC.NoteFileFromNoteFileUID NOTEFILEUID))
	     Card NOTECARDUID)
	    (SETQ Card (NC.GetNewCard NoteFile))
	    (SETQ NOTECARDUID (ffetch (Card UID) of Card))
	    (for CardPart in NCSERVER.NCCARDPARTS
	       do (NCSERVER.MAKEWRITER NOTEFILEUID NOTECARDUID CardPart CLIENTADDRESS)
		    (NCSERVER.ADDSUBSCRIBER NOTEFILEUID NOTECARDUID CardPart CLIENTADDRESS))
                                                             (* And now, notify all subscribers to the NoteFile 
							     that a new card has been created.)
	    (NCSERVER.NOTIFYSUBSCRIBERS (NCNOTEFILEPROP.NoteFileGetProp NoteFile (QUOTE CLIENTS)
									    )
					  (LIST (QUOTE CARDCREATED)
						  NOTEFILEUID NOTECARDUID)
					  CLIENTADDRESS)
	    (RETURN NOTECARDUID])

(NCSERVER.DELETECARD
  [LAMBDA (NOTEFILEUID NOTECARDUID CLIENT)                   (* Feuerman " 8-May-86 09:32")

          (* * Deletes the card referred to by NOTECARDUID. Performs the rudimentary check of making sure that all card parts
	  are writelocked by the client first, though the client should also own writelocks on all card parts that will be 
	  changed by the card deletion. This includes the ToLinks of any card with pointers to this card.)


    (PROG ((NOTEFILE (NC.NoteFileFromNoteFileUID NOTEFILEUID)))
	    (RETURN (COND
			((for CardPart in NCSERVER.NCCARDPARTS
			    always (NCSERVER.NSEQUAL CLIENT (NCSERVER.GETWRITER NOTEFILEUID 
										      NOTECARDUID 
										      CardPart)))
                                                             (* Yes, the client does own all of the writelocks.)
			  (NCSERVER.DELETECARDFROMNOTEFILE NOTEFILE (NC.CardFromUID NOTECARDUID 
											NOTEFILE))
			  (NCSERVER.NOTIFYSUBSCRIBERS (NCNOTEFILEPROP.NoteFileGetProp
							  NOTEFILE
							  (QUOTE CLIENTS))
							(LIST (QUOTE CARDDELETED)
								NOTEFILEUID NOTECARDUID)
							CLIENT)
			  T])

(NCSERVER.GETCARDPART
  [LAMBDA (NOTEFILEUID NOTECARDUID CARDPART CLIENTADDRESS BUCKETSTREAM)
                                                             (* Feuerman " 8-May-86 09:43")

          (* * Finds and returns the card part request by the client. Adds the client to the readers list for that card 
	  part.)


    (PROG ((NoteFile (NC.NoteFileFromNoteFileUID NOTEFILEUID))
	     (CORESTREAM (OPENSTREAM (QUOTE {NODIRCORE})
				       (QUOTE BOTH)))
	     Card)
	    (SETQ Card (NC.CardFromUID NOTECARDUID NoteFile))
	    (WITH.MONITOR (NCSERVER.GETCARDPARTMONITOR Card CARDPART)
			  (WITH.MONITOR (NC.FetchMonitor NoteFile)
					(NCSERVER.GETCARDPARTBITS NoteFile Card CARDPART CORESTREAM)
					)
			  (SETFILEPTR CORESTREAM 0)
			  (COPYBYTES CORESTREAM BUCKETSTREAM)
			  (NCSERVER.ADDSUBSCRIBER NOTEFILEUID NOTECARDUID CARDPART CLIENTADDRESS))
	    (CLOSEF CORESTREAM)

          (* Now, check to see if the writelock is owned. If so, notify the client that they have just gotten something that 
	  is likely to change shortly.)


	    [AND (NCSERVER.GETWRITER NOTEFILEUID NOTECARDUID CARDPART)
		   (RESETVARS ((NCSERVER.NOTIFYINSTIGATORP T))
			        (RETURN (NCSERVER.NOTIFYSUBSCRIBERS (LIST CLIENTADDRESS)
									(LIST (QUOTE 
										WRITELOCKOBTAINED)
										NOTEFILEUID 
										NOTECARDUID CARDPART]
	    (RETURN])

(NCSERVER.OBTAINWRITELOCK
  [LAMBDA (NOTEFILEUID NOTECARDUID CARDPART CLIENTADDRESS)   (* Feuerman " 7-May-86 09:34")

          (* * This function checks to see if anyone own's the write lock on the CARDPART already. If so, and IF that owner 
	  is not the client already, then a NIL is returned. Otherwise, the client becomes the write lock owner and the 
	  function returns T.)


    (NCSERVER.MAKEWRITER NOTEFILEUID NOTECARDUID CARDPART CLIENTADDRESS])

(NCSERVER.PUTCARDPART
  [LAMBDA (NOTEFILEUID NOTECARDUID CARDPART BUCKETSTREAM CLIENTADDRESS)
                                                             (* Feuerman " 8-May-86 10:24")

          (* * Performs the Put of the card part to the NoteFile.)


    (COND
      ((NCSERVER.NSEQUAL CLIENTADDRESS (NCSERVER.GETWRITER NOTEFILEUID NOTECARDUID CARDPART))
                                                             (* First, we checked here to make sure the client owns
							     the writelock.)
	(PROG ((NoteFile (NC.NoteFileFromNoteFileUID NOTEFILEUID))
		 (CORESTREAM (OPENSTREAM (QUOTE {NODIRCORE})
					   (QUOTE BOTH)))
		 Card)
	        (SETQ Card (NC.CardFromUID NOTECARDUID NoteFile))
	        (WITH.MONITOR (NCSERVER.GETCARDPARTMONITOR Card CARDPART)
			      (COPYBYTES BUCKETSTREAM CORESTREAM)
			      (SETFILEPTR CORESTREAM 0)
			      (WITH.MONITOR (NC.FetchMonitor NoteFile)
					    (NCSERVER.PUTCARDPARTBITS NoteFile Card CARDPART 
									CORESTREAM)))
	        (CLOSEF CORESTREAM)                        (* Now, tell everyone that the card part was changed.)
	        (NCSERVER.NOTIFYSUBSCRIBERS (NCSERVER.GETSUBSCRIBERS NOTEFILEUID NOTECARDUID 
									 CARDPART)
					      (LIST (QUOTE CARDPARTCHANGED)
						      NOTEFILEUID NOTECARDUID CARDPART)
					      CLIENTADDRESS)

          (* Special note: The CARDPARTCHANGED notification is different from all others in that it actually affects some 
	  changes in the access list. If a Client reponds to the notification in the affirmative, that client is removed as a
	  subscriber.)


	        (RETURN T)))
      (T NIL])

(NCSERVER.RELEASEWRITELOCK
  [LAMBDA (NOTEFILEUID NOTECARDUID CARDPART CLIENTADDRESS)   (* Feuerman " 7-May-86 10:14")

          (* * Releases the write lock for the card part.)


    (NCSERVER.REMOVEWRITER NOTEFILEUID NOTECARDUID CARDPART CLIENTADDRESS])

(NCSERVER.CANCELCARDPARTSUBSCRIPTION
  [LAMBDA (NOTEFILEUID NOTECARDUID CARDPART CLIENTADDRESS)   (* Feuerman " 7-May-86 10:17")

          (* * Removes the client from the subscription list for the card part.)


    (NCSERVER.REMOVESUBSCRIBER NOTEFILEUID NOTECARDUID CARDPART CLIENTADDRESS])
)
[DECLARE: EVAL@COMPILE 

(RECORD NFTOPBOXES (NOTEFILE TABLEOFCONTENTS ORPHANS TOBEFILED LINKLABELS REGISTRY))
]
(* * The Notification functions which are triggered by NoteFile changes. These perform calls 
to the Courier program NoteCardsClient.)

(DEFINEQ

(NCSERVER.NOTIFYSUBSCRIBERS
  [LAMBDA (SUBSCRIBERS NOTIFICATION INSTIGATOR)              (* Feuerman " 8-May-86 09:28")

          (* * The top-level notification function; all notifications to clients are done here. SUBSCRIBERS is a list of 
	  clients to be notified, NOTIFICATION is a list, the CAR of which is one of the LITATOMs CARDCREATED, CARDDELETED, 
	  WRITELOCKOBTAINED, CARDPARTCHANGED, or WRITELOCKRELEASED. The CDR of NOTIFICATION is the extra information such as 
	  NOTEFILEUID or NOTECARDUID that is needed by the specific notification to inform the clients exactly what is going 
	  on. INSTIGATOR is the client responsible for the necessity of the notification, and can usually be left out of the 
	  notification list. The global variable NCSERVER.NOTIFYINSTIGATORP makes that decision.)



          (* * Yes, we do want to add a process for each notification that goes out. The reason is that just because one of 
	  the clients may take a long time to respond to a notification doesn't mean that the rest of the clients should be 
	  held up in hearing about the changes.)


    (AND SUBSCRIBERS (PROG [(NOTIFICATIONFN (SELECTQ (CAR NOTIFICATION)
							   (CARDCREATED (FUNCTION 
								      NCSERVER.NOTIFY.CARDCREATED))
							   (CARDDELETED (FUNCTION 
								      NCSERVER.NOTIFY.CARDDELETED))
							   (WRITELOCKOBTAINED (FUNCTION 
								NCSERVER.NOTIFY.WRITELOCKOBTAINED))
							   (CARDPARTCHANGED (FUNCTION 
								  NCSERVER.NOTIFY.CARDPARTCHANGED))
							   (WRITELOCKRELEASED (FUNCTION 
								NCSERVER.NOTIFY.WRITELOCKRELEASED))
							   (SHOULDNT (CONCAT 
									"Don't know how to do a "
										 (CAR NOTIFICATION)
										 " notification."]
			       (for Client in SUBSCRIBERS unless (AND (NOT 
								       NCSERVER.NOTIFYINSTIGATORP)
									      (NCSERVER.NSEQUAL
										INSTIGATOR Client))
				  do (ADD.PROCESS [LIST (QUOTE APPLY)
							      (KWOTE NOTIFICATIONFN)
							      (KWOTE (CONS Client (CDR 
										     NOTIFICATION]
						      (QUOTE NAME)
						      (PACK* Client (CAR NOTIFICATION])

(NCSERVER.NOTIFY.CARDCREATED
  [LAMBDA (CLIENT NOTEFILEUID NOTECARDUID)                   (* Feuerman " 8-May-86 08:37")

          (* * Notifies the CLIENT that a new card has appeared on the scene. The UID of the card is NOTECARDUID for notefile
	  NOTEFILEUID.)


    (COND
      ((EQ CLIENT (QUOTE SELF))
	(NCCLIENT.LOCALCARDCREATED NOTEFILEUID NOTECARDUID))
      (T (COURIER.CALL (NCSERVER.GETCLIENTCOURIERSTREAM CLIENT)
			 (QUOTE NoteCardsClient)
			 (QUOTE CardCreated)
			 NOTEFILEUID NOTECARDUID])

(NCSERVER.NOTIFY.CARDDELETED
  [LAMBDA (CLIENT NOTEFILEUID NOTECARDUID)                   (* Feuerman " 8-May-86 08:40")

          (* * Notifies the CLIENT that a new card has appeared on the scene. The UID of the card is NOTECARDUID for notefile
	  NOTEFILEUID.)


    (COND
      ((EQ CLIENT (QUOTE SELF))
	(NCCLIENT.LOCALCARDDELETED NOTEFILEUID NOTECARDUID))
      (T (COURIER.CALL (NCSERVER.GETCLIENTCOURIERSTREAM CLIENT)
			 (QUOTE NoteCardsClient)
			 (QUOTE CardDeleted)
			 NOTEFILEUID NOTECARDUID])

(NCSERVER.NOTIFY.CARDPARTCHANGED
  [LAMBDA (CLIENT NOTEFILEUID NOTECARDUID CARDPART)          (* Feuerman " 8-May-86 10:20")

          (* * Notifies CLIENT that CARDPART has just changed, so he'd better flush his cache.)


    (COND
      ((COND
	  ((EQ CLIENT (QUOTE SELF))
	    (NCCLIENT.LOCALCARDPARTCHANGED NOTEFILEUID NOTECARDUID CARDPART))
	  (T (COURIER.CALL (NCSERVER.GETCLIENTCOURIERSTREAM CLIENT)
			     (QUOTE NoteCardsClient)
			     (QUOTE CardPartChanged)
			     NOTEFILEUID NOTECARDUID CARDPART)))
                                                             (* If this returns T, then we've been acknowledged, so
							     remove the subscriber because he's probably flushed 
							     his cache.)
	(NCSERVER.REMOVESUBSCRIBER NOTEFILEUID NOTECARDUID CARDPART CLIENT])

(NCSERVER.NOTIFY.WRITELOCKOBTAINED
  [LAMBDA (CLIENT NOTEFILEUID NOTECARDUID CARDPART)          (* Feuerman " 8-May-86 08:45")

          (* * Notifies CLIENT that the writelock has just been obtained for the card part. This means that in all 
	  likelihood, the card will be changing.)


    (COND
      ((EQ CLIENT (QUOTE SELF))
	(NCCLIENT.LOCALWRITELOCKOBTAINED NOTEFILEUID NOTECARDUID CARDPART))
      (T (COURIER.CALL (NCSERVER.GETCLIENTCOURIERSTREAM CLIENT)
			 (QUOTE NoteCardsClient)
			 (QUOTE WriteLockObtained)
			 NOTEFILEUID NOTECARDUID CARDPART])

(NCSERVER.NOTIFY.WRITELOCKRELEASED
  [LAMBDA (CLIENT NOTEFILEUID NOTECARDUID CARDPART)          (* Feuerman " 8-May-86 08:52")

          (* * Notifies CLIENT that the writelock has just been released for the card part.)


    (COND
      ((EQ CLIENT (QUOTE SELF))
	(NCCLIENT.LOCALWRITELOCKRELEASED NOTEFILEUID NOTECARDUID CARDPART))
      (T (COURIER.CALL (NCSERVER.GETCLIENTCOURIERSTREAM CLIENT)
			 (QUOTE NoteCardsClient)
			 (QUOTE WriteLockReleased)
			 NOTEFILEUID NOTECARDUID CARDPART])
)
(* * The "bit bucket" functions. These take care of your basic GetCardPartBits and 
PutCardPartBits functionality.)

(DEFINEQ

(NCSERVER.GETCARDPARTBITS
  [LAMBDA (NOTEFILE NOTECARD CARDPART BUCKETSTREAM)          (* Feuerman " 5-May-86 17:41")

          (* * The top-level GetCardPartBits function. This function dumps the bits associated with CARDPART into the 
	  BUCKETSTREAM. Note that in the remote case, this stream will be the actual BULKDATASINK.)


    (SELECTQ CARDPART
	       (SUBSTANCE (NCSERVER.GETSUBSTANCEBITS NOTEFILE NOTECARD BUCKETSTREAM))
	       (TOLINKS (NCSERVER.GETTOLINKSBITS NOTEFILE NOTECARD BUCKETSTREAM))
	       (FROMLINKS (NCSERVER.GETFROMLINKSBITS NOTEFILE NOTECARD BUCKETSTREAM))
	       (TITLE (NCSERVER.GETTITLEBITS NOTEFILE NOTECARD BUCKETSTREAM))
	       (PROPLIST (NCSERVER.GETPROPLISTBITS NOTEFILE NOTECARD BUCKETSTREAM))
	       (GLOBALTOLINKS (NCSERVER.GETGLOBALTOLINKSBITS NOTEFILE NOTECARD BUCKETSTREAM))
	       (SHOULDNT (CONCAT "Illegal card part:  " CARDPART])

(NCSERVER.GETPROPLISTBITS
  [LAMBDA (NOTEFILE NOTECARD BUCKETSTREAM)                   (* Feuerman " 5-May-86 17:40")

          (* * Dumps the substance of NOTECARDUID into the BUCKETSTREAM and returns the stream.)



          (* * The function sets the pointer of the NoteFile data stream to the beginning of the PropListLoc area of the 
	  Card. The first three bytes there are the Length field of the CardPart Header, which indicates exactly how many 
	  bytes this card part takes up in the stream. That's how many bytes we're going to copy into the BUCKETSTREAM.)


    (PROG ((DATASTREAM (ffetch (NoteFile Stream) of NOTEFILE))
	     LENGTH)
	    (SETFILEPTR DATASTREAM (ffetch (Card PropListLoc) of NOTECARD))
	    (SETQ LENGTH (NC.ReadPtr DATASTREAM 3))
	    (NC.WritePtr BUCKETSTREAM LENGTH 3)
	    (COPYBYTES DATASTREAM BUCKETSTREAM (DIFFERENCE LENGTH 3))
	    (RETURN BUCKETSTREAM])

(NCSERVER.GETSUBSTANCEBITS
  [LAMBDA (NOTEFILE NOTECARD BUCKETSTREAM)                   (* Feuerman " 5-May-86 17:32")

          (* * Dumps the substance of NOTECARDUID into the BUCKETSTREAM and returns the stream.)



          (* * The function sets the pointer of the NoteFile data stream to the beginning of the MainLoc area of the Card.
	  The first three bytes there are the Length field of the CardPart Header, which indicates exactly how many bytes 
	  this card part takes up in the stream. That's how many bytes we're going to copy into the BUCKETSTREAM.)


    (PROG ((DATASTREAM (ffetch (NoteFile Stream) of NOTEFILE))
	     LENGTH)
	    (SETFILEPTR DATASTREAM (ffetch (Card MainLoc) of NOTECARD))
	    (SETQ LENGTH (NC.ReadPtr DATASTREAM 3))
	    (NC.WritePtr BUCKETSTREAM LENGTH 3)
	    (COPYBYTES DATASTREAM BUCKETSTREAM (DIFFERENCE LENGTH 3))
	    (RETURN BUCKETSTREAM])

(NCSERVER.GETTITLEBITS
  [LAMBDA (NOTEFILE NOTECARD BUCKETSTREAM)                   (* Feuerman " 5-May-86 17:34")

          (* * Dumps the substance of NOTECARDUID into the BUCKETSTREAM and returns the stream.)



          (* * The function sets the pointer of the NoteFile data stream to the beginning of the TitleLoc area of the Card.
	  The first three bytes there are the Length field of the CardPart Header, which indicates exactly how many bytes 
	  this card part takes up in the stream. That's how many bytes we're going to copy into the BUCKETSTREAM.)


    (PROG ((DATASTREAM (ffetch (NoteFile Stream) of NOTEFILE))
	     LENGTH)
	    (SETFILEPTR DATASTREAM (ffetch (Card TitleLoc) of NOTECARD))
	    (SETQ LENGTH (NC.ReadPtr DATASTREAM 3))
	    (NC.WritePtr BUCKETSTREAM LENGTH 3)
	    (COPYBYTES DATASTREAM BUCKETSTREAM (DIFFERENCE LENGTH 3))
	    (RETURN BUCKETSTREAM])

(NCSERVER.GETFROMLINKSBITS
  [LAMBDA (NOTEFILE NOTECARD BUCKETSTREAM)                   (* Feuerman " 5-May-86 17:39")

          (* * Dumps the FromLinks of NOTECARDUID into the BUCKETSTREAM and returns the stream.)



          (* * The only difference between this function and the GetBits functions for Substance, PropList, and Title is that
	  we need to only pass onto the Client the FromLinks info, which is in the same area of the NoteFile as the ToLinks 
	  and GlobalToLinks. In this case, the FromLinks are the second list of links in the data area, so only copy over 
	  that much.)


    (PROG ((DATASTREAM (ffetch (NoteFile Stream) of NOTEFILE)))
	    (SETFILEPTR DATASTREAM (ffetch (Card LinksLoc) of NOTECARD))
	    (NCSERVER.COPYCARDPARTHEADER DATASTREAM BUCKETSTREAM)
                                                             (* First read past the ToLinks.)
	    (NC.ReadListOfLinks DATASTREAM)                (* Now you've got the FromLinks right in front of 
							     you.)
	    (NC.WriteListOfLinks BUCKETSTREAM (NC.ReadListOfLinks DATASTREAM))
	    (RETURN BUCKETSTREAM])

(NCSERVER.GETGLOBALTOLINKSBITS
  [LAMBDA (NOTEFILE NOTECARD BUCKETSTREAM)                   (* Feuerman " 5-May-86 17:41")

          (* * Dumps the GlobalToLinks of NOTECARDUID into the BUCKETSTREAM and returns the stream.)



          (* * The only difference between this function and the GetBits functions for Substance, PropList, and Title is that
	  we need to only pass onto the Client the GlobalToLinks info, which is in the same area of the NoteFile as the 
	  ToLinks and FromLinks. In this case, the GlobalToLinks are the third list of links in the data area, so only copy 
	  over that much.)


    (PROG ((DATASTREAM (ffetch (NoteFile Stream) of NOTEFILE))
	     Card)
	    (SETFILEPTR DATASTREAM (ffetch (Card LinksLoc) of NOTECARD))
	    (NCSERVER.COPYCARDPARTHEADER DATASTREAM BUCKETSTREAM)
                                                             (* First read past the ToLinks and FromLinks)
	    (NC.ReadListOfLinks DATASTREAM)
	    (NC.ReadListOfLinks DATASTREAM)                (* Now you've got the GlobalToLinks right in front of 
							     you.)
	    (NC.WriteListOfLinks BUCKETSTREAM (NC.ReadListOfLinks DATASTREAM))
	    (RETURN BUCKETSTREAM])

(NCSERVER.GETTOLINKSBITS
  [LAMBDA (NOTEFILE NOTECARD BUCKETSTREAM)                   (* Feuerman " 5-May-86 17:37")

          (* * Dumps the ToLinks of NOTECARDUID into the BUCKETSTREAM and returns the stream.)



          (* * The only difference between this function and the GetBits functions for Substance, PropList, and Title is that
	  we need to only pass onto the Client the ToLinks info, which is in the same area of the NoteFile as the FromLinks 
	  and GlobalToLinks. In this case, the ToLinks are the first list of links in the data area, so only copy over that 
	  much.)


    (PROG ((DATASTREAM (ffetch (NoteFile Stream) of NOTEFILE)))
	    (SETFILEPTR DATASTREAM (ffetch (Card LinksLoc) of NOTECARD))
	    (NCSERVER.COPYCARDPARTHEADER DATASTREAM BUCKETSTREAM)
	    (NC.WriteListOfLinks BUCKETSTREAM (NC.ReadListOfLinks DATASTREAM))
	    (RETURN BUCKETSTREAM])
)
(DEFINEQ

(NCSERVER.PUTCARDPARTBITS
  [LAMBDA (NOTEFILE NOTECARD CARDPART SOURCESTREAM)          (* Feuerman " 6-May-86 10:23")

          (* * This is the generic "put bits into NoteFile stream" function. SOURCESTREAM is the source of these bits.
	  This function merely forks off into the different functions based on what the CARDPART is.)


    (SELECTQ CARDPART
	       (SUBSTANCE (NCSERVER.PUTSUBSTANCEBITS NOTEFILE NOTECARD SOURCESTREAM))
	       (TOLINKS (NCSERVER.PUTTOLINKSBITS NOTEFILE NOTECARD SOURCESTREAM))
	       (FROMLINKS (NCSERVER.PUTFROMLINKSBITS NOTEFILE NOTECARD SOURCESTREAM))
	       (TITLE (NCSERVER.PUTTITLEBITS NOTEFILE NOTECARD SOURCESTREAM))
	       (PROPLIST (NCSERVER.PUTPROPLISTBITS NOTEFILE NOTECARD SOURCESTREAM))
	       (GLOBALTOLINKS (NCSERVER.PUTGLOBALTOLINKSBITS NOTEFILE NOTECARD SOURCESTREAM))
	       (SHOULDNT (CONCAT "Bad card part:  " CARDPART])

(NCSERVER.PUTGLOBALTOLINKSBITS
  [LAMBDA (NOTEFILE NOTECARD SOURCESTREAM)                   (* Feuerman " 6-May-86 11:11")

          (* * Puts the GlobalToLinks back to the NoteFile. Because they are combined with other links we have to make sure 
	  we combine stuff together, then do the put.)


    (DECLARE (GLOBALVARS NC.OrigReadTable))
    (PROG ((NOTEFILESTREAM (ffetch (NoteFile Stream) of NOTEFILE))
	     (OLDLINKSCONTENTS (OPENSTREAM (QUOTE {NODIRCORE})
					     (QUOTE BOTH)))
	     DATASTART)                                      (* First, collect the old information onto a temp 
							     stream.)
	    (NCSERVER.COLLECTOLDLINKS NOTEFILESTREAM OLDLINKSCONTENTS NOTECARD)
                                                             (* Now, toss out the card part header of the old links
							     information, because the new header will be coming 
							     from the SOURCESTREAM.)
	    (SETFILEPTR OLDLINKSCONTENTS 0)
	    (NC.ReadPtr OLDLINKSCONTENTS 3)
	    (READ OLDLINKSCONTENTS NC.OrigReadTable)
	    (BIN OLDLINKSCONTENTS)
	    (BIN OLDLINKSCONTENTS)
	    (NC.ReadDate OLDLINKSCONTENTS)
	    (NC.ReadUID OLDLINKSCONTENTS)                  (* Now, set up the write to the end of the NoteFile.)
	    (SETFILEPTR NOTEFILESTREAM (SETQ DATASTART (GETEOFPTR NOTEFILESTREAM)))
                                                             (* Copy the card part header from the SOURCESTREAM 
							     that was passed in by the client.)
	    (NCSERVER.COPYCARDPARTHEADER SOURCESTREAM NOTEFILESTREAM)
                                                             (* Now copy over the ToLinks and FromLinks from the 
							     OLDLINKSCONTENTS)
	    (NC.WriteListOfLinks NOTEFILESTREAM (NC.ReadListOfLinks OLDLINKSCONTENTS))
	    (NC.WriteListOfLinks NOTEFILESTREAM (NC.ReadListOfLinks OLDLINKSCONTENTS))
                                                             (* Now copy over the GlobalToLinks from the 
							     SOURCESTREAM)
	    (NC.WriteListOfLinks NOTEFILESTREAM (NC.ReadListOfLinks SOURCESTREAM))

          (* Finally, go back and update the Length info at the beginning of the Card Header since the client is not expected
	  to have provided a proper value.)


	    (SETFILEPTR NOTEFILESTREAM DATASTART)
	    (NC.WritePtr NOTEFILESTREAM (DIFFERENCE (GETEOFPTR NOTEFILESTREAM)
						      DATASTART)
			 3)

          (* * See comments in NCSERVER.PUTTITLEBITS.)


	    (NC.SetLinksLoc NOTECARD DATASTART)
	    (NC.DeactivateCard NOTECARD)
	    (RETURN SOURCESTREAM])

(NCSERVER.PUTFROMLINKSBITS
  [LAMBDA (NOTEFILE NOTECARD SOURCESTREAM)                   (* Feuerman " 6-May-86 11:11")

          (* * Puts the FromLinks back to the NoteFile. Because they are combined with other links we have to make sure we 
	  combine stuff together, then do the put.)


    (DECLARE (GLOBALVARS NC.OrigReadTable))
    (PROG ((NOTEFILESTREAM (ffetch (NoteFile Stream) of NOTEFILE))
	     (OLDLINKSCONTENTS (OPENSTREAM (QUOTE {NODIRCORE})
					     (QUOTE BOTH)))
	     DATASTART)                                      (* First, collect the old information onto a temp 
							     stream.)
	    (NCSERVER.COLLECTOLDLINKS NOTEFILESTREAM OLDLINKSCONTENTS NOTECARD)
                                                             (* Now, toss out the card part header of the old links
							     information, because the new header will be coming 
							     from the SOURCESTREAM.)
	    (SETFILEPTR OLDLINKSCONTENTS 0)
	    (NC.ReadPtr OLDLINKSCONTENTS 3)
	    (READ OLDLINKSCONTENTS NC.OrigReadTable)
	    (BIN OLDLINKSCONTENTS)
	    (BIN OLDLINKSCONTENTS)
	    (NC.ReadDate OLDLINKSCONTENTS)
	    (NC.ReadUID OLDLINKSCONTENTS)                  (* Now, set up the write to the end of the NoteFile.)
	    (SETFILEPTR NOTEFILESTREAM (SETQ DATASTART (GETEOFPTR NOTEFILESTREAM)))
                                                             (* Copy the card part header from the SOURCESTREAM 
							     that was passed in by the client.)
	    (NCSERVER.COPYCARDPARTHEADER SOURCESTREAM NOTEFILESTREAM)
                                                             (* Now copy over the ToLinks from the 
							     OLDLINKSCONTENTS)
	    (NC.WriteListOfLinks NOTEFILESTREAM (NC.ReadListOfLinks OLDLINKSCONTENTS))
                                                             (* Grab the new from links from the source.)
	    (NC.WriteListOfLinks NOTEFILESTREAM (NC.ReadListOfLinks SOURCESTREAM))
                                                             (* Now copy over the GlobalToLinks from the 
							     OLDLINKSCONTENTS)
	    (NC.WriteListOfLinks NOTEFILESTREAM (NC.ReadListOfLinks OLDLINKSCONTENTS))

          (* Finally, go back and update the Length info at the beginning of the Card Header since the client is not expected
	  to have provided a proper value.)


	    (SETFILEPTR NOTEFILESTREAM DATASTART)
	    (NC.WritePtr NOTEFILESTREAM (DIFFERENCE (GETEOFPTR NOTEFILESTREAM)
						      DATASTART)
			 3)

          (* * See comments in NCSERVER.PUTTITLEBITS.)


	    (NC.SetLinksLoc NOTECARD DATASTART)
	    (NC.DeactivateCard NOTECARD)
	    (RETURN SOURCESTREAM])

(NCSERVER.PUTPROPLISTBITS
  [LAMBDA (NOTEFILE NOTECARD SOURCESTREAM)                   (* Feuerman " 6-May-86 09:58")

          (* * Puts new PROPLIST info for the card according to the contents of SOURCESTREAM.)


    (PROG ((NOTEFILESTREAM (ffetch (NoteFile Stream) of NOTEFILE))
	     DATASTART)
	    (SETFILEPTR NOTEFILESTREAM (SETQ DATASTART (GETEOFPTR NOTEFILESTREAM)))
	    (COPYBYTES SOURCESTREAM NOTEFILESTREAM)
	    (NC.SetPropListLoc NOTECARD DATASTART)

          (* * See comments in NCSERVER.PUTTITLEBITS.)


	    (NC.SetPropList NOTECARD)
	    (NC.RetrievePropList NOTECARD)
	    (RETURN SOURCESTREAM])

(NCSERVER.PUTSUBSTANCEBITS
  [LAMBDA (NOTEFILE NOTECARD SOURCESTREAM)                   (* Feuerman " 6-May-86 09:56")

          (* * Puts the substance at the back of the NoteFile, and records it in the datastructure cache.)


    (PROG ((NOTEFILESTREAM (ffetch (NoteFile Stream) of NOTEFILE))
	     DATASTART)
	    (SETFILEPTR NOTEFILESTREAM (SETQ DATASTART (GETEOFPTR NOTEFILESTREAM)))
	    (COPYBYTES SOURCESTREAM NOTEFILESTREAM)
	    (NC.SetMainLoc NOTECARD DATASTART)

          (* * See comments in NSERVER.PUTTITLEBITS.)


	    (NC.DeactivateCard NOTECARD)
	    (RETURN SOURCESTREAM])

(NCSERVER.PUTTITLEBITS
  [LAMBDA (NOTEFILE NOTECARD SOURCESTREAM)                   (* Feuerman " 6-May-86 09:43")

          (* * Sets the title of the card according to the contents of SOURCESTREAM.)


    (PROG ((NOTEFILESTREAM (ffetch (NoteFile Stream) of NOTEFILE))
	     DATASTART)
	    (SETFILEPTR NOTEFILESTREAM (SETQ DATASTART (GETEOFPTR NOTEFILESTREAM)))
	    (COPYBYTES SOURCESTREAM NOTEFILESTREAM)
	    (NC.SetTitleLoc NOTECARD DATASTART)

          (* * For now, to make sure that anybody who tries to read the title from the card object has the right one, we'll 
	  update the Title field of the datastructure.)

                                                             (* First, flush out the old one)
	    (NC.SetTitle NOTECARD)                         (* Now, retrieve the new one just shoved in at the end
							     of the NoteFile stream.)
	    (NC.RetrieveTitle NOTECARD)
	    (RETURN SOURCESTREAM])

(NCSERVER.PUTTOLINKSBITS
  [LAMBDA (NOTEFILE NOTECARD SOURCESTREAM)                   (* Feuerman " 6-May-86 11:11")

          (* * Puts the Tolinks back to the NoteFile. Because Tolinks are combined with from link and globaltolinks, we have 
	  to make sure we combine stuff together, then do the put.)


    (DECLARE (GLOBALVARS NC.OrigReadTable))
    (PROG ((NOTEFILESTREAM (ffetch (NoteFile Stream) of NOTEFILE))
	     (OLDLINKSCONTENTS (OPENSTREAM (QUOTE {NODIRCORE})
					     (QUOTE BOTH)))
	     DATASTART)                                      (* First, collect the old information onto a temp 
							     stream.)
	    (NCSERVER.COLLECTOLDLINKS NOTEFILESTREAM OLDLINKSCONTENTS NOTECARD)
                                                             (* Now, toss out the card part header of the old links
							     information, because the new header will be coming 
							     from the SOURCESTREAM.)
	    (SETFILEPTR OLDLINKSCONTENTS 0)
	    (NC.ReadPtr OLDLINKSCONTENTS 3)
	    (READ OLDLINKSCONTENTS NC.OrigReadTable)
	    (BIN OLDLINKSCONTENTS)
	    (BIN OLDLINKSCONTENTS)
	    (NC.ReadDate OLDLINKSCONTENTS)
	    (NC.ReadUID OLDLINKSCONTENTS)                  (* Now, set up the write to the end of the NoteFile.)
	    (SETFILEPTR NOTEFILESTREAM (SETQ DATASTART (GETEOFPTR NOTEFILESTREAM)))
                                                             (* Copy the card part header from the SOURCESTREAM 
							     that was passed in by the client.)
	    (NCSERVER.COPYCARDPARTHEADER SOURCESTREAM NOTEFILESTREAM)
                                                             (* Now copy over the ToLinks from the SOURCESTREAM.)
	    (NC.WriteListOfLinks NOTEFILESTREAM (NC.ReadListOfLinks SOURCESTREAM))
                                                             (* Copy the FromLinks and GlobalToLinks from the old 
							     links information.)
	    (NC.WriteListOfLinks NOTEFILESTREAM (NC.ReadListOfLinks OLDLINKSCONTENTS))
	    (NC.WriteListOfLinks NOTEFILESTREAM (NC.ReadListOfLinks OLDLINKSCONTENTS))

          (* Finally, go back and update the Length info at the beginning of the Card Header since the client is not expected
	  to have provided a proper value.)


	    (SETFILEPTR NOTEFILESTREAM DATASTART)
	    (NC.WritePtr NOTEFILESTREAM (DIFFERENCE (GETEOFPTR NOTEFILESTREAM)
						      DATASTART)
			 3)

          (* * See comments in NCSERVER.PUTTITLEBITS.)


	    (NC.SetLinksLoc NOTECARD DATASTART)
	    (NC.DeactivateCard NOTECARD)
	    (RETURN SOURCESTREAM])
)



(* These functions are necessary for splitting and combining links information at the server 
end.)

(DEFINEQ

(NCSERVER.COPYCARDPARTHEADER
  [LAMBDA (SOURCESTREAM DESTINATIONSTREAM)                   (* Feuerman " 6-May-86 10:47")

          (* * ASSUMES that the pointers are already in place. Simply copies a card part header from SOURCESTREAM to 
	  DESTINATIONSTREAM. Results in advancing the stream pointers accordingly.)


    (DECLARE (GLOBALVARS NC.OrigReadTable))              (* First, copy over the three-byte length info.)
    (COPYBYTES SOURCESTREAM DESTINATIONSTREAM 3)           (* Next, copy over the Identifier.)
    (PRINT (READ SOURCESTREAM NC.OrigReadTable)
	     DESTINATIONSTREAM NC.OrigReadTable)
    (BIN SOURCESTREAM)                                     (* Next, the version number.)
    (BOUT DESTINATIONSTREAM (BIN SOURCESTREAM))          (* Now copy over the date.)
    (NC.WriteDate DESTINATIONSTREAM (NC.ReadDate SOURCESTREAM))

          (* And finally, the UID. Someday we may have enough confidence to do this with a COPYBYTES, but for now, we should 
	  stick to the "right" way to do it.)


    (NC.WriteUID DESTINATIONSTREAM (NC.ReadUID SOURCESTREAM])

(NCSERVER.COLLECTOLDLINKS
  [LAMBDA (NOTEFILESTREAM TARGETSTREAM NOTECARD)             (* Feuerman " 6-May-86 10:45")

          (* * Copies only the links info sans card part header into TARGETSTREAM.)


    (PROG (LENGTH)
	    (SETFILEPTR NOTEFILESTREAM (ffetch (Card LinksLoc) of NOTECARD))
	    (SETQ LENGTH (NC.ReadPtr NOTEFILESTREAM 3))
	    (NC.WritePtr TARGETSTREAM LENGTH 3)
	    (COPYBYTES NOTEFILESTREAM TARGETSTREAM (DIFFERENCE LENGTH 3))
	    (RETURN TARGETSTREAM])
)
(* * Functions to manipulate the checkout lists.)

(DEFINEQ

(NCSERVER.ADDCLIENT
  [LAMBDA (CLIENTNETADDRESS NOTEFILE)                        (* Feuerman " 2-May-86 08:15")

          (* * Adds CLIENTNETADDRESS to the list of clients being kept track of for this NOTEFILE. NOTEFILE is an instance of
	  the NoteFile datatype, not a file name. CLIENTNETADDRESS is an instance of NSADDRESS.)


    (OR (find ClientAddress in (NCNOTEFILEPROP.NoteFileGetProp NOTEFILE (QUOTE CLIENTS))
	     suchthat (NCSERVER.NSEQUAL CLIENTNETADDRESS ClientAddress))
	  (NCNOTEFILEPROP.NoteFileAddProp NOTEFILE (QUOTE CLIENTS)
					    CLIENTNETADDRESS])

(NCSERVER.REMOVECLIENT
  [LAMBDA (NOTEFILE CLIENT)                                  (* Feuerman " 8-May-86 09:09")

          (* * This function removes CLIENT from any interested part of NOTEFILE.)


    (NCNOTEFILEPROP.NoteFileSubtractProp NOTEFILE (QUOTE CLIENTS)
					   CLIENT
					   (FUNCTION NCSERVER.NSEQUAL))
    (MAPHASH (ffetch (NoteFile HashArray) of NOTEFILE)
	       (FUNCTION (LAMBDA (VALUE KEY)
		   (NCSERVER.REMOVECLIENTFROMCARD (ffetch (NoteFile UID) of NOTEFILE)
						    KEY CLIENT])
)
(DEFINEQ

(NCSERVER.MAKEWRITER
  [LAMBDA (NOTEFILEUID NOTECARDUID CARDPART CLIENT)          (* Feuerman " 8-May-86 10:03")

          (* * Assigns CLIENT to be the write-lock owner of CARDPART for NOTECARDUID in NOTEFILEUID. If successful, returns 
	  CLIENT. If the lock is already owned by someone else, then NO ERROR OCCURS; simply returns NIL.)


    (PROG (CARDPARTLIST)
	    (RETURN (COND
			((ffetch (CardPartUsers WRITER) of (SETQ CARDPARTLIST
								 (NCSERVER.GETCARDPARTUSERS
								   (NCSERVER.GETCARDUSERS 
										      NOTEFILEUID 
										      NOTECARDUID)
								   CARDPART)))
                                                             (* OK, there is a write-lock owner.
							     If that owner happens to be the CLIENT, return his 
							     netaddress. Otherwise, return NIL.)
			  (AND (NCSERVER.NSEQUAL CLIENT (ffetch (CardPartUsers WRITER)
							       of CARDPARTLIST))
				 CLIENT))
			(T                                   (* No one owns the write-lock.
							     Make the CLIENT the owner.)
			   (replace (CardPartUsers WRITER) of CARDPARTLIST with CLIENT)
                                                             (* Notify all about the fact that the writelock was 
							     just grabbed.)
			   (NCSERVER.NOTIFYSUBSCRIBERS (ffetch (CardPartUsers READERS)
							    of CARDPARTLIST)
							 (LIST (QUOTE WRITELOCKOBTAINED)
								 NOTEFILEUID NOTECARDUID CARDPART)
							 CLIENT)
			   CLIENT])

(NCSERVER.REMOVEWRITER
  [LAMBDA (NOTEFILEUID NOTECARDUID CARDPART CLIENT)          (* Feuerman " 8-May-86 08:26")

          (* * Removes the writer CLIENT from the write-lock owner of CARDPART. Returns NIL if the CLIENT wasn't the 
	  write-lock owner, CLIENT if he was.)


    (PROG ((CARDPARTUSERS (NCSERVER.GETCARDPARTUSERS (NCSERVER.GETCARDUSERS NOTEFILEUID 
										  NOTECARDUID)
							 CARDPART)))
	    (RETURN (COND
			((NCSERVER.NSEQUAL CLIENT (ffetch (CardPartUsers WRITER) of 
										    CARDPARTUSERS))
			  (replace (CardPartUsers WRITER) of CARDPARTUSERS with NIL)
			  (NCSERVER.NOTIFYSUBSCRIBERS (ffetch (CardPartUsers READERS)
							   of CARDPARTUSERS)
							(LIST (QUOTE WRITELOCKRELEASED)
								NOTEFILEUID NOTECARDUID CARDPART)
							CLIENT)
			  CLIENT])

(NCSERVER.GETWRITER
  [LAMBDA (NOTEFILEUID NOTECARDUID CARDPART)                 (* Feuerman " 6-May-86 07:51")

          (* * Simply returns the net address of the client who currently owns the writelock for the given card part.)


    (ffetch (CardPartUsers WRITER) of (NCSERVER.GETCARDPARTUSERS (NCSERVER.GETCARDUSERS
									 NOTEFILEUID NOTECARDUID)
								       CARDPART])

(NCSERVER.ADDSUBSCRIBER
  [LAMBDA (NOTEFILEUID NOTECARDUID CARDPART CLIENT)          (* Feuerman " 1-May-86 15:20")

          (* * Adds CLIENT to the reader's list for CARDPART of NOTECARDUID in NOTEFILEUID.)


    (PROG ((CARDPARTUSERS (NCSERVER.GETCARDPARTUSERS (NCSERVER.GETCARDUSERS NOTEFILEUID 
										  NOTECARDUID)
							 CARDPART)))
	    (RETURN (OR (find Client in (ffetch (CardPartUsers READERS) of CARDPARTUSERS)
			       suchthat (NCSERVER.NSEQUAL CLIENT Client))
			    (push (ffetch (CardPartUsers READERS) of CARDPARTUSERS)
				    CLIENT])

(NCSERVER.REMOVESUBSCRIBER
  [LAMBDA (NOTEFILEUID NOTECARDUID CARDPART CLIENT)          (* Feuerman " 5-May-86 09:00")

          (* * Finds a client on the subscribers list for CARDPART of NOTECARDUID in NOTEFILEUID that has an NSADDRESS that 
	  is NSEQUAL to CLIENT, and removes him from the list.)


    (PROG ((CARDPARTUSERS (NCSERVER.GETCARDPARTUSERS (NCSERVER.GETCARDUSERS NOTEFILEUID 
										  NOTECARDUID)
							 CARDPART))
	     CURRENTREADERS CLIENTREADERMEMBER)
	    (SETQ CURRENTREADERS (ffetch (CardPartUsers READERS) of CARDPARTUSERS))
	    (SETQ CLIENTREADERMEMBER (find Client in CURRENTREADERS suchthat (
										 NCSERVER.NSEQUAL
										       CLIENT Client))
	      )
	    (RETURN (COND
			(CLIENTREADERMEMBER (replace (CardPartUsers READERS) of CARDPARTUSERS
					       with (DREMOVE CLIENTREADERMEMBER CURRENTREADERS))
					    CLIENTREADERMEMBER])

(NCSERVER.GETSUBSCRIBERS
  [LAMBDA (NOTEFILEUID NOTECARDUID CARDPART)                 (* Feuerman " 8-May-86 10:15")

          (* * Simply returns the net addresses of the clients who currently are subscribing to the given card part.)


    (ffetch (CardPartUsers READERS) of (NCSERVER.GETCARDPARTUSERS (NCSERVER.GETCARDUSERS
									  NOTEFILEUID NOTECARDUID)
									CARDPART])
)



(* Functions that make use of the Card-level checkout lists.)

(DEFINEQ

(NCSERVER.GETCARDUSERS
  [LAMBDA (NOTEFILEUID NOTECARDUID)                          (* Feuerman " 1-May-86 15:29")

          (* * Given NOTEFILEUID and NOTECARDUID, this function returns the checkout list for all of the parts of the 
	  NoteCard. This includes all readers and writers for all parts of the NoteCard.)


    (OR (NC.FetchUserDataProp (NC.CardFromUID NOTECARDUID (NC.NoteFileFromNoteFileUID 
										      NOTEFILEUID))
				  (QUOTE CHECKOUTLIST))
	  (CADR (NC.SetUserDataProp (NC.CardFromUID NOTECARDUID (NC.NoteFileFromNoteFileUID
							    NOTEFILEUID))
					(QUOTE CHECKOUTLIST)
					(create CardUsers])
)



(* Functions that access the Card-PART-level lists.)

(DEFINEQ

(NCSERVER.GETCARDPARTUSERS
  [LAMBDA (CARDUSERS CARDPART)                               (* Feuerman "26-Mar-86 09:41")

          (* * CARDUSERS is an instance of whatever the representation is for all of the readers and writers for all of the 
	  card parts associated with a particular card. This function returns the instance of CardPartUsers datatype which 
	  contains the readers and the writer for an individual card part.)



          (* * The big long SELECTQ is done for run-time efficiency, at the expense of compile time and program space.)


    (SELECTQ CARDPART
	       (SUBSTANCE (ffetch (CardUsers SUBSTANCE) of CARDUSERS))
	       (TOLINKS (ffetch (CardUsers TOLINKS) of CARDUSERS))
	       (FROMLINKS (ffetch (CardUsers FROMLINKS) of CARDUSERS))
	       (TITLE (ffetch (CardUsers TITLE) of CARDUSERS))
	       (PROPLIST (ffetch (CardUsers PROPLIST) of CARDUSERS))
	       (GLOBALTOLINKS (ffetch (CardUsers GLOBALTOLINKS) of CARDUSERS))
	       (SHOULDNT (CONCAT "Illegal card part:  " CARDPART])
)
[DECLARE: EVAL@COMPILE 

(DATATYPE CardPartUsers (READERS WRITER))

(DATATYPE CardUsers (SUBSTANCE TOLINKS FROMLINKS TITLE PROPLIST GLOBALTOLINKS)
		      SUBSTANCE ←(create CardPartUsers)
		      TOLINKS ←(create CardPartUsers)
		      FROMLINKS ←(create CardPartUsers)
		      TITLE ←(create CardPartUsers)
		      PROPLIST ←(create CardPartUsers)
		      GLOBALTOLINKS ←(create CardPartUsers))
]
(/DECLAREDATATYPE (QUOTE CardPartUsers)
		  (QUOTE (POINTER POINTER))
		  (QUOTE ((CardPartUsers 0 POINTER)
			  (CardPartUsers 2 POINTER)))
		  (QUOTE 4))
(/DECLAREDATATYPE (QUOTE CardUsers)
		  (QUOTE (POINTER POINTER POINTER POINTER POINTER POINTER))
		  (QUOTE ((CardUsers 0 POINTER)
			  (CardUsers 2 POINTER)
			  (CardUsers 4 POINTER)
			  (CardUsers 6 POINTER)
			  (CardUsers 8 POINTER)
			  (CardUsers 10 POINTER)))
		  (QUOTE 12))
(* * Card part Monitor functions.)

(DEFINEQ

(NCSERVER.GETCARDPARTMONITOR
  [LAMBDA (CARD CARDPART)                                    (* Feuerman " 5-May-86 11:15")

          (* * Returns the MONITOR for CARDPART of the CardObject CARD. If no MONITOR exists yet, then it is created and 
	  shoved into the CardObject. This is thus a guaranteed "get.")



          (* * NOTE: A PROPRECORD is used as the data structure for the various monitor locks. The reason for this is that it
	  is considered an efficient representation for a structure whose fields could very easily be mostly NIL.
	  See Blue Bible, p. 3.6)


    (PROG [(CARDMONITORS (OR (ffetch (Card Monitor) of CARD)
				 (NCSERVER.SETCARDPARTMONITOR CARD]
	    (RETURN (OR (LISTGET CARDMONITORS CARDPART)
			    (LISTPUT CARDMONITORS CARDPART (CREATE.MONITORLOCK])

(NCSERVER.SETCARDPARTMONITOR
  [LAMBDA (CARD)                                             (* Feuerman " 5-May-86 11:12")

          (* * Sets the Monitor field of the CARD to be the PROPLIST record of monitor locks for each card part.)


    (replace (Card Monitor) of CARD with (create CardPartMonitor])
)
[DECLARE: EVAL@COMPILE 

(PROPRECORD CardPartMonitor (SUBSTANCE TOLINKS FROMLINKS TITLE PROPLIST GLOBALTOLINKS))
]
(* * Miscellaneous and utility functions.)

(DEFINEQ

(NCSERVER.SERVICENOTIMPLEMENTED
  [LAMBDA (COURIERSTREAM PROGRAM MESSAGE)                    (* Feuerman "19-Mar-86 08:11")

          (* * The generic "Service Not Implemented yet" abort message.)


    (COURIER.ABORT COURIERSTREAM PROGRAM (QUOTE ServiceNotImplemented)
		     (LIST MESSAGE])

(NCSERVER.GETCLIENTCOURIERSTREAM
  [LAMBDA (CLIENTNETADDRESS)                                 (* Feuerman " 8-May-86 09:09")

          (* * Returns the Courier stream for CLIENTNETADDRESS, creating one if necessary. Also, performs a quick check to 
	  make sure the stream is still legit, opening a new one if necessary.)


    (PROG [(CLIENT.STREAM (find Client.Stream in NCSERVER.CLIENTSTREAMS
			       suchthat (NCSERVER.NSEQUAL CLIENTNETADDRESS (CAR Client.Stream]
	    (RETURN (COND
			[CLIENT.STREAM (COND
					 ((AND (OPENP (CDR CLIENT.STREAM))
						 (SPPOUTPUTSTREAM (CDR CLIENT.STREAM)))
                                                             (* That AND clause does the "legit" check.)
					   (CDR CLIENT.STREAM))
					 (T (RPLACD CLIENT.STREAM (COURIER.OPEN CLIENTNETADDRESS))
					    (CDR CLIENT.STREAM]
			(T                                   (* No entry on the NCSERVER.CLIENTSTREAMS list yet for
							     CLIENTNETADDRESS, so add one up front.)
			   (SETQ NCSERVER.CLIENTSTREAMS (CONS (CONS CLIENTNETADDRESS
									  (COURIER.OPEN 
										 CLIENTNETADDRESS))
								  NCSERVER.CLIENTSTREAMS))
			   (CDAR NCSERVER.CLIENTSTREAMS])

(NCSERVER.DELETECARDFROMNOTEFILE
  [LAMBDA (NOTEFILE NOTECARD)                                (* Feuerman " 6-May-86 16:22")

          (* * Performs whatever steps are necessary to really delete the card from the NoteFile. For now, just mark the 
	  status.)


    (NC.SetStatus NOTECARD (QUOTE DELETED])

(NC.NOTEFILEP
  [LAMBDA (NOTEFILENAME)                                     (* Feuerman "20-Mar-86 09:23")

          (* * Soon we'll figure out how to really check this, but for now we'll just check to make sure that the filename 
	  extension is indeed .NOTEFILE)


    (EQ (U-CASE (FILENAMEFIELD NOTEFILENAME (QUOTE EXTENSION)))
	  (QUOTE NOTEFILE])

(NCSERVER.COLLECTHASHKEYS
  [LAMBDA (HARRAY)                                         (* Feuerman " 1-May-86 14:54")
    (PROG (KEYS)
	    [MAPHASH HARRAY (FUNCTION (LAMBDA (VAL KEY)
			   (SETQ KEYS (CONS KEY KEYS]
	    (RETURN KEYS])

(NCSERVER.REMOVECLIENTFROMCARD
  [LAMBDA (NOTEFILEUID NOTECARDUID CLIENT)                   (* Feuerman " 7-May-86 10:38")

          (* * Given CARDOBJECT and CLIENT, removes any subscription to any card part that CLIENT might have.
	  Also, removes CLIENT as the write-lock owner if owned.)


    (for CardPart in NCSERVER.NCCARDPARTS
       do (NCSERVER.REMOVEWRITER NOTEFILEUID NOTECARDUID CardPart CLIENT)
	    (NCSERVER.REMOVESUBSCRIBER NOTEFILEUID NOTECARDUID CardPart CLIENT])

(NCSERVER.GETNOTEFILENAME
  [LAMBDA (FILENAMEorUID)                                    (* Feuerman " 7-May-86 13:55")

          (* * Coerces FILENAMEorUID into a local file name for the NoteFile. Returns NIL if coercion fails for whatever 
	  reason. Guarantees that the returned value exists as a file.)


    (PROG (NoteFile FullFileName)
	    (RETURN (SELECTQ (CAR FILENAMEorUID)
				 (NOTEFILEUID (SETQ NoteFile (NC.NoteFileFromNoteFileUID
						  (CADR FILENAMEorUID)))
					      (AND (type? NoteFile NoteFile)
						     (SETQ FullFileName (ffetch (NoteFile 
										     FullFileName)
									     of NoteFile))
						     (INFILEP FullFileName)))
				 [FILENAME (INFILEP (PACK* (QUOTE {DSK})
							       (NCSERVER.REMOVEHOST (CADR 
										    FILENAMEorUID]
				 NIL])

(NCSERVER.CONSTRUCTFILELIST
  [LAMBDA (NOTEFILEPATTERN)                                  (* Feuerman "19-Mar-86 14:05")

          (* * Returns a list of strings to be sent to the client. Each string is the filename of the NoteFile that matches 
	  the NOTEFILEPATTERN, sans host name which will be provided by the client at the other end.)


    (PROG ((UNPACKEDPATTERN (UNPACKFILENAME NOTEFILEPATTERN)))
	    (for FieldName in (QUOTE (HOST NAME EXTENSION)) as FieldValue
	       in (QUOTE (DSK * NOTEFILE)) do (OR (LISTGET UNPACKEDPATTERN FieldName)
							  (LISTPUT UNPACKEDPATTERN FieldName 
								     FieldValue)))
	    (RETURN (for F in (DIRECTORY (PACKFILENAME UNPACKEDPATTERN))
			 collect (MKSTRING (NCSERVER.REMOVEHOSTNAME F])

(NCSERVER.GETTOPLEVELUIDS
  [LAMBDA (NOTEFILE)                                         (* Feuerman " 7-May-86 08:32")

          (* * Returns the UIDs for the NoteFile and the five top-level file boxes. They are returned as an instance of the 
	  Courier Record NoteCardsServer NFTOPBOXES.)


    (COND
      ((NOT (OPENP (ffetch (NoteFile FullFileName) of NOTEFILE)))
	(ERROR "Need to open NoteFile first before retrieving top-level UIDs." NOTEFILE))
      (T (create NFTOPBOXES
		   NOTEFILE ←(ffetch (NoteFile UID) of NOTEFILE)
		   TABLEOFCONTENTS ←(ffetch (CardObject UID) of (ffetch (NoteFile 
									      TableOfContentsCard)
								       of NOTEFILE))
		   ORPHANS ←(ffetch (CardObject UID) of (ffetch (NoteFile OrphansCard)
							       of NOTEFILE))
		   TOBEFILED ←(ffetch (CardObject UID) of (ffetch (NoteFile ToBeFiledCard)
								 of NOTEFILE))
		   LINKLABELS ←(ffetch (CardObject UID) of (ffetch (NoteFile LinkLabelsCard)
								  of NOTEFILE))
		   REGISTRY ←(ffetch (CardObject UID) of (ffetch (NoteFile RegistryCard)
								of NOTEFILE])

(NCSERVER.NSEQUAL
  [LAMBDA (NSADR1 NSADR2)                                    (* Feuerman " 7-May-86 08:37")

          (* * Returns non-NIL if NSADR1 and NSADR2 are the same NS net address.)



          (* * Added possibility that NSADR1 and/or NSADR2 could be (QUOTE SELF))


    (OR (AND (EQ NSADR1 (QUOTE SELF))
		 (EQ NSADR2 (QUOTE SELF)))
	  (AND NSADR1 NSADR2 (type? NSADDRESS NSADR1)
		 (type? NSADDRESS NSADR2)
		 (EQ (ffetch (NSADDRESS NSNET) of NSADR1)
		       (ffetch (NSADDRESS NSNET) of NSADR2))
		 (EQ (ffetch (NSADDRESS NSHNM0) of NSADR1)
		       (ffetch (NSADDRESS NSHNM0) of NSADR2))
		 (EQ (ffetch (NSADDRESS NSHNM1) of NSADR1)
		       (ffetch (NSADDRESS NSHNM1) of NSADR2))
		 (EQ (ffetch (NSADDRESS NSHNM2) of NSADR1)
		       (ffetch (NSADDRESS NSHNM2) of NSADR2))
		 (EQ (ffetch (NSADDRESS NSSOCKET) of NSADR1)
		       (ffetch (NSADDRESS NSSOCKET) of NSADR2])

(NCSERVER.REALLYOPENNOTEFILE
  [LAMBDA (NOTEFILENAME)                                     (* Feuerman "20-Mar-86 13:32")

          (* * If the NoteFile isn't really opened yet, this function is called to open the file and perform everything that 
	  the normal NC.OpenDatabaseFile does, except bring up the NoteFile control window.)


    (NC.OpenDatabaseFile NOTEFILENAME NIL NIL (QUOTE QUIET)
			   (QUOTE DONTCREATE)
			   (QUOTE CONVERT)
			   NIL NIL (QUOTE NOINTERFACE])

(NCSERVER.REMOVEHOST
  [LAMBDA (FILENAME)                                         (* Feuerman "20-Mar-86 08:43")

          (* * Simple strips the host name out of FILENAME. Useful for exchanging file names between client and server, 
	  because the server will want to refer to the host as {DSK}, but the client will want to call it {GNUDNIK:VISTA} or 
	  whatever the host is called.)


    (PROG ((UNPACKEDFILENAME (UNPACKFILENAME FILENAME)))
	    (LISTPUT UNPACKEDFILENAME (QUOTE HOST)
		       NIL)
	    (RETURN (PACKFILENAME UNPACKEDFILENAME])

(NCSERVER.REMOVEHOSTNAME
  [LAMBDA (FILENAME)                                         (* Feuerman "19-Mar-86 14:05")

          (* * Checks to see if DSK is the hostname of FILENAME, and if so, removes it. Otherwise it is left alone.)


    (COND
      ((EQ (FILENAMEFIELD FILENAME (QUOTE HOST))
	     (QUOTE DSK))
	(SUBATOM FILENAME 6))
      (T FILENAME])
)
(FILESLOAD NCNOTEFILEPROP NCCOURIER (FROM VALUEOF LISPUSERSDIRECTORIES SYSLOAD)
	   COURIERSERVE)
(DECLARE: DOEVAL@COMPILE DONTCOPY

(GLOBALVARS NCSERVER.ALLOW.ONLY.NOTEFILES.DELETE NCSERVER.NCCARDPARTS NCSERVER.NOTIFYINSTIGATORP 
	    NCSERVER.CLIENTSTREAMS)
)

(RPAQQ NCSERVER.NCCARDPARTS (SUBSTANCE TOLINKS FROMLINKS TITLE PROPLIST GLOBALTOLINKS))

(RPAQ? NCSERVER.ALLOW.ONLY.NOTEFILES.DELETE T)

(RPAQ? NCSERVER.NOTIFYINSTIGATORP NIL)

(RPAQ? NCSERVER.CLIENTSTREAMS NIL)
(DECLARE: DONTCOPY 
[DECLARE: EVAL@COMPILE 

(DATATYPE NSADDRESS ((NSNET FIXP)
		       (NSHNM0 WORD)
		       (NSHNM1 WORD)
		       (NSHNM2 WORD)
		       (NSSOCKET WORD))
		      (ACCESSFNS (NSHOSTNUMBER (LOADNSHOSTNUMBER (LOCF (fetch NSHNM0
									    of DATUM)))
						 (STORENSHOSTNUMBER (LOCF (fetch NSHNM0
									     of DATUM))
								    NEWVALUE)))
		      (BLOCKRECORD NSADDRESS ((NSNETHI WORD)
				      (NSNETLO WORD))))
]
(/DECLAREDATATYPE (QUOTE NSADDRESS)
		  (QUOTE (FIXP WORD WORD WORD WORD))
		  [QUOTE ((NSADDRESS 0 FIXP)
			  (NSADDRESS 2 (BITS . 15))
			  (NSADDRESS 3 (BITS . 15))
			  (NSADDRESS 4 (BITS . 15))
			  (NSADDRESS 5 (BITS . 15]
		  (QUOTE 6))
)
(COURIER.START.SERVER)
(DECLARE: DONTCOPY
  (FILEMAP (NIL (4063 4245 (NCSERVER.FILELOADEDP 4073 . 4243)) (4519 12896 (
NCSERVER.COURIERLISTNOTEFILES 4529 . 4868) (NCSERVER.COURIERCREATENOTEFILE 4870 . 5531) (
NCSERVER.COURIERDELETENOTEFILE 5533 . 6074) (NCSERVER.COURIERSUBSCRIBETONOTEFILE 6076 . 6734) (
NCSERVER.COURIERCANCELNOTEFILESUBSCRIPTION 6736 . 7581) (NCSERVER.COURIERLISTUIDS 7583 . 7877) (
NCSERVER.COURIERLISTCLIENTS 7879 . 8379) (NCSERVER.COURIERCREATECARD 8381 . 8793) (
NCSERVER.COURIERDELETECARD 8795 . 9513) (NCSERVER.COURIERGETCARDPART 9515 . 10153) (
NCSERVER.COURIEROBTAINWRITELOCK 10155 . 10702) (NCSERVER.COURIERPUTCARDPART 10704 . 11536) (
NCSERVER.COURIERRELEASEWRITELOCK 11538 . 12198) (NCSERVER.COURIERCANCELCARDPARTSUBSCRIPTION 12200 . 
12894)) (12979 23765 (NCSERVER.LISTNOTEFILES 12989 . 13230) (NCSERVER.CREATENOTEFILE 13232 . 13818) (
NCSERVER.DELETENOTEFILE 13820 . 14690) (NCSERVER.SUBSCRIBETONOTEFILE 14692 . 15420) (
NCSERVER.CANCELNOTEFILESUBSCRIPTION 15422 . 16431) (NCSERVER.LISTUIDS 16433 . 16769) (
NCSERVER.LISTCLIENTS 16771 . 17106) (NCSERVER.CREATECARD 17108 . 18292) (NCSERVER.DELETECARD 18294 . 
19504) (NCSERVER.GETCARDPART 19506 . 20969) (NCSERVER.OBTAINWRITELOCK 20971 . 21452) (
NCSERVER.PUTCARDPART 21454 . 23179) (NCSERVER.RELEASEWRITELOCK 23181 . 23453) (
NCSERVER.CANCELCARDPARTSUBSCRIPTION 23455 . 23763)) (24023 29394 (NCSERVER.NOTIFYSUBSCRIBERS 24033 . 
26270) (NCSERVER.NOTIFY.CARDCREATED 26272 . 26828) (NCSERVER.NOTIFY.CARDDELETED 26830 . 27386) (
NCSERVER.NOTIFY.CARDPARTCHANGED 27388 . 28242) (NCSERVER.NOTIFY.WRITELOCKOBTAINED 28244 . 28852) (
NCSERVER.NOTIFY.WRITELOCKRELEASED 28854 . 29392)) (29517 36736 (NCSERVER.GETCARDPARTBITS 29527 . 30469
) (NCSERVER.GETPROPLISTBITS 30471 . 31430) (NCSERVER.GETSUBSTANCEBITS 31432 . 32383) (
NCSERVER.GETTITLEBITS 32385 . 33334) (NCSERVER.GETFROMLINKSBITS 33336 . 34520) (
NCSERVER.GETGLOBALTOLINKSBITS 34522 . 35786) (NCSERVER.GETTOLINKSBITS 35788 . 36734)) (36737 48231 (
NCSERVER.PUTCARDPARTBITS 36747 . 37687) (NCSERVER.PUTGLOBALTOLINKSBITS 37689 . 40396) (
NCSERVER.PUTFROMLINKSBITS 40398 . 43197) (NCSERVER.PUTPROPLISTBITS 43199 . 43877) (
NCSERVER.PUTSUBSTANCEBITS 43879 . 44528) (NCSERVER.PUTTITLEBITS 44530 . 45531) (
NCSERVER.PUTTOLINKSBITS 45533 . 48229)) (48340 50045 (NCSERVER.COPYCARDPARTHEADER 48350 . 49515) (
NCSERVER.COLLECTOLDLINKS 49517 . 50043)) (50102 51299 (NCSERVER.ADDCLIENT 50112 . 50737) (
NCSERVER.REMOVECLIENT 50739 . 51297)) (51300 56173 (NCSERVER.MAKEWRITER 51310 . 52875) (
NCSERVER.REMOVEWRITER 52877 . 53746) (NCSERVER.GETWRITER 53748 . 54158) (NCSERVER.ADDSUBSCRIBER 54160
 . 54789) (NCSERVER.REMOVESUBSCRIBER 54791 . 55759) (NCSERVER.GETSUBSCRIBERS 55761 . 56171)) (56244 
56941 (NCSERVER.GETCARDUSERS 56254 . 56939)) (57003 58122 (NCSERVER.GETCARDPARTUSERS 57013 . 58120)) (
59037 60234 (NCSERVER.GETCARDPARTMONITOR 59047 . 59898) (NCSERVER.SETCARDPARTMONITOR 59900 . 60232)) (
60403 68993 (NCSERVER.SERVICENOTIMPLEMENTED 60413 . 60730) (NCSERVER.GETCLIENTCOURIERSTREAM 60732 . 
62017) (NCSERVER.DELETECARDFROMNOTEFILE 62019 . 62348) (NC.NOTEFILEP 62350 . 62737) (
NCSERVER.COLLECTHASHKEYS 62739 . 63009) (NCSERVER.REMOVECLIENTFROMCARD 63011 . 63531) (
NCSERVER.GETNOTEFILENAME 63533 . 64407) (NCSERVER.CONSTRUCTFILELIST 64409 . 65245) (
NCSERVER.GETTOPLEVELUIDS 65247 . 66444) (NCSERVER.NSEQUAL 66446 . 67486) (NCSERVER.REALLYOPENNOTEFILE 
67488 . 68001) (NCSERVER.REMOVEHOST 68003 . 68596) (NCSERVER.REMOVEHOSTNAME 68598 . 68991)))))
STOP