]> git.sesse.net Git - rdpsrv/blobdiff - Xserver/programs/Xserver/Xext/xprint.c
Import X server from vnc-3.3.7.
[rdpsrv] / Xserver / programs / Xserver / Xext / xprint.c
diff --git a/Xserver/programs/Xserver/Xext/xprint.c b/Xserver/programs/Xserver/Xext/xprint.c
new file mode 100644 (file)
index 0000000..829a8f3
--- /dev/null
@@ -0,0 +1,2873 @@
+/* $XConsortium: xprint.c /main/3 1996/11/23 17:11:55 rws $ */
+/*
+(c) Copyright 1996 Hewlett-Packard Company
+(c) Copyright 1996 International Business Machines Corp.
+(c) Copyright 1996 Sun Microsystems, Inc.
+(c) Copyright 1996 Novell, Inc.
+(c) Copyright 1996 Digital Equipment Corp.
+(c) Copyright 1996 Fujitsu Limited
+(c) Copyright 1996 Hitachi, Ltd.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+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
+COPYRIGHT HOLDERS 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 names of the copyright holders shall
+not be used in advertising or otherwise to promote the sale, use or other
+dealings in this Software without prior written authorization from said
+copyright holders.
+*/
+/*******************************************************************
+**
+**    *********************************************************
+**    *
+**    *  File:          xprint.c
+**    *
+**    *  Copyright:     Copyright 1993, 1995 Hewlett-Packard Company
+**    *
+**    *                Copyright 1989 by The Massachusetts Institute of Technology
+**    *
+**    *                Permission to use, copy, modify, and distribute this
+**    *                software and its documentation for any purpose and without
+**    *                fee is hereby granted, provided that the above copyright
+**    *                notice appear in all copies and that both that copyright
+**    *                notice and this permission notice appear in supporting
+**    *                documentation, and that the name of MIT not be used in
+**    *                advertising or publicity pertaining to distribution of the
+**    *                software without specific prior written permission.
+**    *                M.I.T. makes no representation about the suitability of
+**    *                this software for any purpose. It is provided "as is"
+**    *                without any express or implied warranty.
+**    *
+**    *                MIT DISCLAIMS ALL WARRANTIES WITH REGARD TO  THIS  SOFTWARE,
+**    *                INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FIT-
+**    *                NESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL MIT BE  LI-
+**    *                ABLE  FOR  ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
+**    *                ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,  DATA  OR
+**    *                PROFITS,  WHETHER  IN  AN  ACTION OF CONTRACT, NEGLIGENCE OR
+**    *                OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION  WITH
+**    *                THE USE OR PERFORMANCE OF THIS SOFTWARE.
+**    *
+**    *********************************************************
+**
+********************************************************************/
+/* $XFree86: xc/programs/Xserver/Xext/xprint.c,v 1.4 1997/01/02 04:05:05 dawes Exp $ */
+
+#include "X.h"
+#define NEED_EVENTS
+#include "Xproto.h"
+#undef NEED_EVENTS
+#include "misc.h"
+#include "windowstr.h"
+#include "scrnintstr.h"
+#include "pixmapstr.h"
+#include "extnsionst.h"
+#include "dixstruct.h"
+#include "Xatom.h"
+#define _XP_PRINT_SERVER_
+#include "Print.h"
+#include "Printstr.h"
+#undef _XP_PRINT_SERVER_
+#include "../Xprint/DiPrint.h"
+
+extern WindowPtr *WindowTable; /* declared in dix:globals.c */
+
+extern WindowPtr XpDiValidatePrinter();
+extern char *XpDiGetDriverName();
+extern char *XpGetAttributes();
+extern char *XpGetOneAttribute();
+extern int XpRehashPrinterList();
+extern void XpSetFontResFunc();
+
+static void XpResetProc();
+
+static int ProcXpDispatch();
+static int ProcXpSwappedDispatch();
+
+static int ProcXpQueryVersion();
+static int ProcXpGetPrinterList();
+static int ProcXpCreateContext();
+static int ProcXpSetContext();
+static int ProcXpGetContext();
+static int ProcXpDestroyContext();
+static int ProcXpGetContextScreen();
+static int ProcXpStartJob();
+static int ProcXpEndJob();
+static int ProcXpStartDoc();
+static int ProcXpEndDoc();
+static int ProcXpStartPage();
+static int ProcXpEndPage();
+static int ProcXpSelectInput();
+static int ProcXpInputSelected();
+static int ProcXpPutDocumentData();
+static int ProcXpGetDocumentData();
+static int ProcXpGetAttributes();
+static int ProcXpGetOneAttribute();
+static int ProcXpSetAttributes();
+static int ProcXpRehashPrinterList();
+static int ProcXpQueryScreens();
+static int ProcXpGetPageDimensions();
+static int ProcXpSetImageResolution();
+static int ProcXpGetImageResolution();
+
+static void SwapXpNotifyEvent();
+static void SwapXpAttributeEvent();
+
+static int SProcXpGetPrinterList();
+static int SProcXpCreateContext();
+static int SProcXpSetContext();
+static int SProcXpGetContext();
+static int SProcXpDestroyContext();
+static int SProcXpGetContextScreen();
+static int SProcXpStartJob();
+static int SProcXpEndJob();
+static int SProcXpStartDoc();
+static int SProcXpEndDoc();
+static int SProcXpStartPage();
+static int SProcXpEndPage();
+static int SProcXpSelectInput();
+static int SProcXpInputSelected();
+static int SProcXpPutDocumentData();
+static int SProcXpGetDocumentData();
+static int SProcXpGetAttributes();
+static int SProcXpGetOneAttribute();
+static int SProcXpSetAttributes();
+static int SProcXpRehashPrinterList();
+static int SProcXpGetPageDimensions();
+static int SProcXpSetImageResolution();
+static int SProcXpGetImageResolution();
+
+static void SendXpNotify();
+static void SendAttributeNotify();
+static int XpFreeClient();
+static int XpFreeContext();
+static int XpFreePage();
+static int XpFreeEvents();
+static Bool XpCloseScreen();
+static CARD32 GetAllEventMasks();
+static struct _XpEvent *AddEventRec();
+static void DeleteEventRec();
+static struct _XpEvent *FindEventRec();
+static struct _XpClient *CreateXpClient();
+static void FreeXpClient();
+static void InitContextPrivates();
+static void ResetContextPrivates();
+static struct _XpClient *FindClient();
+static struct _XpClient *AcquireClient();
+
+typedef struct _driver {
+    struct _driver *next;
+    char *name;
+    int (* CreateContext)();
+} XpDriverRec, *XpDriverPtr;
+
+typedef struct  _xpScreen {
+    Bool (* CloseScreen)();
+    struct _driver *drivers;
+} XpScreenRec, *XpScreenPtr;
+
+/*
+ * Each context has a list of XpClients indicating which clients have
+ * associated this context with their connection.
+ * Each such client has a RTclient resource allocated for it,
+ * and this per-client
+ * resource is used to delete the XpClientRec if/when the client closes
+ * its connection.
+ * The list of XpClients is also walked if/when the context is destroyed
+ * so that the ContextPtr can be removed from the client's devPrivates.
+ */
+typedef struct _XpClient {
+       struct _XpClient *pNext;
+       ClientPtr       client;
+       XpContextPtr    context;
+       CARD32          eventMask;
+       XID             contextClientID; /* unneeded sanity check? */
+} XpClientRec, *XpClientPtr;
+
+/*
+ * Each StartPage request specifies a window which forms the top level
+ * window of the page.  One of the following structs is created as a
+ * RTpage resource with the same ID as the window itself.  This enables 
+ * us to clean up when/if the window is destroyed, and to prevent the
+ * same window from being simultaneously referenced in multiple contexts.
+ * The page resource is created at the first StartPage on a given window,
+ * and is only destroyed when/if the window is destroyed.  When the
+ * EndPage is recieved (or an EndDoc or EndJob) the context field is
+ * set to NULL, but the resource remains alive.
+ */
+typedef struct _XpPage {
+       XpContextPtr    context;
+} XpPageRec, *XpPagePtr;
+
+typedef struct _XpStPageRec {
+    XpContextPtr pContext;
+    Bool slept;
+    XpPagePtr pPage;
+    WindowPtr pWin;
+} XpStPageRec, *XpStPagePtr;
+
+typedef struct _XpStDocRec {
+    XpContextPtr pContext;
+    Bool slept;
+    CARD8 type;
+} XpStDocRec, *XpStDocPtr;
+
+#define QUADPAD(x) ((((x)+3)>>2)<<2)
+
+/*
+ * Possible bit-mask values in the "state" field of a XpContextRec.
+ */
+#define JOB_STARTED (1 << 0)
+#define DOC_RAW_STARTED (1 << 1)
+#define DOC_COOKED_STARTED (1 << 2)
+#define PAGE_STARTED (1 << 3)
+#define GET_DOC_DATA_STARTED (1 << 4)
+#define JOB_GET_DATA (1 << 5)
+    
+static XpScreenPtr XpScreens[MAXSCREENS];
+static unsigned char XpReqCode;
+static int XpEventBase;
+static int XpErrorBase;
+static int XpGeneration = 0;
+static int XpWindowPrivateIndex;
+static int XpClientPrivateIndex;
+
+/* Variables for the context private machinery. 
+ * These must be initialized at compile time because
+ * main() calls InitOutput before InitExtensions, and the
+ * output drivers are likely to call AllocateContextPrivate.
+ * These variables are reset at CloseScreen time.  CloseScreen
+ * is used because it occurs after FreeAllResources, and before
+ * the next InitOutput cycle.
+ */
+static int  contextPrivateCount = 0;
+static int contextPrivateLen = 0;
+static unsigned *contextPrivateSizes = (unsigned *)NULL;
+static unsigned totalContextSize = sizeof(XpContextRec);
+
+/*
+ * There are three types of resources involved.  One is the resource associated
+ * with the context itself, with an ID specified by a printing client.  The
+ * next is a resource created by us on the client's behalf (and unknown to
+ * the client) when a client inits or sets a context which allows us to 
+ * track each client's interest in events
+ * on a particular context, and also allows us to clean up this interest
+ * record when/if the client's connection is closed.  Finally, there is
+ * a resource created for each window that's specified in a StartPage.  This
+ * resource carries the same ID as the window itself, and enables us to
+ * easily prevent the same window being referenced in multiple contexts
+ * simultaneously, and enables us to clean up if the window is destroyed
+ * before the EndPage.
+ */
+static RESTYPE RTclient, RTcontext, RTpage;
+
+/*
+ * allEvents is the OR of all the legal event mask bits.
+ */
+static CARD32 allEvents = XPPrintMask | XPAttributeMask;
+
+
+/*******************************************************************************
+ *
+ * ExtensionInit, Driver Init functions, QueryVersion, and Dispatch procs
+ *
+ ******************************************************************************/
+
+/*
+ * XpExtensionInit
+ *
+ * Called from InitExtensions in main() usually through miinitextension
+ *
+ */
+
+void
+XpExtensionInit()
+{
+    ExtensionEntry *extEntry, *AddExtension();
+    int i;
+
+    RTclient = CreateNewResourceType(XpFreeClient);
+    RTcontext = CreateNewResourceType(XpFreeContext);
+    RTpage = CreateNewResourceType(XpFreePage);
+    if (RTclient && RTcontext && RTpage &&
+        (extEntry = AddExtension(XP_PRINTNAME, XP_EVENTS, XP_ERRORS,
+                               ProcXpDispatch, ProcXpSwappedDispatch,
+                               XpResetProc, StandardMinorOpcode)))
+    {
+        XpReqCode = (unsigned char)extEntry->base;
+        XpEventBase = extEntry->eventBase;
+        XpErrorBase = extEntry->errorBase;
+        EventSwapVector[XpEventBase] = SwapXpNotifyEvent;
+        EventSwapVector[XpEventBase+1] = SwapXpAttributeEvent;
+    }
+
+    if(XpGeneration != serverGeneration)
+    {
+       XpClientPrivateIndex = AllocateClientPrivateIndex();
+       /*
+        * We allocate 0 length & simply stuff a pointer to the
+        * ContextRec in the DevUnion.
+        */
+       if(AllocateClientPrivate(XpClientPrivateIndex, 0) != TRUE)
+       {
+               /* we can't alloc a client private, should we bail??? XXX */
+       }
+       XpGeneration = serverGeneration;
+    }
+
+    for(i = 0; i < MAXSCREENS; i++)
+    {
+       /*
+        * If a screen has registered with our extension, then we
+        * wrap the screen's CloseScreen function to allow us to
+        * reset our ContextPrivate stuff.  Note that this
+        * requires a printing DDX to call XpRegisterInitFunc
+        * _before_ this extension is initialized - i.e. at screen init
+        * time, _not_ at root window creation time.
+        */
+       if(XpScreens[i] != (XpScreenPtr)NULL)
+       {
+           XpScreens[i]->CloseScreen = screenInfo.screens[i]->CloseScreen;
+           screenInfo.screens[i]->CloseScreen = XpCloseScreen;
+       }
+    }
+    DeclareExtensionSecurity(XP_PRINTNAME, TRUE);
+}
+
+static void
+XpResetProc(extEntry)
+    ExtensionEntry extEntry;
+{
+    int i;
+
+    /*
+     * We can't free up the XpScreens recs here, because extensions are
+     * closed before screens, and our CloseScreen function uses the XpScreens
+     * recs.
+    for(i = 0; i < MAXSCREENS; i++)
+    {
+       if(XpScreens[i] != (XpScreenPtr)NULL)
+           Xfree(XpScreens[i]);
+       XpScreens[i] = (XpScreenPtr)NULL;
+    }
+    */
+}
+
+static Bool
+XpCloseScreen(index, pScreen)
+    int index;
+    ScreenPtr pScreen;
+{
+    Bool (* CloseScreen)();
+
+    CloseScreen = XpScreens[index]->CloseScreen;
+    if(XpScreens[index] != (XpScreenPtr)NULL)
+    {
+       XpDriverPtr pDriv, nextDriv;
+
+       pDriv = XpScreens[index]->drivers;
+       while(pDriv != (XpDriverPtr)NULL)
+       {
+           nextDriv = pDriv->next;
+            Xfree(pDriv);
+           pDriv = nextDriv;
+       }
+       Xfree(XpScreens[index]);
+    }
+    XpScreens[index] = (XpScreenPtr)NULL;
+
+    /*
+     * It's wasteful to call ResetContextPrivates() at every CloseScreen, 
+     * but it's the best we know how to do for now.  We do this because we
+     * have to wait until after all resources have been freed (so we know
+     * how to free the ContextRecs), and before the next InitOutput cycle.
+     * See dix/main.c for the order of initialization and reset.
+     */
+    ResetContextPrivates();
+    return (*CloseScreen)(index, pScreen);
+}
+
+static void
+FreeScreenEntry(pScreenEntry)
+    XpScreenPtr pScreenEntry;
+{
+    XpDriverPtr pDriver;
+
+    pDriver = pScreenEntry->drivers; 
+    while(pDriver != (XpDriverPtr)NULL)
+    {
+       XpDriverPtr tmp;
+
+       tmp = pDriver->next;
+       xfree(pDriver);
+       pDriver = tmp;
+    }
+    xfree(pScreenEntry);
+}
+
+/*
+ * XpRegisterInitFunc tells the print extension which screens
+ * are printers as opposed to displays, and what drivers are
+ * supported on each screen.  This eliminates the need of
+ * allocating print-related private structures on windows on _all_ screens.
+ * It also hands the extension a pointer to the routine to be called
+ * whenever a context gets created for a particular driver on this screen.
+ */
+void
+XpRegisterInitFunc(pScreen, driverName, initContext)
+    ScreenPtr pScreen;
+    char *driverName;
+    int (*initContext)();
+{
+    XpDriverPtr pDriver;
+
+    if(XpScreens[pScreen->myNum] == (XpScreenPtr)NULL)
+    {
+        if((XpScreens[pScreen->myNum] =
+           (XpScreenPtr) Xalloc(sizeof(XpScreenRec))) == (XpScreenPtr)NULL)
+            return;
+       XpScreens[pScreen->myNum]->CloseScreen = (Bool(*)())NULL;
+       XpScreens[pScreen->myNum]->drivers = (XpDriverPtr)NULL;
+    }
+
+    if((pDriver = (XpDriverPtr)Xalloc(sizeof(XpDriverRec))) == 
+       (XpDriverPtr)NULL)
+       return;
+    pDriver->next = XpScreens[pScreen->myNum]->drivers;
+    pDriver->name = driverName;
+    pDriver->CreateContext = initContext;
+    XpScreens[pScreen->myNum]->drivers = pDriver;
+}
+
+static int 
+ProcXpDispatch(client)
+    ClientPtr client;
+{
+    REQUEST(xReq);
+
+    switch(stuff->data)
+    {
+       case X_PrintQueryVersion:
+            return ProcXpQueryVersion(client);
+       case X_PrintGetPrinterList:
+           return ProcXpGetPrinterList(client);
+       case X_PrintCreateContext:
+           return ProcXpCreateContext(client);
+       case X_PrintSetContext:
+           return ProcXpSetContext(client);
+       case X_PrintGetContext:
+           return ProcXpGetContext(client);
+       case X_PrintDestroyContext:
+           return ProcXpDestroyContext(client);
+       case X_PrintGetContextScreen:
+           return ProcXpGetContextScreen(client);
+       case X_PrintStartJob:
+            return ProcXpStartJob(client);
+       case X_PrintEndJob:
+            return ProcXpEndJob(client);
+       case X_PrintStartDoc:
+            return ProcXpStartDoc(client);
+       case X_PrintEndDoc:
+            return ProcXpEndDoc(client);
+       case X_PrintStartPage:
+            return ProcXpStartPage(client);
+       case X_PrintEndPage:
+            return ProcXpEndPage(client);
+       case X_PrintSelectInput:
+            return ProcXpSelectInput(client);
+       case X_PrintInputSelected:
+            return ProcXpInputSelected(client);
+       case X_PrintPutDocumentData:
+            return ProcXpPutDocumentData(client);
+       case X_PrintGetDocumentData:
+            return ProcXpGetDocumentData(client);
+       case X_PrintSetAttributes:
+           return ProcXpSetAttributes(client);
+       case X_PrintGetAttributes:
+           return ProcXpGetAttributes(client);
+       case X_PrintGetOneAttribute:
+           return ProcXpGetOneAttribute(client);
+       case X_PrintRehashPrinterList:
+           return ProcXpRehashPrinterList(client);
+       case X_PrintQueryScreens:
+            return ProcXpQueryScreens(client);
+       case X_PrintGetPageDimensions:
+            return ProcXpGetPageDimensions(client);
+       case X_PrintSetImageResolution:
+            return ProcXpSetImageResolution(client);
+       case X_PrintGetImageResolution:
+            return ProcXpGetImageResolution(client);
+       default:
+           return BadRequest;
+    }
+}
+
+static int 
+ProcXpSwappedDispatch(client)
+    ClientPtr client;
+{
+    int temp;
+    REQUEST(xReq);
+
+    switch(stuff->data)
+    {
+       case X_PrintQueryVersion:
+           swaps(&stuff->length, temp);
+            return ProcXpQueryVersion(client);
+       case X_PrintGetPrinterList:
+           return SProcXpGetPrinterList(client);
+       case X_PrintCreateContext:
+           return SProcXpCreateContext(client);
+       case X_PrintSetContext:
+           return SProcXpSetContext(client);
+       case X_PrintGetContext:
+           return SProcXpGetContext(client);
+       case X_PrintDestroyContext:
+           return SProcXpDestroyContext(client);
+       case X_PrintGetContextScreen:
+           return SProcXpGetContextScreen(client);
+       case X_PrintStartJob:
+            return SProcXpStartJob(client);
+       case X_PrintEndJob:
+            return SProcXpEndJob(client);
+       case X_PrintStartDoc:
+            return SProcXpStartDoc(client);
+       case X_PrintEndDoc:
+            return SProcXpEndDoc(client);
+       case X_PrintStartPage:
+            return SProcXpStartPage(client);
+       case X_PrintEndPage:
+            return SProcXpEndPage(client);
+       case X_PrintSelectInput:
+           return SProcXpSelectInput(client);
+       case X_PrintInputSelected:
+           return SProcXpInputSelected(client);
+       case X_PrintPutDocumentData:
+            return SProcXpPutDocumentData(client);
+       case X_PrintGetDocumentData:
+            return SProcXpGetDocumentData(client);
+       case X_PrintSetAttributes:
+           return SProcXpSetAttributes(client);
+       case X_PrintGetAttributes:
+           return SProcXpGetAttributes(client);
+       case X_PrintGetOneAttribute:
+           return SProcXpGetOneAttribute(client);
+       case X_PrintRehashPrinterList:
+           return SProcXpRehashPrinterList(client);
+       case X_PrintQueryScreens:
+           swaps(&stuff->length, temp);
+            return ProcXpQueryScreens(client);
+       case X_PrintGetPageDimensions:
+            return SProcXpGetPageDimensions(client);
+       case X_PrintSetImageResolution:
+            return SProcXpSetImageResolution(client);
+       case X_PrintGetImageResolution:
+            return SProcXpGetImageResolution(client);
+       default:
+           return BadRequest;
+    }
+}
+
+static int
+ProcXpQueryVersion(client)
+    ClientPtr client;
+{
+    REQUEST(xPrintQueryVersionReq);
+    xPrintQueryVersionReply rep;
+    register int n;
+    long l;
+
+    REQUEST_SIZE_MATCH(xPrintQueryVersionReq);
+    rep.type = X_Reply;
+    rep.length = 0;
+    rep.sequenceNumber = client->sequence;
+    rep.majorVersion = XP_MAJOR_VERSION;
+    rep.minorVersion = XP_MINOR_VERSION;
+    if (client->swapped) {
+        swaps(&rep.sequenceNumber, n);
+        swapl(&rep.length, l);
+        swaps(&rep.majorVersion, n);
+        swaps(&rep.minorVersion, n);
+    }
+    WriteToClient(client, sz_xPrintQueryVersionReply, (char *)&rep);
+    return client->noClientException;
+}
+
+/*******************************************************************************
+ *
+ * GetPrinterList : Return a list of all printers associated with this
+ *                  server.  Calls XpDiGetPrinterList, which is defined in
+ *                 the device-independent code in Xserver/Xprint.
+ *
+ ******************************************************************************/
+
+static int
+ProcXpGetPrinterList(client)
+    ClientPtr client;
+{
+    REQUEST(xPrintGetPrinterListReq);
+    int totalSize, numEntries;
+    XpDiListEntry **pList, *pEntry;
+    xPrintGetPrinterListReply *rep;
+    int n, i, totalBytes;
+    long l;
+    char *curByte;
+
+    REQUEST_AT_LEAST_SIZE(xPrintGetPrinterListReq);
+
+    totalSize = ((sz_xPrintGetPrinterListReq) >> 2) +
+                ((stuff->printerNameLen + 3) >> 2) +
+                ((stuff->localeLen + 3) >> 2);
+    if(totalSize != client->req_len)
+        return BadLength;
+
+    pList = XpDiGetPrinterList(stuff->printerNameLen, (char *)(stuff + 1), 
+                              stuff->localeLen, (char *)((stuff + 1) + 
+                              QUADPAD(stuff->printerNameLen)));
+
+    for(numEntries = 0, totalBytes = sz_xPrintGetPrinterListReply;
+       pList[numEntries] != (XpDiListEntry *)NULL;
+       numEntries++)
+    {
+       totalBytes += 2 * sizeof(CARD32); 
+       totalBytes += QUADPAD(strlen(pList[numEntries]->name));
+       totalBytes += QUADPAD(strlen(pList[numEntries]->description));
+    }
+
+    if((rep = (xPrintGetPrinterListReply *)xalloc(totalBytes)) == 
+       (xPrintGetPrinterListReply *)NULL)
+       return BadAlloc;
+
+    rep->type = X_Reply;
+    rep->length = (totalBytes - sz_xPrintGetPrinterListReply) >> 2;
+    rep->sequenceNumber = client->sequence;
+    rep->listCount = numEntries;
+    if (client->swapped) {
+        swaps(&rep->sequenceNumber, n);
+        swapl(&rep->length, l);
+        swapl(&rep->listCount, l);
+    }
+
+    for(i = 0, curByte = (char *)(rep + 1); i < numEntries; i++)
+    {
+       CARD32 *pCrd;
+       int len;
+
+       pCrd = (CARD32 *)curByte;
+       len = strlen(pList[i]->name);
+       *pCrd = len;
+        if (client->swapped)
+            swapl((long *)curByte, l);
+       curByte += sizeof(CARD32);
+       strncpy(curByte, pList[i]->name, len);
+       curByte += QUADPAD(len);
+
+       pCrd = (CARD32 *)curByte;
+       len = strlen(pList[i]->description);
+       *pCrd = len;
+        if (client->swapped)
+            swapl((long *)curByte, l);
+       curByte += sizeof(CARD32);
+       strncpy(curByte, pList[i]->description, len);
+       curByte += QUADPAD(len);
+    }
+
+    XpDiFreePrinterList(pList);
+
+    WriteToClient(client, totalBytes, (char *)rep);
+    xfree(rep);
+    return client->noClientException;
+}
+
+/*******************************************************************************
+ *
+ * QueryScreens: Returns the list of screens which are associated with
+ *               print drivers.
+ *
+ ******************************************************************************/
+
+static int
+ProcXpQueryScreens(client)
+    ClientPtr client;
+{
+    REQUEST(xPrintQueryScreensReq);
+    int i, numPrintScreens, totalSize;
+    WINDOW *pWinId;
+    xPrintQueryScreensReply *rep;
+    long l;
+
+    REQUEST_SIZE_MATCH(xPrintQueryScreensReq);
+
+    rep = (xPrintQueryScreensReply *)xalloc(sz_xPrintQueryScreensReply);
+    pWinId = (WINDOW *)(rep + 1);
+
+    for(i = 0, numPrintScreens = 0, totalSize = sz_xPrintQueryScreensReply; 
+       i < MAXSCREENS; i++)
+    {
+       /*
+        * If a screen has registered with our extension, then it's
+        * a printer screen.
+        */
+       if(XpScreens[i] != (XpScreenPtr)NULL)
+       {
+           numPrintScreens++;
+           totalSize += sizeof(WINDOW);
+           rep = (xPrintQueryScreensReply *)xrealloc(rep, totalSize);
+           *pWinId = WindowTable[i]->drawable.id;
+            if (client->swapped)
+                swapl((long *)pWinId, l);
+           pWinId++;
+       }
+    }
+
+    rep->type = X_Reply;
+    rep->sequenceNumber = client->sequence;
+    rep->length = (totalSize - sz_xPrintQueryScreensReply) >> 2;
+    rep->listCount = numPrintScreens;
+    if (client->swapped)
+    {
+       int n;
+
+        swaps(&rep->sequenceNumber, n);
+        swapl(&rep->length, l);
+        swapl(&rep->listCount, l);
+    }
+
+    WriteToClient(client, totalSize, (char *)rep);
+    xfree(rep);
+    return client->noClientException;
+}
+
+static int 
+ProcXpGetPageDimensions(client)
+    ClientPtr client;
+{
+    REQUEST(xPrintGetPageDimensionsReq);
+    CARD16 width, height;
+    xRectangle rect;
+    xPrintGetPageDimensionsReply rep;
+    XpContextPtr pContext;
+    int result;
+
+    REQUEST_SIZE_MATCH(xPrintGetPageDimensionsReq);
+
+    if((pContext =(XpContextPtr)SecurityLookupIDByType(client,
+                                                      stuff->printContext,
+                                                      RTcontext,
+                                                      SecurityReadAccess))
+       == (XpContextPtr)NULL)
+    {
+       client->errorValue = stuff->printContext;
+        return XpErrorBase+XPBadContext;
+    }
+
+    if(pContext->funcs.GetMediumDimensions != (int (*)())NULL)
+        result = pContext->funcs.GetMediumDimensions(pContext, &width, &height);
+    else
+        return BadImplementation;
+
+    if(pContext->funcs.GetReproducibleArea != (int (*)())NULL)
+        result = pContext->funcs.GetReproducibleArea(pContext, &rect);
+    else
+        return BadImplementation;
+
+    rep.type = X_Reply;
+    rep.sequenceNumber = client->sequence;
+    rep.length = 0;
+    rep.width = width;
+    rep.height = height;
+    rep.rx = rect.x;
+    rep.ry = rect.y;
+    rep.rwidth = rect.width;
+    rep.rheight = rect.height;
+
+    if(client->swapped)
+    {
+       int n;
+       long l;
+
+        swaps(&rep.sequenceNumber, n);
+        swapl(&rep.length, l);
+        swaps(&rep.width, n);
+        swaps(&rep.height, n);
+        swaps(&rep.rx, n);
+        swaps(&rep.ry, n);
+        swaps(&rep.rwidth, n);
+        swaps(&rep.rheight, n);
+    }
+
+    WriteToClient(client, sz_xPrintGetPageDimensionsReply, (char *)&rep);
+    return client->noClientException;
+}
+
+static int 
+ProcXpSetImageResolution(client)
+    ClientPtr client;
+{
+    REQUEST(xPrintSetImageResolutionReq);
+    xPrintSetImageResolutionReply rep;
+    XpContextPtr pContext;
+    Bool status;
+    int result;
+
+    REQUEST_SIZE_MATCH(xPrintSetImageResolutionReq);
+
+    if((pContext =(XpContextPtr)SecurityLookupIDByType(client,
+                                                      stuff->printContext,
+                                                      RTcontext,
+                                                      SecurityWriteAccess))
+       == (XpContextPtr)NULL)
+    {
+       client->errorValue = stuff->printContext;
+        return XpErrorBase+XPBadContext;
+    }
+
+    rep.prevRes = pContext->imageRes;
+    if(pContext->funcs.SetImageResolution != (int (*)())NULL)
+        result = pContext->funcs.SetImageResolution(pContext,
+                                                   (int)stuff->imageRes,
+                                                   &status);
+    else
+        status = FALSE;
+
+    rep.type = X_Reply;
+    rep.sequenceNumber = client->sequence;
+    rep.length = 0;
+    rep.status = status;
+
+    if(client->swapped)
+    {
+       int n;
+       long l;
+
+        swaps(&rep.sequenceNumber, n);
+        swapl(&rep.length, l);
+        swaps(&rep.prevRes, n);
+    }
+
+    WriteToClient(client, sz_xPrintSetImageResolutionReply, (char *)&rep);
+    return client->noClientException;
+}
+
+static int 
+ProcXpGetImageResolution(client)
+    ClientPtr client;
+{
+    REQUEST(xPrintGetImageResolutionReq);
+    xPrintGetImageResolutionReply rep;
+    XpContextPtr pContext;
+    Bool status;
+    int result;
+
+    REQUEST_SIZE_MATCH(xPrintGetImageResolutionReq);
+
+    if((pContext =(XpContextPtr)SecurityLookupIDByType(client,
+                                                      stuff->printContext,
+                                                      RTcontext,
+                                                      SecurityReadAccess))
+       == (XpContextPtr)NULL)
+    {
+       client->errorValue = stuff->printContext;
+        return XpErrorBase+XPBadContext;
+    }
+
+    rep.type = X_Reply;
+    rep.sequenceNumber = client->sequence;
+    rep.length = 0;
+    rep.imageRes = pContext->imageRes;
+
+    if(client->swapped)
+    {
+       int n;
+       long l;
+
+        swaps(&rep.sequenceNumber, n);
+        swapl(&rep.length, l);
+        swaps(&rep.imageRes, n);
+    }
+
+    WriteToClient(client, sz_xPrintGetImageResolutionReply, (char *)&rep);
+    return client->noClientException;
+}
+
+/*******************************************************************************
+ *
+ * RehashPrinterList : Cause the server's list of printers to be rebuilt.
+ *                     This allows new printers to be added, or old ones
+ *                    deleted without needing to restart the server.
+ *
+ ******************************************************************************/
+
+static int
+ProcXpRehashPrinterList(client)
+    ClientPtr client;
+{
+    REQUEST(xPrintRehashPrinterListReq);
+
+    REQUEST_SIZE_MATCH(xPrintRehashPrinterListReq);
+
+    return XpRehashPrinterList();
+}
+
+/******************************************************************************
+ *
+ * Context functions: Init, Set, Destroy, FreeContext
+ *                     AllocateContextPrivateIndex, AllocateContextPrivate
+ *                     and supporting functions.
+ *
+ *     Init creates a context, creates a XpClientRec for the calling
+ *     client, and stores the contextPtr in the client's devPrivates.
+ *
+ *     Set creates a XpClientRec for the calling client, and stores the
+ *     contextPtr in the client's devPrivates unless the context is None.
+ *     If the context is None, then the client's connection association
+ *     with any context is removed.
+ *
+ *     Destroy frees any and all XpClientRecs associated with the context,
+ *     frees the context itself, and removes the contextPtr from any
+ *     relevant client devPrivates.
+ *
+ *     FreeContext is called by FreeResource to free up a context.
+ *
+ ******************************************************************************/
+
+/*
+ * CreateContext creates and initializes the memory for the context itself.
+ * The driver's CreateContext function
+ * is then called.
+ */
+static int
+ProcXpCreateContext(client)
+    ClientPtr client;
+{
+    REQUEST(xPrintCreateContextReq);
+    XpScreenPtr pPrintScreen;
+    WindowPtr pRoot;
+    char *printerName, *driverName;
+    XpContextPtr pContext;
+    XpClientPtr pNewPrintClient;
+    int result = Success;
+    XpDriverPtr pDriver;
+
+    REQUEST_AT_LEAST_SIZE(xPrintCreateContextReq);
+
+    LEGAL_NEW_RESOURCE(stuff->contextID, client);
+
+    /*
+     * Check to see if the printer name is valid.
+     */
+    if((pRoot = XpDiValidatePrinter(stuff + 1, stuff->printerNameLen)) == 
+       (WindowPtr)NULL)
+       return BadMatch;
+
+    pPrintScreen = XpScreens[pRoot->drawable.pScreen->myNum];
+
+    /*
+     * Allocate and add the context resource.
+     */
+    if((pContext = (XpContextPtr) xalloc(totalContextSize)) == 
+       (XpContextPtr) NULL)
+       return BadAlloc;
+
+    InitContextPrivates(pContext);
+
+    if(AddResource(stuff->contextID, RTcontext, (pointer) pContext)
+       != TRUE)
+    {
+       xfree(pContext);
+       return BadAlloc;
+    }
+
+    pContext->contextID = stuff->contextID;
+    pContext->clientHead = (XpClientPtr)NULL;
+    pContext->screenNum = pRoot->drawable.pScreen->myNum;
+    pContext->state = 0;
+    pContext->clientSlept = (ClientPtr)NULL;
+    pContext->imageRes = 0;
+
+    pContext->funcs.DestroyContext = (int (*)())NULL;
+    pContext->funcs.StartJob = (int (*)())NULL;
+    pContext->funcs.EndJob = (int (*)())NULL;
+    pContext->funcs.StartDoc = (int (*)())NULL;
+    pContext->funcs.EndDoc = (int (*)())NULL;
+    pContext->funcs.StartPage = (int (*)())NULL;
+    pContext->funcs.EndPage = (int (*)())NULL;
+    pContext->funcs.PutDocumentData = (int (*)())NULL;
+    pContext->funcs.GetDocumentData = (int (*)())NULL;
+    pContext->funcs.GetAttributes = (char * (*)())NULL;
+    pContext->funcs.GetOneAttribute = (char * (*)())NULL;
+    pContext->funcs.SetAttributes = (int (*)())NULL;
+    pContext->funcs.AugmentAttributes = (int (*)())NULL;
+    pContext->funcs.GetMediumDimensions = (int (*)())NULL;
+    pContext->funcs.GetReproducibleArea = (int (*)())NULL;
+    pContext->funcs.SetImageResolution = (int (*)())NULL;
+
+    if((pContext->printerName = (char *)xalloc(stuff->printerNameLen + 1)) == 
+       (char *)NULL)
+    {
+       /* Freeing the context also causes the XpClients to be freed. */
+       FreeResource(stuff->contextID, RT_NONE);
+       return BadAlloc;
+    }
+    strncpy(pContext->printerName, (char *)(stuff + 1), stuff->printerNameLen);
+    pContext->printerName[stuff->printerNameLen] = (char)'\0';
+
+    driverName = XpDiGetDriverName(pRoot->drawable.pScreen->myNum, 
+                                  pContext->printerName);
+    
+    for(pDriver = pPrintScreen->drivers; 
+       pDriver != (XpDriverPtr)NULL;
+       pDriver = pDriver->next)
+    {
+       if(!strcmp(driverName, pDriver->name))
+       {
+           if(pDriver->CreateContext != (Bool (*)())NULL)
+               pDriver->CreateContext(pContext);
+           else
+               return BadImplementation;
+           break;
+       }
+    }
+
+    if (client->noClientException != Success)
+        return client->noClientException;
+    else
+       return result;
+}
+
+/*
+ * SetContext creates the calling client's contextClient resource,
+ * and stashes the contextID in the client's devPrivate.
+ */
+static int
+ProcXpSetContext(client)
+    ClientPtr client;
+{
+    REQUEST(xPrintSetContextReq);
+
+    XpContextPtr pContext;
+    XpClientPtr pPrintClient;
+    int result = Success;
+
+    REQUEST_AT_LEAST_SIZE(xPrintSetContextReq);
+
+    if((pContext = client->devPrivates[XpClientPrivateIndex].ptr) != 
+       (pointer)NULL)
+    {
+       /*
+        * Erase this client's knowledge of its old context, if any.
+        */
+        if((pPrintClient = FindClient(pContext, client)) != (XpClientPtr)NULL)
+        {
+           XpUnsetFontResFunc(client);
+           
+           if(pPrintClient->eventMask == 0)
+               FreeXpClient(pPrintClient, TRUE);
+        }
+
+        client->devPrivates[XpClientPrivateIndex].ptr = (pointer)NULL;
+    }
+    if(stuff->printContext == None)
+        return Success;
+
+    /*
+     * Check to see that the supplied XID is really a valid print context
+     * in this server.
+     */
+    if((pContext =(XpContextPtr)SecurityLookupIDByType(client,
+                                                      stuff->printContext,
+                                                      RTcontext,
+                                                      SecurityWriteAccess))
+       == (XpContextPtr)NULL)
+    {
+       client->errorValue = stuff->printContext;
+        return XpErrorBase+XPBadContext;
+    }
+
+    if((pPrintClient = AcquireClient(pContext, client)) == (XpClientPtr)NULL)
+        return BadAlloc;
+
+    client->devPrivates[XpClientPrivateIndex].ptr = pContext;
+
+    XpSetFontResFunc(client);
+
+    if (client->noClientException != Success)
+        return client->noClientException;
+    else
+       return result;
+}
+
+XpContextPtr
+XpGetPrintContext(client)
+    ClientPtr client;
+{
+    return (client->devPrivates[XpClientPrivateIndex].ptr);
+}
+
+static int
+ProcXpGetContext(client)
+    ClientPtr client;
+{
+    REQUEST(xPrintGetContextReq);
+    xPrintGetContextReply rep;
+
+    XpContextPtr pContext;
+    XpClientPtr pNewPrintClient;
+    int result = Success;
+    register int n;
+    register long l;
+
+    REQUEST_SIZE_MATCH(xPrintGetContextReq);
+
+    if((pContext = client->devPrivates[XpClientPrivateIndex].ptr) == 
+       (pointer)NULL)
+       rep.printContext = None;
+    else
+        rep.printContext = pContext->contextID;
+    rep.type = X_Reply;
+    rep.length = 0;
+    rep.sequenceNumber = client->sequence;
+    if (client->swapped) {
+        swaps(&rep.sequenceNumber, n);
+        swapl(&rep.length, l);
+        swapl(&rep.printContext, l);
+    }
+    WriteToClient(client, sz_xPrintGetContextReply, (char *)&rep);
+    return client->noClientException;
+}
+
+
+/*
+ * DestroyContext frees the context associated with the calling client.
+ * It operates by freeing the context resource ID, thus causing XpFreeContext
+ * to be called.
+ */
+static int
+ProcXpDestroyContext(client)
+    ClientPtr client;
+{
+    REQUEST(xPrintDestroyContextReq);
+
+    XpContextPtr pContext;
+    XpClientPtr pXpClient;
+    ClientPtr curClient;
+
+    REQUEST_SIZE_MATCH(xPrintDestroyContextReq);
+
+    if((pContext =(XpContextPtr)SecurityLookupIDByType(client,
+                                                      stuff->printContext,
+                                                      RTcontext,
+                                                      SecurityDestroyAccess))
+       == (XpContextPtr)NULL)
+    {
+       client->errorValue = stuff->printContext;
+        return XpErrorBase+XPBadContext;
+    }
+
+    XpUnsetFontResFunc(client);
+           
+    FreeResource(pContext->contextID, RT_NONE);
+
+    return Success;
+}
+
+static int
+ProcXpGetContextScreen(client)
+    ClientPtr client;
+{
+    REQUEST(xPrintGetContextScreenReq);
+    xPrintGetContextScreenReply rep;
+    XpContextPtr pContext;
+    int n;
+    long l;
+
+    if((pContext =(XpContextPtr)SecurityLookupIDByType(client,
+                                                      stuff->printContext,
+                                                      RTcontext,
+                                                      SecurityReadAccess))
+       == (XpContextPtr)NULL)
+        return XpErrorBase+XPBadContext;
+    
+    rep.type = X_Reply;
+    rep.sequenceNumber = client->sequence;
+    rep.length = 0;
+    rep.rootWindow = WindowTable[pContext->screenNum]->drawable.id;
+
+    if (client->swapped) {
+        swaps(&rep.sequenceNumber, n);
+        swapl(&rep.length, l);
+        swapl(&rep.rootWindow, l);
+    }
+
+    WriteToClient(client, sz_xPrintGetContextScreenReply, (char *)&rep);
+    return client->noClientException;
+}
+
+/*
+ * XpFreeContext is the routine called by dix:FreeResource when a context
+ * resource ID is freed.
+ * It checks to see if there's a partial job pending on the context, and
+ * if so it calls the appropriate End procs with the cancel flag set.
+ * It calls the driver's DestroyContext routine to allow the driver to clean
+ * up any context-related memory or state.
+ * It calls FreeXpClient to free all the 
+ * associated XpClientRecs and to set all the client->devPrivates to NULL.
+ * It frees the printer name string, and frees the context
+ * itself.
+ */
+static int
+XpFreeContext(data, id)
+    pointer data;
+    XID id;
+{
+    XpContextPtr pContext = (XpContextPtr)data;
+
+    /* Clean up any pending job on this context */
+    if(pContext->state != 0)
+    {
+       if(pContext->state & PAGE_STARTED)
+       {
+           WindowPtr pWin = (WindowPtr )LookupIDByType(
+                                      pContext->pageWin, RT_WINDOW);
+           XpPagePtr pPage = (XpPagePtr)LookupIDByType(
+                                      pContext->pageWin, RTpage);
+
+           pContext->funcs.EndPage(pContext, pWin, TRUE);
+           SendXpNotify(pContext, XPEndPageNotify, TRUE);
+           pContext->state &= ~PAGE_STARTED;
+           if(pPage)
+               pPage->context = (XpContextPtr)NULL;
+       }
+       if((pContext->state & DOC_RAW_STARTED) || 
+          (pContext->state & DOC_COOKED_STARTED))
+       {
+           pContext->funcs.EndDoc(pContext, TRUE);
+           SendXpNotify(pContext, XPEndDocNotify, TRUE);
+           pContext->state &= ~DOC_RAW_STARTED;
+           pContext->state &= ~DOC_COOKED_STARTED;
+       }
+       if(pContext->funcs.EndJob != (int (*)())NULL)
+       {
+           pContext->funcs.EndJob(pContext, TRUE);
+           SendXpNotify(pContext, XPEndJobNotify, TRUE);
+           pContext->state &= ~JOB_STARTED;
+           pContext->state &= ~GET_DOC_DATA_STARTED;
+       }
+    }
+
+    /* 
+     * Tell the driver we're destroying the context
+     * This allows the driver to free and ContextPrivate data
+     */
+    if(pContext->funcs.DestroyContext != (int (*)())NULL)
+       pContext->funcs.DestroyContext(pContext);
+
+    /* Free up all the XpClientRecs */
+    while(pContext->clientHead != (XpClientPtr)NULL)
+    {
+       FreeXpClient(pContext->clientHead, TRUE);
+    }
+
+    xfree(pContext->printerName);
+    xfree(pContext);
+    return Success; /* ??? */
+}
+
+/*
+ * XpFreeClient is the routine called by dix:FreeResource when a RTclient
+ * is freed.  It simply calls the FreeXpClient routine to do the work.
+ */
+static int
+XpFreeClient(data, id)
+    pointer data;
+    XID id;
+{
+    FreeXpClient((XpClientPtr)data, FALSE);
+}
+
+/*
+ * FreeXpClient 
+ * frees the ClientRec passed in, and sets the client->devPrivates to NULL
+ * if the client->devPrivates points to the same context as the XpClient.
+ * Called from XpFreeContext(from FreeResource), and 
+ * XpFreeClient.  The boolean freeResource specifies whether or not to call
+ * FreeResource for the XpClientRec's XID.  We should free it except if we're
+ * called from XpFreeClient (which is itself called from FreeResource for the
+ * XpClientRec's XID).
+ */
+static void
+FreeXpClient(pXpClient, freeResource)
+    XpClientPtr pXpClient;
+    Bool freeResource;
+{
+    XpClientPtr pCurrent, pPrev;
+    XpContextPtr pContext = pXpClient->context;
+
+    /*
+     * If we're freeing the clientRec associated with the context tied
+     * to the client's devPrivates, then we need to clear the devPrivates.
+     */
+    if(pXpClient->client->devPrivates[XpClientPrivateIndex].ptr == 
+       pXpClient->context)
+    {
+        pXpClient->client->devPrivates[XpClientPrivateIndex].ptr = 
+                                       (pointer)NULL;
+    }
+
+    for(pPrev = (XpClientPtr)NULL, pCurrent = pContext->clientHead; 
+       pCurrent != (XpClientPtr)NULL; 
+       pCurrent = pCurrent->pNext)
+    {
+       if(pCurrent == pXpClient)
+       {
+           if(freeResource == TRUE)
+                FreeResource (pCurrent->contextClientID, RTclient);
+
+            if (pPrev != (XpClientPtr)NULL)
+                pPrev->pNext = pCurrent->pNext;
+            else
+                pContext->clientHead = pCurrent->pNext;
+
+            xfree (pCurrent);
+           break;
+       }
+       pPrev = pCurrent;
+    }
+}
+
+/*
+ * CreateXpClient takes a ClientPtr and returns a pointer to a
+ * XpClientRec which it allocates.  It also initializes the Rec,
+ * including adding a resource on behalf of the client to enable the
+ * freeing of the Rec when the client's connection is closed.
+ */
+static XpClientPtr
+CreateXpClient(client)
+    ClientPtr client;
+{
+    XpClientPtr pNewPrintClient;
+    XID clientResource;
+
+    if((pNewPrintClient = (XpClientPtr)xalloc(sizeof(XpClientRec))) ==
+      (XpClientPtr)NULL)
+        return (XpClientPtr)NULL;
+
+    clientResource = FakeClientID(client->index);
+    if(!AddResource(clientResource, RTclient, (pointer)pNewPrintClient))
+    {
+        xfree (pNewPrintClient);
+        return (XpClientPtr)NULL;
+    }
+
+    pNewPrintClient->pNext = (XpClientPtr)NULL;
+    pNewPrintClient->client = client;
+    pNewPrintClient->context = (XpContextPtr)NULL;
+    pNewPrintClient->eventMask = 0;
+    pNewPrintClient->contextClientID = clientResource;
+
+    return pNewPrintClient;
+}
+
+/*
+ * XpFreePage is the routine called by dix:FreeResource to free the page
+ * resource built with the same ID as a page window.  It checks to see
+ * if we're in the middle of a page, and if so calls the driver's EndPage
+ * function with 'cancel' set TRUE.  It frees the memory associated with
+ * the page resource.
+ */
+static int
+XpFreePage(data, id)
+    pointer data;
+    XID id;
+{
+    XpPagePtr page = (XpPagePtr)data;
+    int result = Success;
+    WindowPtr pWin = (WindowPtr )LookupIDByType(id, RT_WINDOW);
+
+    /* Check to see if the window's being deleted in the middle of a page */
+    if(page->context != (XpContextPtr)NULL && 
+       page->context->state & PAGE_STARTED)
+    {
+       XpScreenPtr pPrintScreen = XpScreens[page->context->screenNum];
+       if(page->context->funcs.EndPage != (int (*)())NULL)
+           result = page->context->funcs.EndPage(page->context, pWin, TRUE);
+        SendXpNotify(page->context, XPEndPageNotify, (int)TRUE);
+       page->context->pageWin = 0; /* None, NULL??? XXX */
+    }
+
+    xfree(page);
+    return result;
+}
+
+/*
+ * ContextPrivate machinery.
+ * Context privates are intended for use by the drivers, allowing the
+ * drivers to maintain context-specific data.  The driver should free
+ * the associated data at DestroyContext time.
+ */
+
+static void
+InitContextPrivates(context)
+    XpContextPtr context;
+{
+    register char *ptr;
+    DevUnion *ppriv;
+    register unsigned *sizes;
+    register unsigned size;
+    register int i;
+
+    if (totalContextSize == sizeof(XpContextRec))
+        ppriv = (DevUnion *)NULL;
+    else 
+        ppriv = (DevUnion *)(context + 1);
+
+    context->devPrivates = ppriv;
+    sizes = contextPrivateSizes;
+    ptr = (char *)(ppriv + contextPrivateLen);
+    for (i = contextPrivateLen; --i >= 0; ppriv++, sizes++)
+    {
+        if ( (size = *sizes) )
+        {
+            ppriv->ptr = (pointer)ptr;
+            ptr += size;
+        }
+        else
+            ppriv->ptr = (pointer)NULL;
+    }
+}
+
+static void
+ResetContextPrivates()
+{
+    contextPrivateCount = 0;
+    contextPrivateLen = 0;
+    xfree(contextPrivateSizes);
+    contextPrivateSizes = (unsigned *)NULL;
+    totalContextSize = sizeof(XpContextRec);
+
+}
+
+int
+XpAllocateContextPrivateIndex()
+{
+    return contextPrivateCount++;
+}
+
+Bool
+XpAllocateContextPrivate(index, amount)
+    int index;
+    unsigned amount;
+{
+    unsigned oldamount;
+
+    if (index >= contextPrivateLen)
+    {
+        unsigned *nsizes;
+        nsizes = (unsigned *)xrealloc(contextPrivateSizes,
+                                      (index + 1) * sizeof(unsigned));
+        if (!nsizes)
+            return FALSE;
+        while (contextPrivateLen <= index)
+        {
+            nsizes[contextPrivateLen++] = 0;
+            totalContextSize += sizeof(DevUnion);
+        }
+        contextPrivateSizes = nsizes;
+    }
+    oldamount = contextPrivateSizes[index];
+    if (amount > oldamount)
+    {
+        contextPrivateSizes[index] = amount;
+        totalContextSize += (amount - oldamount);
+    }
+    return TRUE;
+}
+
+static XpClientPtr
+AcquireClient(pContext, client)
+    XpContextPtr pContext;
+    ClientPtr client;
+{
+    XpClientPtr pXpClient;
+
+    if((pXpClient = FindClient(pContext, client)) != (XpClientPtr)NULL)
+       return pXpClient;
+
+    if((pXpClient = CreateXpClient(client)) == (XpClientPtr)NULL)
+           return (XpClientPtr)NULL;
+
+    pXpClient->context = pContext;
+    pXpClient->pNext = pContext->clientHead;
+    pContext->clientHead = pXpClient;
+
+    return pXpClient;
+}
+
+static XpClientPtr
+FindClient(pContext, client)
+    XpContextPtr pContext;
+    ClientPtr client;
+{
+    XpClientPtr pXpClient;
+
+    for(pXpClient = pContext->clientHead; pXpClient != (XpClientPtr)NULL;
+       pXpClient = pXpClient->pNext)
+    {
+       if(pXpClient->client == client)  return pXpClient;
+    }
+    return (XpClientPtr)NULL;
+}
+
+
+/******************************************************************************
+ *
+ * Start/End Functions: StartJob, EndJob, StartDoc, EndDoc, StartPage, EndPage
+ *
+ ******************************************************************************/
+
+static int
+ProcXpStartJob(client)
+    ClientPtr client;
+{
+    REQUEST(xPrintStartJobReq);
+    XpContextPtr pContext;
+    int result = Success;
+    XpScreenPtr pPrintScreen;
+
+    REQUEST_SIZE_MATCH(xPrintStartJobReq);
+
+    /* Check to see that a context has been established by this client. */
+    if((pContext = (XpContextPtr)client->devPrivates[XpClientPrivateIndex].ptr)
+       == (XpContextPtr)NULL)
+        return XpErrorBase+XPBadContext;
+
+    if(pContext->state != 0)
+       return XpErrorBase+XPBadSequence;
+
+    if(stuff->saveData != XPSpool && stuff->saveData != XPGetData)
+    {
+       client->errorValue = stuff->saveData;
+       return BadValue;
+    }
+
+    pPrintScreen = XpScreens[pContext->screenNum];
+    if(pContext->funcs.StartJob != (int (*)())NULL)
+        result = pContext->funcs.StartJob(pContext, 
+                        (stuff->saveData == XPGetData)? TRUE:FALSE);
+    else
+        return BadImplementation;
+
+    pContext->state = JOB_STARTED;
+    if(stuff->saveData == XPGetData)
+       pContext->state |= JOB_GET_DATA;
+
+    SendXpNotify(pContext, XPStartJobNotify, FALSE);
+
+    if (client->noClientException != Success)
+        return client->noClientException;
+    else
+        return result;
+}
+
+static int
+ProcXpEndJob(client)
+    ClientPtr client;
+{
+    REQUEST(xPrintEndJobReq);
+    XpScreenPtr pPrintScreen;
+    WindowPtr pWin;
+    int result = Success;
+    XpContextPtr pContext;
+
+    REQUEST_SIZE_MATCH(xPrintEndJobReq);
+
+    if((pContext = (XpContextPtr)client->devPrivates[XpClientPrivateIndex].ptr)
+       == (XpContextPtr)NULL)
+        return XpErrorBase+XPBadSequence;
+
+    pPrintScreen = XpScreens[pContext->screenNum];
+
+    if(!(pContext->state & JOB_STARTED))
+       return XpErrorBase+XPBadSequence;
+    
+    /* Check for missing EndDoc */
+    if((pContext->state & DOC_RAW_STARTED) || 
+       (pContext->state & DOC_COOKED_STARTED))
+    {
+       if(pContext->state & PAGE_STARTED)
+       {
+           WindowPtr pWin = (WindowPtr )LookupIDByType(
+                                          pContext->pageWin, RT_WINDOW);
+           XpPagePtr pPage = (XpPagePtr)LookupIDByType(
+                                      pContext->pageWin, RTpage);
+
+           if(stuff->cancel != TRUE)
+               return XpErrorBase+XPBadSequence;
+
+            if(pContext->funcs.EndPage != (int (*)())NULL)
+                result = pContext->funcs.EndPage(pContext, pWin, TRUE);
+            else
+               return BadImplementation;
+
+           SendXpNotify(pContext, XPEndPageNotify, TRUE);
+
+           pContext->state &= ~PAGE_STARTED;
+
+           if(pPage)
+               pPage->context = (XpContextPtr)NULL;
+
+           if(result != Success) return result;
+       }
+
+        if(pContext->funcs.EndDoc != (int (*)())NULL)
+            result = pContext->funcs.EndDoc(pContext, stuff->cancel);
+        else
+           return BadImplementation;
+
+        SendXpNotify(pContext, XPEndDocNotify, stuff->cancel);
+    }
+
+    if(pContext->funcs.EndJob != (int (*)())NULL)
+        result = pContext->funcs.EndJob(pContext, stuff->cancel);
+    else
+       return BadImplementation;
+
+    pContext->state = 0;
+
+    SendXpNotify(pContext, XPEndJobNotify, stuff->cancel);
+
+    if (client->noClientException != Success)
+        return client->noClientException;
+    else
+        return result;
+}
+
+static Bool
+DoStartDoc(client, c)
+    ClientPtr client;
+    XpStDocPtr c;
+{
+    XpScreenPtr pPrintScreen;
+    int result = Success;
+    XpContextPtr pContext = c->pContext;
+
+    if(c->pContext->state & JOB_GET_DATA && 
+       !(c->pContext->state & GET_DOC_DATA_STARTED))
+    {
+       if(!c->slept)
+       {
+           c->slept = TRUE;
+           ClientSleep(client, (ClientSleepProcPtr)DoStartDoc, (pointer) c);
+           c->pContext->clientSlept = client;
+       }
+       return TRUE;
+    }
+    
+    pPrintScreen = XpScreens[pContext->screenNum];
+
+    if(pContext->funcs.StartDoc != (int (*)())NULL)
+        result = pContext->funcs.StartDoc(pContext, c->type);
+    else
+    {
+           SendErrorToClient(client, XpReqCode, X_PrintStartPage, 0, 
+                             BadImplementation);
+           return TRUE;
+    }
+
+    if(c->type == XPDocNormal)
+        pContext->state |= DOC_COOKED_STARTED;
+    else
+       pContext->state |= DOC_RAW_STARTED;
+
+    SendXpNotify(pContext, XPStartDocNotify, (int)FALSE);
+
+    xfree(c);
+    return TRUE;
+}
+
+static int
+ProcXpStartDoc(client)
+    ClientPtr client;
+{
+    REQUEST(xPrintStartDocReq);
+    XpScreenPtr pPrintScreen;
+    int result = Success;
+    XpContextPtr pContext;
+    XpStDocPtr c;
+
+    REQUEST_SIZE_MATCH(xPrintStartDocReq);
+
+    if((pContext = (XpContextPtr)client->devPrivates[XpClientPrivateIndex].ptr)
+       == (XpContextPtr)NULL)
+        return XpErrorBase+XPBadSequence;
+
+    if(!(pContext->state & JOB_STARTED) || 
+       pContext->state & DOC_RAW_STARTED ||
+       pContext->state & DOC_COOKED_STARTED)
+       return XpErrorBase+XPBadSequence;
+
+    if(stuff->type != XPDocNormal && stuff->type != XPDocRaw)
+    {
+       client->errorValue = stuff->type;
+       return BadValue;
+    }
+
+    c = (XpStDocPtr)xalloc(sizeof(XpStDocRec));
+    c->pContext = pContext;
+    c->type = stuff->type;
+    c->slept = FALSE;
+    (void)DoStartDoc(client, c);
+
+    if (client->noClientException != Success)
+        return client->noClientException;
+    else
+        return result;
+}
+
+static int
+ProcXpEndDoc(client)
+    ClientPtr client;
+{
+    REQUEST(xPrintEndDocReq);
+    XpScreenPtr pPrintScreen;
+    XpContextPtr pContext;
+    int result = Success;
+
+    REQUEST_SIZE_MATCH(xPrintEndDocReq);
+
+    if((pContext = (XpContextPtr)client->devPrivates[XpClientPrivateIndex].ptr)
+       == (XpContextPtr)NULL)
+        return XpErrorBase+XPBadSequence;
+
+    pPrintScreen = XpScreens[pContext->screenNum];
+
+    if(!(pContext->state & DOC_RAW_STARTED) &&
+       !(pContext->state & DOC_COOKED_STARTED))
+       return XpErrorBase+XPBadSequence;
+    
+    if(pContext->state & PAGE_STARTED)
+    {
+       if(stuff->cancel == TRUE)
+       {
+           WindowPtr pWin = (WindowPtr )LookupIDByType(
+                                          pContext->pageWin, RT_WINDOW);
+           XpPagePtr pPage = (XpPagePtr)LookupIDByType(
+                                      pContext->pageWin, RTpage);
+
+            if(pContext->funcs.EndPage != (int (*)())NULL)
+                result = pContext->funcs.EndPage(pContext, pWin, TRUE);
+            else
+               return BadImplementation;
+
+           SendXpNotify(pContext, XPEndPageNotify, TRUE);
+
+           if(pPage)
+               pPage->context = (XpContextPtr)NULL;
+       }
+       else
+           return XpErrorBase+XPBadSequence;
+       if(result != Success)
+           return result;
+    }
+
+    if(pContext->funcs.EndDoc != (int (*)())NULL)
+        result = pContext->funcs.EndDoc(pContext, stuff->cancel);
+    else
+       return BadImplementation;
+
+    pContext->state &= ~DOC_RAW_STARTED;
+    pContext->state &= ~DOC_COOKED_STARTED;
+
+    SendXpNotify(pContext, XPEndDocNotify, stuff->cancel);
+
+    if (client->noClientException != Success)
+        return client->noClientException;
+    else
+        return result;
+}
+
+static Bool
+DoStartPage(client, c)
+    ClientPtr client;
+    XpStPagePtr c;
+{
+    XpScreenPtr pPrintScreen;
+    WindowPtr pWin = c->pWin;
+    int result = Success;
+    XpContextPtr pContext = c->pContext;
+    XpPagePtr pPage;
+
+    if(c->pContext->state & JOB_GET_DATA && 
+       !(c->pContext->state & GET_DOC_DATA_STARTED))
+    {
+       if(!c->slept)
+       {
+           c->slept = TRUE;
+           ClientSleep(client, (ClientSleepProcPtr)DoStartPage, (pointer) c);
+           c->pContext->clientSlept = client;
+       }
+       return TRUE;
+    }
+
+    if(!(pContext->state & DOC_COOKED_STARTED))
+    {
+       /* Implied StartDoc if it was omitted */
+        if(pContext->funcs.StartDoc != (int (*)())NULL)
+            result = pContext->funcs.StartDoc(pContext, XPDocNormal);
+        else
+       {
+           SendErrorToClient(client, XpReqCode, X_PrintStartPage, 0, 
+                             BadImplementation);
+           return TRUE;
+       }
+
+       if(result != Success) 
+       {
+           SendErrorToClient(client, XpReqCode, X_PrintStartPage, 0, result);
+           return TRUE;
+       }
+
+        pContext->state |= DOC_COOKED_STARTED;
+        SendXpNotify(pContext, XPStartDocNotify, (int)FALSE);
+    }
+
+    /* ensure the window's not already being used as a page */
+    if((pPage = (XpPagePtr)LookupIDByType(c->pWin->drawable.id, RTpage)) != 
+       (XpPagePtr)NULL)
+    {
+        if(pPage->context != (XpContextPtr)NULL)
+       {
+           SendErrorToClient(client, XpReqCode, X_PrintStartPage, 0, 
+                             BadWindow);
+           return TRUE;
+       }
+    }
+    else
+    {
+        if((pPage = (XpPagePtr)xalloc(sizeof(XpPageRec))) == (XpPagePtr)NULL)
+       {
+           SendErrorToClient(client, XpReqCode, X_PrintStartPage, 0, 
+                             BadAlloc);
+           return TRUE;
+       }
+        if(AddResource(c->pWin->drawable.id, RTpage, pPage) == FALSE)
+        {
+           xfree(pPage);
+           SendErrorToClient(client, XpReqCode, X_PrintStartPage, 0, 
+                             BadAlloc);
+           return TRUE;
+        }
+    }
+
+    pPage->context = pContext;
+    pContext->pageWin = c->pWin->drawable.id;
+
+    pPrintScreen = XpScreens[pContext->screenNum];
+
+
+    if(pContext->funcs.StartPage != (int (*)())NULL)
+        result = pContext->funcs.StartPage(pContext, pWin);
+    else
+    {
+       SendErrorToClient(client, XpReqCode, X_PrintStartPage, 0, 
+                         BadImplementation);
+       return TRUE;
+    }
+
+    pContext->state |= PAGE_STARTED;
+
+    (void)MapWindow(pWin, client);
+
+    SendXpNotify(pContext, XPStartPageNotify, (int)FALSE);
+
+    return TRUE;
+}
+
+static int
+ProcXpStartPage(client)
+    ClientPtr client;
+{
+    REQUEST(xPrintStartPageReq);
+    XpScreenPtr pPrintScreen;
+    WindowPtr pWin;
+    int result = Success;
+    XpContextPtr pContext;
+    XpPagePtr pPage;
+    XpStPagePtr c;
+
+    REQUEST_SIZE_MATCH(xPrintStartPageReq);
+
+    if((pContext = (XpContextPtr)client->devPrivates[XpClientPrivateIndex].ptr)
+       == (XpContextPtr)NULL)
+        return XpErrorBase+XPBadSequence;
+
+    if(!(pContext->state & JOB_STARTED))
+       return XpErrorBase+XPBadSequence;
+
+    /* can't have pages in a raw documented */
+    if(pContext->state & DOC_RAW_STARTED)
+       return XpErrorBase+XPBadSequence;
+    
+    if(pContext->state & PAGE_STARTED)
+       return XpErrorBase+XPBadSequence;
+
+    pWin = (WindowPtr)SecurityLookupWindow(stuff->window, client,
+                                          SecurityWriteAccess);
+    if (!pWin || pWin->drawable.pScreen->myNum != pContext->screenNum)
+       return BadWindow;
+
+    if((c = (XpStPagePtr)xalloc(sizeof(XpStPageRec))) == (XpStPagePtr)NULL)
+       return BadAlloc;
+    c->pContext = pContext;
+    c->slept = FALSE;
+    c->pWin = pWin;
+
+    (void)DoStartPage(client, c);
+
+    if (client->noClientException != Success)
+        return client->noClientException;
+    else
+        return result;
+}
+
+static int
+ProcXpEndPage(client)
+    ClientPtr client;
+{
+    REQUEST(xPrintEndPageReq);
+    XpScreenPtr pPrintScreen;
+    int result = Success;
+    XpContextPtr pContext;
+    XpPagePtr page;
+    WindowPtr pWin;
+
+    REQUEST_SIZE_MATCH(xPrintEndPageReq);
+
+    if((pContext = (XpContextPtr)client->devPrivates[XpClientPrivateIndex].ptr)
+       == (XpContextPtr)NULL)
+        return XpErrorBase+XPBadSequence;
+
+    if(!(pContext->state & PAGE_STARTED))
+       return XpErrorBase+XPBadSequence;
+
+    pPrintScreen = XpScreens[pContext->screenNum];
+    pWin = (WindowPtr )LookupIDByType(pContext->pageWin, RT_WINDOW);
+
+    /* Call the ddx's EndPage proc. */
+    if(pContext->funcs.EndPage != (int (*)())NULL)
+        result = pContext->funcs.EndPage(pContext, pWin, stuff->cancel);
+    else
+       return BadImplementation;
+
+    if((page = (XpPagePtr)LookupIDByType(pContext->pageWin, RTpage)) !=
+       (XpPagePtr)NULL)
+       page->context = (XpContextPtr)NULL;
+
+    pContext->state &= ~PAGE_STARTED;
+    pContext->pageWin = 0; /* None, NULL??? XXX */
+
+    (void)UnmapWindow(pWin, FALSE);
+
+    SendXpNotify(pContext, XPEndPageNotify, stuff->cancel);
+
+    if (client->noClientException != Success)
+        return client->noClientException;
+    else
+        return result;
+}
+
+/*******************************************************************************
+ *
+ * Document Data Functions: PutDocumentData, GetDocumentData
+ *
+ ******************************************************************************/
+
+static int
+ProcXpPutDocumentData(client)
+    ClientPtr client;
+{
+    REQUEST(xPrintPutDocumentDataReq);
+    XpContextPtr pContext;
+    DrawablePtr pDraw;
+    int result = Success;
+    int len, totalSize;
+    char *pData, *pDoc_fmt, *pOptions;
+
+    REQUEST_AT_LEAST_SIZE(xPrintPutDocumentDataReq);
+
+    if((pContext = (XpContextPtr)client->devPrivates[XpClientPrivateIndex].ptr)
+       == (XpContextPtr)NULL)
+        return XpErrorBase+XPBadSequence;
+
+    if(!(pContext->state & DOC_RAW_STARTED) &&
+       !(pContext->state & DOC_COOKED_STARTED))
+        return XpErrorBase+XPBadSequence;
+
+    if (stuff->drawable) {
+       if (pContext->state & DOC_RAW_STARTED)
+           return BadDrawable;
+       pDraw = (DrawablePtr)LookupDrawable(stuff->drawable, client);
+       if (!pDraw || pDraw->pScreen->myNum != pContext->screenNum)
+           return BadDrawable;
+    } else {
+       if (pContext->state & DOC_COOKED_STARTED)
+           return BadDrawable;
+       pDraw = NULL;
+    }
+
+    pData = (char *)(&stuff[1]);
+
+    totalSize = (stuff->len_data + 3) >> 2;
+    pDoc_fmt = pData + (totalSize << 2);
+
+    totalSize += (stuff->len_fmt + 3) >> 2;
+    pOptions = pData + (totalSize << 2);
+
+    totalSize += (stuff->len_options + 3) >> 2;
+    if((totalSize + (sz_xPrintPutDocumentDataReq >> 2)) != client->req_len)
+        return BadLength;
+    
+    if(pContext->funcs.PutDocumentData != (int (*)())NULL)
+    {
+        result = (*pContext->funcs.PutDocumentData)(pContext, pDraw,
+                                         pData, stuff->len_data,
+                                         pDoc_fmt, stuff->len_fmt,
+                                         pOptions, stuff->len_options,
+                                         client);
+    }
+    else
+       return BadImplementation;
+
+    if (client->noClientException != Success)
+        return client->noClientException;
+    else
+        return result;
+}
+
+static int
+ProcXpGetDocumentData(client)
+    ClientPtr client;
+{
+    REQUEST(xPrintGetDocumentDataReq);
+    xPrintGetDocumentDataReply rep;
+    XpScreenPtr pPrintScreen;
+    XpContextPtr pContext;
+    int result = Success;
+
+    REQUEST_SIZE_MATCH(xPrintGetDocumentDataReq);
+
+    if((pContext = (XpContextPtr)SecurityLookupIDByType(client,
+                                                       stuff->printContext, 
+                                                       RTcontext,
+                                                       SecurityWriteAccess))
+       == (XpContextPtr)NULL)
+    {
+        client->errorValue = stuff->printContext;
+        return XpErrorBase+XPBadContext;
+    }
+
+    if(pContext->funcs.GetDocumentData == (int (*)())NULL)
+       return BadImplementation;
+
+    if(!(pContext->state & JOB_GET_DATA) || 
+       pContext->state & GET_DOC_DATA_STARTED)
+       return XpErrorBase+XPBadSequence;
+
+    if(stuff->maxBufferSize <= 0)
+    {
+       client->errorValue = stuff->maxBufferSize;
+        return BadValue; /* gotta have a positive buffer size */
+    }
+
+    result = (*pContext->funcs.GetDocumentData)(pContext, client, 
+                                               stuff->maxBufferSize);
+    if(result != Success)
+    {
+       rep.type = X_Reply;
+       rep.sequenceNumber = client->sequence;
+       rep.length = 0;
+       rep.dataLen = 0;
+       rep.statusCode = 1;
+       rep.finishedFlag = TRUE;
+        if (client->swapped) {
+            int n;
+            long l;
+
+            swaps(&rep.sequenceNumber, n);
+            swapl(&rep.statusCode, l); /* XXX Why are these longs??? */
+            swapl(&rep.finishedFlag, l); /* XXX Why are these longs??? */
+        }
+       (void)WriteToClient(client,sz_xPrintGetDocumentDataReply,(char *)&rep);
+    }
+    else
+        pContext->state |= GET_DOC_DATA_STARTED;
+
+    if(pContext->clientSlept != (ClientPtr)NULL)
+    {
+       ClientSignal(pContext->clientSlept);
+       ClientWakeup(pContext->clientSlept);
+       pContext->clientSlept = (ClientPtr)NULL;
+    }
+
+    return result;
+}
+
+/*******************************************************************************
+ *
+ * Attribute requests: GetAttributes, SetAttributes, GetOneAttribute
+ *
+ ******************************************************************************/
+
+static int 
+ProcXpGetAttributes(client)
+    ClientPtr client;
+{
+    REQUEST(xPrintGetAttributesReq);
+    XpContextPtr pContext;
+    char *attrs;
+    xPrintGetAttributesReply *pRep;
+    int totalSize, n;
+    unsigned long l;
+
+    REQUEST_SIZE_MATCH(xPrintGetAttributesReq);
+
+    if(stuff->type < XPJobAttr || stuff->type > XPServerAttr)
+    {
+       client->errorValue = stuff->type;
+       return BadValue;
+    }
+
+    if(stuff->type != XPServerAttr)
+    {
+        if((pContext = (XpContextPtr)SecurityLookupIDByType(
+                                               client,
+                                               stuff->printContext,
+                                               RTcontext,
+                                               SecurityReadAccess))
+          == (XpContextPtr)NULL)
+        {
+           client->errorValue = stuff->printContext;
+            return XpErrorBase+XPBadContext;
+        }
+
+        if(pContext->funcs.GetAttributes == (char *(*)())NULL)
+           return BadImplementation;
+        if((attrs = (*pContext->funcs.GetAttributes)(pContext, stuff->type)) == 
+           (char *)NULL) 
+           return BadAlloc;
+    }
+    else
+    {
+       if((attrs = XpGetAttributes((XpContextPtr)NULL, XPServerAttr)) ==
+          (char *)NULL)
+           return BadAlloc;
+    }
+
+    totalSize = sz_xPrintGetAttributesReply + QUADPAD(strlen(attrs));
+    if((pRep = (xPrintGetAttributesReply *)malloc(totalSize)) ==
+       (xPrintGetAttributesReply *)NULL)
+       return BadAlloc;
+
+    pRep->type = X_Reply;
+    pRep->length = (totalSize - sz_xPrintGetAttributesReply) >> 2;
+    pRep->sequenceNumber = client->sequence;
+    pRep->stringLen = strlen(attrs);
+
+    if (client->swapped) {
+        swaps(&pRep->sequenceNumber, n);
+        swapl(&pRep->length, l);
+        swapl(&pRep->stringLen, l);
+    }
+
+    strncpy((char*)(pRep + 1), attrs, strlen(attrs));
+    xfree(attrs);
+
+    WriteToClient(client, totalSize, (char *)pRep);
+
+    xfree(pRep);
+
+    return client->noClientException;
+}
+
+static int 
+ProcXpSetAttributes(client)
+    ClientPtr client;
+{
+    REQUEST(xPrintSetAttributesReq);
+    int result = Success;
+    XpContextPtr pContext;
+    char *attr;
+
+    REQUEST_AT_LEAST_SIZE(xPrintSetAttributesReq);
+
+    if(stuff->type < XPJobAttr || stuff->type > XPServerAttr)
+    {
+       client->errorValue = stuff->type;
+       return BadValue;
+    }
+
+    /*
+     * Disallow changing of read-only attribute pools
+     */
+    if(stuff->type == XPPrinterAttr || stuff->type == XPServerAttr)
+       return BadMatch;
+
+    if((pContext = (XpContextPtr)SecurityLookupIDByType(
+                                       client,
+                                       stuff->printContext,
+                                       RTcontext,
+                                       SecurityWriteAccess))
+       == (XpContextPtr)NULL)
+    {
+        client->errorValue = stuff->printContext;
+        return XpErrorBase+XPBadContext;
+    }
+
+    if(pContext->funcs.SetAttributes == (int (*)())NULL)
+       return BadImplementation;
+    
+    /* 
+     * Check for attributes being set after their relevant phase
+     * has already begun (e.g. Job attributes set after StartJob).
+     */
+    if((pContext->state & JOB_STARTED) && stuff->type == XPJobAttr)
+       return XpErrorBase+XPBadSequence;
+    if(((pContext->state & DOC_RAW_STARTED) || 
+       (pContext->state & DOC_COOKED_STARTED)) && stuff->type == XPDocAttr)
+       return XpErrorBase+XPBadSequence;
+    if((pContext->state & PAGE_STARTED) && stuff->type == XPPageAttr)
+       return XpErrorBase+XPBadSequence;
+
+    if((attr = (char *)malloc(stuff->stringLen + 1)) == (char *)NULL)
+       return BadAlloc;
+
+    strncpy(attr, (char *)(stuff + 1), stuff->stringLen);
+    attr[stuff->stringLen] = (char)'\0';
+
+    if(stuff->rule == XPAttrReplace)
+        (*pContext->funcs.SetAttributes)(pContext, stuff->type, attr);
+    else if(stuff->rule == XPAttrMerge)
+        (*pContext->funcs.AugmentAttributes)(pContext, stuff->type, attr);
+    else
+    {
+       client->errorValue = stuff->rule;
+       result = BadValue;
+    }
+
+    xfree(attr);
+
+    SendAttributeNotify(pContext, stuff->type);
+
+    return result;
+}
+
+static int 
+ProcXpGetOneAttribute(client)
+    ClientPtr client;
+{
+    REQUEST(xPrintGetOneAttributeReq);
+    XpContextPtr pContext;
+    char *value, *attrName;
+    xPrintGetOneAttributeReply *pRep;
+    int totalSize, n;
+    unsigned long l;
+
+    REQUEST_AT_LEAST_SIZE(xPrintGetOneAttributeReq);
+
+    totalSize = ((sz_xPrintGetOneAttributeReq) >> 2) +
+                ((stuff->nameLen + 3) >> 2);
+    if(totalSize != client->req_len)
+        return BadLength;
+
+    if(stuff->type < XPJobAttr || stuff->type > XPServerAttr)
+    {
+       client->errorValue = stuff->type;
+       return BadValue;
+    }
+    
+    if((attrName = (char *)malloc(stuff->nameLen + 1)) == (char *)NULL)
+       return BadAlloc;
+    strncpy(attrName, (char *)(stuff+1), stuff->nameLen);
+    attrName[stuff->nameLen] = (char)'\0';
+
+    if(stuff->type != XPServerAttr)
+    {
+        if((pContext = (XpContextPtr)SecurityLookupIDByType(
+                                               client,
+                                               stuff->printContext, 
+                                               RTcontext,
+                                               SecurityReadAccess))
+          == (XpContextPtr)NULL)
+        {
+           client->errorValue = stuff->printContext;
+            return XpErrorBase+XPBadContext;
+        }
+
+        if(pContext->funcs.GetOneAttribute == (char *(*)())NULL)
+           return BadImplementation;
+        if((value = (*pContext->funcs.GetOneAttribute)(pContext, stuff->type,
+           attrName)) == (char *)NULL) 
+           return BadAlloc;
+    }
+    else
+    {
+       if((value = XpGetOneAttribute((XpContextPtr)NULL, XPServerAttr,
+           attrName)) == (char *)NULL)
+           return BadAlloc;
+    }
+
+    free(attrName);
+
+    totalSize = sz_xPrintGetOneAttributeReply + QUADPAD(strlen(value));
+    if((pRep = (xPrintGetOneAttributeReply *)malloc(totalSize)) ==
+       (xPrintGetOneAttributeReply *)NULL)
+       return BadAlloc;
+
+    pRep->type = X_Reply;
+    pRep->length = (totalSize - sz_xPrintGetOneAttributeReply) >> 2;
+    pRep->sequenceNumber = client->sequence;
+    pRep->valueLen = strlen(value);
+
+    if (client->swapped) {
+        swaps(&pRep->sequenceNumber, n);
+        swapl(&pRep->length, l);
+        swapl(&pRep->valueLen, l);
+    }
+
+    strncpy((char*)(pRep + 1), value, strlen(value));
+
+    WriteToClient(client, totalSize, (char *)pRep);
+
+    xfree(pRep);
+
+    return client->noClientException;
+}
+
+/*******************************************************************************
+ *
+ * Print Event requests: SelectInput InputSelected, SendXpNotify
+ *
+ ******************************************************************************/
+
+
+static int
+ProcXpSelectInput(client)
+    ClientPtr client;
+{
+    REQUEST(xPrintSelectInputReq);
+    int result = Success;
+    XpContextPtr pContext;
+    XpClientPtr pPrintClient;
+
+    REQUEST_SIZE_MATCH(xPrintSelectInputReq);
+
+    /*
+     * Check to see that the supplied XID is really a valid print context
+     * in this server.
+     */
+    if((pContext=(XpContextPtr)SecurityLookupIDByType(client,
+                                                     stuff->printContext,
+                                                     RTcontext,
+                                                     SecurityWriteAccess))
+       == (XpContextPtr)NULL)
+    {
+       client->errorValue = stuff->printContext;
+        return XpErrorBase+XPBadContext;
+    }
+
+    if(stuff->eventMask & ~allEvents)
+    {
+       client->errorValue = stuff->eventMask;
+        return BadValue; /* bogus event mask bits */
+    }
+
+    if((pPrintClient = AcquireClient(pContext, client)) == (XpClientPtr)NULL)
+       return BadAlloc;
+
+    pPrintClient->eventMask = stuff->eventMask;
+
+    return result;
+}
+
+static int
+ProcXpInputSelected(client)
+    ClientPtr client;
+{
+    REQUEST(xPrintInputSelectedReq);
+    xPrintInputSelectedReply rep;
+    register int n;
+    long l, allMask;
+    WindowPtr pWin;
+    XpClientPtr pXpClient;
+    XpContextPtr pContext;
+
+    REQUEST_SIZE_MATCH(xPrintInputSelectedReq);
+
+    if((pContext=(XpContextPtr)SecurityLookupIDByType(client,
+                                                     stuff->printContext,
+                                                     RTcontext,
+                                                     SecurityReadAccess))
+       == (XpContextPtr)NULL)
+    {
+       client->errorValue = stuff->printContext;
+        return XpErrorBase+XPBadContext;
+    }
+
+    pXpClient = FindClient(pContext, client);
+
+    rep.type = X_Reply;
+    rep.length = 0;
+    rep.sequenceNumber = client->sequence;
+    rep.eventMask = (pXpClient != (XpClientPtr)NULL)? pXpClient->eventMask : 0;
+    rep.allEventsMask = GetAllEventMasks(pContext);
+
+    if (client->swapped) {
+        swaps(&rep.sequenceNumber, n);
+        swapl(&rep.length, l);
+        swapl(&rep.eventMask, l);
+        swapl(&rep.allEventsMask, l);
+    }
+
+    WriteToClient(client, sz_xPrintInputSelectedReply, (char *)&rep);
+    return client->noClientException;
+}
+
+static void
+SendAttributeNotify(pContext, which)
+    XpContextPtr pContext;
+    int which;
+{
+    XpClientPtr        pXpClient;
+    xPrintAttributeEvent   ae;
+    ClientPtr  client;
+
+    pXpClient = pContext->clientHead;
+    if(pXpClient == (XpClientPtr)NULL) 
+        return; /* Nobody's interested in the events (or this context). */
+
+    for (pXpClient = pContext->clientHead; 
+         pXpClient != (XpClientPtr)NULL; 
+         pXpClient = pXpClient->pNext)
+    {
+        client = pXpClient->client;
+        if (client == serverClient || client->clientGone || 
+           !(pXpClient->eventMask & XPAttributeMask))
+            continue;
+        ae.type = XPAttributeNotify + XpEventBase;
+        ae.detail = which;
+        ae.printContext = pContext->contextID;
+        ae.sequenceNumber = client->sequence;
+        WriteEventsToClient (client, 1, (xEvent *) &ae);
+    }
+}
+static void
+SendXpNotify(pContext, which, val)
+    XpContextPtr pContext;
+    int which;
+    int val;
+{
+    XpClientPtr        pXpClient;
+    xPrintPrintEvent   pe;
+    ClientPtr  client;
+
+    pXpClient = pContext->clientHead;
+    if(pXpClient == (XpClientPtr)NULL) 
+        return; /* Nobody's interested in the events (or this context). */
+
+    for (pXpClient = pContext->clientHead; 
+         pXpClient != (XpClientPtr)NULL; 
+         pXpClient = pXpClient->pNext)
+    {
+        client = pXpClient->client;
+        if (client == serverClient || client->clientGone || 
+           !(pXpClient->eventMask & XPPrintMask))
+            continue;
+        pe.type = XPPrintNotify + XpEventBase;
+        pe.detail = which;
+        pe.printContext = pContext->contextID;
+       pe.cancel = (Bool)val;
+        pe.sequenceNumber = client->sequence;
+        WriteEventsToClient (client, 1, (xEvent *) &pe);
+    }
+}
+
+static CARD32
+GetAllEventMasks(pContext)
+    XpContextPtr pContext;
+{
+    XpClientPtr pPrintClient;
+    CARD32 totalMask = (CARD32)0;
+    
+    for (pPrintClient = pContext->clientHead;
+         pPrintClient != (XpClientPtr)NULL;
+         pPrintClient = pPrintClient->pNext)
+    {
+        totalMask |= pPrintClient->eventMask;
+    }
+    return totalMask;
+}
+
+/*
+ * XpContextOfClient - returns the XpContextPtr to the context
+ * associated with the specified client, or NULL if the client
+ * does not currently have a context set.
+ */
+XpContextPtr
+XpContextOfClient(client)
+    ClientPtr client;
+{
+    XpContextPtr pContext;
+
+    return (XpContextPtr)client->devPrivates[XpClientPrivateIndex].ptr;
+}
+
+
+/*******************************************************************************
+ *
+ * Swap-request functions
+ *
+ ******************************************************************************/
+
+static int
+SProcXpCreateContext(client)
+    ClientPtr client;
+{
+    int i;
+    long n;
+
+    REQUEST(xPrintCreateContextReq);
+
+    swaps(&stuff->length, i);
+    swapl(&stuff->contextID, n);
+    swapl(&stuff->printerNameLen, n);
+    swapl(&stuff->localeLen, n);
+    return ProcXpCreateContext(client);
+}
+
+static int
+SProcXpGetPrinterList(client)
+    ClientPtr client;
+{
+    int i;
+    long n;
+
+    REQUEST(xPrintGetPrinterListReq);
+
+    swaps(&stuff->length, i);
+    swapl(&stuff->printerNameLen, n);
+    swapl(&stuff->localeLen, n);
+    return ProcXpGetPrinterList(client);
+}
+
+static int
+SProcXpRehashPrinterList(client)
+    ClientPtr client;
+{
+    int i;
+    long n;
+
+    REQUEST(xPrintRehashPrinterListReq);
+    swaps(&stuff->length, i);
+    return ProcXpRehashPrinterList(client);
+}
+
+static int
+SProcXpSetContext(client)
+    ClientPtr client;
+{
+    int i;
+    long n;
+
+    REQUEST(xPrintSetContextReq);
+    swaps(&stuff->length, i);
+    swapl(&stuff->printContext, i);
+    return ProcXpSetContext(client);
+}
+
+static int
+SProcXpGetContext(client)
+    ClientPtr client;
+{
+    int i;
+
+    REQUEST(xPrintGetContextReq);
+    swaps(&stuff->length, i);
+    return ProcXpGetContext(client);
+}
+
+static int
+SProcXpDestroyContext(client)
+    ClientPtr client;
+{
+    int i;
+    long n;
+
+    REQUEST(xPrintDestroyContextReq);
+    swaps(&stuff->length, i);
+    swapl(&stuff->printContext, n);
+    return ProcXpDestroyContext(client);
+}
+
+static int
+SProcXpGetContextScreen(client)
+    ClientPtr client;
+{
+    int i;
+    long n;
+
+    REQUEST(xPrintGetContextScreenReq);
+    swaps(&stuff->length, i);
+    swapl(&stuff->printContext, n);
+    return ProcXpGetContextScreen(client);
+}
+
+static int
+SProcXpInputSelected(client)
+    ClientPtr client;
+{
+    int i;
+    long n;
+
+    REQUEST(xPrintInputSelectedReq);
+    swaps(&stuff->length, i);
+    swapl(&stuff->printContext, n);
+    return ProcXpInputSelected(client);
+}
+
+static int
+SProcXpStartJob(client)
+    ClientPtr client;
+{
+    int i;
+
+    REQUEST(xPrintStartJobReq);
+    swaps(&stuff->length, i);
+    return ProcXpStartJob(client);
+}
+
+static int
+SProcXpEndJob(client)
+    ClientPtr client;
+{
+    int i;
+
+    REQUEST(xPrintEndJobReq);
+    swaps(&stuff->length, i);
+    return ProcXpEndJob(client);
+}
+
+static int
+SProcXpStartDoc(client)
+    ClientPtr client;
+{
+    int i;
+
+    REQUEST(xPrintStartDocReq);
+    swaps(&stuff->length, i);
+    return ProcXpStartDoc(client);
+}
+
+static int
+SProcXpEndDoc(client)
+    ClientPtr client;
+{
+    int i;
+
+    REQUEST(xPrintEndDocReq);
+    swaps(&stuff->length, i);
+    return ProcXpEndDoc(client);
+}
+
+static int
+SProcXpStartPage(client)
+    ClientPtr client;
+{
+    int i;
+    long n;
+
+    REQUEST(xPrintStartPageReq);
+    swaps(&stuff->length, i);
+    swapl(&stuff->window, n);
+    return ProcXpStartPage(client);
+}
+
+static int
+SProcXpEndPage(client)
+    ClientPtr client;
+{
+    int i;
+
+    REQUEST(xPrintEndPageReq);
+    swaps(&stuff->length, i);
+    return ProcXpEndPage(client);
+}
+
+static int
+SProcXpPutDocumentData(client)
+    ClientPtr client;
+{
+    long n;
+    int i;
+
+    REQUEST(xPrintPutDocumentDataReq);
+    swaps(&stuff->length, i);
+    swapl(&stuff->drawable, n);
+    swapl(&stuff->len_data, n);
+    swaps(&stuff->len_fmt, i);
+    swaps(&stuff->len_options, i);
+    return ProcXpPutDocumentData(client);
+}
+
+static int
+SProcXpGetDocumentData(client)
+    ClientPtr client;
+{
+    long n;
+    int i;
+
+    REQUEST(xPrintGetDocumentDataReq);
+    swaps(&stuff->length, i);
+    swapl(&stuff->printContext, n);
+    swapl(&stuff->maxBufferSize, n);
+    return ProcXpGetDocumentData(client);
+}
+
+static int
+SProcXpGetAttributes(client)
+    ClientPtr client;
+{
+    long n;
+    int i;
+
+    REQUEST(xPrintGetAttributesReq);
+    swaps(&stuff->length, i);
+    swapl(&stuff->printContext, n);
+    return ProcXpGetAttributes(client);
+}
+
+static int
+SProcXpSetAttributes(client)
+    ClientPtr client;
+{
+    long n;
+    int i;
+
+    REQUEST(xPrintSetAttributesReq);
+    swaps(&stuff->length, i);
+    swapl(&stuff->printContext, n);
+    swapl(&stuff->stringLen, n);
+    return ProcXpSetAttributes(client);
+}
+
+static int
+SProcXpGetOneAttribute(client)
+    ClientPtr client;
+{
+    long n;
+    int i;
+
+    REQUEST(xPrintGetOneAttributeReq);
+    swaps(&stuff->length, i);
+    swapl(&stuff->printContext, n);
+    swapl(&stuff->nameLen, n);
+    return ProcXpGetOneAttribute(client);
+}
+
+static int
+SProcXpSelectInput(client)
+    ClientPtr client;
+{
+    long n;
+    int i;
+
+    REQUEST(xPrintSelectInputReq);
+    swaps(&stuff->length, i);
+    swapl(&stuff->eventMask, n);
+    swapl(&stuff->printContext, n);
+    return ProcXpSelectInput(client);
+}
+static int 
+SProcXpGetPageDimensions(client)
+    ClientPtr client;
+{
+    long n;
+    int i;
+
+    REQUEST(xPrintGetPageDimensionsReq);
+    swaps(&stuff->length, i);
+    swapl(&stuff->printContext, n);
+    return ProcXpGetPageDimensions(client);
+}
+static int 
+SProcXpSetImageResolution(client)
+    ClientPtr client;
+{
+    long n;
+    int i;
+
+    REQUEST(xPrintSetImageResolutionReq);
+    swaps(&stuff->length, i);
+    swapl(&stuff->printContext, n);
+    swaps(&stuff->imageRes, i);
+    return ProcXpSetImageResolution(client);
+}
+static int 
+SProcXpGetImageResolution(client)
+    ClientPtr client;
+{
+    long n;
+    int i;
+
+    REQUEST(xPrintGetImageResolutionReq);
+    swaps(&stuff->length, i);
+    swapl(&stuff->printContext, n);
+    return ProcXpGetImageResolution(client);
+}
+
+static void
+SwapXpNotifyEvent(src, dst)
+    xPrintPrintEvent *src, *dst;
+{
+    /*
+     * Swap the sequence number and context fields.
+     */
+    cpswaps(src->sequenceNumber, dst->sequenceNumber);
+    cpswapl(src->printContext, dst->printContext);
+
+    /*
+     * Copy the byte-long fields.
+     */
+    dst->type = src->type;
+    dst->detail = src->detail;
+    dst->cancel = src->cancel;
+}
+
+static void
+SwapXpAttributeEvent(src, dst)
+    xPrintAttributeEvent *src, *dst;
+{
+    /*
+     * Swap the sequence number and context fields.
+     */
+    cpswaps(src->sequenceNumber, dst->sequenceNumber);
+    cpswapl(src->printContext, dst->printContext);
+
+    /*
+     * Copy the byte-long fields.
+     */
+    dst->type = src->type;
+    dst->detail = src->detail;
+}