From 08cbf3b50bfe713044f36b363c73768cd042f13c Mon Sep 17 00:00:00 2001
From: marha <marha@users.sourceforge.net>
Date: Mon, 16 May 2011 08:06:12 +0000
Subject: xserver xkeyboar-config mesa git update 16 May 2011

---
 xorg-server/record/record.c | 5872 +++++++++++++++++++++----------------------
 1 file changed, 2936 insertions(+), 2936 deletions(-)

(limited to 'xorg-server/record')

diff --git a/xorg-server/record/record.c b/xorg-server/record/record.c
index cafe02168..69fca727e 100644
--- a/xorg-server/record/record.c
+++ b/xorg-server/record/record.c
@@ -1,2936 +1,2936 @@
-
-/*
-
-Copyright 1995, 1998  The Open Group
-
-Permission to use, copy, modify, distribute, and sell this software and its
-documentation for any purpose is hereby granted without fee, provided that
-the above copyright notice appear in all copies and that both that
-copyright notice and this permission notice appear in supporting
-documentation.
-
-The above copyright notice and this permission notice shall be
-included in all copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
-EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
-MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
-IN NO EVENT SHALL THE OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR
-OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
-ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
-OTHER DEALINGS IN THE SOFTWARE.
-
-Except as contained in this notice, the name of The Open Group shall
-not be used in advertising or otherwise to promote the sale, use or
-other dealings in this Software without prior written authorization
-from The Open Group.
-
-Author: David P. Wiggins, The Open Group
-
-This work benefited from earlier work done by Martha Zimet of NCD
-and Jim Haggerty of Metheus.
-
-*/
-
-#ifdef HAVE_DIX_CONFIG_H
-#include <dix-config.h>
-#endif
-
-#include "dixstruct.h"
-#include "extnsionst.h"
-#include <X11/extensions/recordproto.h>
-#include "set.h"
-#include "swaprep.h"
-#include "inputstr.h"
-#include "eventconvert.h"
-#include "scrnintstr.h"
-
-
-#include <stdio.h>
-#include <assert.h>
-
-#ifdef PANORAMIX
-#include "globals.h"
-#include "panoramiX.h"
-#include "panoramiXsrv.h"
-#include "cursor.h"
-#endif
-
-#include "protocol-versions.h"
-
-static RESTYPE RTContext;   /* internal resource type for Record contexts */
-
-/* How many bytes of protocol data to buffer in a context. Don't set to less
- * than 32.
- */
-#define REPLY_BUF_SIZE 1024
-
-/* Record Context structure */
-
-typedef struct {
-    XID		id;		   /* resource id of context */
-    ClientPtr	pRecordingClient;  /* client that has context enabled */
-    struct _RecordClientsAndProtocolRec *pListOfRCAP; /* all registered info */
-    ClientPtr	pBufClient;	   /* client whose protocol is in replyBuffer*/
-    unsigned int continuedReply:1; /* recording a reply that is split up? */
-    char	elemHeaders;	   /* element header flags (time/seq no.) */
-    char	bufCategory;	   /* category of protocol in replyBuffer */
-    int		numBufBytes;	   /* number of bytes in replyBuffer */
-    char	replyBuffer[REPLY_BUF_SIZE]; /* buffered recorded protocol */
-    int		inFlush;           /*  are we inside RecordFlushReplyBuffer */
-} RecordContextRec, *RecordContextPtr;
-
-/*  RecordMinorOpRec - to hold minor opcode selections for extension requests
- *  and replies
- */
-
-typedef union {
-    int count; /* first element of array: how many "major" structs to follow */
-    struct {   /* rest of array elements are this */
-	short first;		/* first major opcode */
-	short last;		/* last major opcode */
-	RecordSetPtr pMinOpSet; /*  minor opcode set for above major range */
-    } major;
-} RecordMinorOpRec, *RecordMinorOpPtr;
-
-
-/*  RecordClientsAndProtocolRec, nicknamed RCAP - holds all the client and 
- *  protocol selections passed in a single CreateContext or RegisterClients.
- *  Generally, a context will have one of these from the create and an
- *  additional one for each RegisterClients.  RCAPs are freed when all their
- *  clients are unregistered.
- */
-
-typedef struct _RecordClientsAndProtocolRec {
-    RecordContextPtr pContext;		 /* context that owns this RCAP */
-    struct _RecordClientsAndProtocolRec *pNextRCAP; /* next RCAP on context */
-    RecordSetPtr     pRequestMajorOpSet; /* requests to record */
-    RecordMinorOpPtr pRequestMinOpInfo;  /* extension requests to record */
-    RecordSetPtr     pReplyMajorOpSet;   /* replies to record */
-    RecordMinorOpPtr pReplyMinOpInfo;    /* extension replies to record */
-    RecordSetPtr     pDeviceEventSet;    /* device events to record */
-    RecordSetPtr     pDeliveredEventSet; /* delivered events to record */
-    RecordSetPtr     pErrorSet;          /* errors to record */
-    XID *	     pClientIDs;	 /* array of clients to record */
-    short 	     numClients;	 /* number of clients in pClientIDs */
-    short	     sizeClients;	 /* size of pClientIDs array */
-    unsigned int     clientStarted:1;	 /* record new client connections? */
-    unsigned int     clientDied:1;	 /* record client disconnections? */
-    unsigned int     clientIDsSeparatelyAllocated:1; /* pClientIDs malloced? */
-} RecordClientsAndProtocolRec, *RecordClientsAndProtocolPtr;
-
-/* how much bigger to make pRCAP->pClientIDs when reallocing */
-#define CLIENT_ARRAY_GROWTH_INCREMENT 4
-
-/* counts the total number of RCAPs belonging to enabled contexts. */
-static int numEnabledRCAPs;
-
-/*  void VERIFY_CONTEXT(RecordContextPtr, XID, ClientPtr)
- *  In the spirit of the VERIFY_* macros in dix.h, this macro fills in
- *  the context pointer if the given ID is a valid Record Context, else it
- *  returns an error.
- */
-#define VERIFY_CONTEXT(_pContext, _contextid, _client) { \
-    int rc = dixLookupResourceByType((pointer *)&(_pContext), _contextid, \
-                                     RTContext, _client, DixUseAccess); \
-    if (rc != Success) \
-	return rc; \
-}
-
-static int RecordDeleteContext(
-    pointer /*value*/,
-    XID /*id*/
-);
-
-void RecordExtensionInit(void);
-
-/***************************************************************************/
-
-/* client private stuff */
-
-/*  To make declarations less obfuscated, have a typedef for a pointer to a
- *  Proc function.
- */
-typedef int (*ProcFunctionPtr)(
-    ClientPtr /*pClient*/
-);
-
-/* Record client private.  Generally a client only has one of these if
- * any of its requests are being recorded.
- */
-typedef struct {
-/* ptr to client's proc vector before Record stuck its nose in */
-    ProcFunctionPtr *originalVector;   
-					
-/* proc vector with pointers for recorded requests redirected to the
- * function RecordARequest
- */
-    ProcFunctionPtr recordVector[256]; 
-} RecordClientPrivateRec, *RecordClientPrivatePtr;
-
-static DevPrivateKeyRec RecordClientPrivateKeyRec;
-#define RecordClientPrivateKey (&RecordClientPrivateKeyRec)
-
-/*  RecordClientPrivatePtr RecordClientPrivate(ClientPtr)
- *  gets the client private of the given client.  Syntactic sugar.
- */
-#define RecordClientPrivate(_pClient) (RecordClientPrivatePtr) \
-    dixLookupPrivate(&(_pClient)->devPrivates, RecordClientPrivateKey)
-
-
-/***************************************************************************/
-
-/* global list of all contexts */
-
-static RecordContextPtr *ppAllContexts;
-
-static int numContexts;/* number of contexts in ppAllContexts */
-
-/* number of currently enabled contexts.  All enabled contexts are bunched
- * up at the front of the ppAllContexts array, from ppAllContexts[0] to
- * ppAllContexts[numEnabledContexts-1], to eliminate time spent skipping
- * past disabled contexts.
- */
-static int numEnabledContexts;
-
-/* RecordFindContextOnAllContexts
- *
- * Arguments:
- *	pContext is the context to search for.
- *
- * Returns:
- *	The index into the array ppAllContexts at which pContext is stored.
- *	If pContext is not found in ppAllContexts, returns -1.
- *
- * Side Effects: none.
- */
-static int
-RecordFindContextOnAllContexts(RecordContextPtr pContext)
-{
-    int i;
-
-    assert(numContexts >= numEnabledContexts);
-    for (i = 0; i < numContexts; i++)
-    {
-	if (ppAllContexts[i] == pContext)
-	    return i;
-    }
-    return -1;
-} /* RecordFindContextOnAllContexts */
-
-
-/***************************************************************************/
-
-/* RecordFlushReplyBuffer
- *
- * Arguments:
- *	pContext is the context to flush.
- *	data1 is a pointer to additional data, and len1 is its length in bytes.
- *	data2 is a pointer to additional data, and len2 is its length in bytes.
- *
- * Returns: nothing.
- *
- * Side Effects:
- *	If the context is enabled, any buffered (recorded) protocol is written
- *	to the recording client, and the number of buffered bytes is set to
- *	zero.  If len1 is not zero, data1/len1 are then written to the
- *	recording client, and similarly for data2/len2 (written after
- *	data1/len1).
- */
-static void
-RecordFlushReplyBuffer(
-    RecordContextPtr pContext,
-    pointer data1,
-    int len1,
-    pointer data2,
-    int len2
-)
-{
-    if (!pContext->pRecordingClient || pContext->pRecordingClient->clientGone || pContext->inFlush)
-	return;
-    ++pContext->inFlush;
-    if (pContext->numBufBytes)
-	WriteToClient(pContext->pRecordingClient, pContext->numBufBytes,
-		      (char *)pContext->replyBuffer);
-    pContext->numBufBytes = 0;
-    if (len1)
-	WriteToClient(pContext->pRecordingClient, len1, (char *)data1);
-    if (len2)
-	WriteToClient(pContext->pRecordingClient, len2, (char *)data2);
-    --pContext->inFlush;
-} /* RecordFlushReplyBuffer */
-
-
-/* RecordAProtocolElement
- *
- * Arguments:
- *	pContext is the context that is recording a protocol element.
- *	pClient is the client whose protocol is being recorded.  For
- *	  device events and EndOfData, pClient is NULL.
- *	category is the category of the protocol element, as defined
- *	  by the RECORD spec.
- *	data is a pointer to the protocol data, and datalen is its length
- *	  in bytes.
- *	futurelen is the number of bytes that will be sent in subsequent
- *	  calls to this function to complete this protocol element.  
- *	  In those subsequent calls, futurelen will be -1 to indicate
- *	  that the current data is a continuation of the same protocol
- *	  element.
- *
- * Returns: nothing.
- *
- * Side Effects:
- *	The context may be flushed.  The new protocol element will be
- *	added to the context's protocol buffer with appropriate element
- *	headers prepended (sequence number and timestamp).  If the data
- *	is continuation data (futurelen == -1), element headers won't
- *	be added.  If the protocol element and headers won't fit in
- *	the context's buffer, it is sent directly to the recording
- *	client (after any buffered data).
- */
-static void
-RecordAProtocolElement(RecordContextPtr pContext, ClientPtr pClient,
-		       int category, pointer data, int datalen, int futurelen)
-{
-    CARD32 elemHeaderData[2];
-    int numElemHeaders = 0;
-    Bool recordingClientSwapped = pContext->pRecordingClient->swapped;
-    int n;
-    CARD32 serverTime = 0;
-    Bool gotServerTime = FALSE;
-    int replylen;
-
-    if (futurelen >= 0)
-    { /* start of new protocol element */
-	xRecordEnableContextReply *pRep = (xRecordEnableContextReply *)
-							pContext->replyBuffer;
-	if (pContext->pBufClient != pClient ||
-	    pContext->bufCategory != category)
-	{
-	    RecordFlushReplyBuffer(pContext, NULL, 0, NULL, 0);
-	    pContext->pBufClient = pClient;
-	    pContext->bufCategory = category;
-	}
-
-	if (!pContext->numBufBytes)
-	{
-	    serverTime = GetTimeInMillis();
-	    gotServerTime = TRUE;
-	    pRep->type          = X_Reply;
-	    pRep->category      = category;
-	    pRep->sequenceNumber = pContext->pRecordingClient->sequence;
-	    pRep->length        = 0;
-	    pRep->elementHeader = pContext->elemHeaders;
-	    pRep->serverTime    = serverTime;
-	    if (pClient)
-	    {
-		pRep->clientSwapped =
-				(pClient->swapped != recordingClientSwapped);
-		pRep->idBase = pClient->clientAsMask;
-		pRep->recordedSequenceNumber = pClient->sequence;
-	    }
-	    else /* it's a device event, StartOfData, or EndOfData */
-	    {
-		pRep->clientSwapped = (category != XRecordFromServer) && 
-						recordingClientSwapped;
-		pRep->idBase = 0;
-		pRep->recordedSequenceNumber = 0;
-	    }
-
-	    if (recordingClientSwapped)
-	    {
-		swaps(&pRep->sequenceNumber, n);
-		swapl(&pRep->length, n);
-		swapl(&pRep->idBase, n);
-		swapl(&pRep->serverTime, n);
-		swapl(&pRep->recordedSequenceNumber, n);
-	    }
-	    pContext->numBufBytes = SIZEOF(xRecordEnableContextReply);
-	}
-
-	/* generate element headers if needed */
-
-	if ( ( (pContext->elemHeaders & XRecordFromClientTime)
-	      && category == XRecordFromClient)
-	    ||
-	    ( (pContext->elemHeaders & XRecordFromServerTime)
-	     && category == XRecordFromServer))
-	{
-	    if (gotServerTime)
-		elemHeaderData[numElemHeaders] = serverTime;
-	    else
-		elemHeaderData[numElemHeaders] = GetTimeInMillis();
-	    if (recordingClientSwapped)
-		swapl(&elemHeaderData[numElemHeaders], n);
-	    numElemHeaders++;
-	}
-
-	if ( (pContext->elemHeaders & XRecordFromClientSequence)
-	    &&
-	    (category == XRecordFromClient || category == XRecordClientDied))
-	{
-	    elemHeaderData[numElemHeaders] = pClient->sequence;
-	    if (recordingClientSwapped)
-		swapl(&elemHeaderData[numElemHeaders], n);
-	    numElemHeaders++;
-	}
-
-	/* adjust reply length */
-
-	replylen = pRep->length;
-	if (recordingClientSwapped) swapl(&replylen, n);
-	replylen += numElemHeaders + bytes_to_int32(datalen) +
-            bytes_to_int32(futurelen);
-	if (recordingClientSwapped) swapl(&replylen, n);
-	pRep->length = replylen;
-    } /* end if not continued reply */
-
-    numElemHeaders *= 4;
-
-    /* if space available >= space needed, buffer the data */
-
-    if (REPLY_BUF_SIZE - pContext->numBufBytes >= datalen + numElemHeaders)
-    {
-	if (numElemHeaders)
-	{
-	    memcpy(pContext->replyBuffer + pContext->numBufBytes,
-		   elemHeaderData, numElemHeaders);
-	    pContext->numBufBytes += numElemHeaders;
-	}
-	if (datalen)
-	{
-	    memcpy(pContext->replyBuffer + pContext->numBufBytes,
-		   data, datalen);
-	    pContext->numBufBytes += datalen;
-	}
-    }
-    else
-	RecordFlushReplyBuffer(pContext, (pointer)elemHeaderData,
-			       numElemHeaders, (pointer)data, datalen);
-
-} /* RecordAProtocolElement */
-
-
-/* RecordFindClientOnContext
- *
- * Arguments:
- *	pContext is the context to search.
- *	clientspec is the resource ID mask identifying the client to search
- *	  for, or XRecordFutureClients.
- *	pposition is a pointer to an int, or NULL.  See Returns.
- *
- * Returns:
- *	The RCAP on which clientspec was found, or NULL if not found on
- *	any RCAP on the given context.
- *	If pposition was not NULL and the returned RCAP is not NULL,
- *	*pposition will be set to the index into the returned the RCAP's
- *	pClientIDs array that holds clientspec.
- *
- * Side Effects: none.
- */
-static RecordClientsAndProtocolPtr
-RecordFindClientOnContext(
-    RecordContextPtr pContext,
-    XID clientspec,
-    int *pposition
-)
-{
-    RecordClientsAndProtocolPtr pRCAP;
-
-    for (pRCAP = pContext->pListOfRCAP; pRCAP; pRCAP = pRCAP->pNextRCAP)
-    {
-	int i;
-	for (i = 0; i < pRCAP->numClients; i++)
-	{
-	    if (pRCAP->pClientIDs[i] == clientspec)
-	    {
-		if (pposition)
-		    *pposition = i;
-		return pRCAP;
-	    }
-	}
-    }
-    return NULL;
-} /* RecordFindClientOnContext */
-
-
-/* RecordABigRequest
- *
- * Arguments:
- *	pContext is the recording context.
- *	client is the client being recorded.
- *	stuff is a pointer to the big request of client (see the Big Requests
- *	extension for details.)
- *
- * Returns: nothing.
- *
- * Side Effects:
- *	The big request is recorded with the correct length field re-inserted.
- *	
- * Note: this function exists mainly to make RecordARequest smaller.
- */
-static void
-RecordABigRequest(RecordContextPtr pContext, ClientPtr client, xReq *stuff)
-{
-    CARD32 bigLength;
-    char n;
-    int bytesLeft;
-
-    /* note: client->req_len has been frobbed by ReadRequestFromClient
-     * (os/io.c) to discount the extra 4 bytes taken by the extended length
-     * field in a big request.  The actual request length to record is
-     * client->req_len + 1 (measured in CARD32s).
-     */
-
-    /* record the request header */
-    bytesLeft = client->req_len << 2;
-    RecordAProtocolElement(pContext, client, XRecordFromClient,
-			   (pointer)stuff, SIZEOF(xReq), bytesLeft);
-
-    /* reinsert the extended length field that was squished out */
-    bigLength = client->req_len + bytes_to_int32(sizeof(bigLength));
-    if (client->swapped)
-	swapl(&bigLength, n);
-    RecordAProtocolElement(pContext, client, XRecordFromClient,
-		(pointer)&bigLength, sizeof(bigLength), /* continuation */ -1);
-    bytesLeft -= sizeof(bigLength);
-
-    /* record the rest of the request after the length */
-    RecordAProtocolElement(pContext, client, XRecordFromClient,
-		(pointer)(stuff + 1), bytesLeft, /* continuation */ -1);
-} /* RecordABigRequest */
-
-
-/* RecordARequest
- *
- * Arguments:
- *	client is a client that the server has dispatched a request to by
- *	calling client->requestVector[request opcode] .
- *	The request is in client->requestBuffer.
- *
- * Returns:
- *	Whatever is returned by the "real" Proc function for this request.
- *	The "real" Proc function is the function that was in
- *	client->requestVector[request opcode]  before it was replaced by
- *	RecordARequest.  (See the function RecordInstallHooks.)
- *
- * Side Effects:
- *	The request is recorded by all contexts that have registered this
- *	request for this client.  The real Proc function is called.
- */
-static int
-RecordARequest(ClientPtr client)
-{
-    RecordContextPtr pContext;
-    RecordClientsAndProtocolPtr pRCAP;
-    int i;
-    RecordClientPrivatePtr pClientPriv;
-    REQUEST(xReq);
-    int majorop;
-
-    majorop = stuff->reqType;
-    for (i = 0; i < numEnabledContexts; i++)
-    {
-	pContext = ppAllContexts[i];
-	pRCAP = RecordFindClientOnContext(pContext, client->clientAsMask,
-					  NULL);
-	if (pRCAP && pRCAP->pRequestMajorOpSet &&
-	    RecordIsMemberOfSet(pRCAP->pRequestMajorOpSet, majorop))
-	{
-	    if (majorop <= 127)
-	    { /* core request */
-
-		if (stuff->length == 0)
-		    RecordABigRequest(pContext, client, stuff);
-		else
-		    RecordAProtocolElement(pContext, client, XRecordFromClient,
-				(pointer)stuff, client->req_len << 2, 0);
-	    }
-	    else /* extension, check minor opcode */
-	    {
-		int minorop = MinorOpcodeOfRequest(client);
-		int numMinOpInfo;
-		RecordMinorOpPtr pMinorOpInfo = pRCAP->pRequestMinOpInfo;
-
-		assert (pMinorOpInfo);
-		numMinOpInfo = pMinorOpInfo->count;
-		pMinorOpInfo++;
-		assert (numMinOpInfo);
-		for ( ; numMinOpInfo; numMinOpInfo--, pMinorOpInfo++)
-		{
-		    if (majorop >= pMinorOpInfo->major.first &&
-			majorop <= pMinorOpInfo->major.last &&
-			RecordIsMemberOfSet(pMinorOpInfo->major.pMinOpSet,
-					    minorop))
-		    {
-			if (stuff->length == 0)
-			    RecordABigRequest(pContext, client, stuff);
-			else
-			    RecordAProtocolElement(pContext, client, 
-					XRecordFromClient, (pointer)stuff,
-					client->req_len << 2, 0);
-			break;
-		    }			    
-		} /* end for each minor op info */
-	    } /* end extension request */
-	} /* end this RCAP wants this major opcode */
-    } /* end for each context */
-    pClientPriv = RecordClientPrivate(client);
-    assert(pClientPriv);
-    return (* pClientPriv->originalVector[majorop])(client);
-} /* RecordARequest */
-
-/* RecordAReply
- *
- * Arguments:
- *	pcbl is &ReplyCallback.
- *	nulldata is NULL.
- *	calldata is a pointer to a ReplyInfoRec (include/os.h)
- *	  which provides information about replies that are being sent
- *	  to clients.
- *
- * Returns: nothing.
- *
- * Side Effects:
- *	The reply is recorded by all contexts that have registered this
- *	reply type for this client.  If more data belonging to the same
- *	reply is expected, and if the reply is being recorded by any
- *	context, pContext->continuedReply is set to 1.
- *	If pContext->continuedReply was already 1 and this is the last
- *	chunk of data belonging to this reply, it is set to 0.
- */
-static void
-RecordAReply(CallbackListPtr *pcbl, pointer nulldata, pointer calldata)
-{
-    RecordContextPtr pContext;
-    RecordClientsAndProtocolPtr pRCAP;
-    int eci;
-    int majorop;
-    ReplyInfoRec *pri = (ReplyInfoRec *)calldata;
-    ClientPtr client = pri->client;
-    REQUEST(xReq);
-
-    majorop = stuff->reqType;
-    for (eci = 0; eci < numEnabledContexts; eci++)
-    {
-	pContext = ppAllContexts[eci];
-	pRCAP = RecordFindClientOnContext(pContext, client->clientAsMask,
-					  NULL);
-	if (pRCAP)
-	{
-	    if (pContext->continuedReply)
-	    {
-		RecordAProtocolElement(pContext, client, XRecordFromServer,
-		   (pointer)pri->replyData, pri->dataLenBytes, /* continuation */ -1);
-		if (!pri->bytesRemaining)
-		    pContext->continuedReply = 0;
-	    }
-	    else if (pri->startOfReply && pRCAP->pReplyMajorOpSet &&
-		     RecordIsMemberOfSet(pRCAP->pReplyMajorOpSet, majorop))
-	    {
-		if (majorop <= 127)
-		{ /* core reply */
-		    RecordAProtocolElement(pContext, client, XRecordFromServer,
-		       (pointer)pri->replyData, pri->dataLenBytes, pri->bytesRemaining);
-		    if (pri->bytesRemaining)
-			pContext->continuedReply = 1;
-		}
-		else /* extension, check minor opcode */
-		{
-		    int minorop = MinorOpcodeOfRequest(client);
-		    int numMinOpInfo;
-		    RecordMinorOpPtr pMinorOpInfo = pRCAP->pReplyMinOpInfo;
-		    		    assert (pMinorOpInfo);
-		    numMinOpInfo = pMinorOpInfo->count;
-		    pMinorOpInfo++;
-		    assert (numMinOpInfo);
-		    for ( ; numMinOpInfo; numMinOpInfo--, pMinorOpInfo++)
-		    {
-			if (majorop >= pMinorOpInfo->major.first &&
-			    majorop <= pMinorOpInfo->major.last &&
-			    RecordIsMemberOfSet(pMinorOpInfo->major.pMinOpSet,
-						minorop))
-			{
-			    RecordAProtocolElement(pContext, client, 
-				XRecordFromServer, (pointer)pri->replyData,
-				pri->dataLenBytes, pri->bytesRemaining);
-			    if (pri->bytesRemaining)
-				pContext->continuedReply = 1;
-			    break;
-			}			    
-		    } /* end for each minor op info */
-		} /* end extension reply */
-	    } /* end continued reply vs. start of reply */
-	} /* end client is registered on this context */
-    } /* end for each context */
-} /* RecordAReply */
-
-
-/* RecordADeliveredEventOrError
- *
- * Arguments:
- *	pcbl is &EventCallback.
- *	nulldata is NULL.
- *	calldata is a pointer to a EventInfoRec (include/dix.h)
- *	  which provides information about events that are being sent
- *	  to clients.
- *
- * Returns: nothing.
- *
- * Side Effects:
- *	The event or error is recorded by all contexts that have registered
- *	it for this client.
- */
-static void
-RecordADeliveredEventOrError(CallbackListPtr *pcbl, pointer nulldata, pointer calldata)
-{
-    EventInfoRec *pei = (EventInfoRec *)calldata;
-    RecordContextPtr pContext;
-    RecordClientsAndProtocolPtr pRCAP;
-    int eci; /* enabled context index */
-    ClientPtr pClient = pei->client;
-
-    for (eci = 0; eci < numEnabledContexts; eci++)
-    {
-	pContext = ppAllContexts[eci];
-	pRCAP = RecordFindClientOnContext(pContext, pClient->clientAsMask,
-					  NULL);
-	if (pRCAP && (pRCAP->pDeliveredEventSet || pRCAP->pErrorSet))
-	{
-	    int ev; /* event index */
-	    xEvent *pev = pei->events;
-	    for (ev = 0; ev < pei->count; ev++, pev++)
-	    {
-		int recordit = 0;
-		if (pRCAP->pErrorSet)
-		{
-		    recordit = RecordIsMemberOfSet(pRCAP->pErrorSet,
-						((xError *)(pev))->errorCode);
-		}
-		else if (pRCAP->pDeliveredEventSet)
-		{
-		    recordit = RecordIsMemberOfSet(pRCAP->pDeliveredEventSet,
-						   pev->u.u.type & 0177);
-		}
-		if (recordit)
-		{
-		    xEvent swappedEvent;
-		    xEvent *pEvToRecord = pev;
-
-		    if (pClient->swapped)
-		    {
-			(*EventSwapVector[pev->u.u.type & 0177])
-			    (pev, &swappedEvent);
-			pEvToRecord = &swappedEvent;
-			
-		    }
-		    RecordAProtocolElement(pContext, pClient,
-			XRecordFromServer, pEvToRecord, SIZEOF(xEvent), 0);
-		}
-	    } /* end for each event */
-	} /* end this client is on this context */
-    } /* end for each enabled context */
-} /* RecordADeliveredEventOrError */
-
-
-static void
-RecordSendProtocolEvents(RecordClientsAndProtocolPtr pRCAP,
-			RecordContextPtr pContext,
-			xEvent* pev, int count)
-{
-    int ev; /* event index */
-
-    for (ev = 0; ev < count; ev++, pev++)
-    {
-	if (RecordIsMemberOfSet(pRCAP->pDeviceEventSet,
-		    pev->u.u.type & 0177))
-	{
-	    xEvent swappedEvent;
-	    xEvent *pEvToRecord = pev;
-#ifdef PANORAMIX
-	    xEvent shiftedEvent;
-
-	    if (!noPanoramiXExtension &&
-		    (pev->u.u.type == MotionNotify ||
-		     pev->u.u.type == ButtonPress ||
-		     pev->u.u.type == ButtonRelease ||
-		     pev->u.u.type == KeyPress ||
-		     pev->u.u.type == KeyRelease)) {
-		int scr = XineramaGetCursorScreen(inputInfo.pointer);
-		memcpy(&shiftedEvent, pev, sizeof(xEvent));
-		shiftedEvent.u.keyButtonPointer.rootX +=
-		    screenInfo.screens[scr]->x -
-		    screenInfo.screens[0]->x;
-		shiftedEvent.u.keyButtonPointer.rootY +=
-		    screenInfo.screens[scr]->y -
-		    screenInfo.screens[0]->y;
-		pEvToRecord = &shiftedEvent;
-	    }
-#endif /* PANORAMIX */
-
-	    if (pContext->pRecordingClient->swapped)
-	    {
-		(*EventSwapVector[pEvToRecord->u.u.type & 0177])
-		    (pEvToRecord, &swappedEvent);
-		pEvToRecord = &swappedEvent;
-	    }
-
-	    RecordAProtocolElement(pContext, NULL,
-		    XRecordFromServer,  pEvToRecord, SIZEOF(xEvent), 0);
-	    /* make sure device events get flushed in the absence
-	     * of other client activity
-	     */
-	    SetCriticalOutputPending();
-	}
-    } /* end for each event */
-
-} /* RecordADeviceEvent */
-
-/* RecordADeviceEvent
- *
- * Arguments:
- *	pcbl is &DeviceEventCallback.
- *	nulldata is NULL.
- *	calldata is a pointer to a DeviceEventInfoRec (include/dix.h)
- *	  which provides information about device events that occur.
- *
- * Returns: nothing.
- *
- * Side Effects:
- *	The device event is recorded by all contexts that have registered
- *	it for this client.
- */
-static void
-RecordADeviceEvent(CallbackListPtr *pcbl, pointer nulldata, pointer calldata)
-{
-    DeviceEventInfoRec *pei = (DeviceEventInfoRec *)calldata;
-    RecordContextPtr pContext;
-    RecordClientsAndProtocolPtr pRCAP;
-    int eci; /* enabled context index */
-
-    for (eci = 0; eci < numEnabledContexts; eci++)
-    {
-	pContext = ppAllContexts[eci];
-	for (pRCAP = pContext->pListOfRCAP; pRCAP; pRCAP = pRCAP->pNextRCAP)
-	{
-	    if (pRCAP->pDeviceEventSet)
-	    {
-		int count;
-		xEvent *xi_events = NULL;
-
-		/* TODO check return values */
-		if (IsMaster(pei->device))
-		{
-		    xEvent *core_events;
-		    EventToCore(pei->event, &core_events, &count);
-		    RecordSendProtocolEvents(pRCAP, pContext, core_events,
-                                             count);
-		    free(core_events);
-		}
-
-		EventToXI(pei->event, &xi_events, &count);
-		RecordSendProtocolEvents(pRCAP, pContext, xi_events, count);
-		free(xi_events);
-	    } /* end this RCAP selects device events */
-	} /* end for each RCAP on this context */
-    } /* end for each enabled context */
-}
-
-
-/* RecordFlushAllContexts
- *
- * Arguments:
- *	pcbl is &FlushCallback.
- *	nulldata and calldata are NULL.
- *
- * Returns: nothing.
- *
- * Side Effects:
- *	All buffered reply data of all enabled contexts is written to
- *	the recording clients.
- */
-static void
-RecordFlushAllContexts(
-    CallbackListPtr *pcbl,
-    pointer nulldata,
-    pointer calldata
-)
-{
-    int eci; /* enabled context index */
-    RecordContextPtr pContext;
-
-    for (eci = 0; eci < numEnabledContexts; eci++)
-    {
-	pContext = ppAllContexts[eci];
-
-	/* In most cases we leave it to RecordFlushReplyBuffer to make
-	 * this check, but this function could be called very often, so we
-	 * check before calling hoping to save the function call cost
-	 * most of the time.
-	 */
-	if (pContext->numBufBytes)
-	    RecordFlushReplyBuffer(ppAllContexts[eci], NULL, 0, NULL, 0);
-    }
-} /* RecordFlushAllContexts */
-
-
-/* RecordInstallHooks
- *
- * Arguments:
- *	pRCAP is an RCAP on an enabled or being-enabled context.
- *	oneclient can be zero or the resource ID mask identifying a client.
- *
- * Returns: BadAlloc if a memory allocation error occurred, else Success.
- *
- * Side Effects:
- *	Recording hooks needed by RCAP are installed.
- *	If oneclient is zero, recording hooks needed for all clients and
- *	protocol on the RCAP are installed.  If oneclient is non-zero,
- *	only those hooks needed for the specified client are installed.
- *	
- *	Client requestVectors may be altered.  numEnabledRCAPs will be
- *	incremented if oneclient == 0.  Callbacks may be added to
- *	various callback lists.
- */
-static int
-RecordInstallHooks(RecordClientsAndProtocolPtr pRCAP, XID oneclient)
-{
-    int i = 0;
-    XID client;
-
-    if (oneclient)
-	client = oneclient;
-    else
-	client = pRCAP->numClients ? pRCAP->pClientIDs[i++] : 0;
-
-    while (client)
-    {
-	if (client != XRecordFutureClients)
-	{
-	    if (pRCAP->pRequestMajorOpSet)
-	    {
-		RecordSetIteratePtr pIter = NULL;
-		RecordSetInterval interval;
-		ClientPtr pClient = clients[CLIENT_ID(client)];
-
-		if (pClient && !RecordClientPrivate(pClient))
-		{
-		    RecordClientPrivatePtr pClientPriv;
-		    /* no Record proc vector; allocate one */
-		    pClientPriv = (RecordClientPrivatePtr)
-				malloc(sizeof(RecordClientPrivateRec));
-		    if (!pClientPriv)
-			return BadAlloc;
-		    /* copy old proc vector to new */
-		    memcpy(pClientPriv->recordVector, pClient->requestVector, 
-			   sizeof (pClientPriv->recordVector));
-		    pClientPriv->originalVector = pClient->requestVector;
-		    dixSetPrivate(&pClient->devPrivates,
-				  RecordClientPrivateKey, pClientPriv);
-		    pClient->requestVector = pClientPriv->recordVector;
-		}
-		while ((pIter = RecordIterateSet(pRCAP->pRequestMajorOpSet,
-						pIter, &interval)))
-		{
-		    unsigned int j;
-		    for (j = interval.first; j <= interval.last; j++)
-			pClient->requestVector[j] = RecordARequest;
-		}
-	    }
-	}
-	if (oneclient)
-	    client = 0;
-	else
-	    client = (i < pRCAP->numClients) ? pRCAP->pClientIDs[i++] : 0;
-    }
-
-    assert(numEnabledRCAPs >= 0);
-    if (!oneclient && ++numEnabledRCAPs == 1)
-    { /* we're enabling the first context */
-	if (!AddCallback(&EventCallback, RecordADeliveredEventOrError, NULL))
-	    return BadAlloc;
-	if (!AddCallback(&DeviceEventCallback, RecordADeviceEvent, NULL))
-	    return BadAlloc;
-	if (!AddCallback(&ReplyCallback, RecordAReply, NULL))
-	    return BadAlloc;
-	if (!AddCallback(&FlushCallback, RecordFlushAllContexts, NULL))
-	    return BadAlloc;
-	/* Alternate context flushing scheme: delete the line above
-	 * and call RegisterBlockAndWakeupHandlers here passing
-	 * RecordFlushAllContexts.  Is this any better?
-	 */
-    }
-    return Success;
-} /* RecordInstallHooks */
-
-
-/* RecordUninstallHooks
- *
- * Arguments:
- *	pRCAP is an RCAP on an enabled or being-disabled context.
- *	oneclient can be zero or the resource ID mask identifying a client.
- *
- * Returns: nothing.
- *
- * Side Effects:
- *	Recording hooks needed by RCAP may be uninstalled.
- *	If oneclient is zero, recording hooks needed for all clients and
- *	protocol on the RCAP may be uninstalled.  If oneclient is non-zero,
- *	only those hooks needed for the specified client may be uninstalled.
- *	
- *	Client requestVectors may be altered.  numEnabledRCAPs will be
- *	decremented if oneclient == 0.  Callbacks may be deleted from
- *	various callback lists.
- */
-static void
-RecordUninstallHooks(RecordClientsAndProtocolPtr pRCAP, XID oneclient)
-{
-    int i = 0;
-    XID client;
-
-    if (oneclient)
-	client = oneclient;
-    else
-	client = pRCAP->numClients ? pRCAP->pClientIDs[i++] : 0;
-
-    while (client)
-    {
-	if (client != XRecordFutureClients)
-	{
-	    if (pRCAP->pRequestMajorOpSet)
-	    {
-		ClientPtr pClient = clients[CLIENT_ID(client)];
-		int c;
-		Bool otherRCAPwantsProcVector = FALSE;
-		RecordClientPrivatePtr pClientPriv = NULL;
-
-		assert (pClient);
-		pClientPriv = RecordClientPrivate(pClient);
-		assert (pClientPriv);
-		memcpy(pClientPriv->recordVector, pClientPriv->originalVector,
-		       sizeof (pClientPriv->recordVector));
-
-		for (c = 0; c < numEnabledContexts; c++)
-		{
-		    RecordClientsAndProtocolPtr pOtherRCAP;
-		    RecordContextPtr pContext = ppAllContexts[c];
-
-		    if (pContext == pRCAP->pContext) continue;
-		    pOtherRCAP = RecordFindClientOnContext(pContext, client,
-							   NULL);
-		    if (pOtherRCAP && pOtherRCAP->pRequestMajorOpSet)
-		    {
-			RecordSetIteratePtr pIter = NULL;
-			RecordSetInterval interval;
-
-			otherRCAPwantsProcVector = TRUE;
-			while ((pIter = RecordIterateSet(
-						pOtherRCAP->pRequestMajorOpSet,
-						pIter, &interval)))
-			{
-			    unsigned int j;
-			    for (j = interval.first; j <= interval.last; j++)
-				pClient->requestVector[j] = RecordARequest;
-			}
-		    }
-		}
-		if (!otherRCAPwantsProcVector)
-		{ /* nobody needs it, so free it */
-		    pClient->requestVector = pClientPriv->originalVector;
-		    dixSetPrivate(&pClient->devPrivates,
-				  RecordClientPrivateKey, NULL);
-		    free(pClientPriv);
-		}
-	    } /* end if this RCAP specifies any requests */
-	} /* end if not future clients */
-	if (oneclient)
-	    client = 0;
-	else
-	    client = (i < pRCAP->numClients) ? pRCAP->pClientIDs[i++] : 0;
-    }
-
-    assert(numEnabledRCAPs >= 1);
-    if (!oneclient && --numEnabledRCAPs == 0)
-    { /* we're disabling the last context */
-	DeleteCallback(&EventCallback, RecordADeliveredEventOrError, NULL);
-	DeleteCallback(&DeviceEventCallback, RecordADeviceEvent, NULL);
-	DeleteCallback(&ReplyCallback, RecordAReply, NULL);
-	DeleteCallback(&FlushCallback, RecordFlushAllContexts, NULL);
-	/* Alternate context flushing scheme: delete the line above
-	 * and call RemoveBlockAndWakeupHandlers here passing
-	 * RecordFlushAllContexts.  Is this any better?
-	 */
-	/* Having deleted the callback, call it one last time. -gildea */
-	RecordFlushAllContexts(&FlushCallback, NULL, NULL);
-    }
-} /* RecordUninstallHooks */
-
-
-/* RecordDeleteClientFromRCAP
- *
- * Arguments:
- *	pRCAP is an RCAP to delete the client from.
- *	position is the index into the array pRCAP->pClientIDs of the
- *	client to delete.
- *
- * Returns: nothing.
- *
- * Side Effects:
- *	Recording hooks needed by client will be uninstalled if the context
- *	is enabled.  The designated client will be removed from the 
- *	pRCAP->pClientIDs array.  If it was the only client on the RCAP, 
- *	the RCAP is removed from the context and freed.  (Invariant: RCAPs
- *	have at least one client.)
- */
-static void
-RecordDeleteClientFromRCAP(RecordClientsAndProtocolPtr pRCAP, int position)
-{
-    if (pRCAP->pContext->pRecordingClient)
-	RecordUninstallHooks(pRCAP, pRCAP->pClientIDs[position]);
-    if (position != pRCAP->numClients - 1)
-	pRCAP->pClientIDs[position] = pRCAP->pClientIDs[pRCAP->numClients - 1];
-    if (--pRCAP->numClients == 0)
-    {	/* no more clients; remove RCAP from context's list */
-	RecordContextPtr pContext = pRCAP->pContext;
-	if (pContext->pRecordingClient)
-	    RecordUninstallHooks(pRCAP, 0);
-	if (pContext->pListOfRCAP == pRCAP)
-	    pContext->pListOfRCAP = pRCAP->pNextRCAP;
-	else
-	{
-	    RecordClientsAndProtocolPtr prevRCAP;
-	    for (prevRCAP = pContext->pListOfRCAP;
-		 prevRCAP->pNextRCAP != pRCAP;
-		 prevRCAP = prevRCAP->pNextRCAP)
-		;
-	    prevRCAP->pNextRCAP = pRCAP->pNextRCAP;
-	}
-	/* free the RCAP */
-	if (pRCAP->clientIDsSeparatelyAllocated)
-	    free(pRCAP->pClientIDs);
-	free(pRCAP);
-    }
-} /* RecordDeleteClientFromRCAP */
-
-
-/* RecordAddClientToRCAP
- *
- * Arguments:
- *	pRCAP is an RCAP to add the client to.
- *	clientspec is the resource ID mask identifying a client, or
- *	  XRecordFutureClients.
- *
- * Returns: nothing.
- *
- * Side Effects:
- *	Recording hooks needed by client will be installed if the context
- *	is enabled.  The designated client will be added to the 
- *	pRCAP->pClientIDs array, which may be realloced.
- *	pRCAP->clientIDsSeparatelyAllocated may be set to 1 if there
- *	is no more room to hold clients internal to the RCAP.
- */
-static void
-RecordAddClientToRCAP(RecordClientsAndProtocolPtr pRCAP, XID clientspec)
-{
-    if (pRCAP->numClients == pRCAP->sizeClients)
-    {
-	if (pRCAP->clientIDsSeparatelyAllocated)
-	{
-	    XID *pNewIDs = (XID *)realloc(pRCAP->pClientIDs,
-			(pRCAP->sizeClients + CLIENT_ARRAY_GROWTH_INCREMENT) *
-								sizeof(XID));
-	    if (!pNewIDs)
-		return;
-	    pRCAP->pClientIDs = pNewIDs;
-	    pRCAP->sizeClients += CLIENT_ARRAY_GROWTH_INCREMENT;
-	}
-	else
-	{
-	    XID *pNewIDs = (XID *)malloc((pRCAP->sizeClients +
-				CLIENT_ARRAY_GROWTH_INCREMENT) * sizeof(XID));
-	    if (!pNewIDs)
-		return;
-	    memcpy(pNewIDs, pRCAP->pClientIDs, pRCAP->numClients *sizeof(XID));
-	    pRCAP->pClientIDs = pNewIDs;
-	    pRCAP->sizeClients += CLIENT_ARRAY_GROWTH_INCREMENT;
-	    pRCAP->clientIDsSeparatelyAllocated = 1;
-	}
-    }
-    pRCAP->pClientIDs[pRCAP->numClients++] = clientspec;
-    if (pRCAP->pContext->pRecordingClient)
-	RecordInstallHooks(pRCAP, clientspec);
-} /* RecordDeleteClientFromRCAP */
-
-
-/* RecordDeleteClientFromContext
- *
- * Arguments:
- *	pContext is the context to delete from.
- *	clientspec is the resource ID mask identifying a client, or
- *	  XRecordFutureClients.
- *
- * Returns: nothing.
- *
- * Side Effects:
- *	If clientspec is on any RCAP of the context, it is deleted from that
- *	RCAP.  (A given clientspec can only be on one RCAP of a context.)
- */
-static void
-RecordDeleteClientFromContext(RecordContextPtr pContext, XID clientspec)
-{
-    RecordClientsAndProtocolPtr pRCAP;
-    int position;
-
-    if ((pRCAP = RecordFindClientOnContext(pContext, clientspec, &position)))
-	RecordDeleteClientFromRCAP(pRCAP, position);
-} /* RecordDeleteClientFromContext */
-
-
-/* RecordSanityCheckClientSpecifiers
- *
- * Arguments:
- *	clientspecs is an array of alleged CLIENTSPECs passed by the client.
- *	nspecs is the number of elements in clientspecs.
- *	errorspec, if non-zero, is the resource id base of a client that
- *	  must not appear in clienspecs.
- *
- * Returns: BadMatch if any of the clientspecs are invalid, else Success.
- *
- * Side Effects: none.
- */
-static int
-RecordSanityCheckClientSpecifiers(ClientPtr client, XID *clientspecs, int nspecs, XID errorspec)
-{
-    int i;
-    int clientIndex;
-    int rc;
-    pointer value;
-
-    for (i = 0; i < nspecs; i++)
-    {
-	if (clientspecs[i] == XRecordCurrentClients ||
-	    clientspecs[i] == XRecordFutureClients ||
-	    clientspecs[i] == XRecordAllClients)
-	    continue;
-	if (errorspec && (CLIENT_BITS(clientspecs[i]) == errorspec) )
-	    return BadMatch;
-	clientIndex = CLIENT_ID(clientspecs[i]);
-	if (clientIndex && clients[clientIndex] &&
-	    clients[clientIndex]->clientState == ClientStateRunning)
-	{
-	    if (clientspecs[i] == clients[clientIndex]->clientAsMask)
-		continue;
-            rc = dixLookupResourceByClass(&value, clientspecs[i], RC_ANY,
-                                          client, DixGetAttrAccess);
-            if (rc != Success)
-                return rc;
-	}
-	else
-	    return BadMatch;
-    }
-    return Success;
-} /* RecordSanityCheckClientSpecifiers */
-
-
-/* RecordCanonicalizeClientSpecifiers
- *
- * Arguments:
- *	pClientspecs is an array of CLIENTSPECs that have been sanity
- *	  checked.
- *	pNumClientspecs is a pointer to the number of elements in pClientspecs.
- *	excludespec, if non-zero, is the resource id base of a client that 
- *	  should not be included in the expansion of XRecordAllClients or 
- *	  XRecordCurrentClients.
- *
- * Returns:
- *	A pointer to an array of CLIENTSPECs that is the same as the
- *	passed array with the following modifications:
- *	  - all but the client id bits of resource IDs are stripped off.
- *	  - duplicates removed.
- *	  - XRecordAllClients expanded to a list of all currently connected
- *	    clients + XRecordFutureClients - excludespec (if non-zero)
- *	  - XRecordCurrentClients expanded to a list of all currently
- *	    connected clients - excludespec (if non-zero)
- *	The returned array may be the passed array modified in place, or
- *	it may be an malloc'ed array.  The caller should keep a pointer to the
- *	original array and free the returned array if it is different.
- *
- *	*pNumClientspecs is set to the number of elements in the returned
- *	array.
- *
- * Side Effects:
- *	pClientspecs may be modified in place.
- */
-static XID *
-RecordCanonicalizeClientSpecifiers(XID *pClientspecs, int *pNumClientspecs, XID excludespec)
-{
-    int i;
-    int numClients = *pNumClientspecs;
-
-    /*  first pass strips off the resource index bits, leaving just the
-     *  client id bits.  This makes searching for a particular client simpler
-     *  (and faster.)
-     */
-    for (i = 0; i < numClients; i++)
-    {
-	XID cs = pClientspecs[i];
-	if (cs > XRecordAllClients)
-	    pClientspecs[i] = CLIENT_BITS(cs);
-    }
-
-    for (i = 0; i < numClients; i++)
-    {
-	if (pClientspecs[i] == XRecordAllClients ||
-	    pClientspecs[i] == XRecordCurrentClients)
-	{ /* expand All/Current */
-	    int j, nc;
-	    XID *pCanon = (XID *)malloc(sizeof(XID) * (currentMaxClients + 1));
-	    if (!pCanon) return NULL;
-	    for (nc = 0, j = 1; j < currentMaxClients; j++)
-	    {
-		ClientPtr client = clients[j];
-		if (client != NullClient &&
-		    client->clientState == ClientStateRunning &&
-		    client->clientAsMask != excludespec)
-		{
-		    pCanon[nc++] = client->clientAsMask;
-		}
-	    }
-	    if (pClientspecs[i] == XRecordAllClients)
-		pCanon[nc++] = XRecordFutureClients;
-	    *pNumClientspecs = nc;
-	    return pCanon;
-	}
-	else /* not All or Current */
-	{
-	    int j;
-	    for (j = i + 1; j < numClients; )
-	    {
-		if (pClientspecs[i] == pClientspecs[j])
-		{
-		    pClientspecs[j] = pClientspecs[--numClients];
-		}
-		else
-		    j++;
-	    }
-	}
-    } /* end for each clientspec */
-    *pNumClientspecs = numClients;
-    return pClientspecs;
-} /* RecordCanonicalizeClientSpecifiers */
-
-
-/****************************************************************************/
-
-/* stuff for RegisterClients */
-
-/* RecordPadAlign
- *
- * Arguments:
- *	size is the number of bytes taken by an object.
- *	align is a byte boundary (e.g. 4, 8)
- *
- * Returns:
- *	the number of pad bytes to add at the end of an object of the
- *	given size so that an object placed immediately behind it will
- *	begin on an <align>-byte boundary.
- *
- * Side Effects: none.
- */
-static int
-RecordPadAlign(int size, int align)
-{
-    return (align - (size & (align - 1))) & (align - 1);
-} /* RecordPadAlign */
-
-
-/* RecordSanityCheckRegisterClients
- *
- * Arguments:
- *	pContext is the context being registered on.
- *	client is the client that issued a RecordCreateContext or
- *	  RecordRegisterClients request.
- *	stuff is a pointer to the request.
- *
- * Returns:
- *	Any one of several possible error values if any of the request
- *	arguments are invalid.  Success if everything is OK.
- *
- * Side Effects: none.
- */
-static int
-RecordSanityCheckRegisterClients(RecordContextPtr pContext, ClientPtr client, xRecordRegisterClientsReq *stuff)
-{
-    int err;
-    xRecordRange *pRange;
-    int i;
-    XID recordingClient;
-
-    if (((client->req_len << 2) - SIZEOF(xRecordRegisterClientsReq)) !=
-	4 * stuff->nClients + SIZEOF(xRecordRange) * stuff->nRanges)
-	return BadLength;
-
-    if (stuff->elementHeader &
-     ~(XRecordFromClientSequence|XRecordFromClientTime|XRecordFromServerTime))
-    {
-	client->errorValue = stuff->elementHeader;
-	return BadValue;
-    }
-
-    recordingClient = pContext->pRecordingClient ?
-		      pContext->pRecordingClient->clientAsMask : 0;
-    err = RecordSanityCheckClientSpecifiers(client, (XID *)&stuff[1],
-					    stuff->nClients, recordingClient);
-    if (err != Success) return err;
-
-    pRange = (xRecordRange *)(((XID *)&stuff[1]) + stuff->nClients);
-    for (i = 0; i < stuff->nRanges; i++, pRange++)
-    {
-	if (pRange->coreRequestsFirst > pRange->coreRequestsLast)
-	{
-	    client->errorValue = pRange->coreRequestsFirst;
-	    return BadValue;
-	}
-	if (pRange->coreRepliesFirst > pRange->coreRepliesLast)
-	{
-	    client->errorValue = pRange->coreRepliesFirst;
-	    return BadValue;
-	}
-	if ((pRange->extRequestsMajorFirst || pRange->extRequestsMajorLast) &&
-	    (pRange->extRequestsMajorFirst < 128 ||
-	     pRange->extRequestsMajorLast < 128 ||
-	     pRange->extRequestsMajorFirst > pRange->extRequestsMajorLast))
-	{
-	    client->errorValue = pRange->extRequestsMajorFirst;
-	    return BadValue;
-	}
-	if (pRange->extRequestsMinorFirst > pRange->extRequestsMinorLast)
-	{
-	    client->errorValue = pRange->extRequestsMinorFirst;
-	    return BadValue;
-	}
-	if ((pRange->extRepliesMajorFirst || pRange->extRepliesMajorLast) &&
-	    (pRange->extRepliesMajorFirst < 128 ||
-	     pRange->extRepliesMajorLast < 128 ||
-	     pRange->extRepliesMajorFirst > pRange->extRepliesMajorLast))
-	{
-	    client->errorValue = pRange->extRepliesMajorFirst;
-	    return BadValue;
-	}
-	if (pRange->extRepliesMinorFirst > pRange->extRepliesMinorLast)
-	{
-	    client->errorValue = pRange->extRepliesMinorFirst;
-	    return BadValue;
-	}
-	if ((pRange->deliveredEventsFirst || pRange->deliveredEventsLast) &&
-	    (pRange->deliveredEventsFirst < 2 ||
-	     pRange->deliveredEventsLast < 2 ||
-	     pRange->deliveredEventsFirst > pRange->deliveredEventsLast))
-	{
-	    client->errorValue = pRange->deliveredEventsFirst;
-	    return BadValue;
-	}
-	if ((pRange->deviceEventsFirst || pRange->deviceEventsLast) &&
-	    (pRange->deviceEventsFirst < 2 ||
-	     pRange->deviceEventsLast < 2 ||
-	     pRange->deviceEventsFirst > pRange->deviceEventsLast))
-	{
-	    client->errorValue = pRange->deviceEventsFirst;
-	    return BadValue;
-	}
-	if (pRange->errorsFirst > pRange->errorsLast)
-	{
-	    client->errorValue = pRange->errorsFirst;
-	    return BadValue;
-	}
-	if (pRange->clientStarted != xFalse && pRange->clientStarted != xTrue)
-	{
-	    client->errorValue = pRange->clientStarted;
-	    return BadValue;
-	}
-	if (pRange->clientDied != xFalse && pRange->clientDied != xTrue)
-	{
-	    client->errorValue = pRange->clientDied;
-	    return BadValue;
-	}
-    } /* end for each range */
-    return Success;
-} /* end RecordSanityCheckRegisterClients */
-
-/* This is a tactical structure used to gather information about all the sets
- * (RecordSetPtr) that need to be created for an RCAP in the process of 
- * digesting a list of RECORDRANGEs (converting it to the internal
- * representation).
- */
-typedef struct
-{
-    int nintervals;	/* number of intervals in following array */
-    RecordSetInterval *intervals;  /* array of intervals for this set */
-    int size;		/* size of intevals array; >= nintervals */
-    int align;		/* alignment restriction for set */
-    int offset;		/* where to store set pointer rel. to start of RCAP */
-    short first, last;	/* if for extension, major opcode interval */
-} SetInfoRec, *SetInfoPtr;
-
-/* These constant are used to index into an array of SetInfoRec. */
-enum {REQ,	/* set info for requests */
-      REP,	/* set info for replies */
-      ERR,	/* set info for errors */
-      DEV,	/* set info for device events */
-      DLEV,	/* set info for delivered events */
-      PREDEFSETS};  /* number of predefined array entries */
-
-
-/* RecordAllocIntervals
- *
- * Arguments:
- *	psi is a pointer to a SetInfoRec whose intervals pointer is NULL.
- *	nIntervals is the desired size of the intervals array.
- *
- * Returns: BadAlloc if a memory allocation error occurred, else Success.
- *
- * Side Effects:
- *	If Success is returned, psi->intervals is a pointer to size
- *	RecordSetIntervals, all zeroed, and psi->size is set to size.
- */
-static int
-RecordAllocIntervals(SetInfoPtr psi, int nIntervals)
-{
-    assert(!psi->intervals);
-    psi->intervals = (RecordSetInterval *)
-			malloc(nIntervals * sizeof(RecordSetInterval));
-    if (!psi->intervals)
-	return BadAlloc;
-    memset(psi->intervals, 0, nIntervals * sizeof(RecordSetInterval));
-    psi->size = nIntervals;
-    return Success;
-} /* end RecordAllocIntervals */
-
-
-/* RecordConvertRangesToIntervals
- *
- * Arguments:
- *	psi is a pointer to the SetInfoRec we are building.
- *	pRanges is an array of xRecordRanges.
- *	nRanges is the number of elements in pRanges.
- *	byteoffset is the offset from the start of an xRecordRange of the
- *	  two bytes (1 for first, 1 for last) we are interested in.
- *	pExtSetInfo, if non-NULL, indicates that the two bytes mentioned
- *	  above are followed by four bytes (2 for first, 2 for last)
- *	  representing a minor opcode range, and this information should be
- *	  stored in one of the SetInfoRecs starting at pExtSetInfo.
- *	pnExtSetInfo is the number of elements in the pExtSetInfo array.
- *
- * Returns:  BadAlloc if a memory allocation error occurred, else Success.
- *
- * Side Effects:
- *	The slice of pRanges indicated by byteoffset is stored in psi.  
- *	If pExtSetInfo is non-NULL, minor opcode intervals are stored
- *	in an existing SetInfoRec if the major opcode interval matches, else
- *	they are stored in a new SetInfoRec, and *pnExtSetInfo is
- *	increased accordingly.
- */
-static int
-RecordConvertRangesToIntervals(
-    SetInfoPtr psi,
-    xRecordRange *pRanges,
-    int nRanges,
-    int byteoffset,
-    SetInfoPtr pExtSetInfo,
-    int *pnExtSetInfo
-)
-{
-    int i;
-    CARD8 *pCARD8;
-    int first, last;
-    int err;
-
-    for (i = 0; i < nRanges; i++, pRanges++)
-    {
-	pCARD8 = ((CARD8 *)pRanges) + byteoffset;
-	first = pCARD8[0];
-	last  = pCARD8[1];
-	if (first || last)
-	{
-	    if (!psi->intervals)
-	    {
-		err = RecordAllocIntervals(psi, 2 * (nRanges - i));
-		if (err != Success)
-		    return err;
-	    }
-	    psi->intervals[psi->nintervals].first = first;
-	    psi->intervals[psi->nintervals].last  = last;
-	    psi->nintervals++;
-	    assert(psi->nintervals <= psi->size);
-	    if (pExtSetInfo)
-	    {
-		SetInfoPtr pesi = pExtSetInfo;
-		CARD16 *pCARD16 = (CARD16 *)(pCARD8 + 2);
-		int j;
-
-		for (j = 0; j < *pnExtSetInfo; j++, pesi++)
-		{
-		    if ( (first == pesi->first) && (last == pesi->last) )
-			break;
-		}
-		if (j == *pnExtSetInfo)
-		{
-		    err = RecordAllocIntervals(pesi, 2 * (nRanges - i));
-		    if (err != Success)
-			return err;
-		    pesi->first = first;
-		    pesi->last  = last;
-		    (*pnExtSetInfo)++;
-		}
-		pesi->intervals[pesi->nintervals].first = pCARD16[0];
-		pesi->intervals[pesi->nintervals].last  = pCARD16[1];
-		pesi->nintervals++;
-		assert(pesi->nintervals <= pesi->size);
-	    }
-	}
-    }
-    return Success;
-}  /* end RecordConvertRangesToIntervals */
-
-#define offset_of(_structure, _field) \
-    ((char *)(& (_structure . _field)) - (char *)(&_structure))
-
-/* RecordRegisterClients
- *
- * Arguments:
- *	pContext is the context on which to register the clients.
- *	client is the client that issued the RecordCreateContext or
- *	  RecordRegisterClients request.
- *	stuff is a pointer to the request.
- *
- * Returns:
- *	Any one of several possible error values defined by the protocol.
- *	Success if everything is OK.
- *
- * Side Effects:
- *	If different element headers are specified, the context is flushed.
- *	If any of the specified clients are already registered on the
- *	context, they are first unregistered.  A new RCAP is created to
- *	hold the specified protocol and clients, and it is linked onto the
- *	context.  If the context is enabled, appropriate hooks are installed
- *	to record the new clients and protocol.
- */
-static int
-RecordRegisterClients(RecordContextPtr pContext, ClientPtr client, xRecordRegisterClientsReq *stuff)
-{
-    int err;
-    int i;
-    SetInfoPtr si;
-    int maxSets;
-    int nExtReqSets = 0;
-    int nExtRepSets = 0;
-    int extReqSetsOffset = 0;
-    int extRepSetsOffset = 0;
-    SetInfoPtr pExtReqSets, pExtRepSets;
-    int clientListOffset;
-    XID *pCanonClients;
-    int clientStarted = 0, clientDied = 0;
-    xRecordRange *pRanges, rr;
-    int nClients;
-    int sizeClients;
-    int totRCAPsize;
-    RecordClientsAndProtocolPtr pRCAP;
-    int pad;
-    XID recordingClient;
-
-    /* do all sanity checking up front */
-
-    err = RecordSanityCheckRegisterClients(pContext, client, stuff);
-    if (err != Success)
-	return err;
-
-    /* if element headers changed, flush buffer */
-	
-    if (pContext->elemHeaders != stuff->elementHeader)
-    {
-	RecordFlushReplyBuffer(pContext, NULL, 0, NULL, 0);
-	pContext->elemHeaders = stuff->elementHeader;
-    }
-
-    nClients = stuff->nClients;
-    if (!nClients)
-	/* if empty clients list, we're done. */
-	return Success;
-
-    recordingClient = pContext->pRecordingClient ?
-		      pContext->pRecordingClient->clientAsMask : 0;
-    pCanonClients = RecordCanonicalizeClientSpecifiers((XID *)&stuff[1],
-						 &nClients, recordingClient);
-    if (!pCanonClients)
-	return BadAlloc;
-
-    /* We may have to create as many as one set for each "predefined"
-     * protocol types, plus one per range for extension reuests, plus one per
-     * range for extension replies.
-     */
-    maxSets = PREDEFSETS + 2 * stuff->nRanges;
-    si = (SetInfoPtr)malloc(sizeof(SetInfoRec) * maxSets);
-    if (!si)
-    {
-	err = BadAlloc;
-	goto bailout;
-    }
-    memset(si, 0, sizeof(SetInfoRec) * maxSets);
-
-    /* theoretically you must do this because NULL may not be all-bits-zero */
-    for (i = 0; i < maxSets; i++)
-	si[i].intervals = NULL;
-
-    pExtReqSets = si + PREDEFSETS;
-    pExtRepSets = pExtReqSets + stuff->nRanges;
-
-    pRanges = (xRecordRange *)(((XID *)&stuff[1]) + stuff->nClients);
-
-    err = RecordConvertRangesToIntervals(&si[REQ], pRanges, stuff->nRanges,
-			offset_of(rr, coreRequestsFirst), NULL, NULL);
-    if (err != Success) goto bailout;
-
-    err = RecordConvertRangesToIntervals(&si[REQ], pRanges, stuff->nRanges,
-	   offset_of(rr, extRequestsMajorFirst), pExtReqSets, &nExtReqSets);
-    if (err != Success) goto bailout;
-
-    err = RecordConvertRangesToIntervals(&si[REP], pRanges, stuff->nRanges,
-			offset_of(rr, coreRepliesFirst), NULL, NULL);
-    if (err != Success) goto bailout;
-
-    err = RecordConvertRangesToIntervals(&si[REP], pRanges, stuff->nRanges,
-	   offset_of(rr, extRepliesMajorFirst), pExtRepSets, &nExtRepSets);
-    if (err != Success) goto bailout;
-
-    err = RecordConvertRangesToIntervals(&si[ERR], pRanges, stuff->nRanges,
-			offset_of(rr, errorsFirst), NULL, NULL);
-    if (err != Success) goto bailout;
-
-    err = RecordConvertRangesToIntervals(&si[DLEV], pRanges, stuff->nRanges,
-			offset_of(rr, deliveredEventsFirst), NULL, NULL);
-    if (err != Success) goto bailout;
-
-    err = RecordConvertRangesToIntervals(&si[DEV], pRanges, stuff->nRanges,
-			offset_of(rr, deviceEventsFirst), NULL, NULL);
-    if (err != Success) goto bailout;
-
-    /* collect client-started and client-died */
-
-    for (i = 0; i < stuff->nRanges; i++)
-    {
-	if (pRanges[i].clientStarted) clientStarted = TRUE;
-	if (pRanges[i].clientDied)    clientDied    = TRUE;
-    }
-
-    /*  We now have all the information collected to create all the sets,
-     * and we can compute the total memory required for the RCAP.
-     */
-
-    totRCAPsize = sizeof(RecordClientsAndProtocolRec);
-
-    /* leave a little room to grow before forcing a separate allocation */
-    sizeClients = nClients + CLIENT_ARRAY_GROWTH_INCREMENT;
-    pad = RecordPadAlign(totRCAPsize, sizeof(XID));
-    clientListOffset = totRCAPsize + pad;
-    totRCAPsize += pad + sizeClients * sizeof(XID);
-
-    if (nExtReqSets)
-    {
-	pad = RecordPadAlign(totRCAPsize, sizeof(RecordSetPtr));
-	extReqSetsOffset = totRCAPsize + pad;
-	totRCAPsize += pad + (nExtReqSets + 1) * sizeof(RecordMinorOpRec);
-    }
-    if (nExtRepSets)
-    {
-	pad = RecordPadAlign(totRCAPsize, sizeof(RecordSetPtr));
-	extRepSetsOffset = totRCAPsize + pad;
-	totRCAPsize += pad + (nExtRepSets + 1) * sizeof(RecordMinorOpRec);
-    }
-
-    for (i = 0; i < maxSets; i++)
-    {
-	if (si[i].nintervals)
-	{
-	    si[i].size = RecordSetMemoryRequirements(
-				si[i].intervals, si[i].nintervals, &si[i].align);
-	    pad = RecordPadAlign(totRCAPsize, si[i].align);
-	    si[i].offset = pad + totRCAPsize;
-	    totRCAPsize += pad + si[i].size;
-	}
-    }
-
-    /* allocate memory for the whole RCAP */
-
-    pRCAP = (RecordClientsAndProtocolPtr)malloc(totRCAPsize);
-    if (!pRCAP) 
-    {
-	err = BadAlloc;
-	goto bailout;
-    }
-
-    /* fill in the RCAP */
-
-    pRCAP->pContext = pContext;
-    pRCAP->pClientIDs = (XID *)((char *)pRCAP + clientListOffset);
-    pRCAP->numClients  = nClients;
-    pRCAP->sizeClients = sizeClients;
-    pRCAP->clientIDsSeparatelyAllocated = 0;
-    for (i = 0; i < nClients; i++)
-    {
-	RecordDeleteClientFromContext(pContext, pCanonClients[i]);
-	pRCAP->pClientIDs[i] = pCanonClients[i];
-    }
-
-    /* create all the sets */
-
-    if (si[REQ].intervals)
-    {
-	pRCAP->pRequestMajorOpSet =
-	    RecordCreateSet(si[REQ].intervals, si[REQ].nintervals,
-		(RecordSetPtr)((char *)pRCAP + si[REQ].offset), si[REQ].size);
-    }
-    else pRCAP->pRequestMajorOpSet = NULL;
-
-    if (si[REP].intervals)
-    {
-	pRCAP->pReplyMajorOpSet =
-	    RecordCreateSet(si[REP].intervals, si[REP].nintervals,
-		(RecordSetPtr)((char *)pRCAP + si[REP].offset), si[REP].size);
-    }
-    else pRCAP->pReplyMajorOpSet = NULL;
-
-    if (si[ERR].intervals)
-    {
-	pRCAP->pErrorSet =
-	    RecordCreateSet(si[ERR].intervals, si[ERR].nintervals,
-		(RecordSetPtr)((char *)pRCAP + si[ERR].offset), si[ERR].size);
-    }
-    else pRCAP->pErrorSet = NULL;
-
-    if (si[DEV].intervals)
-    {
-	pRCAP->pDeviceEventSet =
-	    RecordCreateSet(si[DEV].intervals, si[DEV].nintervals,
-		(RecordSetPtr)((char *)pRCAP + si[DEV].offset), si[DEV].size);
-    }
-    else pRCAP->pDeviceEventSet = NULL;
-
-    if (si[DLEV].intervals)
-    {
-	pRCAP->pDeliveredEventSet =
-	    RecordCreateSet(si[DLEV].intervals, si[DLEV].nintervals,
-	      (RecordSetPtr)((char *)pRCAP + si[DLEV].offset), si[DLEV].size);
-    }
-    else pRCAP->pDeliveredEventSet = NULL;
-
-    if (nExtReqSets)
-    {
-	pRCAP->pRequestMinOpInfo = (RecordMinorOpPtr)
-					((char *)pRCAP + extReqSetsOffset);
-	pRCAP->pRequestMinOpInfo[0].count = nExtReqSets;
-	for (i = 0; i < nExtReqSets; i++, pExtReqSets++)
-	{
-	    pRCAP->pRequestMinOpInfo[i+1].major.first = pExtReqSets->first;
-	    pRCAP->pRequestMinOpInfo[i+1].major.last  = pExtReqSets->last;
-	    pRCAP->pRequestMinOpInfo[i+1].major.pMinOpSet =
-		RecordCreateSet(pExtReqSets->intervals,
-				pExtReqSets->nintervals, 
-		  (RecordSetPtr)((char *)pRCAP + pExtReqSets->offset),
-				pExtReqSets->size);
-	}
-    }
-    else pRCAP->pRequestMinOpInfo = NULL;
-
-    if (nExtRepSets)
-    {
-	pRCAP->pReplyMinOpInfo = (RecordMinorOpPtr)
-					((char *)pRCAP + extRepSetsOffset);
-	pRCAP->pReplyMinOpInfo[0].count = nExtRepSets;
-	for (i = 0; i < nExtRepSets; i++, pExtRepSets++)
-	{
-	    pRCAP->pReplyMinOpInfo[i+1].major.first = pExtRepSets->first;
-	    pRCAP->pReplyMinOpInfo[i+1].major.last  = pExtRepSets->last;
-	    pRCAP->pReplyMinOpInfo[i+1].major.pMinOpSet =
-		RecordCreateSet(pExtRepSets->intervals,
-				pExtRepSets->nintervals, 
-		  (RecordSetPtr)((char *)pRCAP + pExtRepSets->offset),
-				pExtRepSets->size);
-	}
-    }
-    else pRCAP->pReplyMinOpInfo = NULL;
-
-    pRCAP->clientStarted = clientStarted;
-    pRCAP->clientDied    = clientDied;
-
-    /* link the RCAP onto the context */
-
-    pRCAP->pNextRCAP = pContext->pListOfRCAP;
-    pContext->pListOfRCAP = pRCAP;
-
-    if (pContext->pRecordingClient) /* context enabled */
-	RecordInstallHooks(pRCAP, 0);
-
-bailout:
-    if (si)
-    {
-	for (i = 0; i < maxSets; i++)
-	    free(si[i].intervals);
-	free(si);
-    }
-    if (pCanonClients && pCanonClients != (XID *)&stuff[1])
-	free(pCanonClients);
-    return err;
-} /* RecordRegisterClients */
-
-
-/* Proc functions all take a client argument, execute the request in
- * client->requestBuffer, and return a protocol error status.
- */
-
-static int
-ProcRecordQueryVersion(ClientPtr client)
-{
-    /* REQUEST(xRecordQueryVersionReq); */
-    xRecordQueryVersionReply 	rep;
-    int 		n;
-
-    REQUEST_SIZE_MATCH(xRecordQueryVersionReq);
-    rep.type        	= X_Reply;
-    rep.sequenceNumber 	= client->sequence;
-    rep.length         	= 0;
-    rep.majorVersion  	= SERVER_RECORD_MAJOR_VERSION;
-    rep.minorVersion  	= SERVER_RECORD_MINOR_VERSION;
-    if(client->swapped)
-    {
-    	swaps(&rep.sequenceNumber, n);
-	swaps(&rep.majorVersion, n);
-	swaps(&rep.minorVersion, n);
-    }
-    (void)WriteToClient(client, sizeof(xRecordQueryVersionReply),
-			(char *)&rep);
-    return Success;
-} /* ProcRecordQueryVersion */
-
-
-static int
-ProcRecordCreateContext(ClientPtr client)
-{
-    REQUEST(xRecordCreateContextReq);
-    RecordContextPtr pContext;
-    RecordContextPtr *ppNewAllContexts = NULL;
-    int err = BadAlloc;
-
-    REQUEST_AT_LEAST_SIZE(xRecordCreateContextReq);
-    LEGAL_NEW_RESOURCE(stuff->context, client);
-
-    pContext = (RecordContextPtr)malloc(sizeof(RecordContextRec));
-    if (!pContext)
-	goto bailout;
-
-    /* make sure there is room in ppAllContexts to store the new context */
-
-    ppNewAllContexts = (RecordContextPtr *)
-	realloc(ppAllContexts, sizeof(RecordContextPtr) * (numContexts + 1));
-    if (!ppNewAllContexts)
-	goto bailout;
-    ppAllContexts = ppNewAllContexts;
-
-    pContext->id = stuff->context;
-    pContext->pRecordingClient = NULL;
-    pContext->pListOfRCAP = NULL;
-    pContext->elemHeaders = 0;
-    pContext->bufCategory = 0;
-    pContext->numBufBytes = 0;
-    pContext->pBufClient = NULL;
-    pContext->continuedReply = 0;
-    pContext->inFlush = 0;
-
-    err = RecordRegisterClients(pContext, client,
-				(xRecordRegisterClientsReq *)stuff);
-    if (err != Success)
-	goto bailout;
-
-    if (AddResource(pContext->id, RTContext, pContext))
-    {
-	ppAllContexts[numContexts++] = pContext;
-	return Success;
-    }
-    else
-    {
-	RecordDeleteContext((pointer)pContext, pContext->id);
-	err = BadAlloc;
-    }
-bailout:
-    free(pContext);
-    return err;
-} /* ProcRecordCreateContext */
-
-
-static int
-ProcRecordRegisterClients(ClientPtr client)
-{
-    RecordContextPtr pContext;
-    REQUEST(xRecordRegisterClientsReq);
-
-    REQUEST_AT_LEAST_SIZE(xRecordRegisterClientsReq);
-    VERIFY_CONTEXT(pContext, stuff->context, client);
-
-    return RecordRegisterClients(pContext, client, stuff);
-} /* ProcRecordRegisterClients */
-
-
-static int
-ProcRecordUnregisterClients(ClientPtr client)
-{
-    RecordContextPtr pContext;
-    int err;
-    REQUEST(xRecordUnregisterClientsReq);
-    XID *pCanonClients;
-    int nClients;
-    int i;
-
-    REQUEST_AT_LEAST_SIZE(xRecordUnregisterClientsReq);
-    if ((client->req_len << 2) - SIZEOF(xRecordUnregisterClientsReq) !=
-	4 * stuff->nClients)
-	return BadLength;
-    VERIFY_CONTEXT(pContext, stuff->context, client);
-    err = RecordSanityCheckClientSpecifiers(client, (XID *)&stuff[1],
-					    stuff->nClients, 0);
-    if (err != Success)
-	return err;
-
-    nClients = stuff->nClients;
-    pCanonClients = RecordCanonicalizeClientSpecifiers((XID *)&stuff[1],
-						 &nClients, 0);
-    if (!pCanonClients)
-	return BadAlloc;
-
-    for (i = 0; i < nClients; i++)
-    {
-	RecordDeleteClientFromContext(pContext, pCanonClients[i]);
-    }
-    if (pCanonClients != (XID *)&stuff[1])
-	free(pCanonClients);
-    return Success;
-} /* ProcRecordUnregisterClients */
-
-
-/****************************************************************************/
-
-/* stuff for GetContext */
-
-/* This is a tactical structure used to hold the xRecordRanges as they are
- * being reconstituted from the sets in the RCAPs.
- */
-
-typedef struct {
-    xRecordRange *pRanges;  /* array of xRecordRanges for one RCAP */
-    int size;		/* number of elements in pRanges, >= nRanges */
-    int nRanges;	/* number of occupied element of pRanges */
-} GetContextRangeInfoRec, *GetContextRangeInfoPtr;
-
-
-/* RecordAllocRanges
- *
- * Arguments:
- *	pri is a pointer to a GetContextRangeInfoRec to allocate for.
- *	nRanges is the number of xRecordRanges desired for pri.
- *
- * Returns: BadAlloc if a memory allocation error occurred, else Success.
- *
- * Side Effects:
- *	If Success is returned, pri->pRanges points to at least nRanges
- *	ranges.  pri->nRanges is set to nRanges.  pri->size is the actual
- *	number of ranges.  Newly allocated ranges are zeroed.
- */
-static int
-RecordAllocRanges(GetContextRangeInfoPtr pri, int nRanges)
-{
-    int newsize;
-    xRecordRange *pNewRange;
-#define SZINCR 8
-
-    newsize = max(pri->size + SZINCR, nRanges);
-    pNewRange = (xRecordRange *)realloc(pri->pRanges,
-			 newsize * sizeof(xRecordRange));
-    if (!pNewRange)
-	return BadAlloc;
-
-    pri->pRanges = pNewRange;
-    pri->size = newsize;
-    memset(&pri->pRanges[pri->size - SZINCR], 0, SZINCR * sizeof(xRecordRange));
-    if (pri->nRanges < nRanges)
-	pri->nRanges = nRanges;
-    return Success;
-} /* RecordAllocRanges */
-
-
-/* RecordConvertSetToRanges
- *
- * Arguments:
- *	pSet is the set to be converted.
- *	pri is where the result should be stored.
- *	byteoffset is the offset from the start of an xRecordRange of the
- *	  two vales (first, last) we are interested in.
- *	card8 is TRUE if the vales are one byte each and FALSE if two bytes
- *	  each.
- *	imax is the largest set value to store in pri->pRanges.
- *	pStartIndex, if non-NULL, is the index of the first range in
- *	  pri->pRanges that should be stored to.  If NULL,
- *	  start at index 0.
- *
- * Returns: BadAlloc if a memory allocation error occurred, else Success.
- *
- * Side Effects:
- *	If Success is returned, the slice of pri->pRanges indicated by
- *	byteoffset and card8 is filled in with the intervals from pSet.
- *	if pStartIndex was non-NULL, *pStartIndex is filled in with one
- *	more than the index of the last xRecordRange that was touched.
- */
-static int
-RecordConvertSetToRanges(
-    RecordSetPtr pSet,
-    GetContextRangeInfoPtr pri,
-    int byteoffset,
-    Bool card8,
-    unsigned int imax,
-    int *pStartIndex
-)
-{
-    int nRanges;
-    RecordSetIteratePtr pIter = NULL;
-    RecordSetInterval interval;
-    CARD8 *pCARD8;
-    CARD16 *pCARD16;
-    int err;
-
-    if (!pSet)
-	return Success;
-
-    nRanges = pStartIndex ? *pStartIndex : 0;
-    while ((pIter = RecordIterateSet(pSet, pIter, &interval)))
-    {
-	if (interval.first > imax) break;
-	if (interval.last  > imax) interval.last = imax;
-	nRanges++;
-	if (nRanges > pri->size)
-	{
-	    err = RecordAllocRanges(pri, nRanges);
-	    if (err != Success)
-		return err;
-	}
-	else
-	    pri->nRanges = max(pri->nRanges, nRanges);
-	if (card8)
-	{
-	    pCARD8 = ((CARD8 *)&pri->pRanges[nRanges-1]) + byteoffset;
-	    *pCARD8++ = interval.first;
-	    *pCARD8   = interval.last;
-	}
-	else
-	{
-	    pCARD16 = (CARD16 *)
-			(((char *)&pri->pRanges[nRanges-1]) + byteoffset);
-	    *pCARD16++ = interval.first;
-	    *pCARD16   = interval.last;
-	}
-    }
-    if (pStartIndex)
-	*pStartIndex = nRanges;
-    return Success;
-} /* RecordConvertSetToRanges */
-
-
-/* RecordConvertMinorOpInfoToRanges
- *
- * Arguments:
- *	pMinOpInfo is the minor opcode info to convert to xRecordRanges.
- *	pri is where the result should be stored.
- *	byteoffset is the offset from the start of an xRecordRange of the
- *	  four vales (CARD8 major_first, CARD8 major_last,
- *	  CARD16 minor_first, CARD16 minor_last) we are going to store.
- *
- * Returns: BadAlloc if a memory allocation error occurred, else Success.
- *
- * Side Effects:
- *	If Success is returned, the slice of pri->pRanges indicated by
- *	byteoffset is filled in with the information from pMinOpInfo.
- */
-static int
-RecordConvertMinorOpInfoToRanges(
-    RecordMinorOpPtr pMinOpInfo,
-    GetContextRangeInfoPtr pri,
-    int byteoffset
-)
-{
-    int nsets;
-    int start;
-    int i;
-    int err;
-
-    if (!pMinOpInfo)
-	return Success;
-
-    nsets = pMinOpInfo->count;
-    pMinOpInfo++;
-    start = 0;
-    for (i = 0; i < nsets; i++)
-    {
-	int j, s;
-	s = start;
-	err = RecordConvertSetToRanges(pMinOpInfo[i].major.pMinOpSet, pri,
-				byteoffset + 2, FALSE, 65535, &start);
-	if (err != Success) return err;
-	for (j = s; j < start; j++)
-	{
-	    CARD8 *pCARD8 = ((CARD8 *)&pri->pRanges[j]) + byteoffset;
-	    *pCARD8++ = pMinOpInfo[i].major.first;
-	    *pCARD8   = pMinOpInfo[i].major.last;
-	}
-    }
-    return Success;
-} /* RecordConvertMinorOpInfoToRanges */
-
-
-/* RecordSwapRanges
- *
- * Arguments:
- *	pRanges is an array of xRecordRanges.
- *	nRanges is the number of elements in pRanges.
- *
- * Returns: nothing.
- *
- * Side Effects:
- *	The 16 bit fields of each xRecordRange are byte swapped.
- */
-static void
-RecordSwapRanges(xRecordRange *pRanges, int nRanges)
-{
-    int i;
-    register char n;
-    for (i = 0; i < nRanges; i++, pRanges++)
-    {
-	swaps(&pRanges->extRequestsMinorFirst, n);
-	swaps(&pRanges->extRequestsMinorLast, n);
-	swaps(&pRanges->extRepliesMinorFirst, n);
-	swaps(&pRanges->extRepliesMinorLast, n);
-    }
-} /* RecordSwapRanges */
-
-
-static int
-ProcRecordGetContext(ClientPtr client)
-{
-    RecordContextPtr pContext;
-    REQUEST(xRecordGetContextReq);
-    xRecordGetContextReply rep;
-    int n;
-    RecordClientsAndProtocolPtr pRCAP;
-    int nRCAPs = 0;
-    GetContextRangeInfoPtr pRangeInfo;
-    GetContextRangeInfoPtr pri;
-    int i;
-    int err;
-
-    REQUEST_SIZE_MATCH(xRecordGetContextReq);
-    VERIFY_CONTEXT(pContext, stuff->context, client);
-
-    /* how many RCAPs are there on this context? */
-
-    for (pRCAP = pContext->pListOfRCAP; pRCAP; pRCAP = pRCAP->pNextRCAP)
-	nRCAPs++;
-
-    /* allocate and initialize space for record range info */
-
-    pRangeInfo = (GetContextRangeInfoPtr)malloc(
-				nRCAPs * sizeof(GetContextRangeInfoRec));
-    if (!pRangeInfo && nRCAPs > 0)
-	return BadAlloc;
-    for (i = 0; i < nRCAPs; i++)
-    {
-	pRangeInfo[i].pRanges = NULL;
-	pRangeInfo[i].size = 0;
-	pRangeInfo[i].nRanges = 0;
-    }
-
-    /* convert the RCAP (internal) representation of the recorded protocol
-     * to the wire protocol (external) representation, storing the information
-     * for the ith RCAP in pri[i]
-     */
-
-    for (pRCAP = pContext->pListOfRCAP, pri = pRangeInfo;
-	 pRCAP;
-	 pRCAP = pRCAP->pNextRCAP, pri++)
-    {
-	xRecordRange rr;
-
-	err = RecordConvertSetToRanges(pRCAP->pRequestMajorOpSet, pri,
-			offset_of(rr, coreRequestsFirst), TRUE, 127, NULL);
-	if (err != Success) goto bailout;
-
-	err = RecordConvertSetToRanges(pRCAP->pReplyMajorOpSet, pri,
-			offset_of(rr, coreRepliesFirst), TRUE, 127, NULL);
-	if (err != Success) goto bailout;
-
-	err = RecordConvertSetToRanges(pRCAP->pDeliveredEventSet, pri,
-			offset_of(rr, deliveredEventsFirst), TRUE, 255, NULL);
-	if (err != Success) goto bailout;
-
-	err = RecordConvertSetToRanges(pRCAP->pDeviceEventSet, pri,
-			offset_of(rr, deviceEventsFirst), TRUE, 255, NULL);
-	if (err != Success) goto bailout;
-
-	err = RecordConvertSetToRanges(pRCAP->pErrorSet, pri,
-			      offset_of(rr, errorsFirst), TRUE, 255, NULL);
-	if (err != Success) goto bailout;
-
-	err = RecordConvertMinorOpInfoToRanges(pRCAP->pRequestMinOpInfo,
-				pri, offset_of(rr, extRequestsMajorFirst));
-	if (err != Success) goto bailout;
-
-	err = RecordConvertMinorOpInfoToRanges(pRCAP->pReplyMinOpInfo,
-				pri, offset_of(rr, extRepliesMajorFirst));
-	if (err != Success) goto bailout;
-
-	if (pRCAP->clientStarted || pRCAP->clientDied)
-	{
-	    if (pri->nRanges == 0)
-		RecordAllocRanges(pri, 1);
-	    pri->pRanges[0].clientStarted = pRCAP->clientStarted;
-	    pri->pRanges[0].clientDied    = pRCAP->clientDied;
-	}
-    }
-
-    /* calculate number of clients and reply length */
-
-    rep.nClients = 0;
-    rep.length = 0;
-    for (pRCAP = pContext->pListOfRCAP, pri = pRangeInfo;
-	 pRCAP;
-	 pRCAP = pRCAP->pNextRCAP, pri++)
-    {
-	rep.nClients += pRCAP->numClients;
-	rep.length += pRCAP->numClients *
-		( bytes_to_int32(sizeof(xRecordClientInfo)) +
-		  pri->nRanges * bytes_to_int32(sizeof(xRecordRange)));
-    }
-
-    /* write the reply header */
-
-    rep.type = X_Reply;
-    rep.sequenceNumber 	= client->sequence;
-    rep.enabled = pContext->pRecordingClient != NULL;
-    rep.elementHeader = pContext->elemHeaders;
-    if(client->swapped)
-    {
-    	swaps(&rep.sequenceNumber, n);
-    	swapl(&rep.length, n);
-    	swapl(&rep.nClients, n);
-    }
-    (void)WriteToClient(client, sizeof(xRecordGetContextReply),
-			(char *)&rep);
-
-    /* write all the CLIENT_INFOs */
-
-    for (pRCAP = pContext->pListOfRCAP, pri = pRangeInfo;
-	 pRCAP;
-	 pRCAP = pRCAP->pNextRCAP, pri++)
-    {
-	xRecordClientInfo rci;
-	rci.nRanges = pri->nRanges;
-	if (client->swapped)
-	{
-	    swapl(&rci.nRanges, n);
-	    RecordSwapRanges(pri->pRanges, pri->nRanges);
-	}
-	for (i = 0; i < pRCAP->numClients; i++)
-	{
-	    rci.clientResource = pRCAP->pClientIDs[i];
-	    if (client->swapped) swapl(&rci.clientResource, n);
-	    WriteToClient(client, sizeof(xRecordClientInfo), (char *)&rci);
-	    WriteToClient(client, sizeof(xRecordRange) * pri->nRanges,
-			  (char *)pri->pRanges);
-	}
-    }
-    err = Success;
-
-bailout:
-    for (i = 0; i < nRCAPs; i++)
-    {
-	free(pRangeInfo[i].pRanges);
-    }
-    free(pRangeInfo);
-    return err;
-} /* ProcRecordGetContext */
-
-
-static int
-ProcRecordEnableContext(ClientPtr client)
-{
-    RecordContextPtr pContext;
-    REQUEST(xRecordEnableContextReq);
-    int i;
-    RecordClientsAndProtocolPtr pRCAP;
-
-    REQUEST_SIZE_MATCH(xRecordGetContextReq);
-    VERIFY_CONTEXT(pContext, stuff->context, client);
-    if (pContext->pRecordingClient)
-	return BadMatch; /* already enabled */
-
-    /* install record hooks for each RCAP */
-
-    for (pRCAP = pContext->pListOfRCAP; pRCAP; pRCAP = pRCAP->pNextRCAP)
-    {
-	int err = RecordInstallHooks(pRCAP, 0);
-	if (err != Success)
-	{ /* undo the previous installs */
-	    RecordClientsAndProtocolPtr pUninstallRCAP;
-	    for (pUninstallRCAP = pContext->pListOfRCAP;
-		 pUninstallRCAP != pRCAP;
-		 pUninstallRCAP = pUninstallRCAP->pNextRCAP)
-	    {
-		RecordUninstallHooks(pUninstallRCAP, 0);
-	    }
-	    return err;
-	}
-    }
-
-    /* Disallow further request processing on this connection until
-     * the context is disabled.
-     */
-    IgnoreClient(client);
-    pContext->pRecordingClient = client;
-
-    /* Don't allow the data connection to record itself; unregister it. */
-    RecordDeleteClientFromContext(pContext,
-				  pContext->pRecordingClient->clientAsMask);
-
-    /* move the newly enabled context to the front part of ppAllContexts,
-     * where all the enabled contexts are
-     */
-    i = RecordFindContextOnAllContexts(pContext);
-    assert(i >= numEnabledContexts);
-    if (i != numEnabledContexts)
-    {
-	ppAllContexts[i] = ppAllContexts[numEnabledContexts];
-	ppAllContexts[numEnabledContexts] = pContext;
-    }
-
-    ++numEnabledContexts;
-    assert(numEnabledContexts > 0);
-
-    /* send StartOfData */
-    RecordAProtocolElement(pContext, NULL, XRecordStartOfData, NULL, 0, 0);
-    RecordFlushReplyBuffer(pContext, NULL, 0, NULL, 0);
-    return Success;
-} /* ProcRecordEnableContext */
-
-
-/* RecordDisableContext
- *
- * Arguments:
- *	pContext is the context to disable.
- *	nRanges is the number of elements in pRanges.
- *
- * Returns: nothing.
- *
- * Side Effects:
- *	If the context was enabled, it is disabled.  An EndOfData
- *	message is sent to the recording client.  Recording hooks for
- *	this context are uninstalled.  The context is moved to the
- *	rear part of the ppAllContexts array.  numEnabledContexts is
- *	decremented.  Request processing for the formerly recording client
- *	is resumed.
- */
-static void
-RecordDisableContext(RecordContextPtr pContext)
-{
-    RecordClientsAndProtocolPtr pRCAP;
-    int i;
-
-    if (!pContext->pRecordingClient) return;
-    if (!pContext->pRecordingClient->clientGone)
-    {
-	RecordAProtocolElement(pContext, NULL, XRecordEndOfData, NULL, 0, 0);
-	RecordFlushReplyBuffer(pContext, NULL, 0, NULL, 0);
-	/* Re-enable request processing on this connection. */
-	AttendClient(pContext->pRecordingClient);
-    }
-
-    for (pRCAP = pContext->pListOfRCAP; pRCAP; pRCAP = pRCAP->pNextRCAP)
-    {
-	RecordUninstallHooks(pRCAP, 0);
-    }
-
-    pContext->pRecordingClient = NULL;
-
-    /* move the newly disabled context to the rear part of ppAllContexts,
-     * where all the disabled contexts are
-     */
-    i = RecordFindContextOnAllContexts(pContext);
-    assert( (i != -1) && (i < numEnabledContexts) );
-    if (i != (numEnabledContexts - 1) )
-    {
-	ppAllContexts[i] = ppAllContexts[numEnabledContexts-1];
-	ppAllContexts[numEnabledContexts-1] = pContext;
-    }
-    --numEnabledContexts;
-    assert(numEnabledContexts >= 0);
-} /* RecordDisableContext */
-
-
-static int
-ProcRecordDisableContext(ClientPtr client)
-{
-    RecordContextPtr pContext;
-    REQUEST(xRecordDisableContextReq);
-
-    REQUEST_SIZE_MATCH(xRecordDisableContextReq);
-    VERIFY_CONTEXT(pContext, stuff->context, client);
-    RecordDisableContext(pContext);
-    return Success;
-} /* ProcRecordDisableContext */
-
-
-/* RecordDeleteContext
- *
- * Arguments:
- *	value is the context to delete.
- *	id is its resource ID.
- *
- * Returns: Success.
- *
- * Side Effects:
- *	Disables the context, frees all associated memory, and removes
- *	it from the ppAllContexts array.
- */
-static int
-RecordDeleteContext(pointer value, XID id)
-{
-    int i;
-    RecordContextPtr pContext = (RecordContextPtr)value;
-    RecordClientsAndProtocolPtr pRCAP;
-
-    RecordDisableContext(pContext);
-
-    /*  Remove all the clients from all the RCAPs.
-     *  As a result, the RCAPs will be freed.
-     */
-
-    while ((pRCAP = pContext->pListOfRCAP))
-    {
-	int numClients = pRCAP->numClients;
-	/* when the last client is deleted, the RCAP will go away. */
-	while(numClients--)
-	{
-	    RecordDeleteClientFromRCAP(pRCAP, numClients);
-	}
-    }
-
-    /* remove context from AllContexts list */
-
-    if (-1 != (i = RecordFindContextOnAllContexts(pContext)))
-    {
-	ppAllContexts[i] = ppAllContexts[numContexts - 1];
-	if (--numContexts == 0)
-	{
-	    free(ppAllContexts);
-	    ppAllContexts = NULL;
-	}
-    }
-    free(pContext);
-
-    return Success;
-} /* RecordDeleteContext */
-
-
-static int
-ProcRecordFreeContext(ClientPtr client)
-{
-    RecordContextPtr pContext;
-    REQUEST(xRecordFreeContextReq);
-
-    REQUEST_SIZE_MATCH(xRecordFreeContextReq);
-    VERIFY_CONTEXT(pContext, stuff->context, client);
-    FreeResource(stuff->context, RT_NONE);
-    return Success;
-} /* ProcRecordFreeContext */
-
-
-static int
-ProcRecordDispatch(ClientPtr client)
-{
-    REQUEST(xReq);
-
-    switch (stuff->data)
-    {
-	case X_RecordQueryVersion:
-	    return ProcRecordQueryVersion(client);
-	case X_RecordCreateContext:
-	    return ProcRecordCreateContext(client);
-	case X_RecordRegisterClients:
-	    return ProcRecordRegisterClients(client);
-	case X_RecordUnregisterClients:
-	    return ProcRecordUnregisterClients(client);
-	case X_RecordGetContext:
-	    return ProcRecordGetContext(client);
-	case X_RecordEnableContext:
-	    return ProcRecordEnableContext(client);
-	case X_RecordDisableContext:
-	    return ProcRecordDisableContext(client);
-	case X_RecordFreeContext:
-	    return ProcRecordFreeContext(client);
-       default:
-	    return BadRequest;
-    }
-} /* ProcRecordDispatch */
-
-
-static int
-SProcRecordQueryVersion(ClientPtr client)
-{
-    REQUEST(xRecordQueryVersionReq);
-    register char 	n;
-
-    swaps(&stuff->length, n);
-    REQUEST_SIZE_MATCH(xRecordQueryVersionReq);
-    swaps(&stuff->majorVersion, n);
-    swaps(&stuff->minorVersion,n);
-    return ProcRecordQueryVersion(client);
-} /* SProcRecordQueryVersion */
-
-
-static int
-SwapCreateRegister(xRecordRegisterClientsReq *stuff)
-{
-    register char n;
-    int i;
-    XID *pClientID;
-
-    swapl(&stuff->context, n);
-    swapl(&stuff->nClients, n);
-    swapl(&stuff->nRanges, n);
-    pClientID = (XID *)&stuff[1];
-    if (stuff->nClients > stuff->length - bytes_to_int32(sz_xRecordRegisterClientsReq))
-	return BadLength;
-    for (i = 0; i < stuff->nClients; i++, pClientID++)
-    {
-	swapl(pClientID, n);
-    }
-    if (stuff->nRanges > stuff->length - bytes_to_int32(sz_xRecordRegisterClientsReq)
-	- stuff->nClients)
-	return BadLength;
-    RecordSwapRanges((xRecordRange *)pClientID, stuff->nRanges);
-    return Success;
-} /* SwapCreateRegister */
-
-
-static int
-SProcRecordCreateContext(ClientPtr client)
-{
-    REQUEST(xRecordCreateContextReq);
-    int			status;
-    register char 	n;
-
-    swaps(&stuff->length, n);
-    REQUEST_AT_LEAST_SIZE(xRecordCreateContextReq);
-    if ((status = SwapCreateRegister((pointer)stuff)) != Success)
-	return status;
-    return ProcRecordCreateContext(client);
-} /* SProcRecordCreateContext */
-
-
-static int
-SProcRecordRegisterClients(ClientPtr client)
-{
-    REQUEST(xRecordRegisterClientsReq);
-    int			status;
-    register char 	n;
-
-    swaps(&stuff->length, n);
-    REQUEST_AT_LEAST_SIZE(xRecordRegisterClientsReq);
-    if ((status = SwapCreateRegister((pointer)stuff)) != Success)
-	return status;
-    return ProcRecordRegisterClients(client);
-} /* SProcRecordRegisterClients */
-
-
-static int
-SProcRecordUnregisterClients(ClientPtr client)
-{
-    REQUEST(xRecordUnregisterClientsReq);
-    register char 	n;
-
-    swaps(&stuff->length, n);
-    REQUEST_AT_LEAST_SIZE(xRecordUnregisterClientsReq);
-    swapl(&stuff->context, n);
-    swapl(&stuff->nClients, n);
-    SwapRestL(stuff);
-    return ProcRecordUnregisterClients(client);
-} /* SProcRecordUnregisterClients */
-
-
-static int
-SProcRecordGetContext(ClientPtr client)
-{
-    REQUEST(xRecordGetContextReq);
-    register char 	n;
-
-    swaps(&stuff->length, n);
-    REQUEST_SIZE_MATCH(xRecordGetContextReq);
-    swapl(&stuff->context, n);
-    return ProcRecordGetContext(client);
-} /* SProcRecordGetContext */
-
-static int
-SProcRecordEnableContext(ClientPtr client)
-{
-    REQUEST(xRecordEnableContextReq);
-    register char 	n;
-
-    swaps(&stuff->length, n);
-    REQUEST_SIZE_MATCH(xRecordEnableContextReq);
-    swapl(&stuff->context, n);
-    return ProcRecordEnableContext(client);
-} /* SProcRecordEnableContext */
-
-
-static int
-SProcRecordDisableContext(ClientPtr client)
-{
-    REQUEST(xRecordDisableContextReq);
-    register char 	n;
-
-    swaps(&stuff->length, n);
-    REQUEST_SIZE_MATCH(xRecordDisableContextReq);
-    swapl(&stuff->context, n);
-    return ProcRecordDisableContext(client);
-} /* SProcRecordDisableContext */
-
-
-static int
-SProcRecordFreeContext(ClientPtr client)
-{
-    REQUEST(xRecordFreeContextReq);
-    register char 	n;
-
-    swaps(&stuff->length, n);
-    REQUEST_SIZE_MATCH(xRecordFreeContextReq);
-    swapl(&stuff->context, n);
-    return ProcRecordFreeContext(client);
-} /* SProcRecordFreeContext */
-
-
-static int
-SProcRecordDispatch(ClientPtr client)
-{
-    REQUEST(xReq);
-
-    switch (stuff->data)
-    {
-	case X_RecordQueryVersion:
-	    return SProcRecordQueryVersion(client);
-	case X_RecordCreateContext:
-	    return SProcRecordCreateContext(client);
-	case X_RecordRegisterClients:
-	    return SProcRecordRegisterClients(client);
-	case X_RecordUnregisterClients:
-	    return SProcRecordUnregisterClients(client);
-	case X_RecordGetContext:
-	    return SProcRecordGetContext(client);
-	case X_RecordEnableContext:
-	    return SProcRecordEnableContext(client);
-	case X_RecordDisableContext:
-	    return SProcRecordDisableContext(client);
-	case X_RecordFreeContext:
-	    return SProcRecordFreeContext(client);
-       default:
-	    return BadRequest;
-    }
-} /* SProcRecordDispatch */
-
-/* RecordConnectionSetupInfo
- *
- * Arguments:
- *	pContext is an enabled context that specifies recording of 
- *	  connection setup info.
- *	pci holds the connection setup info.
- *
- * Returns: nothing.
- *
- * Side Effects:
- *	The connection setup info is sent to the recording client.
- */
-static void
-RecordConnectionSetupInfo(RecordContextPtr pContext, NewClientInfoRec *pci)
-{
-    int prefixsize = SIZEOF(xConnSetupPrefix);
-    int restsize = pci->prefix->length * 4;
-
-    if (pci->client->swapped)
-    {
-	char *pConnSetup = (char *)malloc(prefixsize + restsize);
-	if (!pConnSetup)
-	    return;
-	SwapConnSetupPrefix(pci->prefix, (xConnSetupPrefix*)pConnSetup);
-	SwapConnSetupInfo((char*)pci->setup, (char*)(pConnSetup + prefixsize));
-	RecordAProtocolElement(pContext, pci->client, XRecordClientStarted,
-			       (pointer)pConnSetup, prefixsize + restsize, 0);
-	free(pConnSetup);
-    }
-    else
-    {
-	/* don't alloc and copy as in the swapped case; just send the
-	 * data in two pieces
-	 */
-	RecordAProtocolElement(pContext, pci->client, XRecordClientStarted,
-			(pointer)pci->prefix, prefixsize, restsize);
-	RecordAProtocolElement(pContext, pci->client, XRecordClientStarted,
-			(pointer)pci->setup, restsize, /* continuation */ -1);
-    }
-} /* RecordConnectionSetupInfo */
-
-
-/* RecordDeleteContext
- *
- * Arguments:
- *	pcbl is &ClientStateCallback.
- *	nullata is NULL.
- *	calldata is a pointer to a NewClientInfoRec (include/dixstruct.h)
- *	which contains information about client state changes.
- *
- * Returns: nothing.
- *
- * Side Effects:
- *	If a new client has connected and any contexts have specified
- *	XRecordFutureClients, the new client is registered on those contexts.
- *	If any of those contexts specify recording of the connection setup
- *	info, it is recorded.
- *
- *	If an existing client has disconnected, it is deleted from any
- *	contexts that it was registered on.  If any of those contexts
- *	specified XRecordClientDied, they record a ClientDied protocol element.
- *	If the disconnectiong client happened to be the data connection of an
- *	enabled context, the context is disabled.
- */
-
-static void
-RecordAClientStateChange(CallbackListPtr *pcbl, pointer nulldata, pointer calldata)
-{
-    NewClientInfoRec *pci = (NewClientInfoRec *)calldata;
-    int i;
-    ClientPtr pClient = pci->client;
-    RecordContextPtr *ppAllContextsCopy = NULL;
-    int numContextsCopy = 0;
-
-    switch (pClient->clientState)
-    {
-    case ClientStateRunning: /* new client */
-	for (i = 0; i < numContexts; i++)
-	{
-	    RecordClientsAndProtocolPtr pRCAP;
-	    RecordContextPtr pContext = ppAllContexts[i];
-
-	    if ((pRCAP = RecordFindClientOnContext(pContext,
-					    XRecordFutureClients, NULL)))
-	    {
-		RecordAddClientToRCAP(pRCAP, pClient->clientAsMask);
-		if (pContext->pRecordingClient && pRCAP->clientStarted)
-		    RecordConnectionSetupInfo(pContext, pci);
-	    }
-	}
-    break;
-
-    case ClientStateGone:
-    case ClientStateRetained: /* client disconnected */
-
-        /* RecordDisableContext modifies contents of ppAllContexts. */
-	numContextsCopy = numContexts;
-	ppAllContextsCopy = malloc(numContextsCopy * sizeof(RecordContextPtr));
-	assert(ppAllContextsCopy);
-	memcpy(ppAllContextsCopy, ppAllContexts, numContextsCopy * sizeof(RecordContextPtr));
-
-	for (i = 0; i < numContextsCopy; i++)
-	{
-	    RecordClientsAndProtocolPtr pRCAP;
-	    RecordContextPtr pContext = ppAllContextsCopy[i];
-	    int pos;
-
-	    if (pContext->pRecordingClient == pClient)
-		RecordDisableContext(pContext);
-	    if ((pRCAP = RecordFindClientOnContext(pContext,
-				    pClient->clientAsMask, &pos)))
-	    {
-		if (pContext->pRecordingClient && pRCAP->clientDied)
-		    RecordAProtocolElement(pContext, pClient,
-					   XRecordClientDied, NULL, 0, 0);
-		RecordDeleteClientFromRCAP(pRCAP, pos);
-	    }
-	}
-
-	free(ppAllContextsCopy);
-    break;
-
-    default:
-    break;
-    } /* end switch on client state */
-} /* RecordAClientStateChange */
-
-
-/* RecordCloseDown
- *
- * Arguments:
- *	extEntry is the extension information for RECORD.
- *
- * Returns: nothing.
- *
- * Side Effects:
- *	Performs any cleanup needed by RECORD at server shutdown time.
- *	
- */
-static void
-RecordCloseDown(ExtensionEntry *extEntry)
-{
-    DeleteCallback(&ClientStateCallback, RecordAClientStateChange, NULL);
-} /* RecordCloseDown */
-
-
-/* RecordExtensionInit
- *
- * Arguments: none.
- *
- * Returns: nothing.
- *
- * Side Effects:
- *	Enables the RECORD extension if possible.
- */
-void 
-RecordExtensionInit(void)
-{
-    ExtensionEntry *extentry;
-
-    RTContext = CreateNewResourceType(RecordDeleteContext, "RecordContext");
-    if (!RTContext)
-	return;
-
-    if (!dixRegisterPrivateKey(RecordClientPrivateKey, PRIVATE_CLIENT, 0))
-        return;
-
-    ppAllContexts = NULL;
-    numContexts = numEnabledContexts = numEnabledRCAPs = 0;
-
-    if (!AddCallback(&ClientStateCallback, RecordAClientStateChange, NULL))
-	return;
-
-    extentry = AddExtension(RECORD_NAME, RecordNumEvents, RecordNumErrors,
-			    ProcRecordDispatch, SProcRecordDispatch,
-			    RecordCloseDown, StandardMinorOpcode);
-    if (!extentry)
-    {
-	DeleteCallback(&ClientStateCallback, RecordAClientStateChange, NULL);
-	return;
-    }
-    SetResourceTypeErrorValue(RTContext, extentry->errorBase + XRecordBadContext);
-
-} /* RecordExtensionInit */
-
+
+/*
+
+Copyright 1995, 1998  The Open Group
+
+Permission to use, copy, modify, distribute, and sell this software and its
+documentation for any purpose is hereby granted without fee, provided that
+the above copyright notice appear in all copies and that both that
+copyright notice and this permission notice appear in supporting
+documentation.
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+IN NO EVENT SHALL THE OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR
+OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+OTHER DEALINGS IN THE SOFTWARE.
+
+Except as contained in this notice, the name of The Open Group shall
+not be used in advertising or otherwise to promote the sale, use or
+other dealings in this Software without prior written authorization
+from The Open Group.
+
+Author: David P. Wiggins, The Open Group
+
+This work benefited from earlier work done by Martha Zimet of NCD
+and Jim Haggerty of Metheus.
+
+*/
+
+#ifdef HAVE_DIX_CONFIG_H
+#include <dix-config.h>
+#endif
+
+#include "dixstruct.h"
+#include "extnsionst.h"
+#include <X11/extensions/recordproto.h>
+#include "set.h"
+#include "swaprep.h"
+#include "inputstr.h"
+#include "eventconvert.h"
+#include "scrnintstr.h"
+
+
+#include <stdio.h>
+#include <assert.h>
+
+#ifdef PANORAMIX
+#include "globals.h"
+#include "panoramiX.h"
+#include "panoramiXsrv.h"
+#include "cursor.h"
+#endif
+
+#include "protocol-versions.h"
+
+static RESTYPE RTContext;   /* internal resource type for Record contexts */
+
+/* How many bytes of protocol data to buffer in a context. Don't set to less
+ * than 32.
+ */
+#define REPLY_BUF_SIZE 1024
+
+/* Record Context structure */
+
+typedef struct {
+    XID		id;		   /* resource id of context */
+    ClientPtr	pRecordingClient;  /* client that has context enabled */
+    struct _RecordClientsAndProtocolRec *pListOfRCAP; /* all registered info */
+    ClientPtr	pBufClient;	   /* client whose protocol is in replyBuffer*/
+    unsigned int continuedReply:1; /* recording a reply that is split up? */
+    char	elemHeaders;	   /* element header flags (time/seq no.) */
+    char	bufCategory;	   /* category of protocol in replyBuffer */
+    int		numBufBytes;	   /* number of bytes in replyBuffer */
+    char	replyBuffer[REPLY_BUF_SIZE]; /* buffered recorded protocol */
+    int		inFlush;           /*  are we inside RecordFlushReplyBuffer */
+} RecordContextRec, *RecordContextPtr;
+
+/*  RecordMinorOpRec - to hold minor opcode selections for extension requests
+ *  and replies
+ */
+
+typedef union {
+    int count; /* first element of array: how many "major" structs to follow */
+    struct {   /* rest of array elements are this */
+	short first;		/* first major opcode */
+	short last;		/* last major opcode */
+	RecordSetPtr pMinOpSet; /*  minor opcode set for above major range */
+    } major;
+} RecordMinorOpRec, *RecordMinorOpPtr;
+
+
+/*  RecordClientsAndProtocolRec, nicknamed RCAP - holds all the client and 
+ *  protocol selections passed in a single CreateContext or RegisterClients.
+ *  Generally, a context will have one of these from the create and an
+ *  additional one for each RegisterClients.  RCAPs are freed when all their
+ *  clients are unregistered.
+ */
+
+typedef struct _RecordClientsAndProtocolRec {
+    RecordContextPtr pContext;		 /* context that owns this RCAP */
+    struct _RecordClientsAndProtocolRec *pNextRCAP; /* next RCAP on context */
+    RecordSetPtr     pRequestMajorOpSet; /* requests to record */
+    RecordMinorOpPtr pRequestMinOpInfo;  /* extension requests to record */
+    RecordSetPtr     pReplyMajorOpSet;   /* replies to record */
+    RecordMinorOpPtr pReplyMinOpInfo;    /* extension replies to record */
+    RecordSetPtr     pDeviceEventSet;    /* device events to record */
+    RecordSetPtr     pDeliveredEventSet; /* delivered events to record */
+    RecordSetPtr     pErrorSet;          /* errors to record */
+    XID *	     pClientIDs;	 /* array of clients to record */
+    short 	     numClients;	 /* number of clients in pClientIDs */
+    short	     sizeClients;	 /* size of pClientIDs array */
+    unsigned int     clientStarted:1;	 /* record new client connections? */
+    unsigned int     clientDied:1;	 /* record client disconnections? */
+    unsigned int     clientIDsSeparatelyAllocated:1; /* pClientIDs malloced? */
+} RecordClientsAndProtocolRec, *RecordClientsAndProtocolPtr;
+
+/* how much bigger to make pRCAP->pClientIDs when reallocing */
+#define CLIENT_ARRAY_GROWTH_INCREMENT 4
+
+/* counts the total number of RCAPs belonging to enabled contexts. */
+static int numEnabledRCAPs;
+
+/*  void VERIFY_CONTEXT(RecordContextPtr, XID, ClientPtr)
+ *  In the spirit of the VERIFY_* macros in dix.h, this macro fills in
+ *  the context pointer if the given ID is a valid Record Context, else it
+ *  returns an error.
+ */
+#define VERIFY_CONTEXT(_pContext, _contextid, _client) { \
+    int rc = dixLookupResourceByType((pointer *)&(_pContext), _contextid, \
+                                     RTContext, _client, DixUseAccess); \
+    if (rc != Success) \
+	return rc; \
+}
+
+static int RecordDeleteContext(
+    pointer /*value*/,
+    XID /*id*/
+);
+
+void RecordExtensionInit(void);
+
+/***************************************************************************/
+
+/* client private stuff */
+
+/*  To make declarations less obfuscated, have a typedef for a pointer to a
+ *  Proc function.
+ */
+typedef int (*ProcFunctionPtr)(
+    ClientPtr /*pClient*/
+);
+
+/* Record client private.  Generally a client only has one of these if
+ * any of its requests are being recorded.
+ */
+typedef struct {
+/* ptr to client's proc vector before Record stuck its nose in */
+    ProcFunctionPtr *originalVector;   
+					
+/* proc vector with pointers for recorded requests redirected to the
+ * function RecordARequest
+ */
+    ProcFunctionPtr recordVector[256]; 
+} RecordClientPrivateRec, *RecordClientPrivatePtr;
+
+static DevPrivateKeyRec RecordClientPrivateKeyRec;
+#define RecordClientPrivateKey (&RecordClientPrivateKeyRec)
+
+/*  RecordClientPrivatePtr RecordClientPrivate(ClientPtr)
+ *  gets the client private of the given client.  Syntactic sugar.
+ */
+#define RecordClientPrivate(_pClient) (RecordClientPrivatePtr) \
+    dixLookupPrivate(&(_pClient)->devPrivates, RecordClientPrivateKey)
+
+
+/***************************************************************************/
+
+/* global list of all contexts */
+
+static RecordContextPtr *ppAllContexts;
+
+static int numContexts;/* number of contexts in ppAllContexts */
+
+/* number of currently enabled contexts.  All enabled contexts are bunched
+ * up at the front of the ppAllContexts array, from ppAllContexts[0] to
+ * ppAllContexts[numEnabledContexts-1], to eliminate time spent skipping
+ * past disabled contexts.
+ */
+static int numEnabledContexts;
+
+/* RecordFindContextOnAllContexts
+ *
+ * Arguments:
+ *	pContext is the context to search for.
+ *
+ * Returns:
+ *	The index into the array ppAllContexts at which pContext is stored.
+ *	If pContext is not found in ppAllContexts, returns -1.
+ *
+ * Side Effects: none.
+ */
+static int
+RecordFindContextOnAllContexts(RecordContextPtr pContext)
+{
+    int i;
+
+    assert(numContexts >= numEnabledContexts);
+    for (i = 0; i < numContexts; i++)
+    {
+	if (ppAllContexts[i] == pContext)
+	    return i;
+    }
+    return -1;
+} /* RecordFindContextOnAllContexts */
+
+
+/***************************************************************************/
+
+/* RecordFlushReplyBuffer
+ *
+ * Arguments:
+ *	pContext is the context to flush.
+ *	data1 is a pointer to additional data, and len1 is its length in bytes.
+ *	data2 is a pointer to additional data, and len2 is its length in bytes.
+ *
+ * Returns: nothing.
+ *
+ * Side Effects:
+ *	If the context is enabled, any buffered (recorded) protocol is written
+ *	to the recording client, and the number of buffered bytes is set to
+ *	zero.  If len1 is not zero, data1/len1 are then written to the
+ *	recording client, and similarly for data2/len2 (written after
+ *	data1/len1).
+ */
+static void
+RecordFlushReplyBuffer(
+    RecordContextPtr pContext,
+    pointer data1,
+    int len1,
+    pointer data2,
+    int len2
+)
+{
+    if (!pContext->pRecordingClient || pContext->pRecordingClient->clientGone || pContext->inFlush)
+	return;
+    ++pContext->inFlush;
+    if (pContext->numBufBytes)
+	WriteToClient(pContext->pRecordingClient, pContext->numBufBytes,
+		      (char *)pContext->replyBuffer);
+    pContext->numBufBytes = 0;
+    if (len1)
+	WriteToClient(pContext->pRecordingClient, len1, (char *)data1);
+    if (len2)
+	WriteToClient(pContext->pRecordingClient, len2, (char *)data2);
+    --pContext->inFlush;
+} /* RecordFlushReplyBuffer */
+
+
+/* RecordAProtocolElement
+ *
+ * Arguments:
+ *	pContext is the context that is recording a protocol element.
+ *	pClient is the client whose protocol is being recorded.  For
+ *	  device events and EndOfData, pClient is NULL.
+ *	category is the category of the protocol element, as defined
+ *	  by the RECORD spec.
+ *	data is a pointer to the protocol data, and datalen is its length
+ *	  in bytes.
+ *	futurelen is the number of bytes that will be sent in subsequent
+ *	  calls to this function to complete this protocol element.  
+ *	  In those subsequent calls, futurelen will be -1 to indicate
+ *	  that the current data is a continuation of the same protocol
+ *	  element.
+ *
+ * Returns: nothing.
+ *
+ * Side Effects:
+ *	The context may be flushed.  The new protocol element will be
+ *	added to the context's protocol buffer with appropriate element
+ *	headers prepended (sequence number and timestamp).  If the data
+ *	is continuation data (futurelen == -1), element headers won't
+ *	be added.  If the protocol element and headers won't fit in
+ *	the context's buffer, it is sent directly to the recording
+ *	client (after any buffered data).
+ */
+static void
+RecordAProtocolElement(RecordContextPtr pContext, ClientPtr pClient,
+		       int category, pointer data, int datalen, int futurelen)
+{
+    CARD32 elemHeaderData[2];
+    int numElemHeaders = 0;
+    Bool recordingClientSwapped = pContext->pRecordingClient->swapped;
+    int n;
+    CARD32 serverTime = 0;
+    Bool gotServerTime = FALSE;
+    int replylen;
+
+    if (futurelen >= 0)
+    { /* start of new protocol element */
+	xRecordEnableContextReply *pRep = (xRecordEnableContextReply *)
+							pContext->replyBuffer;
+	if (pContext->pBufClient != pClient ||
+	    pContext->bufCategory != category)
+	{
+	    RecordFlushReplyBuffer(pContext, NULL, 0, NULL, 0);
+	    pContext->pBufClient = pClient;
+	    pContext->bufCategory = category;
+	}
+
+	if (!pContext->numBufBytes)
+	{
+	    serverTime = GetTimeInMillis();
+	    gotServerTime = TRUE;
+	    pRep->type          = X_Reply;
+	    pRep->category      = category;
+	    pRep->sequenceNumber = pContext->pRecordingClient->sequence;
+	    pRep->length        = 0;
+	    pRep->elementHeader = pContext->elemHeaders;
+	    pRep->serverTime    = serverTime;
+	    if (pClient)
+	    {
+		pRep->clientSwapped =
+				(pClient->swapped != recordingClientSwapped);
+		pRep->idBase = pClient->clientAsMask;
+		pRep->recordedSequenceNumber = pClient->sequence;
+	    }
+	    else /* it's a device event, StartOfData, or EndOfData */
+	    {
+		pRep->clientSwapped = (category != XRecordFromServer) && 
+						recordingClientSwapped;
+		pRep->idBase = 0;
+		pRep->recordedSequenceNumber = 0;
+	    }
+
+	    if (recordingClientSwapped)
+	    {
+		swaps(&pRep->sequenceNumber, n);
+		swapl(&pRep->length, n);
+		swapl(&pRep->idBase, n);
+		swapl(&pRep->serverTime, n);
+		swapl(&pRep->recordedSequenceNumber, n);
+	    }
+	    pContext->numBufBytes = SIZEOF(xRecordEnableContextReply);
+	}
+
+	/* generate element headers if needed */
+
+	if ( ( (pContext->elemHeaders & XRecordFromClientTime)
+	      && category == XRecordFromClient)
+	    ||
+	    ( (pContext->elemHeaders & XRecordFromServerTime)
+	     && category == XRecordFromServer))
+	{
+	    if (gotServerTime)
+		elemHeaderData[numElemHeaders] = serverTime;
+	    else
+		elemHeaderData[numElemHeaders] = GetTimeInMillis();
+	    if (recordingClientSwapped)
+		swapl(&elemHeaderData[numElemHeaders], n);
+	    numElemHeaders++;
+	}
+
+	if ( (pContext->elemHeaders & XRecordFromClientSequence)
+	    &&
+	    (category == XRecordFromClient || category == XRecordClientDied))
+	{
+	    elemHeaderData[numElemHeaders] = pClient->sequence;
+	    if (recordingClientSwapped)
+		swapl(&elemHeaderData[numElemHeaders], n);
+	    numElemHeaders++;
+	}
+
+	/* adjust reply length */
+
+	replylen = pRep->length;
+	if (recordingClientSwapped) swapl(&replylen, n);
+	replylen += numElemHeaders + bytes_to_int32(datalen) +
+            bytes_to_int32(futurelen);
+	if (recordingClientSwapped) swapl(&replylen, n);
+	pRep->length = replylen;
+    } /* end if not continued reply */
+
+    numElemHeaders *= 4;
+
+    /* if space available >= space needed, buffer the data */
+
+    if (REPLY_BUF_SIZE - pContext->numBufBytes >= datalen + numElemHeaders)
+    {
+	if (numElemHeaders)
+	{
+	    memcpy(pContext->replyBuffer + pContext->numBufBytes,
+		   elemHeaderData, numElemHeaders);
+	    pContext->numBufBytes += numElemHeaders;
+	}
+	if (datalen)
+	{
+	    memcpy(pContext->replyBuffer + pContext->numBufBytes,
+		   data, datalen);
+	    pContext->numBufBytes += datalen;
+	}
+    }
+    else
+	RecordFlushReplyBuffer(pContext, (pointer)elemHeaderData,
+			       numElemHeaders, (pointer)data, datalen);
+
+} /* RecordAProtocolElement */
+
+
+/* RecordFindClientOnContext
+ *
+ * Arguments:
+ *	pContext is the context to search.
+ *	clientspec is the resource ID mask identifying the client to search
+ *	  for, or XRecordFutureClients.
+ *	pposition is a pointer to an int, or NULL.  See Returns.
+ *
+ * Returns:
+ *	The RCAP on which clientspec was found, or NULL if not found on
+ *	any RCAP on the given context.
+ *	If pposition was not NULL and the returned RCAP is not NULL,
+ *	*pposition will be set to the index into the returned the RCAP's
+ *	pClientIDs array that holds clientspec.
+ *
+ * Side Effects: none.
+ */
+static RecordClientsAndProtocolPtr
+RecordFindClientOnContext(
+    RecordContextPtr pContext,
+    XID clientspec,
+    int *pposition
+)
+{
+    RecordClientsAndProtocolPtr pRCAP;
+
+    for (pRCAP = pContext->pListOfRCAP; pRCAP; pRCAP = pRCAP->pNextRCAP)
+    {
+	int i;
+	for (i = 0; i < pRCAP->numClients; i++)
+	{
+	    if (pRCAP->pClientIDs[i] == clientspec)
+	    {
+		if (pposition)
+		    *pposition = i;
+		return pRCAP;
+	    }
+	}
+    }
+    return NULL;
+} /* RecordFindClientOnContext */
+
+
+/* RecordABigRequest
+ *
+ * Arguments:
+ *	pContext is the recording context.
+ *	client is the client being recorded.
+ *	stuff is a pointer to the big request of client (see the Big Requests
+ *	extension for details.)
+ *
+ * Returns: nothing.
+ *
+ * Side Effects:
+ *	The big request is recorded with the correct length field re-inserted.
+ *	
+ * Note: this function exists mainly to make RecordARequest smaller.
+ */
+static void
+RecordABigRequest(RecordContextPtr pContext, ClientPtr client, xReq *stuff)
+{
+    CARD32 bigLength;
+    char n;
+    int bytesLeft;
+
+    /* note: client->req_len has been frobbed by ReadRequestFromClient
+     * (os/io.c) to discount the extra 4 bytes taken by the extended length
+     * field in a big request.  The actual request length to record is
+     * client->req_len + 1 (measured in CARD32s).
+     */
+
+    /* record the request header */
+    bytesLeft = client->req_len << 2;
+    RecordAProtocolElement(pContext, client, XRecordFromClient,
+			   (pointer)stuff, SIZEOF(xReq), bytesLeft);
+
+    /* reinsert the extended length field that was squished out */
+    bigLength = client->req_len + bytes_to_int32(sizeof(bigLength));
+    if (client->swapped)
+	swapl(&bigLength, n);
+    RecordAProtocolElement(pContext, client, XRecordFromClient,
+		(pointer)&bigLength, sizeof(bigLength), /* continuation */ -1);
+    bytesLeft -= sizeof(bigLength);
+
+    /* record the rest of the request after the length */
+    RecordAProtocolElement(pContext, client, XRecordFromClient,
+		(pointer)(stuff + 1), bytesLeft, /* continuation */ -1);
+} /* RecordABigRequest */
+
+
+/* RecordARequest
+ *
+ * Arguments:
+ *	client is a client that the server has dispatched a request to by
+ *	calling client->requestVector[request opcode] .
+ *	The request is in client->requestBuffer.
+ *
+ * Returns:
+ *	Whatever is returned by the "real" Proc function for this request.
+ *	The "real" Proc function is the function that was in
+ *	client->requestVector[request opcode]  before it was replaced by
+ *	RecordARequest.  (See the function RecordInstallHooks.)
+ *
+ * Side Effects:
+ *	The request is recorded by all contexts that have registered this
+ *	request for this client.  The real Proc function is called.
+ */
+static int
+RecordARequest(ClientPtr client)
+{
+    RecordContextPtr pContext;
+    RecordClientsAndProtocolPtr pRCAP;
+    int i;
+    RecordClientPrivatePtr pClientPriv;
+    REQUEST(xReq);
+    int majorop;
+
+    majorop = stuff->reqType;
+    for (i = 0; i < numEnabledContexts; i++)
+    {
+	pContext = ppAllContexts[i];
+	pRCAP = RecordFindClientOnContext(pContext, client->clientAsMask,
+					  NULL);
+	if (pRCAP && pRCAP->pRequestMajorOpSet &&
+	    RecordIsMemberOfSet(pRCAP->pRequestMajorOpSet, majorop))
+	{
+	    if (majorop <= 127)
+	    { /* core request */
+
+		if (stuff->length == 0)
+		    RecordABigRequest(pContext, client, stuff);
+		else
+		    RecordAProtocolElement(pContext, client, XRecordFromClient,
+				(pointer)stuff, client->req_len << 2, 0);
+	    }
+	    else /* extension, check minor opcode */
+	    {
+		int minorop = MinorOpcodeOfRequest(client);
+		int numMinOpInfo;
+		RecordMinorOpPtr pMinorOpInfo = pRCAP->pRequestMinOpInfo;
+
+		assert (pMinorOpInfo);
+		numMinOpInfo = pMinorOpInfo->count;
+		pMinorOpInfo++;
+		assert (numMinOpInfo);
+		for ( ; numMinOpInfo; numMinOpInfo--, pMinorOpInfo++)
+		{
+		    if (majorop >= pMinorOpInfo->major.first &&
+			majorop <= pMinorOpInfo->major.last &&
+			RecordIsMemberOfSet(pMinorOpInfo->major.pMinOpSet,
+					    minorop))
+		    {
+			if (stuff->length == 0)
+			    RecordABigRequest(pContext, client, stuff);
+			else
+			    RecordAProtocolElement(pContext, client, 
+					XRecordFromClient, (pointer)stuff,
+					client->req_len << 2, 0);
+			break;
+		    }			    
+		} /* end for each minor op info */
+	    } /* end extension request */
+	} /* end this RCAP wants this major opcode */
+    } /* end for each context */
+    pClientPriv = RecordClientPrivate(client);
+    assert(pClientPriv);
+    return (* pClientPriv->originalVector[majorop])(client);
+} /* RecordARequest */
+
+/* RecordAReply
+ *
+ * Arguments:
+ *	pcbl is &ReplyCallback.
+ *	nulldata is NULL.
+ *	calldata is a pointer to a ReplyInfoRec (include/os.h)
+ *	  which provides information about replies that are being sent
+ *	  to clients.
+ *
+ * Returns: nothing.
+ *
+ * Side Effects:
+ *	The reply is recorded by all contexts that have registered this
+ *	reply type for this client.  If more data belonging to the same
+ *	reply is expected, and if the reply is being recorded by any
+ *	context, pContext->continuedReply is set to 1.
+ *	If pContext->continuedReply was already 1 and this is the last
+ *	chunk of data belonging to this reply, it is set to 0.
+ */
+static void
+RecordAReply(CallbackListPtr *pcbl, pointer nulldata, pointer calldata)
+{
+    RecordContextPtr pContext;
+    RecordClientsAndProtocolPtr pRCAP;
+    int eci;
+    int majorop;
+    ReplyInfoRec *pri = (ReplyInfoRec *)calldata;
+    ClientPtr client = pri->client;
+    REQUEST(xReq);
+
+    majorop = stuff->reqType;
+    for (eci = 0; eci < numEnabledContexts; eci++)
+    {
+	pContext = ppAllContexts[eci];
+	pRCAP = RecordFindClientOnContext(pContext, client->clientAsMask,
+					  NULL);
+	if (pRCAP)
+	{
+	    if (pContext->continuedReply)
+	    {
+		RecordAProtocolElement(pContext, client, XRecordFromServer,
+		   (pointer)pri->replyData, pri->dataLenBytes, /* continuation */ -1);
+		if (!pri->bytesRemaining)
+		    pContext->continuedReply = 0;
+	    }
+	    else if (pri->startOfReply && pRCAP->pReplyMajorOpSet &&
+		     RecordIsMemberOfSet(pRCAP->pReplyMajorOpSet, majorop))
+	    {
+		if (majorop <= 127)
+		{ /* core reply */
+		    RecordAProtocolElement(pContext, client, XRecordFromServer,
+		       (pointer)pri->replyData, pri->dataLenBytes, pri->bytesRemaining);
+		    if (pri->bytesRemaining)
+			pContext->continuedReply = 1;
+		}
+		else /* extension, check minor opcode */
+		{
+		    int minorop = MinorOpcodeOfRequest(client);
+		    int numMinOpInfo;
+		    RecordMinorOpPtr pMinorOpInfo = pRCAP->pReplyMinOpInfo;
+		    		    assert (pMinorOpInfo);
+		    numMinOpInfo = pMinorOpInfo->count;
+		    pMinorOpInfo++;
+		    assert (numMinOpInfo);
+		    for ( ; numMinOpInfo; numMinOpInfo--, pMinorOpInfo++)
+		    {
+			if (majorop >= pMinorOpInfo->major.first &&
+			    majorop <= pMinorOpInfo->major.last &&
+			    RecordIsMemberOfSet(pMinorOpInfo->major.pMinOpSet,
+						minorop))
+			{
+			    RecordAProtocolElement(pContext, client, 
+				XRecordFromServer, (pointer)pri->replyData,
+				pri->dataLenBytes, pri->bytesRemaining);
+			    if (pri->bytesRemaining)
+				pContext->continuedReply = 1;
+			    break;
+			}			    
+		    } /* end for each minor op info */
+		} /* end extension reply */
+	    } /* end continued reply vs. start of reply */
+	} /* end client is registered on this context */
+    } /* end for each context */
+} /* RecordAReply */
+
+
+/* RecordADeliveredEventOrError
+ *
+ * Arguments:
+ *	pcbl is &EventCallback.
+ *	nulldata is NULL.
+ *	calldata is a pointer to a EventInfoRec (include/dix.h)
+ *	  which provides information about events that are being sent
+ *	  to clients.
+ *
+ * Returns: nothing.
+ *
+ * Side Effects:
+ *	The event or error is recorded by all contexts that have registered
+ *	it for this client.
+ */
+static void
+RecordADeliveredEventOrError(CallbackListPtr *pcbl, pointer nulldata, pointer calldata)
+{
+    EventInfoRec *pei = (EventInfoRec *)calldata;
+    RecordContextPtr pContext;
+    RecordClientsAndProtocolPtr pRCAP;
+    int eci; /* enabled context index */
+    ClientPtr pClient = pei->client;
+
+    for (eci = 0; eci < numEnabledContexts; eci++)
+    {
+	pContext = ppAllContexts[eci];
+	pRCAP = RecordFindClientOnContext(pContext, pClient->clientAsMask,
+					  NULL);
+	if (pRCAP && (pRCAP->pDeliveredEventSet || pRCAP->pErrorSet))
+	{
+	    int ev; /* event index */
+	    xEvent *pev = pei->events;
+	    for (ev = 0; ev < pei->count; ev++, pev++)
+	    {
+		int recordit = 0;
+		if (pRCAP->pErrorSet)
+		{
+		    recordit = RecordIsMemberOfSet(pRCAP->pErrorSet,
+						((xError *)(pev))->errorCode);
+		}
+		else if (pRCAP->pDeliveredEventSet)
+		{
+		    recordit = RecordIsMemberOfSet(pRCAP->pDeliveredEventSet,
+						   pev->u.u.type & 0177);
+		}
+		if (recordit)
+		{
+		    xEvent swappedEvent;
+		    xEvent *pEvToRecord = pev;
+
+		    if (pClient->swapped)
+		    {
+			(*EventSwapVector[pev->u.u.type & 0177])
+			    (pev, &swappedEvent);
+			pEvToRecord = &swappedEvent;
+			
+		    }
+		    RecordAProtocolElement(pContext, pClient,
+			XRecordFromServer, pEvToRecord, SIZEOF(xEvent), 0);
+		}
+	    } /* end for each event */
+	} /* end this client is on this context */
+    } /* end for each enabled context */
+} /* RecordADeliveredEventOrError */
+
+
+static void
+RecordSendProtocolEvents(RecordClientsAndProtocolPtr pRCAP,
+			RecordContextPtr pContext,
+			xEvent* pev, int count)
+{
+    int ev; /* event index */
+
+    for (ev = 0; ev < count; ev++, pev++)
+    {
+	if (RecordIsMemberOfSet(pRCAP->pDeviceEventSet,
+		    pev->u.u.type & 0177))
+	{
+	    xEvent swappedEvent;
+	    xEvent *pEvToRecord = pev;
+#ifdef PANORAMIX
+	    xEvent shiftedEvent;
+
+	    if (!noPanoramiXExtension &&
+		    (pev->u.u.type == MotionNotify ||
+		     pev->u.u.type == ButtonPress ||
+		     pev->u.u.type == ButtonRelease ||
+		     pev->u.u.type == KeyPress ||
+		     pev->u.u.type == KeyRelease)) {
+		int scr = XineramaGetCursorScreen(inputInfo.pointer);
+		memcpy(&shiftedEvent, pev, sizeof(xEvent));
+		shiftedEvent.u.keyButtonPointer.rootX +=
+		    screenInfo.screens[scr]->x -
+		    screenInfo.screens[0]->x;
+		shiftedEvent.u.keyButtonPointer.rootY +=
+		    screenInfo.screens[scr]->y -
+		    screenInfo.screens[0]->y;
+		pEvToRecord = &shiftedEvent;
+	    }
+#endif /* PANORAMIX */
+
+	    if (pContext->pRecordingClient->swapped)
+	    {
+		(*EventSwapVector[pEvToRecord->u.u.type & 0177])
+		    (pEvToRecord, &swappedEvent);
+		pEvToRecord = &swappedEvent;
+	    }
+
+	    RecordAProtocolElement(pContext, NULL,
+		    XRecordFromServer,  pEvToRecord, SIZEOF(xEvent), 0);
+	    /* make sure device events get flushed in the absence
+	     * of other client activity
+	     */
+	    SetCriticalOutputPending();
+	}
+    } /* end for each event */
+
+} /* RecordADeviceEvent */
+
+/* RecordADeviceEvent
+ *
+ * Arguments:
+ *	pcbl is &DeviceEventCallback.
+ *	nulldata is NULL.
+ *	calldata is a pointer to a DeviceEventInfoRec (include/dix.h)
+ *	  which provides information about device events that occur.
+ *
+ * Returns: nothing.
+ *
+ * Side Effects:
+ *	The device event is recorded by all contexts that have registered
+ *	it for this client.
+ */
+static void
+RecordADeviceEvent(CallbackListPtr *pcbl, pointer nulldata, pointer calldata)
+{
+    DeviceEventInfoRec *pei = (DeviceEventInfoRec *)calldata;
+    RecordContextPtr pContext;
+    RecordClientsAndProtocolPtr pRCAP;
+    int eci; /* enabled context index */
+
+    for (eci = 0; eci < numEnabledContexts; eci++)
+    {
+	pContext = ppAllContexts[eci];
+	for (pRCAP = pContext->pListOfRCAP; pRCAP; pRCAP = pRCAP->pNextRCAP)
+	{
+	    if (pRCAP->pDeviceEventSet)
+	    {
+		int count;
+		xEvent *xi_events = NULL;
+
+		/* TODO check return values */
+		if (IsMaster(pei->device))
+		{
+		    xEvent *core_events;
+		    EventToCore(pei->event, &core_events, &count);
+		    RecordSendProtocolEvents(pRCAP, pContext, core_events,
+                                             count);
+		    free(core_events);
+		}
+
+		EventToXI(pei->event, &xi_events, &count);
+		RecordSendProtocolEvents(pRCAP, pContext, xi_events, count);
+		free(xi_events);
+	    } /* end this RCAP selects device events */
+	} /* end for each RCAP on this context */
+    } /* end for each enabled context */
+}
+
+
+/* RecordFlushAllContexts
+ *
+ * Arguments:
+ *	pcbl is &FlushCallback.
+ *	nulldata and calldata are NULL.
+ *
+ * Returns: nothing.
+ *
+ * Side Effects:
+ *	All buffered reply data of all enabled contexts is written to
+ *	the recording clients.
+ */
+static void
+RecordFlushAllContexts(
+    CallbackListPtr *pcbl,
+    pointer nulldata,
+    pointer calldata
+)
+{
+    int eci; /* enabled context index */
+    RecordContextPtr pContext;
+
+    for (eci = 0; eci < numEnabledContexts; eci++)
+    {
+	pContext = ppAllContexts[eci];
+
+	/* In most cases we leave it to RecordFlushReplyBuffer to make
+	 * this check, but this function could be called very often, so we
+	 * check before calling hoping to save the function call cost
+	 * most of the time.
+	 */
+	if (pContext->numBufBytes)
+	    RecordFlushReplyBuffer(ppAllContexts[eci], NULL, 0, NULL, 0);
+    }
+} /* RecordFlushAllContexts */
+
+
+/* RecordInstallHooks
+ *
+ * Arguments:
+ *	pRCAP is an RCAP on an enabled or being-enabled context.
+ *	oneclient can be zero or the resource ID mask identifying a client.
+ *
+ * Returns: BadAlloc if a memory allocation error occurred, else Success.
+ *
+ * Side Effects:
+ *	Recording hooks needed by RCAP are installed.
+ *	If oneclient is zero, recording hooks needed for all clients and
+ *	protocol on the RCAP are installed.  If oneclient is non-zero,
+ *	only those hooks needed for the specified client are installed.
+ *	
+ *	Client requestVectors may be altered.  numEnabledRCAPs will be
+ *	incremented if oneclient == 0.  Callbacks may be added to
+ *	various callback lists.
+ */
+static int
+RecordInstallHooks(RecordClientsAndProtocolPtr pRCAP, XID oneclient)
+{
+    int i = 0;
+    XID client;
+
+    if (oneclient)
+	client = oneclient;
+    else
+	client = pRCAP->numClients ? pRCAP->pClientIDs[i++] : 0;
+
+    while (client)
+    {
+	if (client != XRecordFutureClients)
+	{
+	    if (pRCAP->pRequestMajorOpSet)
+	    {
+		RecordSetIteratePtr pIter = NULL;
+		RecordSetInterval interval;
+		ClientPtr pClient = clients[CLIENT_ID(client)];
+
+		if (pClient && !RecordClientPrivate(pClient))
+		{
+		    RecordClientPrivatePtr pClientPriv;
+		    /* no Record proc vector; allocate one */
+		    pClientPriv = (RecordClientPrivatePtr)
+				malloc(sizeof(RecordClientPrivateRec));
+		    if (!pClientPriv)
+			return BadAlloc;
+		    /* copy old proc vector to new */
+		    memcpy(pClientPriv->recordVector, pClient->requestVector, 
+			   sizeof (pClientPriv->recordVector));
+		    pClientPriv->originalVector = pClient->requestVector;
+		    dixSetPrivate(&pClient->devPrivates,
+				  RecordClientPrivateKey, pClientPriv);
+		    pClient->requestVector = pClientPriv->recordVector;
+		}
+		while ((pIter = RecordIterateSet(pRCAP->pRequestMajorOpSet,
+						pIter, &interval)))
+		{
+		    unsigned int j;
+		    for (j = interval.first; j <= interval.last; j++)
+			pClient->requestVector[j] = RecordARequest;
+		}
+	    }
+	}
+	if (oneclient)
+	    client = 0;
+	else
+	    client = (i < pRCAP->numClients) ? pRCAP->pClientIDs[i++] : 0;
+    }
+
+    assert(numEnabledRCAPs >= 0);
+    if (!oneclient && ++numEnabledRCAPs == 1)
+    { /* we're enabling the first context */
+	if (!AddCallback(&EventCallback, RecordADeliveredEventOrError, NULL))
+	    return BadAlloc;
+	if (!AddCallback(&DeviceEventCallback, RecordADeviceEvent, NULL))
+	    return BadAlloc;
+	if (!AddCallback(&ReplyCallback, RecordAReply, NULL))
+	    return BadAlloc;
+	if (!AddCallback(&FlushCallback, RecordFlushAllContexts, NULL))
+	    return BadAlloc;
+	/* Alternate context flushing scheme: delete the line above
+	 * and call RegisterBlockAndWakeupHandlers here passing
+	 * RecordFlushAllContexts.  Is this any better?
+	 */
+    }
+    return Success;
+} /* RecordInstallHooks */
+
+
+/* RecordUninstallHooks
+ *
+ * Arguments:
+ *	pRCAP is an RCAP on an enabled or being-disabled context.
+ *	oneclient can be zero or the resource ID mask identifying a client.
+ *
+ * Returns: nothing.
+ *
+ * Side Effects:
+ *	Recording hooks needed by RCAP may be uninstalled.
+ *	If oneclient is zero, recording hooks needed for all clients and
+ *	protocol on the RCAP may be uninstalled.  If oneclient is non-zero,
+ *	only those hooks needed for the specified client may be uninstalled.
+ *	
+ *	Client requestVectors may be altered.  numEnabledRCAPs will be
+ *	decremented if oneclient == 0.  Callbacks may be deleted from
+ *	various callback lists.
+ */
+static void
+RecordUninstallHooks(RecordClientsAndProtocolPtr pRCAP, XID oneclient)
+{
+    int i = 0;
+    XID client;
+
+    if (oneclient)
+	client = oneclient;
+    else
+	client = pRCAP->numClients ? pRCAP->pClientIDs[i++] : 0;
+
+    while (client)
+    {
+	if (client != XRecordFutureClients)
+	{
+	    if (pRCAP->pRequestMajorOpSet)
+	    {
+		ClientPtr pClient = clients[CLIENT_ID(client)];
+		int c;
+		Bool otherRCAPwantsProcVector = FALSE;
+		RecordClientPrivatePtr pClientPriv = NULL;
+
+		assert (pClient);
+		pClientPriv = RecordClientPrivate(pClient);
+		assert (pClientPriv);
+		memcpy(pClientPriv->recordVector, pClientPriv->originalVector,
+		       sizeof (pClientPriv->recordVector));
+
+		for (c = 0; c < numEnabledContexts; c++)
+		{
+		    RecordClientsAndProtocolPtr pOtherRCAP;
+		    RecordContextPtr pContext = ppAllContexts[c];
+
+		    if (pContext == pRCAP->pContext) continue;
+		    pOtherRCAP = RecordFindClientOnContext(pContext, client,
+							   NULL);
+		    if (pOtherRCAP && pOtherRCAP->pRequestMajorOpSet)
+		    {
+			RecordSetIteratePtr pIter = NULL;
+			RecordSetInterval interval;
+
+			otherRCAPwantsProcVector = TRUE;
+			while ((pIter = RecordIterateSet(
+						pOtherRCAP->pRequestMajorOpSet,
+						pIter, &interval)))
+			{
+			    unsigned int j;
+			    for (j = interval.first; j <= interval.last; j++)
+				pClient->requestVector[j] = RecordARequest;
+			}
+		    }
+		}
+		if (!otherRCAPwantsProcVector)
+		{ /* nobody needs it, so free it */
+		    pClient->requestVector = pClientPriv->originalVector;
+		    dixSetPrivate(&pClient->devPrivates,
+				  RecordClientPrivateKey, NULL);
+		    free(pClientPriv);
+		}
+	    } /* end if this RCAP specifies any requests */
+	} /* end if not future clients */
+	if (oneclient)
+	    client = 0;
+	else
+	    client = (i < pRCAP->numClients) ? pRCAP->pClientIDs[i++] : 0;
+    }
+
+    assert(numEnabledRCAPs >= 1);
+    if (!oneclient && --numEnabledRCAPs == 0)
+    { /* we're disabling the last context */
+	DeleteCallback(&EventCallback, RecordADeliveredEventOrError, NULL);
+	DeleteCallback(&DeviceEventCallback, RecordADeviceEvent, NULL);
+	DeleteCallback(&ReplyCallback, RecordAReply, NULL);
+	DeleteCallback(&FlushCallback, RecordFlushAllContexts, NULL);
+	/* Alternate context flushing scheme: delete the line above
+	 * and call RemoveBlockAndWakeupHandlers here passing
+	 * RecordFlushAllContexts.  Is this any better?
+	 */
+	/* Having deleted the callback, call it one last time. -gildea */
+	RecordFlushAllContexts(&FlushCallback, NULL, NULL);
+    }
+} /* RecordUninstallHooks */
+
+
+/* RecordDeleteClientFromRCAP
+ *
+ * Arguments:
+ *	pRCAP is an RCAP to delete the client from.
+ *	position is the index into the array pRCAP->pClientIDs of the
+ *	client to delete.
+ *
+ * Returns: nothing.
+ *
+ * Side Effects:
+ *	Recording hooks needed by client will be uninstalled if the context
+ *	is enabled.  The designated client will be removed from the 
+ *	pRCAP->pClientIDs array.  If it was the only client on the RCAP, 
+ *	the RCAP is removed from the context and freed.  (Invariant: RCAPs
+ *	have at least one client.)
+ */
+static void
+RecordDeleteClientFromRCAP(RecordClientsAndProtocolPtr pRCAP, int position)
+{
+    if (pRCAP->pContext->pRecordingClient)
+	RecordUninstallHooks(pRCAP, pRCAP->pClientIDs[position]);
+    if (position != pRCAP->numClients - 1)
+	pRCAP->pClientIDs[position] = pRCAP->pClientIDs[pRCAP->numClients - 1];
+    if (--pRCAP->numClients == 0)
+    {	/* no more clients; remove RCAP from context's list */
+	RecordContextPtr pContext = pRCAP->pContext;
+	if (pContext->pRecordingClient)
+	    RecordUninstallHooks(pRCAP, 0);
+	if (pContext->pListOfRCAP == pRCAP)
+	    pContext->pListOfRCAP = pRCAP->pNextRCAP;
+	else
+	{
+	    RecordClientsAndProtocolPtr prevRCAP;
+	    for (prevRCAP = pContext->pListOfRCAP;
+		 prevRCAP->pNextRCAP != pRCAP;
+		 prevRCAP = prevRCAP->pNextRCAP)
+		;
+	    prevRCAP->pNextRCAP = pRCAP->pNextRCAP;
+	}
+	/* free the RCAP */
+	if (pRCAP->clientIDsSeparatelyAllocated)
+	    free(pRCAP->pClientIDs);
+	free(pRCAP);
+    }
+} /* RecordDeleteClientFromRCAP */
+
+
+/* RecordAddClientToRCAP
+ *
+ * Arguments:
+ *	pRCAP is an RCAP to add the client to.
+ *	clientspec is the resource ID mask identifying a client, or
+ *	  XRecordFutureClients.
+ *
+ * Returns: nothing.
+ *
+ * Side Effects:
+ *	Recording hooks needed by client will be installed if the context
+ *	is enabled.  The designated client will be added to the 
+ *	pRCAP->pClientIDs array, which may be realloced.
+ *	pRCAP->clientIDsSeparatelyAllocated may be set to 1 if there
+ *	is no more room to hold clients internal to the RCAP.
+ */
+static void
+RecordAddClientToRCAP(RecordClientsAndProtocolPtr pRCAP, XID clientspec)
+{
+    if (pRCAP->numClients == pRCAP->sizeClients)
+    {
+	if (pRCAP->clientIDsSeparatelyAllocated)
+	{
+	    XID *pNewIDs = (XID *)realloc(pRCAP->pClientIDs,
+			(pRCAP->sizeClients + CLIENT_ARRAY_GROWTH_INCREMENT) *
+								sizeof(XID));
+	    if (!pNewIDs)
+		return;
+	    pRCAP->pClientIDs = pNewIDs;
+	    pRCAP->sizeClients += CLIENT_ARRAY_GROWTH_INCREMENT;
+	}
+	else
+	{
+	    XID *pNewIDs = (XID *)malloc((pRCAP->sizeClients +
+				CLIENT_ARRAY_GROWTH_INCREMENT) * sizeof(XID));
+	    if (!pNewIDs)
+		return;
+	    memcpy(pNewIDs, pRCAP->pClientIDs, pRCAP->numClients *sizeof(XID));
+	    pRCAP->pClientIDs = pNewIDs;
+	    pRCAP->sizeClients += CLIENT_ARRAY_GROWTH_INCREMENT;
+	    pRCAP->clientIDsSeparatelyAllocated = 1;
+	}
+    }
+    pRCAP->pClientIDs[pRCAP->numClients++] = clientspec;
+    if (pRCAP->pContext->pRecordingClient)
+	RecordInstallHooks(pRCAP, clientspec);
+} /* RecordDeleteClientFromRCAP */
+
+
+/* RecordDeleteClientFromContext
+ *
+ * Arguments:
+ *	pContext is the context to delete from.
+ *	clientspec is the resource ID mask identifying a client, or
+ *	  XRecordFutureClients.
+ *
+ * Returns: nothing.
+ *
+ * Side Effects:
+ *	If clientspec is on any RCAP of the context, it is deleted from that
+ *	RCAP.  (A given clientspec can only be on one RCAP of a context.)
+ */
+static void
+RecordDeleteClientFromContext(RecordContextPtr pContext, XID clientspec)
+{
+    RecordClientsAndProtocolPtr pRCAP;
+    int position;
+
+    if ((pRCAP = RecordFindClientOnContext(pContext, clientspec, &position)))
+	RecordDeleteClientFromRCAP(pRCAP, position);
+} /* RecordDeleteClientFromContext */
+
+
+/* RecordSanityCheckClientSpecifiers
+ *
+ * Arguments:
+ *	clientspecs is an array of alleged CLIENTSPECs passed by the client.
+ *	nspecs is the number of elements in clientspecs.
+ *	errorspec, if non-zero, is the resource id base of a client that
+ *	  must not appear in clienspecs.
+ *
+ * Returns: BadMatch if any of the clientspecs are invalid, else Success.
+ *
+ * Side Effects: none.
+ */
+static int
+RecordSanityCheckClientSpecifiers(ClientPtr client, XID *clientspecs, int nspecs, XID errorspec)
+{
+    int i;
+    int clientIndex;
+    int rc;
+    pointer value;
+
+    for (i = 0; i < nspecs; i++)
+    {
+	if (clientspecs[i] == XRecordCurrentClients ||
+	    clientspecs[i] == XRecordFutureClients ||
+	    clientspecs[i] == XRecordAllClients)
+	    continue;
+	if (errorspec && (CLIENT_BITS(clientspecs[i]) == errorspec) )
+	    return BadMatch;
+	clientIndex = CLIENT_ID(clientspecs[i]);
+	if (clientIndex && clients[clientIndex] &&
+	    clients[clientIndex]->clientState == ClientStateRunning)
+	{
+	    if (clientspecs[i] == clients[clientIndex]->clientAsMask)
+		continue;
+            rc = dixLookupResourceByClass(&value, clientspecs[i], RC_ANY,
+                                          client, DixGetAttrAccess);
+            if (rc != Success)
+                return rc;
+	}
+	else
+	    return BadMatch;
+    }
+    return Success;
+} /* RecordSanityCheckClientSpecifiers */
+
+
+/* RecordCanonicalizeClientSpecifiers
+ *
+ * Arguments:
+ *	pClientspecs is an array of CLIENTSPECs that have been sanity
+ *	  checked.
+ *	pNumClientspecs is a pointer to the number of elements in pClientspecs.
+ *	excludespec, if non-zero, is the resource id base of a client that 
+ *	  should not be included in the expansion of XRecordAllClients or 
+ *	  XRecordCurrentClients.
+ *
+ * Returns:
+ *	A pointer to an array of CLIENTSPECs that is the same as the
+ *	passed array with the following modifications:
+ *	  - all but the client id bits of resource IDs are stripped off.
+ *	  - duplicates removed.
+ *	  - XRecordAllClients expanded to a list of all currently connected
+ *	    clients + XRecordFutureClients - excludespec (if non-zero)
+ *	  - XRecordCurrentClients expanded to a list of all currently
+ *	    connected clients - excludespec (if non-zero)
+ *	The returned array may be the passed array modified in place, or
+ *	it may be an malloc'ed array.  The caller should keep a pointer to the
+ *	original array and free the returned array if it is different.
+ *
+ *	*pNumClientspecs is set to the number of elements in the returned
+ *	array.
+ *
+ * Side Effects:
+ *	pClientspecs may be modified in place.
+ */
+static XID *
+RecordCanonicalizeClientSpecifiers(XID *pClientspecs, int *pNumClientspecs, XID excludespec)
+{
+    int i;
+    int numClients = *pNumClientspecs;
+
+    /*  first pass strips off the resource index bits, leaving just the
+     *  client id bits.  This makes searching for a particular client simpler
+     *  (and faster.)
+     */
+    for (i = 0; i < numClients; i++)
+    {
+	XID cs = pClientspecs[i];
+	if (cs > XRecordAllClients)
+	    pClientspecs[i] = CLIENT_BITS(cs);
+    }
+
+    for (i = 0; i < numClients; i++)
+    {
+	if (pClientspecs[i] == XRecordAllClients ||
+	    pClientspecs[i] == XRecordCurrentClients)
+	{ /* expand All/Current */
+	    int j, nc;
+	    XID *pCanon = (XID *)malloc(sizeof(XID) * (currentMaxClients + 1));
+	    if (!pCanon) return NULL;
+	    for (nc = 0, j = 1; j < currentMaxClients; j++)
+	    {
+		ClientPtr client = clients[j];
+		if (client != NullClient &&
+		    client->clientState == ClientStateRunning &&
+		    client->clientAsMask != excludespec)
+		{
+		    pCanon[nc++] = client->clientAsMask;
+		}
+	    }
+	    if (pClientspecs[i] == XRecordAllClients)
+		pCanon[nc++] = XRecordFutureClients;
+	    *pNumClientspecs = nc;
+	    return pCanon;
+	}
+	else /* not All or Current */
+	{
+	    int j;
+	    for (j = i + 1; j < numClients; )
+	    {
+		if (pClientspecs[i] == pClientspecs[j])
+		{
+		    pClientspecs[j] = pClientspecs[--numClients];
+		}
+		else
+		    j++;
+	    }
+	}
+    } /* end for each clientspec */
+    *pNumClientspecs = numClients;
+    return pClientspecs;
+} /* RecordCanonicalizeClientSpecifiers */
+
+
+/****************************************************************************/
+
+/* stuff for RegisterClients */
+
+/* RecordPadAlign
+ *
+ * Arguments:
+ *	size is the number of bytes taken by an object.
+ *	align is a byte boundary (e.g. 4, 8)
+ *
+ * Returns:
+ *	the number of pad bytes to add at the end of an object of the
+ *	given size so that an object placed immediately behind it will
+ *	begin on an <align>-byte boundary.
+ *
+ * Side Effects: none.
+ */
+static int
+RecordPadAlign(int size, int align)
+{
+    return (align - (size & (align - 1))) & (align - 1);
+} /* RecordPadAlign */
+
+
+/* RecordSanityCheckRegisterClients
+ *
+ * Arguments:
+ *	pContext is the context being registered on.
+ *	client is the client that issued a RecordCreateContext or
+ *	  RecordRegisterClients request.
+ *	stuff is a pointer to the request.
+ *
+ * Returns:
+ *	Any one of several possible error values if any of the request
+ *	arguments are invalid.  Success if everything is OK.
+ *
+ * Side Effects: none.
+ */
+static int
+RecordSanityCheckRegisterClients(RecordContextPtr pContext, ClientPtr client, xRecordRegisterClientsReq *stuff)
+{
+    int err;
+    xRecordRange *pRange;
+    int i;
+    XID recordingClient;
+
+    if (((client->req_len << 2) - SIZEOF(xRecordRegisterClientsReq)) !=
+	4 * stuff->nClients + SIZEOF(xRecordRange) * stuff->nRanges)
+	return BadLength;
+
+    if (stuff->elementHeader &
+     ~(XRecordFromClientSequence|XRecordFromClientTime|XRecordFromServerTime))
+    {
+	client->errorValue = stuff->elementHeader;
+	return BadValue;
+    }
+
+    recordingClient = pContext->pRecordingClient ?
+		      pContext->pRecordingClient->clientAsMask : 0;
+    err = RecordSanityCheckClientSpecifiers(client, (XID *)&stuff[1],
+					    stuff->nClients, recordingClient);
+    if (err != Success) return err;
+
+    pRange = (xRecordRange *)(((XID *)&stuff[1]) + stuff->nClients);
+    for (i = 0; i < stuff->nRanges; i++, pRange++)
+    {
+	if (pRange->coreRequestsFirst > pRange->coreRequestsLast)
+	{
+	    client->errorValue = pRange->coreRequestsFirst;
+	    return BadValue;
+	}
+	if (pRange->coreRepliesFirst > pRange->coreRepliesLast)
+	{
+	    client->errorValue = pRange->coreRepliesFirst;
+	    return BadValue;
+	}
+	if ((pRange->extRequestsMajorFirst || pRange->extRequestsMajorLast) &&
+	    (pRange->extRequestsMajorFirst < 128 ||
+	     pRange->extRequestsMajorLast < 128 ||
+	     pRange->extRequestsMajorFirst > pRange->extRequestsMajorLast))
+	{
+	    client->errorValue = pRange->extRequestsMajorFirst;
+	    return BadValue;
+	}
+	if (pRange->extRequestsMinorFirst > pRange->extRequestsMinorLast)
+	{
+	    client->errorValue = pRange->extRequestsMinorFirst;
+	    return BadValue;
+	}
+	if ((pRange->extRepliesMajorFirst || pRange->extRepliesMajorLast) &&
+	    (pRange->extRepliesMajorFirst < 128 ||
+	     pRange->extRepliesMajorLast < 128 ||
+	     pRange->extRepliesMajorFirst > pRange->extRepliesMajorLast))
+	{
+	    client->errorValue = pRange->extRepliesMajorFirst;
+	    return BadValue;
+	}
+	if (pRange->extRepliesMinorFirst > pRange->extRepliesMinorLast)
+	{
+	    client->errorValue = pRange->extRepliesMinorFirst;
+	    return BadValue;
+	}
+	if ((pRange->deliveredEventsFirst || pRange->deliveredEventsLast) &&
+	    (pRange->deliveredEventsFirst < 2 ||
+	     pRange->deliveredEventsLast < 2 ||
+	     pRange->deliveredEventsFirst > pRange->deliveredEventsLast))
+	{
+	    client->errorValue = pRange->deliveredEventsFirst;
+	    return BadValue;
+	}
+	if ((pRange->deviceEventsFirst || pRange->deviceEventsLast) &&
+	    (pRange->deviceEventsFirst < 2 ||
+	     pRange->deviceEventsLast < 2 ||
+	     pRange->deviceEventsFirst > pRange->deviceEventsLast))
+	{
+	    client->errorValue = pRange->deviceEventsFirst;
+	    return BadValue;
+	}
+	if (pRange->errorsFirst > pRange->errorsLast)
+	{
+	    client->errorValue = pRange->errorsFirst;
+	    return BadValue;
+	}
+	if (pRange->clientStarted != xFalse && pRange->clientStarted != xTrue)
+	{
+	    client->errorValue = pRange->clientStarted;
+	    return BadValue;
+	}
+	if (pRange->clientDied != xFalse && pRange->clientDied != xTrue)
+	{
+	    client->errorValue = pRange->clientDied;
+	    return BadValue;
+	}
+    } /* end for each range */
+    return Success;
+} /* end RecordSanityCheckRegisterClients */
+
+/* This is a tactical structure used to gather information about all the sets
+ * (RecordSetPtr) that need to be created for an RCAP in the process of 
+ * digesting a list of RECORDRANGEs (converting it to the internal
+ * representation).
+ */
+typedef struct
+{
+    int nintervals;	/* number of intervals in following array */
+    RecordSetInterval *intervals;  /* array of intervals for this set */
+    int size;		/* size of intevals array; >= nintervals */
+    int align;		/* alignment restriction for set */
+    int offset;		/* where to store set pointer rel. to start of RCAP */
+    short first, last;	/* if for extension, major opcode interval */
+} SetInfoRec, *SetInfoPtr;
+
+/* These constant are used to index into an array of SetInfoRec. */
+enum {REQ,	/* set info for requests */
+      REP,	/* set info for replies */
+      ERR,	/* set info for errors */
+      DEV,	/* set info for device events */
+      DLEV,	/* set info for delivered events */
+      PREDEFSETS};  /* number of predefined array entries */
+
+
+/* RecordAllocIntervals
+ *
+ * Arguments:
+ *	psi is a pointer to a SetInfoRec whose intervals pointer is NULL.
+ *	nIntervals is the desired size of the intervals array.
+ *
+ * Returns: BadAlloc if a memory allocation error occurred, else Success.
+ *
+ * Side Effects:
+ *	If Success is returned, psi->intervals is a pointer to size
+ *	RecordSetIntervals, all zeroed, and psi->size is set to size.
+ */
+static int
+RecordAllocIntervals(SetInfoPtr psi, int nIntervals)
+{
+    assert(!psi->intervals);
+    psi->intervals = (RecordSetInterval *)
+			malloc(nIntervals * sizeof(RecordSetInterval));
+    if (!psi->intervals)
+	return BadAlloc;
+    memset(psi->intervals, 0, nIntervals * sizeof(RecordSetInterval));
+    psi->size = nIntervals;
+    return Success;
+} /* end RecordAllocIntervals */
+
+
+/* RecordConvertRangesToIntervals
+ *
+ * Arguments:
+ *	psi is a pointer to the SetInfoRec we are building.
+ *	pRanges is an array of xRecordRanges.
+ *	nRanges is the number of elements in pRanges.
+ *	byteoffset is the offset from the start of an xRecordRange of the
+ *	  two bytes (1 for first, 1 for last) we are interested in.
+ *	pExtSetInfo, if non-NULL, indicates that the two bytes mentioned
+ *	  above are followed by four bytes (2 for first, 2 for last)
+ *	  representing a minor opcode range, and this information should be
+ *	  stored in one of the SetInfoRecs starting at pExtSetInfo.
+ *	pnExtSetInfo is the number of elements in the pExtSetInfo array.
+ *
+ * Returns:  BadAlloc if a memory allocation error occurred, else Success.
+ *
+ * Side Effects:
+ *	The slice of pRanges indicated by byteoffset is stored in psi.  
+ *	If pExtSetInfo is non-NULL, minor opcode intervals are stored
+ *	in an existing SetInfoRec if the major opcode interval matches, else
+ *	they are stored in a new SetInfoRec, and *pnExtSetInfo is
+ *	increased accordingly.
+ */
+static int
+RecordConvertRangesToIntervals(
+    SetInfoPtr psi,
+    xRecordRange *pRanges,
+    int nRanges,
+    int byteoffset,
+    SetInfoPtr pExtSetInfo,
+    int *pnExtSetInfo
+)
+{
+    int i;
+    CARD8 *pCARD8;
+    int first, last;
+    int err;
+
+    for (i = 0; i < nRanges; i++, pRanges++)
+    {
+	pCARD8 = ((CARD8 *)pRanges) + byteoffset;
+	first = pCARD8[0];
+	last  = pCARD8[1];
+	if (first || last)
+	{
+	    if (!psi->intervals)
+	    {
+		err = RecordAllocIntervals(psi, 2 * (nRanges - i));
+		if (err != Success)
+		    return err;
+	    }
+	    psi->intervals[psi->nintervals].first = first;
+	    psi->intervals[psi->nintervals].last  = last;
+	    psi->nintervals++;
+	    assert(psi->nintervals <= psi->size);
+	    if (pExtSetInfo)
+	    {
+		SetInfoPtr pesi = pExtSetInfo;
+		CARD16 *pCARD16 = (CARD16 *)(pCARD8 + 2);
+		int j;
+
+		for (j = 0; j < *pnExtSetInfo; j++, pesi++)
+		{
+		    if ( (first == pesi->first) && (last == pesi->last) )
+			break;
+		}
+		if (j == *pnExtSetInfo)
+		{
+		    err = RecordAllocIntervals(pesi, 2 * (nRanges - i));
+		    if (err != Success)
+			return err;
+		    pesi->first = first;
+		    pesi->last  = last;
+		    (*pnExtSetInfo)++;
+		}
+		pesi->intervals[pesi->nintervals].first = pCARD16[0];
+		pesi->intervals[pesi->nintervals].last  = pCARD16[1];
+		pesi->nintervals++;
+		assert(pesi->nintervals <= pesi->size);
+	    }
+	}
+    }
+    return Success;
+}  /* end RecordConvertRangesToIntervals */
+
+#define offset_of(_structure, _field) \
+    ((char *)(& (_structure . _field)) - (char *)(&_structure))
+
+/* RecordRegisterClients
+ *
+ * Arguments:
+ *	pContext is the context on which to register the clients.
+ *	client is the client that issued the RecordCreateContext or
+ *	  RecordRegisterClients request.
+ *	stuff is a pointer to the request.
+ *
+ * Returns:
+ *	Any one of several possible error values defined by the protocol.
+ *	Success if everything is OK.
+ *
+ * Side Effects:
+ *	If different element headers are specified, the context is flushed.
+ *	If any of the specified clients are already registered on the
+ *	context, they are first unregistered.  A new RCAP is created to
+ *	hold the specified protocol and clients, and it is linked onto the
+ *	context.  If the context is enabled, appropriate hooks are installed
+ *	to record the new clients and protocol.
+ */
+static int
+RecordRegisterClients(RecordContextPtr pContext, ClientPtr client, xRecordRegisterClientsReq *stuff)
+{
+    int err;
+    int i;
+    SetInfoPtr si;
+    int maxSets;
+    int nExtReqSets = 0;
+    int nExtRepSets = 0;
+    int extReqSetsOffset = 0;
+    int extRepSetsOffset = 0;
+    SetInfoPtr pExtReqSets, pExtRepSets;
+    int clientListOffset;
+    XID *pCanonClients;
+    int clientStarted = 0, clientDied = 0;
+    xRecordRange *pRanges, rr;
+    int nClients;
+    int sizeClients;
+    int totRCAPsize;
+    RecordClientsAndProtocolPtr pRCAP;
+    int pad;
+    XID recordingClient;
+
+    /* do all sanity checking up front */
+
+    err = RecordSanityCheckRegisterClients(pContext, client, stuff);
+    if (err != Success)
+	return err;
+
+    /* if element headers changed, flush buffer */
+	
+    if (pContext->elemHeaders != stuff->elementHeader)
+    {
+	RecordFlushReplyBuffer(pContext, NULL, 0, NULL, 0);
+	pContext->elemHeaders = stuff->elementHeader;
+    }
+
+    nClients = stuff->nClients;
+    if (!nClients)
+	/* if empty clients list, we're done. */
+	return Success;
+
+    recordingClient = pContext->pRecordingClient ?
+		      pContext->pRecordingClient->clientAsMask : 0;
+    pCanonClients = RecordCanonicalizeClientSpecifiers((XID *)&stuff[1],
+						 &nClients, recordingClient);
+    if (!pCanonClients)
+	return BadAlloc;
+
+    /* We may have to create as many as one set for each "predefined"
+     * protocol types, plus one per range for extension reuests, plus one per
+     * range for extension replies.
+     */
+    maxSets = PREDEFSETS + 2 * stuff->nRanges;
+    si = (SetInfoPtr)malloc(sizeof(SetInfoRec) * maxSets);
+    if (!si)
+    {
+	err = BadAlloc;
+	goto bailout;
+    }
+    memset(si, 0, sizeof(SetInfoRec) * maxSets);
+
+    /* theoretically you must do this because NULL may not be all-bits-zero */
+    for (i = 0; i < maxSets; i++)
+	si[i].intervals = NULL;
+
+    pExtReqSets = si + PREDEFSETS;
+    pExtRepSets = pExtReqSets + stuff->nRanges;
+
+    pRanges = (xRecordRange *)(((XID *)&stuff[1]) + stuff->nClients);
+
+    err = RecordConvertRangesToIntervals(&si[REQ], pRanges, stuff->nRanges,
+			offset_of(rr, coreRequestsFirst), NULL, NULL);
+    if (err != Success) goto bailout;
+
+    err = RecordConvertRangesToIntervals(&si[REQ], pRanges, stuff->nRanges,
+	   offset_of(rr, extRequestsMajorFirst), pExtReqSets, &nExtReqSets);
+    if (err != Success) goto bailout;
+
+    err = RecordConvertRangesToIntervals(&si[REP], pRanges, stuff->nRanges,
+			offset_of(rr, coreRepliesFirst), NULL, NULL);
+    if (err != Success) goto bailout;
+
+    err = RecordConvertRangesToIntervals(&si[REP], pRanges, stuff->nRanges,
+	   offset_of(rr, extRepliesMajorFirst), pExtRepSets, &nExtRepSets);
+    if (err != Success) goto bailout;
+
+    err = RecordConvertRangesToIntervals(&si[ERR], pRanges, stuff->nRanges,
+			offset_of(rr, errorsFirst), NULL, NULL);
+    if (err != Success) goto bailout;
+
+    err = RecordConvertRangesToIntervals(&si[DLEV], pRanges, stuff->nRanges,
+			offset_of(rr, deliveredEventsFirst), NULL, NULL);
+    if (err != Success) goto bailout;
+
+    err = RecordConvertRangesToIntervals(&si[DEV], pRanges, stuff->nRanges,
+			offset_of(rr, deviceEventsFirst), NULL, NULL);
+    if (err != Success) goto bailout;
+
+    /* collect client-started and client-died */
+
+    for (i = 0; i < stuff->nRanges; i++)
+    {
+	if (pRanges[i].clientStarted) clientStarted = TRUE;
+	if (pRanges[i].clientDied)    clientDied    = TRUE;
+    }
+
+    /*  We now have all the information collected to create all the sets,
+     * and we can compute the total memory required for the RCAP.
+     */
+
+    totRCAPsize = sizeof(RecordClientsAndProtocolRec);
+
+    /* leave a little room to grow before forcing a separate allocation */
+    sizeClients = nClients + CLIENT_ARRAY_GROWTH_INCREMENT;
+    pad = RecordPadAlign(totRCAPsize, sizeof(XID));
+    clientListOffset = totRCAPsize + pad;
+    totRCAPsize += pad + sizeClients * sizeof(XID);
+
+    if (nExtReqSets)
+    {
+	pad = RecordPadAlign(totRCAPsize, sizeof(RecordSetPtr));
+	extReqSetsOffset = totRCAPsize + pad;
+	totRCAPsize += pad + (nExtReqSets + 1) * sizeof(RecordMinorOpRec);
+    }
+    if (nExtRepSets)
+    {
+	pad = RecordPadAlign(totRCAPsize, sizeof(RecordSetPtr));
+	extRepSetsOffset = totRCAPsize + pad;
+	totRCAPsize += pad + (nExtRepSets + 1) * sizeof(RecordMinorOpRec);
+    }
+
+    for (i = 0; i < maxSets; i++)
+    {
+	if (si[i].nintervals)
+	{
+	    si[i].size = RecordSetMemoryRequirements(
+				si[i].intervals, si[i].nintervals, &si[i].align);
+	    pad = RecordPadAlign(totRCAPsize, si[i].align);
+	    si[i].offset = pad + totRCAPsize;
+	    totRCAPsize += pad + si[i].size;
+	}
+    }
+
+    /* allocate memory for the whole RCAP */
+
+    pRCAP = (RecordClientsAndProtocolPtr)malloc(totRCAPsize);
+    if (!pRCAP) 
+    {
+	err = BadAlloc;
+	goto bailout;
+    }
+
+    /* fill in the RCAP */
+
+    pRCAP->pContext = pContext;
+    pRCAP->pClientIDs = (XID *)((char *)pRCAP + clientListOffset);
+    pRCAP->numClients  = nClients;
+    pRCAP->sizeClients = sizeClients;
+    pRCAP->clientIDsSeparatelyAllocated = 0;
+    for (i = 0; i < nClients; i++)
+    {
+	RecordDeleteClientFromContext(pContext, pCanonClients[i]);
+	pRCAP->pClientIDs[i] = pCanonClients[i];
+    }
+
+    /* create all the sets */
+
+    if (si[REQ].intervals)
+    {
+	pRCAP->pRequestMajorOpSet =
+	    RecordCreateSet(si[REQ].intervals, si[REQ].nintervals,
+		(RecordSetPtr)((char *)pRCAP + si[REQ].offset), si[REQ].size);
+    }
+    else pRCAP->pRequestMajorOpSet = NULL;
+
+    if (si[REP].intervals)
+    {
+	pRCAP->pReplyMajorOpSet =
+	    RecordCreateSet(si[REP].intervals, si[REP].nintervals,
+		(RecordSetPtr)((char *)pRCAP + si[REP].offset), si[REP].size);
+    }
+    else pRCAP->pReplyMajorOpSet = NULL;
+
+    if (si[ERR].intervals)
+    {
+	pRCAP->pErrorSet =
+	    RecordCreateSet(si[ERR].intervals, si[ERR].nintervals,
+		(RecordSetPtr)((char *)pRCAP + si[ERR].offset), si[ERR].size);
+    }
+    else pRCAP->pErrorSet = NULL;
+
+    if (si[DEV].intervals)
+    {
+	pRCAP->pDeviceEventSet =
+	    RecordCreateSet(si[DEV].intervals, si[DEV].nintervals,
+		(RecordSetPtr)((char *)pRCAP + si[DEV].offset), si[DEV].size);
+    }
+    else pRCAP->pDeviceEventSet = NULL;
+
+    if (si[DLEV].intervals)
+    {
+	pRCAP->pDeliveredEventSet =
+	    RecordCreateSet(si[DLEV].intervals, si[DLEV].nintervals,
+	      (RecordSetPtr)((char *)pRCAP + si[DLEV].offset), si[DLEV].size);
+    }
+    else pRCAP->pDeliveredEventSet = NULL;
+
+    if (nExtReqSets)
+    {
+	pRCAP->pRequestMinOpInfo = (RecordMinorOpPtr)
+					((char *)pRCAP + extReqSetsOffset);
+	pRCAP->pRequestMinOpInfo[0].count = nExtReqSets;
+	for (i = 0; i < nExtReqSets; i++, pExtReqSets++)
+	{
+	    pRCAP->pRequestMinOpInfo[i+1].major.first = pExtReqSets->first;
+	    pRCAP->pRequestMinOpInfo[i+1].major.last  = pExtReqSets->last;
+	    pRCAP->pRequestMinOpInfo[i+1].major.pMinOpSet =
+		RecordCreateSet(pExtReqSets->intervals,
+				pExtReqSets->nintervals, 
+		  (RecordSetPtr)((char *)pRCAP + pExtReqSets->offset),
+				pExtReqSets->size);
+	}
+    }
+    else pRCAP->pRequestMinOpInfo = NULL;
+
+    if (nExtRepSets)
+    {
+	pRCAP->pReplyMinOpInfo = (RecordMinorOpPtr)
+					((char *)pRCAP + extRepSetsOffset);
+	pRCAP->pReplyMinOpInfo[0].count = nExtRepSets;
+	for (i = 0; i < nExtRepSets; i++, pExtRepSets++)
+	{
+	    pRCAP->pReplyMinOpInfo[i+1].major.first = pExtRepSets->first;
+	    pRCAP->pReplyMinOpInfo[i+1].major.last  = pExtRepSets->last;
+	    pRCAP->pReplyMinOpInfo[i+1].major.pMinOpSet =
+		RecordCreateSet(pExtRepSets->intervals,
+				pExtRepSets->nintervals, 
+		  (RecordSetPtr)((char *)pRCAP + pExtRepSets->offset),
+				pExtRepSets->size);
+	}
+    }
+    else pRCAP->pReplyMinOpInfo = NULL;
+
+    pRCAP->clientStarted = clientStarted;
+    pRCAP->clientDied    = clientDied;
+
+    /* link the RCAP onto the context */
+
+    pRCAP->pNextRCAP = pContext->pListOfRCAP;
+    pContext->pListOfRCAP = pRCAP;
+
+    if (pContext->pRecordingClient) /* context enabled */
+	RecordInstallHooks(pRCAP, 0);
+
+bailout:
+    if (si)
+    {
+	for (i = 0; i < maxSets; i++)
+	    free(si[i].intervals);
+	free(si);
+    }
+    if (pCanonClients && pCanonClients != (XID *)&stuff[1])
+	free(pCanonClients);
+    return err;
+} /* RecordRegisterClients */
+
+
+/* Proc functions all take a client argument, execute the request in
+ * client->requestBuffer, and return a protocol error status.
+ */
+
+static int
+ProcRecordQueryVersion(ClientPtr client)
+{
+    /* REQUEST(xRecordQueryVersionReq); */
+    xRecordQueryVersionReply 	rep;
+    int 		n;
+
+    REQUEST_SIZE_MATCH(xRecordQueryVersionReq);
+    rep.type        	= X_Reply;
+    rep.sequenceNumber 	= client->sequence;
+    rep.length         	= 0;
+    rep.majorVersion  	= SERVER_RECORD_MAJOR_VERSION;
+    rep.minorVersion  	= SERVER_RECORD_MINOR_VERSION;
+    if(client->swapped)
+    {
+    	swaps(&rep.sequenceNumber, n);
+	swaps(&rep.majorVersion, n);
+	swaps(&rep.minorVersion, n);
+    }
+    (void)WriteToClient(client, sizeof(xRecordQueryVersionReply),
+			(char *)&rep);
+    return Success;
+} /* ProcRecordQueryVersion */
+
+
+static int
+ProcRecordCreateContext(ClientPtr client)
+{
+    REQUEST(xRecordCreateContextReq);
+    RecordContextPtr pContext;
+    RecordContextPtr *ppNewAllContexts = NULL;
+    int err = BadAlloc;
+
+    REQUEST_AT_LEAST_SIZE(xRecordCreateContextReq);
+    LEGAL_NEW_RESOURCE(stuff->context, client);
+
+    pContext = (RecordContextPtr)malloc(sizeof(RecordContextRec));
+    if (!pContext)
+	goto bailout;
+
+    /* make sure there is room in ppAllContexts to store the new context */
+
+    ppNewAllContexts = (RecordContextPtr *)
+	realloc(ppAllContexts, sizeof(RecordContextPtr) * (numContexts + 1));
+    if (!ppNewAllContexts)
+	goto bailout;
+    ppAllContexts = ppNewAllContexts;
+
+    pContext->id = stuff->context;
+    pContext->pRecordingClient = NULL;
+    pContext->pListOfRCAP = NULL;
+    pContext->elemHeaders = 0;
+    pContext->bufCategory = 0;
+    pContext->numBufBytes = 0;
+    pContext->pBufClient = NULL;
+    pContext->continuedReply = 0;
+    pContext->inFlush = 0;
+
+    err = RecordRegisterClients(pContext, client,
+				(xRecordRegisterClientsReq *)stuff);
+    if (err != Success)
+	goto bailout;
+
+    if (AddResource(pContext->id, RTContext, pContext))
+    {
+	ppAllContexts[numContexts++] = pContext;
+	return Success;
+    }
+    else
+    {
+	RecordDeleteContext((pointer)pContext, pContext->id);
+	return BadAlloc;
+    }
+bailout:
+    free(pContext);
+    return err;
+} /* ProcRecordCreateContext */
+
+
+static int
+ProcRecordRegisterClients(ClientPtr client)
+{
+    RecordContextPtr pContext;
+    REQUEST(xRecordRegisterClientsReq);
+
+    REQUEST_AT_LEAST_SIZE(xRecordRegisterClientsReq);
+    VERIFY_CONTEXT(pContext, stuff->context, client);
+
+    return RecordRegisterClients(pContext, client, stuff);
+} /* ProcRecordRegisterClients */
+
+
+static int
+ProcRecordUnregisterClients(ClientPtr client)
+{
+    RecordContextPtr pContext;
+    int err;
+    REQUEST(xRecordUnregisterClientsReq);
+    XID *pCanonClients;
+    int nClients;
+    int i;
+
+    REQUEST_AT_LEAST_SIZE(xRecordUnregisterClientsReq);
+    if ((client->req_len << 2) - SIZEOF(xRecordUnregisterClientsReq) !=
+	4 * stuff->nClients)
+	return BadLength;
+    VERIFY_CONTEXT(pContext, stuff->context, client);
+    err = RecordSanityCheckClientSpecifiers(client, (XID *)&stuff[1],
+					    stuff->nClients, 0);
+    if (err != Success)
+	return err;
+
+    nClients = stuff->nClients;
+    pCanonClients = RecordCanonicalizeClientSpecifiers((XID *)&stuff[1],
+						 &nClients, 0);
+    if (!pCanonClients)
+	return BadAlloc;
+
+    for (i = 0; i < nClients; i++)
+    {
+	RecordDeleteClientFromContext(pContext, pCanonClients[i]);
+    }
+    if (pCanonClients != (XID *)&stuff[1])
+	free(pCanonClients);
+    return Success;
+} /* ProcRecordUnregisterClients */
+
+
+/****************************************************************************/
+
+/* stuff for GetContext */
+
+/* This is a tactical structure used to hold the xRecordRanges as they are
+ * being reconstituted from the sets in the RCAPs.
+ */
+
+typedef struct {
+    xRecordRange *pRanges;  /* array of xRecordRanges for one RCAP */
+    int size;		/* number of elements in pRanges, >= nRanges */
+    int nRanges;	/* number of occupied element of pRanges */
+} GetContextRangeInfoRec, *GetContextRangeInfoPtr;
+
+
+/* RecordAllocRanges
+ *
+ * Arguments:
+ *	pri is a pointer to a GetContextRangeInfoRec to allocate for.
+ *	nRanges is the number of xRecordRanges desired for pri.
+ *
+ * Returns: BadAlloc if a memory allocation error occurred, else Success.
+ *
+ * Side Effects:
+ *	If Success is returned, pri->pRanges points to at least nRanges
+ *	ranges.  pri->nRanges is set to nRanges.  pri->size is the actual
+ *	number of ranges.  Newly allocated ranges are zeroed.
+ */
+static int
+RecordAllocRanges(GetContextRangeInfoPtr pri, int nRanges)
+{
+    int newsize;
+    xRecordRange *pNewRange;
+#define SZINCR 8
+
+    newsize = max(pri->size + SZINCR, nRanges);
+    pNewRange = (xRecordRange *)realloc(pri->pRanges,
+			 newsize * sizeof(xRecordRange));
+    if (!pNewRange)
+	return BadAlloc;
+
+    pri->pRanges = pNewRange;
+    pri->size = newsize;
+    memset(&pri->pRanges[pri->size - SZINCR], 0, SZINCR * sizeof(xRecordRange));
+    if (pri->nRanges < nRanges)
+	pri->nRanges = nRanges;
+    return Success;
+} /* RecordAllocRanges */
+
+
+/* RecordConvertSetToRanges
+ *
+ * Arguments:
+ *	pSet is the set to be converted.
+ *	pri is where the result should be stored.
+ *	byteoffset is the offset from the start of an xRecordRange of the
+ *	  two vales (first, last) we are interested in.
+ *	card8 is TRUE if the vales are one byte each and FALSE if two bytes
+ *	  each.
+ *	imax is the largest set value to store in pri->pRanges.
+ *	pStartIndex, if non-NULL, is the index of the first range in
+ *	  pri->pRanges that should be stored to.  If NULL,
+ *	  start at index 0.
+ *
+ * Returns: BadAlloc if a memory allocation error occurred, else Success.
+ *
+ * Side Effects:
+ *	If Success is returned, the slice of pri->pRanges indicated by
+ *	byteoffset and card8 is filled in with the intervals from pSet.
+ *	if pStartIndex was non-NULL, *pStartIndex is filled in with one
+ *	more than the index of the last xRecordRange that was touched.
+ */
+static int
+RecordConvertSetToRanges(
+    RecordSetPtr pSet,
+    GetContextRangeInfoPtr pri,
+    int byteoffset,
+    Bool card8,
+    unsigned int imax,
+    int *pStartIndex
+)
+{
+    int nRanges;
+    RecordSetIteratePtr pIter = NULL;
+    RecordSetInterval interval;
+    CARD8 *pCARD8;
+    CARD16 *pCARD16;
+    int err;
+
+    if (!pSet)
+	return Success;
+
+    nRanges = pStartIndex ? *pStartIndex : 0;
+    while ((pIter = RecordIterateSet(pSet, pIter, &interval)))
+    {
+	if (interval.first > imax) break;
+	if (interval.last  > imax) interval.last = imax;
+	nRanges++;
+	if (nRanges > pri->size)
+	{
+	    err = RecordAllocRanges(pri, nRanges);
+	    if (err != Success)
+		return err;
+	}
+	else
+	    pri->nRanges = max(pri->nRanges, nRanges);
+	if (card8)
+	{
+	    pCARD8 = ((CARD8 *)&pri->pRanges[nRanges-1]) + byteoffset;
+	    *pCARD8++ = interval.first;
+	    *pCARD8   = interval.last;
+	}
+	else
+	{
+	    pCARD16 = (CARD16 *)
+			(((char *)&pri->pRanges[nRanges-1]) + byteoffset);
+	    *pCARD16++ = interval.first;
+	    *pCARD16   = interval.last;
+	}
+    }
+    if (pStartIndex)
+	*pStartIndex = nRanges;
+    return Success;
+} /* RecordConvertSetToRanges */
+
+
+/* RecordConvertMinorOpInfoToRanges
+ *
+ * Arguments:
+ *	pMinOpInfo is the minor opcode info to convert to xRecordRanges.
+ *	pri is where the result should be stored.
+ *	byteoffset is the offset from the start of an xRecordRange of the
+ *	  four vales (CARD8 major_first, CARD8 major_last,
+ *	  CARD16 minor_first, CARD16 minor_last) we are going to store.
+ *
+ * Returns: BadAlloc if a memory allocation error occurred, else Success.
+ *
+ * Side Effects:
+ *	If Success is returned, the slice of pri->pRanges indicated by
+ *	byteoffset is filled in with the information from pMinOpInfo.
+ */
+static int
+RecordConvertMinorOpInfoToRanges(
+    RecordMinorOpPtr pMinOpInfo,
+    GetContextRangeInfoPtr pri,
+    int byteoffset
+)
+{
+    int nsets;
+    int start;
+    int i;
+    int err;
+
+    if (!pMinOpInfo)
+	return Success;
+
+    nsets = pMinOpInfo->count;
+    pMinOpInfo++;
+    start = 0;
+    for (i = 0; i < nsets; i++)
+    {
+	int j, s;
+	s = start;
+	err = RecordConvertSetToRanges(pMinOpInfo[i].major.pMinOpSet, pri,
+				byteoffset + 2, FALSE, 65535, &start);
+	if (err != Success) return err;
+	for (j = s; j < start; j++)
+	{
+	    CARD8 *pCARD8 = ((CARD8 *)&pri->pRanges[j]) + byteoffset;
+	    *pCARD8++ = pMinOpInfo[i].major.first;
+	    *pCARD8   = pMinOpInfo[i].major.last;
+	}
+    }
+    return Success;
+} /* RecordConvertMinorOpInfoToRanges */
+
+
+/* RecordSwapRanges
+ *
+ * Arguments:
+ *	pRanges is an array of xRecordRanges.
+ *	nRanges is the number of elements in pRanges.
+ *
+ * Returns: nothing.
+ *
+ * Side Effects:
+ *	The 16 bit fields of each xRecordRange are byte swapped.
+ */
+static void
+RecordSwapRanges(xRecordRange *pRanges, int nRanges)
+{
+    int i;
+    register char n;
+    for (i = 0; i < nRanges; i++, pRanges++)
+    {
+	swaps(&pRanges->extRequestsMinorFirst, n);
+	swaps(&pRanges->extRequestsMinorLast, n);
+	swaps(&pRanges->extRepliesMinorFirst, n);
+	swaps(&pRanges->extRepliesMinorLast, n);
+    }
+} /* RecordSwapRanges */
+
+
+static int
+ProcRecordGetContext(ClientPtr client)
+{
+    RecordContextPtr pContext;
+    REQUEST(xRecordGetContextReq);
+    xRecordGetContextReply rep;
+    int n;
+    RecordClientsAndProtocolPtr pRCAP;
+    int nRCAPs = 0;
+    GetContextRangeInfoPtr pRangeInfo;
+    GetContextRangeInfoPtr pri;
+    int i;
+    int err;
+
+    REQUEST_SIZE_MATCH(xRecordGetContextReq);
+    VERIFY_CONTEXT(pContext, stuff->context, client);
+
+    /* how many RCAPs are there on this context? */
+
+    for (pRCAP = pContext->pListOfRCAP; pRCAP; pRCAP = pRCAP->pNextRCAP)
+	nRCAPs++;
+
+    /* allocate and initialize space for record range info */
+
+    pRangeInfo = (GetContextRangeInfoPtr)malloc(
+				nRCAPs * sizeof(GetContextRangeInfoRec));
+    if (!pRangeInfo && nRCAPs > 0)
+	return BadAlloc;
+    for (i = 0; i < nRCAPs; i++)
+    {
+	pRangeInfo[i].pRanges = NULL;
+	pRangeInfo[i].size = 0;
+	pRangeInfo[i].nRanges = 0;
+    }
+
+    /* convert the RCAP (internal) representation of the recorded protocol
+     * to the wire protocol (external) representation, storing the information
+     * for the ith RCAP in pri[i]
+     */
+
+    for (pRCAP = pContext->pListOfRCAP, pri = pRangeInfo;
+	 pRCAP;
+	 pRCAP = pRCAP->pNextRCAP, pri++)
+    {
+	xRecordRange rr;
+
+	err = RecordConvertSetToRanges(pRCAP->pRequestMajorOpSet, pri,
+			offset_of(rr, coreRequestsFirst), TRUE, 127, NULL);
+	if (err != Success) goto bailout;
+
+	err = RecordConvertSetToRanges(pRCAP->pReplyMajorOpSet, pri,
+			offset_of(rr, coreRepliesFirst), TRUE, 127, NULL);
+	if (err != Success) goto bailout;
+
+	err = RecordConvertSetToRanges(pRCAP->pDeliveredEventSet, pri,
+			offset_of(rr, deliveredEventsFirst), TRUE, 255, NULL);
+	if (err != Success) goto bailout;
+
+	err = RecordConvertSetToRanges(pRCAP->pDeviceEventSet, pri,
+			offset_of(rr, deviceEventsFirst), TRUE, 255, NULL);
+	if (err != Success) goto bailout;
+
+	err = RecordConvertSetToRanges(pRCAP->pErrorSet, pri,
+			      offset_of(rr, errorsFirst), TRUE, 255, NULL);
+	if (err != Success) goto bailout;
+
+	err = RecordConvertMinorOpInfoToRanges(pRCAP->pRequestMinOpInfo,
+				pri, offset_of(rr, extRequestsMajorFirst));
+	if (err != Success) goto bailout;
+
+	err = RecordConvertMinorOpInfoToRanges(pRCAP->pReplyMinOpInfo,
+				pri, offset_of(rr, extRepliesMajorFirst));
+	if (err != Success) goto bailout;
+
+	if (pRCAP->clientStarted || pRCAP->clientDied)
+	{
+	    if (pri->nRanges == 0)
+		RecordAllocRanges(pri, 1);
+	    pri->pRanges[0].clientStarted = pRCAP->clientStarted;
+	    pri->pRanges[0].clientDied    = pRCAP->clientDied;
+	}
+    }
+
+    /* calculate number of clients and reply length */
+
+    rep.nClients = 0;
+    rep.length = 0;
+    for (pRCAP = pContext->pListOfRCAP, pri = pRangeInfo;
+	 pRCAP;
+	 pRCAP = pRCAP->pNextRCAP, pri++)
+    {
+	rep.nClients += pRCAP->numClients;
+	rep.length += pRCAP->numClients *
+		( bytes_to_int32(sizeof(xRecordClientInfo)) +
+		  pri->nRanges * bytes_to_int32(sizeof(xRecordRange)));
+    }
+
+    /* write the reply header */
+
+    rep.type = X_Reply;
+    rep.sequenceNumber 	= client->sequence;
+    rep.enabled = pContext->pRecordingClient != NULL;
+    rep.elementHeader = pContext->elemHeaders;
+    if(client->swapped)
+    {
+    	swaps(&rep.sequenceNumber, n);
+    	swapl(&rep.length, n);
+    	swapl(&rep.nClients, n);
+    }
+    (void)WriteToClient(client, sizeof(xRecordGetContextReply),
+			(char *)&rep);
+
+    /* write all the CLIENT_INFOs */
+
+    for (pRCAP = pContext->pListOfRCAP, pri = pRangeInfo;
+	 pRCAP;
+	 pRCAP = pRCAP->pNextRCAP, pri++)
+    {
+	xRecordClientInfo rci;
+	rci.nRanges = pri->nRanges;
+	if (client->swapped)
+	{
+	    swapl(&rci.nRanges, n);
+	    RecordSwapRanges(pri->pRanges, pri->nRanges);
+	}
+	for (i = 0; i < pRCAP->numClients; i++)
+	{
+	    rci.clientResource = pRCAP->pClientIDs[i];
+	    if (client->swapped) swapl(&rci.clientResource, n);
+	    WriteToClient(client, sizeof(xRecordClientInfo), (char *)&rci);
+	    WriteToClient(client, sizeof(xRecordRange) * pri->nRanges,
+			  (char *)pri->pRanges);
+	}
+    }
+    err = Success;
+
+bailout:
+    for (i = 0; i < nRCAPs; i++)
+    {
+	free(pRangeInfo[i].pRanges);
+    }
+    free(pRangeInfo);
+    return err;
+} /* ProcRecordGetContext */
+
+
+static int
+ProcRecordEnableContext(ClientPtr client)
+{
+    RecordContextPtr pContext;
+    REQUEST(xRecordEnableContextReq);
+    int i;
+    RecordClientsAndProtocolPtr pRCAP;
+
+    REQUEST_SIZE_MATCH(xRecordGetContextReq);
+    VERIFY_CONTEXT(pContext, stuff->context, client);
+    if (pContext->pRecordingClient)
+	return BadMatch; /* already enabled */
+
+    /* install record hooks for each RCAP */
+
+    for (pRCAP = pContext->pListOfRCAP; pRCAP; pRCAP = pRCAP->pNextRCAP)
+    {
+	int err = RecordInstallHooks(pRCAP, 0);
+	if (err != Success)
+	{ /* undo the previous installs */
+	    RecordClientsAndProtocolPtr pUninstallRCAP;
+	    for (pUninstallRCAP = pContext->pListOfRCAP;
+		 pUninstallRCAP != pRCAP;
+		 pUninstallRCAP = pUninstallRCAP->pNextRCAP)
+	    {
+		RecordUninstallHooks(pUninstallRCAP, 0);
+	    }
+	    return err;
+	}
+    }
+
+    /* Disallow further request processing on this connection until
+     * the context is disabled.
+     */
+    IgnoreClient(client);
+    pContext->pRecordingClient = client;
+
+    /* Don't allow the data connection to record itself; unregister it. */
+    RecordDeleteClientFromContext(pContext,
+				  pContext->pRecordingClient->clientAsMask);
+
+    /* move the newly enabled context to the front part of ppAllContexts,
+     * where all the enabled contexts are
+     */
+    i = RecordFindContextOnAllContexts(pContext);
+    assert(i >= numEnabledContexts);
+    if (i != numEnabledContexts)
+    {
+	ppAllContexts[i] = ppAllContexts[numEnabledContexts];
+	ppAllContexts[numEnabledContexts] = pContext;
+    }
+
+    ++numEnabledContexts;
+    assert(numEnabledContexts > 0);
+
+    /* send StartOfData */
+    RecordAProtocolElement(pContext, NULL, XRecordStartOfData, NULL, 0, 0);
+    RecordFlushReplyBuffer(pContext, NULL, 0, NULL, 0);
+    return Success;
+} /* ProcRecordEnableContext */
+
+
+/* RecordDisableContext
+ *
+ * Arguments:
+ *	pContext is the context to disable.
+ *	nRanges is the number of elements in pRanges.
+ *
+ * Returns: nothing.
+ *
+ * Side Effects:
+ *	If the context was enabled, it is disabled.  An EndOfData
+ *	message is sent to the recording client.  Recording hooks for
+ *	this context are uninstalled.  The context is moved to the
+ *	rear part of the ppAllContexts array.  numEnabledContexts is
+ *	decremented.  Request processing for the formerly recording client
+ *	is resumed.
+ */
+static void
+RecordDisableContext(RecordContextPtr pContext)
+{
+    RecordClientsAndProtocolPtr pRCAP;
+    int i;
+
+    if (!pContext->pRecordingClient) return;
+    if (!pContext->pRecordingClient->clientGone)
+    {
+	RecordAProtocolElement(pContext, NULL, XRecordEndOfData, NULL, 0, 0);
+	RecordFlushReplyBuffer(pContext, NULL, 0, NULL, 0);
+	/* Re-enable request processing on this connection. */
+	AttendClient(pContext->pRecordingClient);
+    }
+
+    for (pRCAP = pContext->pListOfRCAP; pRCAP; pRCAP = pRCAP->pNextRCAP)
+    {
+	RecordUninstallHooks(pRCAP, 0);
+    }
+
+    pContext->pRecordingClient = NULL;
+
+    /* move the newly disabled context to the rear part of ppAllContexts,
+     * where all the disabled contexts are
+     */
+    i = RecordFindContextOnAllContexts(pContext);
+    assert( (i != -1) && (i < numEnabledContexts) );
+    if (i != (numEnabledContexts - 1) )
+    {
+	ppAllContexts[i] = ppAllContexts[numEnabledContexts-1];
+	ppAllContexts[numEnabledContexts-1] = pContext;
+    }
+    --numEnabledContexts;
+    assert(numEnabledContexts >= 0);
+} /* RecordDisableContext */
+
+
+static int
+ProcRecordDisableContext(ClientPtr client)
+{
+    RecordContextPtr pContext;
+    REQUEST(xRecordDisableContextReq);
+
+    REQUEST_SIZE_MATCH(xRecordDisableContextReq);
+    VERIFY_CONTEXT(pContext, stuff->context, client);
+    RecordDisableContext(pContext);
+    return Success;
+} /* ProcRecordDisableContext */
+
+
+/* RecordDeleteContext
+ *
+ * Arguments:
+ *	value is the context to delete.
+ *	id is its resource ID.
+ *
+ * Returns: Success.
+ *
+ * Side Effects:
+ *	Disables the context, frees all associated memory, and removes
+ *	it from the ppAllContexts array.
+ */
+static int
+RecordDeleteContext(pointer value, XID id)
+{
+    int i;
+    RecordContextPtr pContext = (RecordContextPtr)value;
+    RecordClientsAndProtocolPtr pRCAP;
+
+    RecordDisableContext(pContext);
+
+    /*  Remove all the clients from all the RCAPs.
+     *  As a result, the RCAPs will be freed.
+     */
+
+    while ((pRCAP = pContext->pListOfRCAP))
+    {
+	int numClients = pRCAP->numClients;
+	/* when the last client is deleted, the RCAP will go away. */
+	while(numClients--)
+	{
+	    RecordDeleteClientFromRCAP(pRCAP, numClients);
+	}
+    }
+
+    /* remove context from AllContexts list */
+
+    if (-1 != (i = RecordFindContextOnAllContexts(pContext)))
+    {
+	ppAllContexts[i] = ppAllContexts[numContexts - 1];
+	if (--numContexts == 0)
+	{
+	    free(ppAllContexts);
+	    ppAllContexts = NULL;
+	}
+    }
+    free(pContext);
+
+    return Success;
+} /* RecordDeleteContext */
+
+
+static int
+ProcRecordFreeContext(ClientPtr client)
+{
+    RecordContextPtr pContext;
+    REQUEST(xRecordFreeContextReq);
+
+    REQUEST_SIZE_MATCH(xRecordFreeContextReq);
+    VERIFY_CONTEXT(pContext, stuff->context, client);
+    FreeResource(stuff->context, RT_NONE);
+    return Success;
+} /* ProcRecordFreeContext */
+
+
+static int
+ProcRecordDispatch(ClientPtr client)
+{
+    REQUEST(xReq);
+
+    switch (stuff->data)
+    {
+	case X_RecordQueryVersion:
+	    return ProcRecordQueryVersion(client);
+	case X_RecordCreateContext:
+	    return ProcRecordCreateContext(client);
+	case X_RecordRegisterClients:
+	    return ProcRecordRegisterClients(client);
+	case X_RecordUnregisterClients:
+	    return ProcRecordUnregisterClients(client);
+	case X_RecordGetContext:
+	    return ProcRecordGetContext(client);
+	case X_RecordEnableContext:
+	    return ProcRecordEnableContext(client);
+	case X_RecordDisableContext:
+	    return ProcRecordDisableContext(client);
+	case X_RecordFreeContext:
+	    return ProcRecordFreeContext(client);
+       default:
+	    return BadRequest;
+    }
+} /* ProcRecordDispatch */
+
+
+static int
+SProcRecordQueryVersion(ClientPtr client)
+{
+    REQUEST(xRecordQueryVersionReq);
+    register char 	n;
+
+    swaps(&stuff->length, n);
+    REQUEST_SIZE_MATCH(xRecordQueryVersionReq);
+    swaps(&stuff->majorVersion, n);
+    swaps(&stuff->minorVersion,n);
+    return ProcRecordQueryVersion(client);
+} /* SProcRecordQueryVersion */
+
+
+static int
+SwapCreateRegister(xRecordRegisterClientsReq *stuff)
+{
+    register char n;
+    int i;
+    XID *pClientID;
+
+    swapl(&stuff->context, n);
+    swapl(&stuff->nClients, n);
+    swapl(&stuff->nRanges, n);
+    pClientID = (XID *)&stuff[1];
+    if (stuff->nClients > stuff->length - bytes_to_int32(sz_xRecordRegisterClientsReq))
+	return BadLength;
+    for (i = 0; i < stuff->nClients; i++, pClientID++)
+    {
+	swapl(pClientID, n);
+    }
+    if (stuff->nRanges > stuff->length - bytes_to_int32(sz_xRecordRegisterClientsReq)
+	- stuff->nClients)
+	return BadLength;
+    RecordSwapRanges((xRecordRange *)pClientID, stuff->nRanges);
+    return Success;
+} /* SwapCreateRegister */
+
+
+static int
+SProcRecordCreateContext(ClientPtr client)
+{
+    REQUEST(xRecordCreateContextReq);
+    int			status;
+    register char 	n;
+
+    swaps(&stuff->length, n);
+    REQUEST_AT_LEAST_SIZE(xRecordCreateContextReq);
+    if ((status = SwapCreateRegister((pointer)stuff)) != Success)
+	return status;
+    return ProcRecordCreateContext(client);
+} /* SProcRecordCreateContext */
+
+
+static int
+SProcRecordRegisterClients(ClientPtr client)
+{
+    REQUEST(xRecordRegisterClientsReq);
+    int			status;
+    register char 	n;
+
+    swaps(&stuff->length, n);
+    REQUEST_AT_LEAST_SIZE(xRecordRegisterClientsReq);
+    if ((status = SwapCreateRegister((pointer)stuff)) != Success)
+	return status;
+    return ProcRecordRegisterClients(client);
+} /* SProcRecordRegisterClients */
+
+
+static int
+SProcRecordUnregisterClients(ClientPtr client)
+{
+    REQUEST(xRecordUnregisterClientsReq);
+    register char 	n;
+
+    swaps(&stuff->length, n);
+    REQUEST_AT_LEAST_SIZE(xRecordUnregisterClientsReq);
+    swapl(&stuff->context, n);
+    swapl(&stuff->nClients, n);
+    SwapRestL(stuff);
+    return ProcRecordUnregisterClients(client);
+} /* SProcRecordUnregisterClients */
+
+
+static int
+SProcRecordGetContext(ClientPtr client)
+{
+    REQUEST(xRecordGetContextReq);
+    register char 	n;
+
+    swaps(&stuff->length, n);
+    REQUEST_SIZE_MATCH(xRecordGetContextReq);
+    swapl(&stuff->context, n);
+    return ProcRecordGetContext(client);
+} /* SProcRecordGetContext */
+
+static int
+SProcRecordEnableContext(ClientPtr client)
+{
+    REQUEST(xRecordEnableContextReq);
+    register char 	n;
+
+    swaps(&stuff->length, n);
+    REQUEST_SIZE_MATCH(xRecordEnableContextReq);
+    swapl(&stuff->context, n);
+    return ProcRecordEnableContext(client);
+} /* SProcRecordEnableContext */
+
+
+static int
+SProcRecordDisableContext(ClientPtr client)
+{
+    REQUEST(xRecordDisableContextReq);
+    register char 	n;
+
+    swaps(&stuff->length, n);
+    REQUEST_SIZE_MATCH(xRecordDisableContextReq);
+    swapl(&stuff->context, n);
+    return ProcRecordDisableContext(client);
+} /* SProcRecordDisableContext */
+
+
+static int
+SProcRecordFreeContext(ClientPtr client)
+{
+    REQUEST(xRecordFreeContextReq);
+    register char 	n;
+
+    swaps(&stuff->length, n);
+    REQUEST_SIZE_MATCH(xRecordFreeContextReq);
+    swapl(&stuff->context, n);
+    return ProcRecordFreeContext(client);
+} /* SProcRecordFreeContext */
+
+
+static int
+SProcRecordDispatch(ClientPtr client)
+{
+    REQUEST(xReq);
+
+    switch (stuff->data)
+    {
+	case X_RecordQueryVersion:
+	    return SProcRecordQueryVersion(client);
+	case X_RecordCreateContext:
+	    return SProcRecordCreateContext(client);
+	case X_RecordRegisterClients:
+	    return SProcRecordRegisterClients(client);
+	case X_RecordUnregisterClients:
+	    return SProcRecordUnregisterClients(client);
+	case X_RecordGetContext:
+	    return SProcRecordGetContext(client);
+	case X_RecordEnableContext:
+	    return SProcRecordEnableContext(client);
+	case X_RecordDisableContext:
+	    return SProcRecordDisableContext(client);
+	case X_RecordFreeContext:
+	    return SProcRecordFreeContext(client);
+       default:
+	    return BadRequest;
+    }
+} /* SProcRecordDispatch */
+
+/* RecordConnectionSetupInfo
+ *
+ * Arguments:
+ *	pContext is an enabled context that specifies recording of 
+ *	  connection setup info.
+ *	pci holds the connection setup info.
+ *
+ * Returns: nothing.
+ *
+ * Side Effects:
+ *	The connection setup info is sent to the recording client.
+ */
+static void
+RecordConnectionSetupInfo(RecordContextPtr pContext, NewClientInfoRec *pci)
+{
+    int prefixsize = SIZEOF(xConnSetupPrefix);
+    int restsize = pci->prefix->length * 4;
+
+    if (pci->client->swapped)
+    {
+	char *pConnSetup = (char *)malloc(prefixsize + restsize);
+	if (!pConnSetup)
+	    return;
+	SwapConnSetupPrefix(pci->prefix, (xConnSetupPrefix*)pConnSetup);
+	SwapConnSetupInfo((char*)pci->setup, (char*)(pConnSetup + prefixsize));
+	RecordAProtocolElement(pContext, pci->client, XRecordClientStarted,
+			       (pointer)pConnSetup, prefixsize + restsize, 0);
+	free(pConnSetup);
+    }
+    else
+    {
+	/* don't alloc and copy as in the swapped case; just send the
+	 * data in two pieces
+	 */
+	RecordAProtocolElement(pContext, pci->client, XRecordClientStarted,
+			(pointer)pci->prefix, prefixsize, restsize);
+	RecordAProtocolElement(pContext, pci->client, XRecordClientStarted,
+			(pointer)pci->setup, restsize, /* continuation */ -1);
+    }
+} /* RecordConnectionSetupInfo */
+
+
+/* RecordDeleteContext
+ *
+ * Arguments:
+ *	pcbl is &ClientStateCallback.
+ *	nullata is NULL.
+ *	calldata is a pointer to a NewClientInfoRec (include/dixstruct.h)
+ *	which contains information about client state changes.
+ *
+ * Returns: nothing.
+ *
+ * Side Effects:
+ *	If a new client has connected and any contexts have specified
+ *	XRecordFutureClients, the new client is registered on those contexts.
+ *	If any of those contexts specify recording of the connection setup
+ *	info, it is recorded.
+ *
+ *	If an existing client has disconnected, it is deleted from any
+ *	contexts that it was registered on.  If any of those contexts
+ *	specified XRecordClientDied, they record a ClientDied protocol element.
+ *	If the disconnectiong client happened to be the data connection of an
+ *	enabled context, the context is disabled.
+ */
+
+static void
+RecordAClientStateChange(CallbackListPtr *pcbl, pointer nulldata, pointer calldata)
+{
+    NewClientInfoRec *pci = (NewClientInfoRec *)calldata;
+    int i;
+    ClientPtr pClient = pci->client;
+    RecordContextPtr *ppAllContextsCopy = NULL;
+    int numContextsCopy = 0;
+
+    switch (pClient->clientState)
+    {
+    case ClientStateRunning: /* new client */
+	for (i = 0; i < numContexts; i++)
+	{
+	    RecordClientsAndProtocolPtr pRCAP;
+	    RecordContextPtr pContext = ppAllContexts[i];
+
+	    if ((pRCAP = RecordFindClientOnContext(pContext,
+					    XRecordFutureClients, NULL)))
+	    {
+		RecordAddClientToRCAP(pRCAP, pClient->clientAsMask);
+		if (pContext->pRecordingClient && pRCAP->clientStarted)
+		    RecordConnectionSetupInfo(pContext, pci);
+	    }
+	}
+    break;
+
+    case ClientStateGone:
+    case ClientStateRetained: /* client disconnected */
+
+        /* RecordDisableContext modifies contents of ppAllContexts. */
+	numContextsCopy = numContexts;
+	ppAllContextsCopy = malloc(numContextsCopy * sizeof(RecordContextPtr));
+	assert(ppAllContextsCopy);
+	memcpy(ppAllContextsCopy, ppAllContexts, numContextsCopy * sizeof(RecordContextPtr));
+
+	for (i = 0; i < numContextsCopy; i++)
+	{
+	    RecordClientsAndProtocolPtr pRCAP;
+	    RecordContextPtr pContext = ppAllContextsCopy[i];
+	    int pos;
+
+	    if (pContext->pRecordingClient == pClient)
+		RecordDisableContext(pContext);
+	    if ((pRCAP = RecordFindClientOnContext(pContext,
+				    pClient->clientAsMask, &pos)))
+	    {
+		if (pContext->pRecordingClient && pRCAP->clientDied)
+		    RecordAProtocolElement(pContext, pClient,
+					   XRecordClientDied, NULL, 0, 0);
+		RecordDeleteClientFromRCAP(pRCAP, pos);
+	    }
+	}
+
+	free(ppAllContextsCopy);
+    break;
+
+    default:
+    break;
+    } /* end switch on client state */
+} /* RecordAClientStateChange */
+
+
+/* RecordCloseDown
+ *
+ * Arguments:
+ *	extEntry is the extension information for RECORD.
+ *
+ * Returns: nothing.
+ *
+ * Side Effects:
+ *	Performs any cleanup needed by RECORD at server shutdown time.
+ *	
+ */
+static void
+RecordCloseDown(ExtensionEntry *extEntry)
+{
+    DeleteCallback(&ClientStateCallback, RecordAClientStateChange, NULL);
+} /* RecordCloseDown */
+
+
+/* RecordExtensionInit
+ *
+ * Arguments: none.
+ *
+ * Returns: nothing.
+ *
+ * Side Effects:
+ *	Enables the RECORD extension if possible.
+ */
+void 
+RecordExtensionInit(void)
+{
+    ExtensionEntry *extentry;
+
+    RTContext = CreateNewResourceType(RecordDeleteContext, "RecordContext");
+    if (!RTContext)
+	return;
+
+    if (!dixRegisterPrivateKey(RecordClientPrivateKey, PRIVATE_CLIENT, 0))
+        return;
+
+    ppAllContexts = NULL;
+    numContexts = numEnabledContexts = numEnabledRCAPs = 0;
+
+    if (!AddCallback(&ClientStateCallback, RecordAClientStateChange, NULL))
+	return;
+
+    extentry = AddExtension(RECORD_NAME, RecordNumEvents, RecordNumErrors,
+			    ProcRecordDispatch, SProcRecordDispatch,
+			    RecordCloseDown, StandardMinorOpcode);
+    if (!extentry)
+    {
+	DeleteCallback(&ClientStateCallback, RecordAClientStateChange, NULL);
+	return;
+    }
+    SetResourceTypeErrorValue(RTContext, extentry->errorBase + XRecordBadContext);
+
+} /* RecordExtensionInit */
+
-- 
cgit v1.2.3