/* $Xorg: xprint.c,v 1.4 2000/08/17 19:47:59 cpqbld Exp $ */ /* (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.11 2001/08/23 13:01:36 alanh Exp $ */ #define _XP_PRINT_SERVER_ #include "X.h" #include "Xos.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" #include "Print.h" #include "Printstr.h" #include "../Xprint/DiPrint.h" #include "../Xprint/attributes.h" static void XpResetProc(ExtensionEntry *); static int ProcXpDispatch(ClientPtr); static int ProcXpSwappedDispatch(ClientPtr); static int ProcXpQueryVersion(ClientPtr); static int ProcXpGetPrinterList(ClientPtr); static int ProcXpCreateContext(ClientPtr); static int ProcXpSetContext(ClientPtr); static int ProcXpGetContext(ClientPtr); static int ProcXpDestroyContext(ClientPtr); static int ProcXpGetContextScreen(ClientPtr); static int ProcXpStartJob(ClientPtr); static int ProcXpEndJob(ClientPtr); static int ProcXpStartDoc(ClientPtr); static int ProcXpEndDoc(ClientPtr); static int ProcXpStartPage(ClientPtr); static int ProcXpEndPage(ClientPtr); static int ProcXpSelectInput(ClientPtr); static int ProcXpInputSelected(ClientPtr); static int ProcXpPutDocumentData(ClientPtr); static int ProcXpGetDocumentData(ClientPtr); static int ProcXpGetAttributes(ClientPtr); static int ProcXpGetOneAttribute(ClientPtr); static int ProcXpSetAttributes(ClientPtr); static int ProcXpRehashPrinterList(ClientPtr); static int ProcXpQueryScreens(ClientPtr); static int ProcXpGetPageDimensions(ClientPtr); static int ProcXpSetImageResolution(ClientPtr); static int ProcXpGetImageResolution(ClientPtr); static void SwapXpNotifyEvent(xPrintPrintEvent *, xPrintPrintEvent *); static void SwapXpAttributeEvent(xPrintAttributeEvent *, xPrintAttributeEvent *); static int SProcXpGetPrinterList(ClientPtr); static int SProcXpCreateContext(ClientPtr); static int SProcXpSetContext(ClientPtr); static int SProcXpGetContext(ClientPtr); static int SProcXpDestroyContext(ClientPtr); static int SProcXpGetContextScreen(ClientPtr); static int SProcXpStartJob(ClientPtr); static int SProcXpEndJob(ClientPtr); static int SProcXpStartDoc(ClientPtr); static int SProcXpEndDoc(ClientPtr); static int SProcXpStartPage(ClientPtr); static int SProcXpEndPage(ClientPtr); static int SProcXpSelectInput(ClientPtr); static int SProcXpInputSelected(ClientPtr); static int SProcXpPutDocumentData(ClientPtr); static int SProcXpGetDocumentData(ClientPtr); static int SProcXpGetAttributes(ClientPtr); static int SProcXpGetOneAttribute(ClientPtr); static int SProcXpSetAttributes(ClientPtr); static int SProcXpRehashPrinterList(ClientPtr); static int SProcXpGetPageDimensions(ClientPtr); static int SProcXpSetImageResolution(ClientPtr); static int SProcXpGetImageResolution(ClientPtr); static void SendXpNotify(XpContextPtr, int, int); static void SendAttributeNotify(XpContextPtr, int); static int XpFreeClient(pointer, XID); static int XpFreeContext(pointer, XID); static int XpFreePage(pointer, XID); static Bool XpCloseScreen(int, ScreenPtr); static CARD32 GetAllEventMasks(XpContextPtr); static struct _XpClient *CreateXpClient(ClientPtr); static void InitContextPrivates(XpContextPtr); static void ResetContextPrivates(void); static struct _XpClient *FindClient(XpContextPtr, ClientPtr); static struct _XpClient *AcquireClient(XpContextPtr, ClientPtr); typedef struct _driver { struct _driver *next; char *name; int (* CreateContext)(XpContextPtr); } XpDriverRec, *XpDriverPtr; typedef struct _xpScreen { Bool (* CloseScreen)(int, ScreenPtr); 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; static void FreeXpClient(XpClientPtr, Bool); /* * 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 unsigned long XpGeneration = 0; 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(void) { ExtensionEntry *extEntry; 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] = (EventSwapPtr) SwapXpNotifyEvent; EventSwapVector[XpEventBase+1] = (EventSwapPtr) 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(ExtensionEntry *extEntry) { /* * We can't free up the XpScreens recs here, because extensions are * closed before screens, and our CloseScreen function uses the XpScreens * recs. int i; for(i = 0; i < MAXSCREENS; i++) { if(XpScreens[i] != (XpScreenPtr)NULL) Xfree(XpScreens[i]); XpScreens[i] = (XpScreenPtr)NULL; } */ } static Bool XpCloseScreen(int index, ScreenPtr pScreen) { Bool (* CloseScreen)(int, ScreenPtr); 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); } #if 0 /* NOT USED */ static void FreeScreenEntry(XpScreenPtr pScreenEntry) { XpDriverPtr pDriver; pDriver = pScreenEntry->drivers; while(pDriver != (XpDriverPtr)NULL) { XpDriverPtr tmp; tmp = pDriver->next; xfree(pDriver); pDriver = tmp; } xfree(pScreenEntry); } #endif /* * 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(ScreenPtr pScreen, char *driverName, int (*initContext)(struct _XpContext *)) { XpDriverPtr pDriver; if(XpScreens[pScreen->myNum] == 0) { if((XpScreens[pScreen->myNum] = (XpScreenPtr) Xalloc(sizeof(XpScreenRec))) == 0) return; XpScreens[pScreen->myNum]->CloseScreen = 0; XpScreens[pScreen->myNum]->drivers = 0; } if((pDriver = (XpDriverPtr)Xalloc(sizeof(XpDriverRec))) == 0) return; pDriver->next = XpScreens[pScreen->myNum]->drivers; pDriver->name = driverName; pDriver->CreateContext = initContext; XpScreens[pScreen->myNum]->drivers = pDriver; } static int ProcXpDispatch(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(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(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(ClientPtr client) { REQUEST(xPrintGetPrinterListReq); int totalSize; int numEntries; XpDiListEntry **pList; 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(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); /* fix of bug: pWinId should be set again after reallocate rep */ pWinId = (WINDOW *)(rep + 1); *pWinId = WindowTable[i]->drawable.id; if (client->swapped) swapl((long *)pWinId, l); } } 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(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 != 0) result = pContext->funcs.GetMediumDimensions(pContext, &width, &height); else return BadImplementation; if(pContext->funcs.GetReproducibleArea != 0) 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(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 != 0) 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(ClientPtr client) { REQUEST(xPrintGetImageResolutionReq); xPrintGetImageResolutionReply rep; XpContextPtr pContext; 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(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(ClientPtr client) { REQUEST(xPrintCreateContextReq); XpScreenPtr pPrintScreen; WindowPtr pRoot; char *driverName; XpContextPtr pContext; 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((char *)(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 = 0; pContext->funcs.StartJob = 0; pContext->funcs.EndJob = 0; pContext->funcs.StartDoc = 0; pContext->funcs.EndDoc = 0; pContext->funcs.StartPage = 0; pContext->funcs.EndPage = 0; pContext->funcs.PutDocumentData = 0; pContext->funcs.GetDocumentData = 0; pContext->funcs.GetAttributes = 0; pContext->funcs.GetOneAttribute = 0; pContext->funcs.SetAttributes = 0; pContext->funcs.AugmentAttributes = 0; pContext->funcs.GetMediumDimensions = 0; pContext->funcs.GetReproducibleArea = 0; pContext->funcs.SetImageResolution = 0; 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 != 0) 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(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(ClientPtr client) { return (client->devPrivates[XpClientPrivateIndex].ptr); } static int ProcXpGetContext(ClientPtr client) { REQUEST(xPrintGetContextReq); xPrintGetContextReply rep; XpContextPtr pContext; 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(ClientPtr client) { REQUEST(xPrintDestroyContextReq); XpContextPtr pContext; 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(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(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); 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 != 0) { 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 != 0) 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(pointer data, XID id) { FreeXpClient((XpClientPtr)data, FALSE); return Success; } /* * 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(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(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(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) { if(page->context->funcs.EndPage != 0) result = page->context->funcs.EndPage(page->context, pWin); 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(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(void) { contextPrivateCount = 0; contextPrivateLen = 0; xfree(contextPrivateSizes); contextPrivateSizes = (unsigned *)NULL; totalContextSize = sizeof(XpContextRec); } int XpAllocateContextPrivateIndex(void) { return contextPrivateCount++; } Bool XpAllocateContextPrivate(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(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(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(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 != 0) result = pContext->funcs.StartJob(pContext, (stuff->saveData == XPGetData)? TRUE:FALSE, client); 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(ClientPtr client) { REQUEST(xPrintEndJobReq); XpScreenPtr pPrintScreen; 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 != 0) result = pContext->funcs.EndPage(pContext, pWin); 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 != 0) result = pContext->funcs.EndDoc(pContext, stuff->cancel); else return BadImplementation; SendXpNotify(pContext, XPEndDocNotify, stuff->cancel); } if(pContext->funcs.EndJob != 0) 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(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 != 0) 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(ClientPtr client) { REQUEST(xPrintStartDocReq); 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(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 != 0) result = pContext->funcs.EndPage(pContext, pWin); 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 != 0) 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( 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 != 0) 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 != 0) 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(ClientPtr client) { REQUEST(xPrintStartPageReq); WindowPtr pWin; int result = Success; XpContextPtr pContext; 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(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 != 0) result = pContext->funcs.EndPage(pContext, pWin); 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(ClientPtr client) { REQUEST(xPrintPutDocumentDataReq); XpContextPtr pContext; DrawablePtr pDraw; int result = Success; unsigned 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 != 0) { 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(ClientPtr client) { REQUEST(xPrintGetDocumentDataReq); xPrintGetDocumentDataReply rep; 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 == 0) 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(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 == 0) 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(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 == 0) 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(ClientPtr client) { REQUEST(xPrintGetOneAttributeReq); XpContextPtr pContext; char *value, *attrName; xPrintGetOneAttributeReply *pRep; int totalSize; int 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 == 0) 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(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(ClientPtr client) { REQUEST(xPrintInputSelectedReq); xPrintInputSelectedReply rep; register int n; long l; 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(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(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(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(ClientPtr client) { return (XpContextPtr)client->devPrivates[XpClientPrivateIndex].ptr; } /******************************************************************************* * * Swap-request functions * ******************************************************************************/ static int SProcXpCreateContext(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(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(ClientPtr client) { int i; REQUEST(xPrintRehashPrinterListReq); swaps(&stuff->length, i); return ProcXpRehashPrinterList(client); } static int SProcXpSetContext(ClientPtr client) { int i; REQUEST(xPrintSetContextReq); swaps(&stuff->length, i); swapl(&stuff->printContext, i); return ProcXpSetContext(client); } static int SProcXpGetContext(ClientPtr client) { int i; REQUEST(xPrintGetContextReq); swaps(&stuff->length, i); return ProcXpGetContext(client); } static int SProcXpDestroyContext(ClientPtr client) { int i; long n; REQUEST(xPrintDestroyContextReq); swaps(&stuff->length, i); swapl(&stuff->printContext, n); return ProcXpDestroyContext(client); } static int SProcXpGetContextScreen(ClientPtr client) { int i; long n; REQUEST(xPrintGetContextScreenReq); swaps(&stuff->length, i); swapl(&stuff->printContext, n); return ProcXpGetContextScreen(client); } static int SProcXpInputSelected(ClientPtr client) { int i; long n; REQUEST(xPrintInputSelectedReq); swaps(&stuff->length, i); swapl(&stuff->printContext, n); return ProcXpInputSelected(client); } static int SProcXpStartJob(ClientPtr client) { int i; REQUEST(xPrintStartJobReq); swaps(&stuff->length, i); return ProcXpStartJob(client); } static int SProcXpEndJob(ClientPtr client) { int i; REQUEST(xPrintEndJobReq); swaps(&stuff->length, i); return ProcXpEndJob(client); } static int SProcXpStartDoc(ClientPtr client) { int i; REQUEST(xPrintStartDocReq); swaps(&stuff->length, i); return ProcXpStartDoc(client); } static int SProcXpEndDoc(ClientPtr client) { int i; REQUEST(xPrintEndDocReq); swaps(&stuff->length, i); return ProcXpEndDoc(client); } static int SProcXpStartPage(ClientPtr client) { int i; long n; REQUEST(xPrintStartPageReq); swaps(&stuff->length, i); swapl(&stuff->window, n); return ProcXpStartPage(client); } static int SProcXpEndPage(ClientPtr client) { int i; REQUEST(xPrintEndPageReq); swaps(&stuff->length, i); return ProcXpEndPage(client); } static int SProcXpPutDocumentData(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(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(ClientPtr client) { long n; int i; REQUEST(xPrintGetAttributesReq); swaps(&stuff->length, i); swapl(&stuff->printContext, n); return ProcXpGetAttributes(client); } static int SProcXpSetAttributes(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(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(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(ClientPtr client) { long n; int i; REQUEST(xPrintGetPageDimensionsReq); swaps(&stuff->length, i); swapl(&stuff->printContext, n); return ProcXpGetPageDimensions(client); } static int SProcXpSetImageResolution(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(ClientPtr client) { long n; int i; REQUEST(xPrintGetImageResolutionReq); swaps(&stuff->length, i); swapl(&stuff->printContext, n); return ProcXpGetImageResolution(client); } static void SwapXpNotifyEvent(xPrintPrintEvent *src, xPrintPrintEvent *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(xPrintAttributeEvent *src, xPrintAttributeEvent *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; }