]> git.sesse.net Git - rdpsrv/blob - Xserver/programs/Xserver/Xext/xprint.c
Import X server from vnc-3.3.7.
[rdpsrv] / Xserver / programs / Xserver / Xext / xprint.c
1 /* $XConsortium: xprint.c /main/3 1996/11/23 17:11:55 rws $ */
2 /*
3 (c) Copyright 1996 Hewlett-Packard Company
4 (c) Copyright 1996 International Business Machines Corp.
5 (c) Copyright 1996 Sun Microsystems, Inc.
6 (c) Copyright 1996 Novell, Inc.
7 (c) Copyright 1996 Digital Equipment Corp.
8 (c) Copyright 1996 Fujitsu Limited
9 (c) Copyright 1996 Hitachi, Ltd.
10
11 Permission is hereby granted, free of charge, to any person obtaining a copy
12 of this software and associated documentation files (the "Software"), to deal
13 in the Software without restriction, including without limitation the rights
14 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
15 copies of the Software, and to permit persons to whom the Software is
16 furnished to do so, subject to the following conditions:
17
18 The above copyright notice and this permission notice shall be included in
19 all copies or substantial portions of the Software.
20
21 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
22 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
24 COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
25 IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
26 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
27
28 Except as contained in this notice, the names of the copyright holders shall
29 not be used in advertising or otherwise to promote the sale, use or other
30 dealings in this Software without prior written authorization from said
31 copyright holders.
32 */
33 /*******************************************************************
34 **
35 **    *********************************************************
36 **    *
37 **    *  File:          xprint.c
38 **    *
39 **    *  Copyright:     Copyright 1993, 1995 Hewlett-Packard Company
40 **    *
41 **    *         Copyright 1989 by The Massachusetts Institute of Technology
42 **    *
43 **    *         Permission to use, copy, modify, and distribute this
44 **    *         software and its documentation for any purpose and without
45 **    *         fee is hereby granted, provided that the above copyright
46 **    *         notice appear in all copies and that both that copyright
47 **    *         notice and this permission notice appear in supporting
48 **    *         documentation, and that the name of MIT not be used in
49 **    *         advertising or publicity pertaining to distribution of the
50 **    *         software without specific prior written permission.
51 **    *         M.I.T. makes no representation about the suitability of
52 **    *         this software for any purpose. It is provided "as is"
53 **    *         without any express or implied warranty.
54 **    *
55 **    *         MIT DISCLAIMS ALL WARRANTIES WITH REGARD TO  THIS  SOFTWARE,
56 **    *         INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FIT-
57 **    *         NESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL MIT BE  LI-
58 **    *         ABLE  FOR  ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
59 **    *         ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,  DATA  OR
60 **    *         PROFITS,  WHETHER  IN  AN  ACTION OF CONTRACT, NEGLIGENCE OR
61 **    *         OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION  WITH
62 **    *         THE USE OR PERFORMANCE OF THIS SOFTWARE.
63 **    *
64 **    *********************************************************
65 **
66 ********************************************************************/
67 /* $XFree86: xc/programs/Xserver/Xext/xprint.c,v 1.4 1997/01/02 04:05:05 dawes Exp $ */
68
69 #include "X.h"
70 #define NEED_EVENTS
71 #include "Xproto.h"
72 #undef NEED_EVENTS
73 #include "misc.h"
74 #include "windowstr.h"
75 #include "scrnintstr.h"
76 #include "pixmapstr.h"
77 #include "extnsionst.h"
78 #include "dixstruct.h"
79 #include "Xatom.h"
80 #define _XP_PRINT_SERVER_
81 #include "Print.h"
82 #include "Printstr.h"
83 #undef _XP_PRINT_SERVER_
84 #include "../Xprint/DiPrint.h"
85
86 extern WindowPtr *WindowTable; /* declared in dix:globals.c */
87
88 extern WindowPtr XpDiValidatePrinter();
89 extern char *XpDiGetDriverName();
90 extern char *XpGetAttributes();
91 extern char *XpGetOneAttribute();
92 extern int XpRehashPrinterList();
93 extern void XpSetFontResFunc();
94
95 static void XpResetProc();
96
97 static int ProcXpDispatch();
98 static int ProcXpSwappedDispatch();
99
100 static int ProcXpQueryVersion();
101 static int ProcXpGetPrinterList();
102 static int ProcXpCreateContext();
103 static int ProcXpSetContext();
104 static int ProcXpGetContext();
105 static int ProcXpDestroyContext();
106 static int ProcXpGetContextScreen();
107 static int ProcXpStartJob();
108 static int ProcXpEndJob();
109 static int ProcXpStartDoc();
110 static int ProcXpEndDoc();
111 static int ProcXpStartPage();
112 static int ProcXpEndPage();
113 static int ProcXpSelectInput();
114 static int ProcXpInputSelected();
115 static int ProcXpPutDocumentData();
116 static int ProcXpGetDocumentData();
117 static int ProcXpGetAttributes();
118 static int ProcXpGetOneAttribute();
119 static int ProcXpSetAttributes();
120 static int ProcXpRehashPrinterList();
121 static int ProcXpQueryScreens();
122 static int ProcXpGetPageDimensions();
123 static int ProcXpSetImageResolution();
124 static int ProcXpGetImageResolution();
125
126 static void SwapXpNotifyEvent();
127 static void SwapXpAttributeEvent();
128
129 static int SProcXpGetPrinterList();
130 static int SProcXpCreateContext();
131 static int SProcXpSetContext();
132 static int SProcXpGetContext();
133 static int SProcXpDestroyContext();
134 static int SProcXpGetContextScreen();
135 static int SProcXpStartJob();
136 static int SProcXpEndJob();
137 static int SProcXpStartDoc();
138 static int SProcXpEndDoc();
139 static int SProcXpStartPage();
140 static int SProcXpEndPage();
141 static int SProcXpSelectInput();
142 static int SProcXpInputSelected();
143 static int SProcXpPutDocumentData();
144 static int SProcXpGetDocumentData();
145 static int SProcXpGetAttributes();
146 static int SProcXpGetOneAttribute();
147 static int SProcXpSetAttributes();
148 static int SProcXpRehashPrinterList();
149 static int SProcXpGetPageDimensions();
150 static int SProcXpSetImageResolution();
151 static int SProcXpGetImageResolution();
152
153 static void SendXpNotify();
154 static void SendAttributeNotify();
155 static int XpFreeClient();
156 static int XpFreeContext();
157 static int XpFreePage();
158 static int XpFreeEvents();
159 static Bool XpCloseScreen();
160 static CARD32 GetAllEventMasks();
161 static struct _XpEvent *AddEventRec();
162 static void DeleteEventRec();
163 static struct _XpEvent *FindEventRec();
164 static struct _XpClient *CreateXpClient();
165 static void FreeXpClient();
166 static void InitContextPrivates();
167 static void ResetContextPrivates();
168 static struct _XpClient *FindClient();
169 static struct _XpClient *AcquireClient();
170
171 typedef struct _driver {
172     struct _driver *next;
173     char *name;
174     int (* CreateContext)();
175 } XpDriverRec, *XpDriverPtr;
176
177 typedef struct  _xpScreen {
178     Bool (* CloseScreen)();
179     struct _driver *drivers;
180 } XpScreenRec, *XpScreenPtr;
181
182 /*
183  * Each context has a list of XpClients indicating which clients have
184  * associated this context with their connection.
185  * Each such client has a RTclient resource allocated for it,
186  * and this per-client
187  * resource is used to delete the XpClientRec if/when the client closes
188  * its connection.
189  * The list of XpClients is also walked if/when the context is destroyed
190  * so that the ContextPtr can be removed from the client's devPrivates.
191  */
192 typedef struct _XpClient {
193         struct _XpClient *pNext;
194         ClientPtr       client;
195         XpContextPtr    context;
196         CARD32          eventMask;
197         XID             contextClientID; /* unneeded sanity check? */
198 } XpClientRec, *XpClientPtr;
199
200 /*
201  * Each StartPage request specifies a window which forms the top level
202  * window of the page.  One of the following structs is created as a
203  * RTpage resource with the same ID as the window itself.  This enables 
204  * us to clean up when/if the window is destroyed, and to prevent the
205  * same window from being simultaneously referenced in multiple contexts.
206  * The page resource is created at the first StartPage on a given window,
207  * and is only destroyed when/if the window is destroyed.  When the
208  * EndPage is recieved (or an EndDoc or EndJob) the context field is
209  * set to NULL, but the resource remains alive.
210  */
211 typedef struct _XpPage {
212         XpContextPtr    context;
213 } XpPageRec, *XpPagePtr;
214
215 typedef struct _XpStPageRec {
216     XpContextPtr pContext;
217     Bool slept;
218     XpPagePtr pPage;
219     WindowPtr pWin;
220 } XpStPageRec, *XpStPagePtr;
221
222 typedef struct _XpStDocRec {
223     XpContextPtr pContext;
224     Bool slept;
225     CARD8 type;
226 } XpStDocRec, *XpStDocPtr;
227
228 #define QUADPAD(x) ((((x)+3)>>2)<<2)
229
230 /*
231  * Possible bit-mask values in the "state" field of a XpContextRec.
232  */
233 #define JOB_STARTED (1 << 0)
234 #define DOC_RAW_STARTED (1 << 1)
235 #define DOC_COOKED_STARTED (1 << 2)
236 #define PAGE_STARTED (1 << 3)
237 #define GET_DOC_DATA_STARTED (1 << 4)
238 #define JOB_GET_DATA (1 << 5)
239     
240 static XpScreenPtr XpScreens[MAXSCREENS];
241 static unsigned char XpReqCode;
242 static int XpEventBase;
243 static int XpErrorBase;
244 static int XpGeneration = 0;
245 static int XpWindowPrivateIndex;
246 static int XpClientPrivateIndex;
247
248 /* Variables for the context private machinery. 
249  * These must be initialized at compile time because
250  * main() calls InitOutput before InitExtensions, and the
251  * output drivers are likely to call AllocateContextPrivate.
252  * These variables are reset at CloseScreen time.  CloseScreen
253  * is used because it occurs after FreeAllResources, and before
254  * the next InitOutput cycle.
255  */
256 static int  contextPrivateCount = 0;
257 static int contextPrivateLen = 0;
258 static unsigned *contextPrivateSizes = (unsigned *)NULL;
259 static unsigned totalContextSize = sizeof(XpContextRec);
260
261 /*
262  * There are three types of resources involved.  One is the resource associated
263  * with the context itself, with an ID specified by a printing client.  The
264  * next is a resource created by us on the client's behalf (and unknown to
265  * the client) when a client inits or sets a context which allows us to 
266  * track each client's interest in events
267  * on a particular context, and also allows us to clean up this interest
268  * record when/if the client's connection is closed.  Finally, there is
269  * a resource created for each window that's specified in a StartPage.  This
270  * resource carries the same ID as the window itself, and enables us to
271  * easily prevent the same window being referenced in multiple contexts
272  * simultaneously, and enables us to clean up if the window is destroyed
273  * before the EndPage.
274  */
275 static RESTYPE RTclient, RTcontext, RTpage;
276
277 /*
278  * allEvents is the OR of all the legal event mask bits.
279  */
280 static CARD32 allEvents = XPPrintMask | XPAttributeMask;
281
282
283 /*******************************************************************************
284  *
285  * ExtensionInit, Driver Init functions, QueryVersion, and Dispatch procs
286  *
287  ******************************************************************************/
288
289 /*
290  * XpExtensionInit
291  *
292  * Called from InitExtensions in main() usually through miinitextension
293  *
294  */
295
296 void
297 XpExtensionInit()
298 {
299     ExtensionEntry *extEntry, *AddExtension();
300     int i;
301
302     RTclient = CreateNewResourceType(XpFreeClient);
303     RTcontext = CreateNewResourceType(XpFreeContext);
304     RTpage = CreateNewResourceType(XpFreePage);
305     if (RTclient && RTcontext && RTpage &&
306         (extEntry = AddExtension(XP_PRINTNAME, XP_EVENTS, XP_ERRORS,
307                                ProcXpDispatch, ProcXpSwappedDispatch,
308                                XpResetProc, StandardMinorOpcode)))
309     {
310         XpReqCode = (unsigned char)extEntry->base;
311         XpEventBase = extEntry->eventBase;
312         XpErrorBase = extEntry->errorBase;
313         EventSwapVector[XpEventBase] = SwapXpNotifyEvent;
314         EventSwapVector[XpEventBase+1] = SwapXpAttributeEvent;
315     }
316
317     if(XpGeneration != serverGeneration)
318     {
319         XpClientPrivateIndex = AllocateClientPrivateIndex();
320         /*
321          * We allocate 0 length & simply stuff a pointer to the
322          * ContextRec in the DevUnion.
323          */
324         if(AllocateClientPrivate(XpClientPrivateIndex, 0) != TRUE)
325         {
326                 /* we can't alloc a client private, should we bail??? XXX */
327         }
328         XpGeneration = serverGeneration;
329     }
330
331     for(i = 0; i < MAXSCREENS; i++)
332     {
333         /*
334          * If a screen has registered with our extension, then we
335          * wrap the screen's CloseScreen function to allow us to
336          * reset our ContextPrivate stuff.  Note that this
337          * requires a printing DDX to call XpRegisterInitFunc
338          * _before_ this extension is initialized - i.e. at screen init
339          * time, _not_ at root window creation time.
340          */
341         if(XpScreens[i] != (XpScreenPtr)NULL)
342         {
343             XpScreens[i]->CloseScreen = screenInfo.screens[i]->CloseScreen;
344             screenInfo.screens[i]->CloseScreen = XpCloseScreen;
345         }
346     }
347     DeclareExtensionSecurity(XP_PRINTNAME, TRUE);
348 }
349
350 static void
351 XpResetProc(extEntry)
352     ExtensionEntry extEntry;
353 {
354     int i;
355
356     /*
357      * We can't free up the XpScreens recs here, because extensions are
358      * closed before screens, and our CloseScreen function uses the XpScreens
359      * recs.
360     for(i = 0; i < MAXSCREENS; i++)
361     {
362         if(XpScreens[i] != (XpScreenPtr)NULL)
363             Xfree(XpScreens[i]);
364         XpScreens[i] = (XpScreenPtr)NULL;
365     }
366     */
367 }
368
369 static Bool
370 XpCloseScreen(index, pScreen)
371     int index;
372     ScreenPtr pScreen;
373 {
374     Bool (* CloseScreen)();
375
376     CloseScreen = XpScreens[index]->CloseScreen;
377     if(XpScreens[index] != (XpScreenPtr)NULL)
378     {
379         XpDriverPtr pDriv, nextDriv;
380
381         pDriv = XpScreens[index]->drivers;
382         while(pDriv != (XpDriverPtr)NULL)
383         {
384             nextDriv = pDriv->next;
385             Xfree(pDriv);
386             pDriv = nextDriv;
387         }
388         Xfree(XpScreens[index]);
389     }
390     XpScreens[index] = (XpScreenPtr)NULL;
391
392     /*
393      * It's wasteful to call ResetContextPrivates() at every CloseScreen, 
394      * but it's the best we know how to do for now.  We do this because we
395      * have to wait until after all resources have been freed (so we know
396      * how to free the ContextRecs), and before the next InitOutput cycle.
397      * See dix/main.c for the order of initialization and reset.
398      */
399     ResetContextPrivates();
400     return (*CloseScreen)(index, pScreen);
401 }
402
403 static void
404 FreeScreenEntry(pScreenEntry)
405     XpScreenPtr pScreenEntry;
406 {
407     XpDriverPtr pDriver;
408
409     pDriver = pScreenEntry->drivers; 
410     while(pDriver != (XpDriverPtr)NULL)
411     {
412         XpDriverPtr tmp;
413
414         tmp = pDriver->next;
415         xfree(pDriver);
416         pDriver = tmp;
417     }
418     xfree(pScreenEntry);
419 }
420
421 /*
422  * XpRegisterInitFunc tells the print extension which screens
423  * are printers as opposed to displays, and what drivers are
424  * supported on each screen.  This eliminates the need of
425  * allocating print-related private structures on windows on _all_ screens.
426  * It also hands the extension a pointer to the routine to be called
427  * whenever a context gets created for a particular driver on this screen.
428  */
429 void
430 XpRegisterInitFunc(pScreen, driverName, initContext)
431     ScreenPtr pScreen;
432     char *driverName;
433     int (*initContext)();
434 {
435     XpDriverPtr pDriver;
436
437     if(XpScreens[pScreen->myNum] == (XpScreenPtr)NULL)
438     {
439         if((XpScreens[pScreen->myNum] =
440            (XpScreenPtr) Xalloc(sizeof(XpScreenRec))) == (XpScreenPtr)NULL)
441             return;
442         XpScreens[pScreen->myNum]->CloseScreen = (Bool(*)())NULL;
443         XpScreens[pScreen->myNum]->drivers = (XpDriverPtr)NULL;
444     }
445
446     if((pDriver = (XpDriverPtr)Xalloc(sizeof(XpDriverRec))) == 
447        (XpDriverPtr)NULL)
448         return;
449     pDriver->next = XpScreens[pScreen->myNum]->drivers;
450     pDriver->name = driverName;
451     pDriver->CreateContext = initContext;
452     XpScreens[pScreen->myNum]->drivers = pDriver;
453 }
454
455 static int 
456 ProcXpDispatch(client)
457     ClientPtr client;
458 {
459     REQUEST(xReq);
460
461     switch(stuff->data)
462     {
463         case X_PrintQueryVersion:
464             return ProcXpQueryVersion(client);
465         case X_PrintGetPrinterList:
466             return ProcXpGetPrinterList(client);
467         case X_PrintCreateContext:
468             return ProcXpCreateContext(client);
469         case X_PrintSetContext:
470             return ProcXpSetContext(client);
471         case X_PrintGetContext:
472             return ProcXpGetContext(client);
473         case X_PrintDestroyContext:
474             return ProcXpDestroyContext(client);
475         case X_PrintGetContextScreen:
476             return ProcXpGetContextScreen(client);
477         case X_PrintStartJob:
478             return ProcXpStartJob(client);
479         case X_PrintEndJob:
480             return ProcXpEndJob(client);
481         case X_PrintStartDoc:
482             return ProcXpStartDoc(client);
483         case X_PrintEndDoc:
484             return ProcXpEndDoc(client);
485         case X_PrintStartPage:
486             return ProcXpStartPage(client);
487         case X_PrintEndPage:
488             return ProcXpEndPage(client);
489         case X_PrintSelectInput:
490             return ProcXpSelectInput(client);
491         case X_PrintInputSelected:
492             return ProcXpInputSelected(client);
493         case X_PrintPutDocumentData:
494             return ProcXpPutDocumentData(client);
495         case X_PrintGetDocumentData:
496             return ProcXpGetDocumentData(client);
497         case X_PrintSetAttributes:
498             return ProcXpSetAttributes(client);
499         case X_PrintGetAttributes:
500             return ProcXpGetAttributes(client);
501         case X_PrintGetOneAttribute:
502             return ProcXpGetOneAttribute(client);
503         case X_PrintRehashPrinterList:
504             return ProcXpRehashPrinterList(client);
505         case X_PrintQueryScreens:
506             return ProcXpQueryScreens(client);
507         case X_PrintGetPageDimensions:
508             return ProcXpGetPageDimensions(client);
509         case X_PrintSetImageResolution:
510             return ProcXpSetImageResolution(client);
511         case X_PrintGetImageResolution:
512             return ProcXpGetImageResolution(client);
513         default:
514             return BadRequest;
515     }
516 }
517
518 static int 
519 ProcXpSwappedDispatch(client)
520     ClientPtr client;
521 {
522     int temp;
523     REQUEST(xReq);
524
525     switch(stuff->data)
526     {
527         case X_PrintQueryVersion:
528             swaps(&stuff->length, temp);
529             return ProcXpQueryVersion(client);
530         case X_PrintGetPrinterList:
531             return SProcXpGetPrinterList(client);
532         case X_PrintCreateContext:
533             return SProcXpCreateContext(client);
534         case X_PrintSetContext:
535             return SProcXpSetContext(client);
536         case X_PrintGetContext:
537             return SProcXpGetContext(client);
538         case X_PrintDestroyContext:
539             return SProcXpDestroyContext(client);
540         case X_PrintGetContextScreen:
541             return SProcXpGetContextScreen(client);
542         case X_PrintStartJob:
543             return SProcXpStartJob(client);
544         case X_PrintEndJob:
545             return SProcXpEndJob(client);
546         case X_PrintStartDoc:
547             return SProcXpStartDoc(client);
548         case X_PrintEndDoc:
549             return SProcXpEndDoc(client);
550         case X_PrintStartPage:
551             return SProcXpStartPage(client);
552         case X_PrintEndPage:
553             return SProcXpEndPage(client);
554         case X_PrintSelectInput:
555             return SProcXpSelectInput(client);
556         case X_PrintInputSelected:
557             return SProcXpInputSelected(client);
558         case X_PrintPutDocumentData:
559             return SProcXpPutDocumentData(client);
560         case X_PrintGetDocumentData:
561             return SProcXpGetDocumentData(client);
562         case X_PrintSetAttributes:
563             return SProcXpSetAttributes(client);
564         case X_PrintGetAttributes:
565             return SProcXpGetAttributes(client);
566         case X_PrintGetOneAttribute:
567             return SProcXpGetOneAttribute(client);
568         case X_PrintRehashPrinterList:
569             return SProcXpRehashPrinterList(client);
570         case X_PrintQueryScreens:
571             swaps(&stuff->length, temp);
572             return ProcXpQueryScreens(client);
573         case X_PrintGetPageDimensions:
574             return SProcXpGetPageDimensions(client);
575         case X_PrintSetImageResolution:
576             return SProcXpSetImageResolution(client);
577         case X_PrintGetImageResolution:
578             return SProcXpGetImageResolution(client);
579         default:
580             return BadRequest;
581     }
582 }
583
584 static int
585 ProcXpQueryVersion(client)
586     ClientPtr client;
587 {
588     REQUEST(xPrintQueryVersionReq);
589     xPrintQueryVersionReply rep;
590     register int n;
591     long l;
592
593     REQUEST_SIZE_MATCH(xPrintQueryVersionReq);
594     rep.type = X_Reply;
595     rep.length = 0;
596     rep.sequenceNumber = client->sequence;
597     rep.majorVersion = XP_MAJOR_VERSION;
598     rep.minorVersion = XP_MINOR_VERSION;
599     if (client->swapped) {
600         swaps(&rep.sequenceNumber, n);
601         swapl(&rep.length, l);
602         swaps(&rep.majorVersion, n);
603         swaps(&rep.minorVersion, n);
604     }
605     WriteToClient(client, sz_xPrintQueryVersionReply, (char *)&rep);
606     return client->noClientException;
607 }
608
609 /*******************************************************************************
610  *
611  * GetPrinterList : Return a list of all printers associated with this
612  *                  server.  Calls XpDiGetPrinterList, which is defined in
613  *                  the device-independent code in Xserver/Xprint.
614  *
615  ******************************************************************************/
616
617 static int
618 ProcXpGetPrinterList(client)
619     ClientPtr client;
620 {
621     REQUEST(xPrintGetPrinterListReq);
622     int totalSize, numEntries;
623     XpDiListEntry **pList, *pEntry;
624     xPrintGetPrinterListReply *rep;
625     int n, i, totalBytes;
626     long l;
627     char *curByte;
628
629     REQUEST_AT_LEAST_SIZE(xPrintGetPrinterListReq);
630
631     totalSize = ((sz_xPrintGetPrinterListReq) >> 2) +
632                 ((stuff->printerNameLen + 3) >> 2) +
633                 ((stuff->localeLen + 3) >> 2);
634     if(totalSize != client->req_len)
635          return BadLength;
636
637     pList = XpDiGetPrinterList(stuff->printerNameLen, (char *)(stuff + 1), 
638                                stuff->localeLen, (char *)((stuff + 1) + 
639                                QUADPAD(stuff->printerNameLen)));
640
641     for(numEntries = 0, totalBytes = sz_xPrintGetPrinterListReply;
642         pList[numEntries] != (XpDiListEntry *)NULL;
643         numEntries++)
644     {
645         totalBytes += 2 * sizeof(CARD32); 
646         totalBytes += QUADPAD(strlen(pList[numEntries]->name));
647         totalBytes += QUADPAD(strlen(pList[numEntries]->description));
648     }
649
650     if((rep = (xPrintGetPrinterListReply *)xalloc(totalBytes)) == 
651        (xPrintGetPrinterListReply *)NULL)
652         return BadAlloc;
653
654     rep->type = X_Reply;
655     rep->length = (totalBytes - sz_xPrintGetPrinterListReply) >> 2;
656     rep->sequenceNumber = client->sequence;
657     rep->listCount = numEntries;
658     if (client->swapped) {
659         swaps(&rep->sequenceNumber, n);
660         swapl(&rep->length, l);
661         swapl(&rep->listCount, l);
662     }
663
664     for(i = 0, curByte = (char *)(rep + 1); i < numEntries; i++)
665     {
666         CARD32 *pCrd;
667         int len;
668
669         pCrd = (CARD32 *)curByte;
670         len = strlen(pList[i]->name);
671         *pCrd = len;
672         if (client->swapped)
673             swapl((long *)curByte, l);
674         curByte += sizeof(CARD32);
675         strncpy(curByte, pList[i]->name, len);
676         curByte += QUADPAD(len);
677
678         pCrd = (CARD32 *)curByte;
679         len = strlen(pList[i]->description);
680         *pCrd = len;
681         if (client->swapped)
682             swapl((long *)curByte, l);
683         curByte += sizeof(CARD32);
684         strncpy(curByte, pList[i]->description, len);
685         curByte += QUADPAD(len);
686     }
687
688     XpDiFreePrinterList(pList);
689
690     WriteToClient(client, totalBytes, (char *)rep);
691     xfree(rep);
692     return client->noClientException;
693 }
694
695 /*******************************************************************************
696  *
697  * QueryScreens: Returns the list of screens which are associated with
698  *               print drivers.
699  *
700  ******************************************************************************/
701
702 static int
703 ProcXpQueryScreens(client)
704     ClientPtr client;
705 {
706     REQUEST(xPrintQueryScreensReq);
707     int i, numPrintScreens, totalSize;
708     WINDOW *pWinId;
709     xPrintQueryScreensReply *rep;
710     long l;
711
712     REQUEST_SIZE_MATCH(xPrintQueryScreensReq);
713
714     rep = (xPrintQueryScreensReply *)xalloc(sz_xPrintQueryScreensReply);
715     pWinId = (WINDOW *)(rep + 1);
716
717     for(i = 0, numPrintScreens = 0, totalSize = sz_xPrintQueryScreensReply; 
718         i < MAXSCREENS; i++)
719     {
720         /*
721          * If a screen has registered with our extension, then it's
722          * a printer screen.
723          */
724         if(XpScreens[i] != (XpScreenPtr)NULL)
725         {
726             numPrintScreens++;
727             totalSize += sizeof(WINDOW);
728             rep = (xPrintQueryScreensReply *)xrealloc(rep, totalSize);
729             *pWinId = WindowTable[i]->drawable.id;
730             if (client->swapped)
731                 swapl((long *)pWinId, l);
732             pWinId++;
733         }
734     }
735
736     rep->type = X_Reply;
737     rep->sequenceNumber = client->sequence;
738     rep->length = (totalSize - sz_xPrintQueryScreensReply) >> 2;
739     rep->listCount = numPrintScreens;
740     if (client->swapped)
741     {
742         int n;
743
744         swaps(&rep->sequenceNumber, n);
745         swapl(&rep->length, l);
746         swapl(&rep->listCount, l);
747     }
748
749     WriteToClient(client, totalSize, (char *)rep);
750     xfree(rep);
751     return client->noClientException;
752 }
753
754 static int 
755 ProcXpGetPageDimensions(client)
756     ClientPtr client;
757 {
758     REQUEST(xPrintGetPageDimensionsReq);
759     CARD16 width, height;
760     xRectangle rect;
761     xPrintGetPageDimensionsReply rep;
762     XpContextPtr pContext;
763     int result;
764
765     REQUEST_SIZE_MATCH(xPrintGetPageDimensionsReq);
766
767     if((pContext =(XpContextPtr)SecurityLookupIDByType(client,
768                                                        stuff->printContext,
769                                                        RTcontext,
770                                                        SecurityReadAccess))
771        == (XpContextPtr)NULL)
772     {
773         client->errorValue = stuff->printContext;
774         return XpErrorBase+XPBadContext;
775     }
776
777     if(pContext->funcs.GetMediumDimensions != (int (*)())NULL)
778         result = pContext->funcs.GetMediumDimensions(pContext, &width, &height);
779     else
780         return BadImplementation;
781
782     if(pContext->funcs.GetReproducibleArea != (int (*)())NULL)
783         result = pContext->funcs.GetReproducibleArea(pContext, &rect);
784     else
785         return BadImplementation;
786
787     rep.type = X_Reply;
788     rep.sequenceNumber = client->sequence;
789     rep.length = 0;
790     rep.width = width;
791     rep.height = height;
792     rep.rx = rect.x;
793     rep.ry = rect.y;
794     rep.rwidth = rect.width;
795     rep.rheight = rect.height;
796
797     if(client->swapped)
798     {
799         int n;
800         long l;
801
802         swaps(&rep.sequenceNumber, n);
803         swapl(&rep.length, l);
804         swaps(&rep.width, n);
805         swaps(&rep.height, n);
806         swaps(&rep.rx, n);
807         swaps(&rep.ry, n);
808         swaps(&rep.rwidth, n);
809         swaps(&rep.rheight, n);
810     }
811
812     WriteToClient(client, sz_xPrintGetPageDimensionsReply, (char *)&rep);
813     return client->noClientException;
814 }
815
816 static int 
817 ProcXpSetImageResolution(client)
818     ClientPtr client;
819 {
820     REQUEST(xPrintSetImageResolutionReq);
821     xPrintSetImageResolutionReply rep;
822     XpContextPtr pContext;
823     Bool status;
824     int result;
825
826     REQUEST_SIZE_MATCH(xPrintSetImageResolutionReq);
827
828     if((pContext =(XpContextPtr)SecurityLookupIDByType(client,
829                                                        stuff->printContext,
830                                                        RTcontext,
831                                                        SecurityWriteAccess))
832        == (XpContextPtr)NULL)
833     {
834         client->errorValue = stuff->printContext;
835         return XpErrorBase+XPBadContext;
836     }
837
838     rep.prevRes = pContext->imageRes;
839     if(pContext->funcs.SetImageResolution != (int (*)())NULL)
840         result = pContext->funcs.SetImageResolution(pContext,
841                                                     (int)stuff->imageRes,
842                                                     &status);
843     else
844         status = FALSE;
845
846     rep.type = X_Reply;
847     rep.sequenceNumber = client->sequence;
848     rep.length = 0;
849     rep.status = status;
850
851     if(client->swapped)
852     {
853         int n;
854         long l;
855
856         swaps(&rep.sequenceNumber, n);
857         swapl(&rep.length, l);
858         swaps(&rep.prevRes, n);
859     }
860
861     WriteToClient(client, sz_xPrintSetImageResolutionReply, (char *)&rep);
862     return client->noClientException;
863 }
864
865 static int 
866 ProcXpGetImageResolution(client)
867     ClientPtr client;
868 {
869     REQUEST(xPrintGetImageResolutionReq);
870     xPrintGetImageResolutionReply rep;
871     XpContextPtr pContext;
872     Bool status;
873     int result;
874
875     REQUEST_SIZE_MATCH(xPrintGetImageResolutionReq);
876
877     if((pContext =(XpContextPtr)SecurityLookupIDByType(client,
878                                                        stuff->printContext,
879                                                        RTcontext,
880                                                        SecurityReadAccess))
881        == (XpContextPtr)NULL)
882     {
883         client->errorValue = stuff->printContext;
884         return XpErrorBase+XPBadContext;
885     }
886
887     rep.type = X_Reply;
888     rep.sequenceNumber = client->sequence;
889     rep.length = 0;
890     rep.imageRes = pContext->imageRes;
891
892     if(client->swapped)
893     {
894         int n;
895         long l;
896
897         swaps(&rep.sequenceNumber, n);
898         swapl(&rep.length, l);
899         swaps(&rep.imageRes, n);
900     }
901
902     WriteToClient(client, sz_xPrintGetImageResolutionReply, (char *)&rep);
903     return client->noClientException;
904 }
905
906 /*******************************************************************************
907  *
908  * RehashPrinterList : Cause the server's list of printers to be rebuilt.
909  *                     This allows new printers to be added, or old ones
910  *                     deleted without needing to restart the server.
911  *
912  ******************************************************************************/
913
914 static int
915 ProcXpRehashPrinterList(client)
916     ClientPtr client;
917 {
918     REQUEST(xPrintRehashPrinterListReq);
919
920     REQUEST_SIZE_MATCH(xPrintRehashPrinterListReq);
921
922     return XpRehashPrinterList();
923 }
924
925 /******************************************************************************
926  *
927  * Context functions: Init, Set, Destroy, FreeContext
928  *                      AllocateContextPrivateIndex, AllocateContextPrivate
929  *                      and supporting functions.
930  *
931  *     Init creates a context, creates a XpClientRec for the calling
932  *     client, and stores the contextPtr in the client's devPrivates.
933  *
934  *     Set creates a XpClientRec for the calling client, and stores the
935  *     contextPtr in the client's devPrivates unless the context is None.
936  *     If the context is None, then the client's connection association
937  *     with any context is removed.
938  *
939  *     Destroy frees any and all XpClientRecs associated with the context,
940  *     frees the context itself, and removes the contextPtr from any
941  *     relevant client devPrivates.
942  *
943  *     FreeContext is called by FreeResource to free up a context.
944  *
945  ******************************************************************************/
946
947 /*
948  * CreateContext creates and initializes the memory for the context itself.
949  * The driver's CreateContext function
950  * is then called.
951  */
952 static int
953 ProcXpCreateContext(client)
954     ClientPtr client;
955 {
956     REQUEST(xPrintCreateContextReq);
957     XpScreenPtr pPrintScreen;
958     WindowPtr pRoot;
959     char *printerName, *driverName;
960     XpContextPtr pContext;
961     XpClientPtr pNewPrintClient;
962     int result = Success;
963     XpDriverPtr pDriver;
964
965     REQUEST_AT_LEAST_SIZE(xPrintCreateContextReq);
966
967     LEGAL_NEW_RESOURCE(stuff->contextID, client);
968
969     /*
970      * Check to see if the printer name is valid.
971      */
972     if((pRoot = XpDiValidatePrinter(stuff + 1, stuff->printerNameLen)) == 
973        (WindowPtr)NULL)
974         return BadMatch;
975
976     pPrintScreen = XpScreens[pRoot->drawable.pScreen->myNum];
977
978     /*
979      * Allocate and add the context resource.
980      */
981     if((pContext = (XpContextPtr) xalloc(totalContextSize)) == 
982        (XpContextPtr) NULL)
983         return BadAlloc;
984
985     InitContextPrivates(pContext);
986
987     if(AddResource(stuff->contextID, RTcontext, (pointer) pContext)
988        != TRUE)
989     {
990        xfree(pContext);
991        return BadAlloc;
992     }
993
994     pContext->contextID = stuff->contextID;
995     pContext->clientHead = (XpClientPtr)NULL;
996     pContext->screenNum = pRoot->drawable.pScreen->myNum;
997     pContext->state = 0;
998     pContext->clientSlept = (ClientPtr)NULL;
999     pContext->imageRes = 0;
1000
1001     pContext->funcs.DestroyContext = (int (*)())NULL;
1002     pContext->funcs.StartJob = (int (*)())NULL;
1003     pContext->funcs.EndJob = (int (*)())NULL;
1004     pContext->funcs.StartDoc = (int (*)())NULL;
1005     pContext->funcs.EndDoc = (int (*)())NULL;
1006     pContext->funcs.StartPage = (int (*)())NULL;
1007     pContext->funcs.EndPage = (int (*)())NULL;
1008     pContext->funcs.PutDocumentData = (int (*)())NULL;
1009     pContext->funcs.GetDocumentData = (int (*)())NULL;
1010     pContext->funcs.GetAttributes = (char * (*)())NULL;
1011     pContext->funcs.GetOneAttribute = (char * (*)())NULL;
1012     pContext->funcs.SetAttributes = (int (*)())NULL;
1013     pContext->funcs.AugmentAttributes = (int (*)())NULL;
1014     pContext->funcs.GetMediumDimensions = (int (*)())NULL;
1015     pContext->funcs.GetReproducibleArea = (int (*)())NULL;
1016     pContext->funcs.SetImageResolution = (int (*)())NULL;
1017
1018     if((pContext->printerName = (char *)xalloc(stuff->printerNameLen + 1)) == 
1019        (char *)NULL)
1020     {
1021         /* Freeing the context also causes the XpClients to be freed. */
1022         FreeResource(stuff->contextID, RT_NONE);
1023         return BadAlloc;
1024     }
1025     strncpy(pContext->printerName, (char *)(stuff + 1), stuff->printerNameLen);
1026     pContext->printerName[stuff->printerNameLen] = (char)'\0';
1027
1028     driverName = XpDiGetDriverName(pRoot->drawable.pScreen->myNum, 
1029                                    pContext->printerName);
1030     
1031     for(pDriver = pPrintScreen->drivers; 
1032         pDriver != (XpDriverPtr)NULL;
1033         pDriver = pDriver->next)
1034     {
1035         if(!strcmp(driverName, pDriver->name))
1036         {
1037             if(pDriver->CreateContext != (Bool (*)())NULL)
1038                 pDriver->CreateContext(pContext);
1039             else
1040                 return BadImplementation;
1041             break;
1042         }
1043     }
1044
1045     if (client->noClientException != Success)
1046         return client->noClientException;
1047     else
1048         return result;
1049 }
1050
1051 /*
1052  * SetContext creates the calling client's contextClient resource,
1053  * and stashes the contextID in the client's devPrivate.
1054  */
1055 static int
1056 ProcXpSetContext(client)
1057     ClientPtr client;
1058 {
1059     REQUEST(xPrintSetContextReq);
1060
1061     XpContextPtr pContext;
1062     XpClientPtr pPrintClient;
1063     int result = Success;
1064
1065     REQUEST_AT_LEAST_SIZE(xPrintSetContextReq);
1066
1067     if((pContext = client->devPrivates[XpClientPrivateIndex].ptr) != 
1068        (pointer)NULL)
1069     {
1070         /*
1071          * Erase this client's knowledge of its old context, if any.
1072          */
1073         if((pPrintClient = FindClient(pContext, client)) != (XpClientPtr)NULL)
1074         {
1075             XpUnsetFontResFunc(client);
1076             
1077             if(pPrintClient->eventMask == 0)
1078                 FreeXpClient(pPrintClient, TRUE);
1079         }
1080
1081         client->devPrivates[XpClientPrivateIndex].ptr = (pointer)NULL;
1082     }
1083     if(stuff->printContext == None)
1084         return Success;
1085
1086     /*
1087      * Check to see that the supplied XID is really a valid print context
1088      * in this server.
1089      */
1090     if((pContext =(XpContextPtr)SecurityLookupIDByType(client,
1091                                                        stuff->printContext,
1092                                                        RTcontext,
1093                                                        SecurityWriteAccess))
1094        == (XpContextPtr)NULL)
1095     {
1096         client->errorValue = stuff->printContext;
1097         return XpErrorBase+XPBadContext;
1098     }
1099
1100     if((pPrintClient = AcquireClient(pContext, client)) == (XpClientPtr)NULL)
1101         return BadAlloc;
1102
1103     client->devPrivates[XpClientPrivateIndex].ptr = pContext;
1104
1105     XpSetFontResFunc(client);
1106
1107     if (client->noClientException != Success)
1108         return client->noClientException;
1109     else
1110         return result;
1111 }
1112
1113 XpContextPtr
1114 XpGetPrintContext(client)
1115     ClientPtr client;
1116 {
1117     return (client->devPrivates[XpClientPrivateIndex].ptr);
1118 }
1119
1120 static int
1121 ProcXpGetContext(client)
1122     ClientPtr client;
1123 {
1124     REQUEST(xPrintGetContextReq);
1125     xPrintGetContextReply rep;
1126
1127     XpContextPtr pContext;
1128     XpClientPtr pNewPrintClient;
1129     int result = Success;
1130     register int n;
1131     register long l;
1132
1133     REQUEST_SIZE_MATCH(xPrintGetContextReq);
1134
1135     if((pContext = client->devPrivates[XpClientPrivateIndex].ptr) == 
1136        (pointer)NULL)
1137         rep.printContext = None;
1138     else
1139         rep.printContext = pContext->contextID;
1140     rep.type = X_Reply;
1141     rep.length = 0;
1142     rep.sequenceNumber = client->sequence;
1143     if (client->swapped) {
1144         swaps(&rep.sequenceNumber, n);
1145         swapl(&rep.length, l);
1146         swapl(&rep.printContext, l);
1147     }
1148     WriteToClient(client, sz_xPrintGetContextReply, (char *)&rep);
1149     return client->noClientException;
1150 }
1151
1152
1153 /*
1154  * DestroyContext frees the context associated with the calling client.
1155  * It operates by freeing the context resource ID, thus causing XpFreeContext
1156  * to be called.
1157  */
1158 static int
1159 ProcXpDestroyContext(client)
1160     ClientPtr client;
1161 {
1162     REQUEST(xPrintDestroyContextReq);
1163
1164     XpContextPtr pContext;
1165     XpClientPtr pXpClient;
1166     ClientPtr curClient;
1167
1168     REQUEST_SIZE_MATCH(xPrintDestroyContextReq);
1169
1170     if((pContext =(XpContextPtr)SecurityLookupIDByType(client,
1171                                                        stuff->printContext,
1172                                                        RTcontext,
1173                                                        SecurityDestroyAccess))
1174        == (XpContextPtr)NULL)
1175     {
1176         client->errorValue = stuff->printContext;
1177         return XpErrorBase+XPBadContext;
1178     }
1179
1180     XpUnsetFontResFunc(client);
1181             
1182     FreeResource(pContext->contextID, RT_NONE);
1183
1184     return Success;
1185 }
1186
1187 static int
1188 ProcXpGetContextScreen(client)
1189     ClientPtr client;
1190 {
1191     REQUEST(xPrintGetContextScreenReq);
1192     xPrintGetContextScreenReply rep;
1193     XpContextPtr pContext;
1194     int n;
1195     long l;
1196
1197     if((pContext =(XpContextPtr)SecurityLookupIDByType(client,
1198                                                        stuff->printContext,
1199                                                        RTcontext,
1200                                                        SecurityReadAccess))
1201        == (XpContextPtr)NULL)
1202         return XpErrorBase+XPBadContext;
1203     
1204     rep.type = X_Reply;
1205     rep.sequenceNumber = client->sequence;
1206     rep.length = 0;
1207     rep.rootWindow = WindowTable[pContext->screenNum]->drawable.id;
1208
1209     if (client->swapped) {
1210         swaps(&rep.sequenceNumber, n);
1211         swapl(&rep.length, l);
1212         swapl(&rep.rootWindow, l);
1213     }
1214
1215     WriteToClient(client, sz_xPrintGetContextScreenReply, (char *)&rep);
1216     return client->noClientException;
1217 }
1218
1219 /*
1220  * XpFreeContext is the routine called by dix:FreeResource when a context
1221  * resource ID is freed.
1222  * It checks to see if there's a partial job pending on the context, and
1223  * if so it calls the appropriate End procs with the cancel flag set.
1224  * It calls the driver's DestroyContext routine to allow the driver to clean
1225  * up any context-related memory or state.
1226  * It calls FreeXpClient to free all the 
1227  * associated XpClientRecs and to set all the client->devPrivates to NULL.
1228  * It frees the printer name string, and frees the context
1229  * itself.
1230  */
1231 static int
1232 XpFreeContext(data, id)
1233     pointer data;
1234     XID id;
1235 {
1236     XpContextPtr pContext = (XpContextPtr)data;
1237
1238     /* Clean up any pending job on this context */
1239     if(pContext->state != 0)
1240     {
1241         if(pContext->state & PAGE_STARTED)
1242         {
1243             WindowPtr pWin = (WindowPtr )LookupIDByType(
1244                                        pContext->pageWin, RT_WINDOW);
1245             XpPagePtr pPage = (XpPagePtr)LookupIDByType(
1246                                        pContext->pageWin, RTpage);
1247
1248             pContext->funcs.EndPage(pContext, pWin, TRUE);
1249             SendXpNotify(pContext, XPEndPageNotify, TRUE);
1250             pContext->state &= ~PAGE_STARTED;
1251             if(pPage)
1252                 pPage->context = (XpContextPtr)NULL;
1253         }
1254         if((pContext->state & DOC_RAW_STARTED) || 
1255            (pContext->state & DOC_COOKED_STARTED))
1256         {
1257             pContext->funcs.EndDoc(pContext, TRUE);
1258             SendXpNotify(pContext, XPEndDocNotify, TRUE);
1259             pContext->state &= ~DOC_RAW_STARTED;
1260             pContext->state &= ~DOC_COOKED_STARTED;
1261         }
1262         if(pContext->funcs.EndJob != (int (*)())NULL)
1263         {
1264             pContext->funcs.EndJob(pContext, TRUE);
1265             SendXpNotify(pContext, XPEndJobNotify, TRUE);
1266             pContext->state &= ~JOB_STARTED;
1267             pContext->state &= ~GET_DOC_DATA_STARTED;
1268         }
1269     }
1270
1271     /* 
1272      * Tell the driver we're destroying the context
1273      * This allows the driver to free and ContextPrivate data
1274      */
1275     if(pContext->funcs.DestroyContext != (int (*)())NULL)
1276         pContext->funcs.DestroyContext(pContext);
1277
1278     /* Free up all the XpClientRecs */
1279     while(pContext->clientHead != (XpClientPtr)NULL)
1280     {
1281         FreeXpClient(pContext->clientHead, TRUE);
1282     }
1283
1284     xfree(pContext->printerName);
1285     xfree(pContext);
1286     return Success; /* ??? */
1287 }
1288
1289 /*
1290  * XpFreeClient is the routine called by dix:FreeResource when a RTclient
1291  * is freed.  It simply calls the FreeXpClient routine to do the work.
1292  */
1293 static int
1294 XpFreeClient(data, id)
1295     pointer data;
1296     XID id;
1297 {
1298     FreeXpClient((XpClientPtr)data, FALSE);
1299 }
1300
1301 /*
1302  * FreeXpClient 
1303  * frees the ClientRec passed in, and sets the client->devPrivates to NULL
1304  * if the client->devPrivates points to the same context as the XpClient.
1305  * Called from XpFreeContext(from FreeResource), and 
1306  * XpFreeClient.  The boolean freeResource specifies whether or not to call
1307  * FreeResource for the XpClientRec's XID.  We should free it except if we're
1308  * called from XpFreeClient (which is itself called from FreeResource for the
1309  * XpClientRec's XID).
1310  */
1311 static void
1312 FreeXpClient(pXpClient, freeResource)
1313     XpClientPtr pXpClient;
1314     Bool freeResource;
1315 {
1316     XpClientPtr pCurrent, pPrev;
1317     XpContextPtr pContext = pXpClient->context;
1318
1319     /*
1320      * If we're freeing the clientRec associated with the context tied
1321      * to the client's devPrivates, then we need to clear the devPrivates.
1322      */
1323     if(pXpClient->client->devPrivates[XpClientPrivateIndex].ptr == 
1324        pXpClient->context)
1325     {
1326         pXpClient->client->devPrivates[XpClientPrivateIndex].ptr = 
1327                                         (pointer)NULL;
1328     }
1329
1330     for(pPrev = (XpClientPtr)NULL, pCurrent = pContext->clientHead; 
1331         pCurrent != (XpClientPtr)NULL; 
1332         pCurrent = pCurrent->pNext)
1333     {
1334         if(pCurrent == pXpClient)
1335         {
1336             if(freeResource == TRUE)
1337                 FreeResource (pCurrent->contextClientID, RTclient);
1338
1339             if (pPrev != (XpClientPtr)NULL)
1340                 pPrev->pNext = pCurrent->pNext;
1341             else
1342                 pContext->clientHead = pCurrent->pNext;
1343
1344             xfree (pCurrent);
1345             break;
1346         }
1347         pPrev = pCurrent;
1348     }
1349 }
1350
1351 /*
1352  * CreateXpClient takes a ClientPtr and returns a pointer to a
1353  * XpClientRec which it allocates.  It also initializes the Rec,
1354  * including adding a resource on behalf of the client to enable the
1355  * freeing of the Rec when the client's connection is closed.
1356  */
1357 static XpClientPtr
1358 CreateXpClient(client)
1359     ClientPtr client;
1360 {
1361     XpClientPtr pNewPrintClient;
1362     XID clientResource;
1363
1364     if((pNewPrintClient = (XpClientPtr)xalloc(sizeof(XpClientRec))) ==
1365       (XpClientPtr)NULL)
1366         return (XpClientPtr)NULL;
1367
1368     clientResource = FakeClientID(client->index);
1369     if(!AddResource(clientResource, RTclient, (pointer)pNewPrintClient))
1370     {
1371         xfree (pNewPrintClient);
1372         return (XpClientPtr)NULL;
1373     }
1374
1375     pNewPrintClient->pNext = (XpClientPtr)NULL;
1376     pNewPrintClient->client = client;
1377     pNewPrintClient->context = (XpContextPtr)NULL;
1378     pNewPrintClient->eventMask = 0;
1379     pNewPrintClient->contextClientID = clientResource;
1380
1381     return pNewPrintClient;
1382 }
1383
1384 /*
1385  * XpFreePage is the routine called by dix:FreeResource to free the page
1386  * resource built with the same ID as a page window.  It checks to see
1387  * if we're in the middle of a page, and if so calls the driver's EndPage
1388  * function with 'cancel' set TRUE.  It frees the memory associated with
1389  * the page resource.
1390  */
1391 static int
1392 XpFreePage(data, id)
1393     pointer data;
1394     XID id;
1395 {
1396     XpPagePtr page = (XpPagePtr)data;
1397     int result = Success;
1398     WindowPtr pWin = (WindowPtr )LookupIDByType(id, RT_WINDOW);
1399
1400     /* Check to see if the window's being deleted in the middle of a page */
1401     if(page->context != (XpContextPtr)NULL && 
1402        page->context->state & PAGE_STARTED)
1403     {
1404         XpScreenPtr pPrintScreen = XpScreens[page->context->screenNum];
1405         if(page->context->funcs.EndPage != (int (*)())NULL)
1406             result = page->context->funcs.EndPage(page->context, pWin, TRUE);
1407         SendXpNotify(page->context, XPEndPageNotify, (int)TRUE);
1408         page->context->pageWin = 0; /* None, NULL??? XXX */
1409     }
1410
1411     xfree(page);
1412     return result;
1413 }
1414
1415 /*
1416  * ContextPrivate machinery.
1417  * Context privates are intended for use by the drivers, allowing the
1418  * drivers to maintain context-specific data.  The driver should free
1419  * the associated data at DestroyContext time.
1420  */
1421
1422 static void
1423 InitContextPrivates(context)
1424     XpContextPtr context;
1425 {
1426     register char *ptr;
1427     DevUnion *ppriv;
1428     register unsigned *sizes;
1429     register unsigned size;
1430     register int i;
1431
1432     if (totalContextSize == sizeof(XpContextRec))
1433         ppriv = (DevUnion *)NULL;
1434     else 
1435         ppriv = (DevUnion *)(context + 1);
1436
1437     context->devPrivates = ppriv;
1438     sizes = contextPrivateSizes;
1439     ptr = (char *)(ppriv + contextPrivateLen);
1440     for (i = contextPrivateLen; --i >= 0; ppriv++, sizes++)
1441     {
1442         if ( (size = *sizes) )
1443         {
1444             ppriv->ptr = (pointer)ptr;
1445             ptr += size;
1446         }
1447         else
1448             ppriv->ptr = (pointer)NULL;
1449     }
1450 }
1451
1452 static void
1453 ResetContextPrivates()
1454 {
1455     contextPrivateCount = 0;
1456     contextPrivateLen = 0;
1457     xfree(contextPrivateSizes);
1458     contextPrivateSizes = (unsigned *)NULL;
1459     totalContextSize = sizeof(XpContextRec);
1460
1461 }
1462
1463 int
1464 XpAllocateContextPrivateIndex()
1465 {
1466     return contextPrivateCount++;
1467 }
1468
1469 Bool
1470 XpAllocateContextPrivate(index, amount)
1471     int index;
1472     unsigned amount;
1473 {
1474     unsigned oldamount;
1475
1476     if (index >= contextPrivateLen)
1477     {
1478         unsigned *nsizes;
1479         nsizes = (unsigned *)xrealloc(contextPrivateSizes,
1480                                       (index + 1) * sizeof(unsigned));
1481         if (!nsizes)
1482             return FALSE;
1483         while (contextPrivateLen <= index)
1484         {
1485             nsizes[contextPrivateLen++] = 0;
1486             totalContextSize += sizeof(DevUnion);
1487         }
1488         contextPrivateSizes = nsizes;
1489     }
1490     oldamount = contextPrivateSizes[index];
1491     if (amount > oldamount)
1492     {
1493         contextPrivateSizes[index] = amount;
1494         totalContextSize += (amount - oldamount);
1495     }
1496     return TRUE;
1497 }
1498
1499 static XpClientPtr
1500 AcquireClient(pContext, client)
1501     XpContextPtr pContext;
1502     ClientPtr client;
1503 {
1504     XpClientPtr pXpClient;
1505
1506     if((pXpClient = FindClient(pContext, client)) != (XpClientPtr)NULL)
1507         return pXpClient;
1508
1509     if((pXpClient = CreateXpClient(client)) == (XpClientPtr)NULL)
1510             return (XpClientPtr)NULL;
1511
1512     pXpClient->context = pContext;
1513     pXpClient->pNext = pContext->clientHead;
1514     pContext->clientHead = pXpClient;
1515
1516     return pXpClient;
1517 }
1518
1519 static XpClientPtr
1520 FindClient(pContext, client)
1521     XpContextPtr pContext;
1522     ClientPtr client;
1523 {
1524     XpClientPtr pXpClient;
1525
1526     for(pXpClient = pContext->clientHead; pXpClient != (XpClientPtr)NULL;
1527         pXpClient = pXpClient->pNext)
1528     {
1529         if(pXpClient->client == client)  return pXpClient;
1530     }
1531     return (XpClientPtr)NULL;
1532 }
1533
1534
1535 /******************************************************************************
1536  *
1537  * Start/End Functions: StartJob, EndJob, StartDoc, EndDoc, StartPage, EndPage
1538  *
1539  ******************************************************************************/
1540
1541 static int
1542 ProcXpStartJob(client)
1543     ClientPtr client;
1544 {
1545     REQUEST(xPrintStartJobReq);
1546     XpContextPtr pContext;
1547     int result = Success;
1548     XpScreenPtr pPrintScreen;
1549
1550     REQUEST_SIZE_MATCH(xPrintStartJobReq);
1551
1552     /* Check to see that a context has been established by this client. */
1553     if((pContext = (XpContextPtr)client->devPrivates[XpClientPrivateIndex].ptr)
1554        == (XpContextPtr)NULL)
1555         return XpErrorBase+XPBadContext;
1556
1557     if(pContext->state != 0)
1558         return XpErrorBase+XPBadSequence;
1559
1560     if(stuff->saveData != XPSpool && stuff->saveData != XPGetData)
1561     {
1562         client->errorValue = stuff->saveData;
1563         return BadValue;
1564     }
1565
1566     pPrintScreen = XpScreens[pContext->screenNum];
1567     if(pContext->funcs.StartJob != (int (*)())NULL)
1568         result = pContext->funcs.StartJob(pContext, 
1569                          (stuff->saveData == XPGetData)? TRUE:FALSE);
1570     else
1571         return BadImplementation;
1572
1573     pContext->state = JOB_STARTED;
1574     if(stuff->saveData == XPGetData)
1575         pContext->state |= JOB_GET_DATA;
1576
1577     SendXpNotify(pContext, XPStartJobNotify, FALSE);
1578
1579     if (client->noClientException != Success)
1580         return client->noClientException;
1581     else
1582         return result;
1583 }
1584
1585 static int
1586 ProcXpEndJob(client)
1587     ClientPtr client;
1588 {
1589     REQUEST(xPrintEndJobReq);
1590     XpScreenPtr pPrintScreen;
1591     WindowPtr pWin;
1592     int result = Success;
1593     XpContextPtr pContext;
1594
1595     REQUEST_SIZE_MATCH(xPrintEndJobReq);
1596
1597     if((pContext = (XpContextPtr)client->devPrivates[XpClientPrivateIndex].ptr)
1598        == (XpContextPtr)NULL)
1599         return XpErrorBase+XPBadSequence;
1600
1601     pPrintScreen = XpScreens[pContext->screenNum];
1602
1603     if(!(pContext->state & JOB_STARTED))
1604         return XpErrorBase+XPBadSequence;
1605     
1606     /* Check for missing EndDoc */
1607     if((pContext->state & DOC_RAW_STARTED) || 
1608        (pContext->state & DOC_COOKED_STARTED))
1609     {
1610         if(pContext->state & PAGE_STARTED)
1611         {
1612             WindowPtr pWin = (WindowPtr )LookupIDByType(
1613                                            pContext->pageWin, RT_WINDOW);
1614             XpPagePtr pPage = (XpPagePtr)LookupIDByType(
1615                                        pContext->pageWin, RTpage);
1616
1617             if(stuff->cancel != TRUE)
1618                 return XpErrorBase+XPBadSequence;
1619
1620             if(pContext->funcs.EndPage != (int (*)())NULL)
1621                 result = pContext->funcs.EndPage(pContext, pWin, TRUE);
1622             else
1623                 return BadImplementation;
1624
1625             SendXpNotify(pContext, XPEndPageNotify, TRUE);
1626
1627             pContext->state &= ~PAGE_STARTED;
1628
1629             if(pPage)
1630                 pPage->context = (XpContextPtr)NULL;
1631
1632             if(result != Success) return result;
1633         }
1634
1635         if(pContext->funcs.EndDoc != (int (*)())NULL)
1636             result = pContext->funcs.EndDoc(pContext, stuff->cancel);
1637         else
1638             return BadImplementation;
1639
1640         SendXpNotify(pContext, XPEndDocNotify, stuff->cancel);
1641     }
1642
1643     if(pContext->funcs.EndJob != (int (*)())NULL)
1644         result = pContext->funcs.EndJob(pContext, stuff->cancel);
1645     else
1646         return BadImplementation;
1647
1648     pContext->state = 0;
1649
1650     SendXpNotify(pContext, XPEndJobNotify, stuff->cancel);
1651
1652     if (client->noClientException != Success)
1653         return client->noClientException;
1654     else
1655         return result;
1656 }
1657
1658 static Bool
1659 DoStartDoc(client, c)
1660     ClientPtr client;
1661     XpStDocPtr c;
1662 {
1663     XpScreenPtr pPrintScreen;
1664     int result = Success;
1665     XpContextPtr pContext = c->pContext;
1666
1667     if(c->pContext->state & JOB_GET_DATA && 
1668        !(c->pContext->state & GET_DOC_DATA_STARTED))
1669     {
1670         if(!c->slept)
1671         {
1672             c->slept = TRUE;
1673             ClientSleep(client, (ClientSleepProcPtr)DoStartDoc, (pointer) c);
1674             c->pContext->clientSlept = client;
1675         }
1676         return TRUE;
1677     }
1678     
1679     pPrintScreen = XpScreens[pContext->screenNum];
1680
1681     if(pContext->funcs.StartDoc != (int (*)())NULL)
1682         result = pContext->funcs.StartDoc(pContext, c->type);
1683     else
1684     {
1685             SendErrorToClient(client, XpReqCode, X_PrintStartPage, 0, 
1686                               BadImplementation);
1687             return TRUE;
1688     }
1689
1690     if(c->type == XPDocNormal)
1691         pContext->state |= DOC_COOKED_STARTED;
1692     else
1693         pContext->state |= DOC_RAW_STARTED;
1694
1695     SendXpNotify(pContext, XPStartDocNotify, (int)FALSE);
1696
1697     xfree(c);
1698     return TRUE;
1699 }
1700
1701 static int
1702 ProcXpStartDoc(client)
1703     ClientPtr client;
1704 {
1705     REQUEST(xPrintStartDocReq);
1706     XpScreenPtr pPrintScreen;
1707     int result = Success;
1708     XpContextPtr pContext;
1709     XpStDocPtr c;
1710
1711     REQUEST_SIZE_MATCH(xPrintStartDocReq);
1712
1713     if((pContext = (XpContextPtr)client->devPrivates[XpClientPrivateIndex].ptr)
1714        == (XpContextPtr)NULL)
1715         return XpErrorBase+XPBadSequence;
1716
1717     if(!(pContext->state & JOB_STARTED) || 
1718        pContext->state & DOC_RAW_STARTED ||
1719        pContext->state & DOC_COOKED_STARTED)
1720         return XpErrorBase+XPBadSequence;
1721
1722     if(stuff->type != XPDocNormal && stuff->type != XPDocRaw)
1723     {
1724         client->errorValue = stuff->type;
1725         return BadValue;
1726     }
1727
1728     c = (XpStDocPtr)xalloc(sizeof(XpStDocRec));
1729     c->pContext = pContext;
1730     c->type = stuff->type;
1731     c->slept = FALSE;
1732     (void)DoStartDoc(client, c);
1733
1734     if (client->noClientException != Success)
1735         return client->noClientException;
1736     else
1737         return result;
1738 }
1739
1740 static int
1741 ProcXpEndDoc(client)
1742     ClientPtr client;
1743 {
1744     REQUEST(xPrintEndDocReq);
1745     XpScreenPtr pPrintScreen;
1746     XpContextPtr pContext;
1747     int result = Success;
1748
1749     REQUEST_SIZE_MATCH(xPrintEndDocReq);
1750
1751     if((pContext = (XpContextPtr)client->devPrivates[XpClientPrivateIndex].ptr)
1752        == (XpContextPtr)NULL)
1753         return XpErrorBase+XPBadSequence;
1754
1755     pPrintScreen = XpScreens[pContext->screenNum];
1756
1757     if(!(pContext->state & DOC_RAW_STARTED) &&
1758        !(pContext->state & DOC_COOKED_STARTED))
1759         return XpErrorBase+XPBadSequence;
1760     
1761     if(pContext->state & PAGE_STARTED)
1762     {
1763         if(stuff->cancel == TRUE)
1764         {
1765             WindowPtr pWin = (WindowPtr )LookupIDByType(
1766                                            pContext->pageWin, RT_WINDOW);
1767             XpPagePtr pPage = (XpPagePtr)LookupIDByType(
1768                                        pContext->pageWin, RTpage);
1769
1770             if(pContext->funcs.EndPage != (int (*)())NULL)
1771                 result = pContext->funcs.EndPage(pContext, pWin, TRUE);
1772             else
1773                 return BadImplementation;
1774
1775             SendXpNotify(pContext, XPEndPageNotify, TRUE);
1776
1777             if(pPage)
1778                 pPage->context = (XpContextPtr)NULL;
1779         }
1780         else
1781             return XpErrorBase+XPBadSequence;
1782         if(result != Success)
1783             return result;
1784     }
1785
1786     if(pContext->funcs.EndDoc != (int (*)())NULL)
1787         result = pContext->funcs.EndDoc(pContext, stuff->cancel);
1788     else
1789         return BadImplementation;
1790
1791     pContext->state &= ~DOC_RAW_STARTED;
1792     pContext->state &= ~DOC_COOKED_STARTED;
1793
1794     SendXpNotify(pContext, XPEndDocNotify, stuff->cancel);
1795
1796     if (client->noClientException != Success)
1797         return client->noClientException;
1798     else
1799         return result;
1800 }
1801
1802 static Bool
1803 DoStartPage(client, c)
1804     ClientPtr client;
1805     XpStPagePtr c;
1806 {
1807     XpScreenPtr pPrintScreen;
1808     WindowPtr pWin = c->pWin;
1809     int result = Success;
1810     XpContextPtr pContext = c->pContext;
1811     XpPagePtr pPage;
1812
1813     if(c->pContext->state & JOB_GET_DATA && 
1814        !(c->pContext->state & GET_DOC_DATA_STARTED))
1815     {
1816         if(!c->slept)
1817         {
1818             c->slept = TRUE;
1819             ClientSleep(client, (ClientSleepProcPtr)DoStartPage, (pointer) c);
1820             c->pContext->clientSlept = client;
1821         }
1822         return TRUE;
1823     }
1824
1825     if(!(pContext->state & DOC_COOKED_STARTED))
1826     {
1827         /* Implied StartDoc if it was omitted */
1828         if(pContext->funcs.StartDoc != (int (*)())NULL)
1829             result = pContext->funcs.StartDoc(pContext, XPDocNormal);
1830         else
1831         {
1832             SendErrorToClient(client, XpReqCode, X_PrintStartPage, 0, 
1833                               BadImplementation);
1834             return TRUE;
1835         }
1836
1837         if(result != Success) 
1838         {
1839             SendErrorToClient(client, XpReqCode, X_PrintStartPage, 0, result);
1840             return TRUE;
1841         }
1842
1843         pContext->state |= DOC_COOKED_STARTED;
1844         SendXpNotify(pContext, XPStartDocNotify, (int)FALSE);
1845     }
1846
1847     /* ensure the window's not already being used as a page */
1848     if((pPage = (XpPagePtr)LookupIDByType(c->pWin->drawable.id, RTpage)) != 
1849        (XpPagePtr)NULL)
1850     {
1851         if(pPage->context != (XpContextPtr)NULL)
1852         {
1853             SendErrorToClient(client, XpReqCode, X_PrintStartPage, 0, 
1854                               BadWindow);
1855             return TRUE;
1856         }
1857     }
1858     else
1859     {
1860         if((pPage = (XpPagePtr)xalloc(sizeof(XpPageRec))) == (XpPagePtr)NULL)
1861         {
1862             SendErrorToClient(client, XpReqCode, X_PrintStartPage, 0, 
1863                               BadAlloc);
1864             return TRUE;
1865         }
1866         if(AddResource(c->pWin->drawable.id, RTpage, pPage) == FALSE)
1867         {
1868             xfree(pPage);
1869             SendErrorToClient(client, XpReqCode, X_PrintStartPage, 0, 
1870                               BadAlloc);
1871             return TRUE;
1872         }
1873     }
1874
1875     pPage->context = pContext;
1876     pContext->pageWin = c->pWin->drawable.id;
1877
1878     pPrintScreen = XpScreens[pContext->screenNum];
1879
1880
1881     if(pContext->funcs.StartPage != (int (*)())NULL)
1882         result = pContext->funcs.StartPage(pContext, pWin);
1883     else
1884     {
1885         SendErrorToClient(client, XpReqCode, X_PrintStartPage, 0, 
1886                           BadImplementation);
1887         return TRUE;
1888     }
1889
1890     pContext->state |= PAGE_STARTED;
1891
1892     (void)MapWindow(pWin, client);
1893
1894     SendXpNotify(pContext, XPStartPageNotify, (int)FALSE);
1895
1896     return TRUE;
1897 }
1898
1899 static int
1900 ProcXpStartPage(client)
1901     ClientPtr client;
1902 {
1903     REQUEST(xPrintStartPageReq);
1904     XpScreenPtr pPrintScreen;
1905     WindowPtr pWin;
1906     int result = Success;
1907     XpContextPtr pContext;
1908     XpPagePtr pPage;
1909     XpStPagePtr c;
1910
1911     REQUEST_SIZE_MATCH(xPrintStartPageReq);
1912
1913     if((pContext = (XpContextPtr)client->devPrivates[XpClientPrivateIndex].ptr)
1914        == (XpContextPtr)NULL)
1915         return XpErrorBase+XPBadSequence;
1916
1917     if(!(pContext->state & JOB_STARTED))
1918         return XpErrorBase+XPBadSequence;
1919
1920     /* can't have pages in a raw documented */
1921     if(pContext->state & DOC_RAW_STARTED)
1922         return XpErrorBase+XPBadSequence;
1923     
1924     if(pContext->state & PAGE_STARTED)
1925         return XpErrorBase+XPBadSequence;
1926
1927     pWin = (WindowPtr)SecurityLookupWindow(stuff->window, client,
1928                                            SecurityWriteAccess);
1929     if (!pWin || pWin->drawable.pScreen->myNum != pContext->screenNum)
1930         return BadWindow;
1931
1932     if((c = (XpStPagePtr)xalloc(sizeof(XpStPageRec))) == (XpStPagePtr)NULL)
1933         return BadAlloc;
1934     c->pContext = pContext;
1935     c->slept = FALSE;
1936     c->pWin = pWin;
1937
1938     (void)DoStartPage(client, c);
1939
1940     if (client->noClientException != Success)
1941         return client->noClientException;
1942     else
1943         return result;
1944 }
1945
1946 static int
1947 ProcXpEndPage(client)
1948     ClientPtr client;
1949 {
1950     REQUEST(xPrintEndPageReq);
1951     XpScreenPtr pPrintScreen;
1952     int result = Success;
1953     XpContextPtr pContext;
1954     XpPagePtr page;
1955     WindowPtr pWin;
1956
1957     REQUEST_SIZE_MATCH(xPrintEndPageReq);
1958
1959     if((pContext = (XpContextPtr)client->devPrivates[XpClientPrivateIndex].ptr)
1960        == (XpContextPtr)NULL)
1961         return XpErrorBase+XPBadSequence;
1962
1963     if(!(pContext->state & PAGE_STARTED))
1964         return XpErrorBase+XPBadSequence;
1965
1966     pPrintScreen = XpScreens[pContext->screenNum];
1967     pWin = (WindowPtr )LookupIDByType(pContext->pageWin, RT_WINDOW);
1968
1969     /* Call the ddx's EndPage proc. */
1970     if(pContext->funcs.EndPage != (int (*)())NULL)
1971         result = pContext->funcs.EndPage(pContext, pWin, stuff->cancel);
1972     else
1973         return BadImplementation;
1974
1975     if((page = (XpPagePtr)LookupIDByType(pContext->pageWin, RTpage)) !=
1976        (XpPagePtr)NULL)
1977         page->context = (XpContextPtr)NULL;
1978
1979     pContext->state &= ~PAGE_STARTED;
1980     pContext->pageWin = 0; /* None, NULL??? XXX */
1981
1982     (void)UnmapWindow(pWin, FALSE);
1983
1984     SendXpNotify(pContext, XPEndPageNotify, stuff->cancel);
1985
1986     if (client->noClientException != Success)
1987         return client->noClientException;
1988     else
1989         return result;
1990 }
1991
1992 /*******************************************************************************
1993  *
1994  * Document Data Functions: PutDocumentData, GetDocumentData
1995  *
1996  ******************************************************************************/
1997
1998 static int
1999 ProcXpPutDocumentData(client)
2000     ClientPtr client;
2001 {
2002     REQUEST(xPrintPutDocumentDataReq);
2003     XpContextPtr pContext;
2004     DrawablePtr pDraw;
2005     int result = Success;
2006     int len, totalSize;
2007     char *pData, *pDoc_fmt, *pOptions;
2008
2009     REQUEST_AT_LEAST_SIZE(xPrintPutDocumentDataReq);
2010
2011     if((pContext = (XpContextPtr)client->devPrivates[XpClientPrivateIndex].ptr)
2012        == (XpContextPtr)NULL)
2013         return XpErrorBase+XPBadSequence;
2014
2015     if(!(pContext->state & DOC_RAW_STARTED) &&
2016        !(pContext->state & DOC_COOKED_STARTED))
2017         return XpErrorBase+XPBadSequence;
2018
2019     if (stuff->drawable) {
2020         if (pContext->state & DOC_RAW_STARTED)
2021             return BadDrawable;
2022         pDraw = (DrawablePtr)LookupDrawable(stuff->drawable, client);
2023         if (!pDraw || pDraw->pScreen->myNum != pContext->screenNum)
2024             return BadDrawable;
2025     } else {
2026         if (pContext->state & DOC_COOKED_STARTED)
2027             return BadDrawable;
2028         pDraw = NULL;
2029     }
2030
2031     pData = (char *)(&stuff[1]);
2032
2033     totalSize = (stuff->len_data + 3) >> 2;
2034     pDoc_fmt = pData + (totalSize << 2);
2035
2036     totalSize += (stuff->len_fmt + 3) >> 2;
2037     pOptions = pData + (totalSize << 2);
2038
2039     totalSize += (stuff->len_options + 3) >> 2;
2040     if((totalSize + (sz_xPrintPutDocumentDataReq >> 2)) != client->req_len)
2041          return BadLength;
2042     
2043     if(pContext->funcs.PutDocumentData != (int (*)())NULL)
2044     {
2045         result = (*pContext->funcs.PutDocumentData)(pContext, pDraw,
2046                                           pData, stuff->len_data,
2047                                           pDoc_fmt, stuff->len_fmt,
2048                                           pOptions, stuff->len_options,
2049                                           client);
2050     }
2051     else
2052         return BadImplementation;
2053
2054     if (client->noClientException != Success)
2055         return client->noClientException;
2056     else
2057         return result;
2058 }
2059
2060 static int
2061 ProcXpGetDocumentData(client)
2062     ClientPtr client;
2063 {
2064     REQUEST(xPrintGetDocumentDataReq);
2065     xPrintGetDocumentDataReply rep;
2066     XpScreenPtr pPrintScreen;
2067     XpContextPtr pContext;
2068     int result = Success;
2069
2070     REQUEST_SIZE_MATCH(xPrintGetDocumentDataReq);
2071
2072     if((pContext = (XpContextPtr)SecurityLookupIDByType(client,
2073                                                         stuff->printContext, 
2074                                                         RTcontext,
2075                                                         SecurityWriteAccess))
2076        == (XpContextPtr)NULL)
2077     {
2078         client->errorValue = stuff->printContext;
2079         return XpErrorBase+XPBadContext;
2080     }
2081
2082     if(pContext->funcs.GetDocumentData == (int (*)())NULL)
2083         return BadImplementation;
2084
2085     if(!(pContext->state & JOB_GET_DATA) || 
2086        pContext->state & GET_DOC_DATA_STARTED)
2087         return XpErrorBase+XPBadSequence;
2088
2089     if(stuff->maxBufferSize <= 0)
2090     {
2091         client->errorValue = stuff->maxBufferSize;
2092         return BadValue; /* gotta have a positive buffer size */
2093     }
2094
2095     result = (*pContext->funcs.GetDocumentData)(pContext, client, 
2096                                                 stuff->maxBufferSize);
2097     if(result != Success)
2098     {
2099         rep.type = X_Reply;
2100         rep.sequenceNumber = client->sequence;
2101         rep.length = 0;
2102         rep.dataLen = 0;
2103         rep.statusCode = 1;
2104         rep.finishedFlag = TRUE;
2105         if (client->swapped) {
2106             int n;
2107             long l;
2108
2109             swaps(&rep.sequenceNumber, n);
2110             swapl(&rep.statusCode, l); /* XXX Why are these longs??? */
2111             swapl(&rep.finishedFlag, l); /* XXX Why are these longs??? */
2112         }
2113         (void)WriteToClient(client,sz_xPrintGetDocumentDataReply,(char *)&rep);
2114     }
2115     else
2116         pContext->state |= GET_DOC_DATA_STARTED;
2117
2118     if(pContext->clientSlept != (ClientPtr)NULL)
2119     {
2120         ClientSignal(pContext->clientSlept);
2121         ClientWakeup(pContext->clientSlept);
2122         pContext->clientSlept = (ClientPtr)NULL;
2123     }
2124
2125     return result;
2126 }
2127
2128 /*******************************************************************************
2129  *
2130  * Attribute requests: GetAttributes, SetAttributes, GetOneAttribute
2131  *
2132  ******************************************************************************/
2133
2134 static int 
2135 ProcXpGetAttributes(client)
2136     ClientPtr client;
2137 {
2138     REQUEST(xPrintGetAttributesReq);
2139     XpContextPtr pContext;
2140     char *attrs;
2141     xPrintGetAttributesReply *pRep;
2142     int totalSize, n;
2143     unsigned long l;
2144
2145     REQUEST_SIZE_MATCH(xPrintGetAttributesReq);
2146
2147     if(stuff->type < XPJobAttr || stuff->type > XPServerAttr)
2148     {
2149         client->errorValue = stuff->type;
2150         return BadValue;
2151     }
2152
2153     if(stuff->type != XPServerAttr)
2154     {
2155         if((pContext = (XpContextPtr)SecurityLookupIDByType(
2156                                                 client,
2157                                                 stuff->printContext,
2158                                                 RTcontext,
2159                                                 SecurityReadAccess))
2160            == (XpContextPtr)NULL)
2161         {
2162             client->errorValue = stuff->printContext;
2163             return XpErrorBase+XPBadContext;
2164         }
2165
2166         if(pContext->funcs.GetAttributes == (char *(*)())NULL)
2167             return BadImplementation;
2168         if((attrs = (*pContext->funcs.GetAttributes)(pContext, stuff->type)) == 
2169            (char *)NULL) 
2170             return BadAlloc;
2171     }
2172     else
2173     {
2174         if((attrs = XpGetAttributes((XpContextPtr)NULL, XPServerAttr)) ==
2175            (char *)NULL)
2176             return BadAlloc;
2177     }
2178
2179     totalSize = sz_xPrintGetAttributesReply + QUADPAD(strlen(attrs));
2180     if((pRep = (xPrintGetAttributesReply *)malloc(totalSize)) ==
2181        (xPrintGetAttributesReply *)NULL)
2182         return BadAlloc;
2183
2184     pRep->type = X_Reply;
2185     pRep->length = (totalSize - sz_xPrintGetAttributesReply) >> 2;
2186     pRep->sequenceNumber = client->sequence;
2187     pRep->stringLen = strlen(attrs);
2188
2189     if (client->swapped) {
2190         swaps(&pRep->sequenceNumber, n);
2191         swapl(&pRep->length, l);
2192         swapl(&pRep->stringLen, l);
2193     }
2194
2195     strncpy((char*)(pRep + 1), attrs, strlen(attrs));
2196     xfree(attrs);
2197
2198     WriteToClient(client, totalSize, (char *)pRep);
2199
2200     xfree(pRep);
2201
2202     return client->noClientException;
2203 }
2204
2205 static int 
2206 ProcXpSetAttributes(client)
2207     ClientPtr client;
2208 {
2209     REQUEST(xPrintSetAttributesReq);
2210     int result = Success;
2211     XpContextPtr pContext;
2212     char *attr;
2213
2214     REQUEST_AT_LEAST_SIZE(xPrintSetAttributesReq);
2215
2216     if(stuff->type < XPJobAttr || stuff->type > XPServerAttr)
2217     {
2218         client->errorValue = stuff->type;
2219         return BadValue;
2220     }
2221
2222     /*
2223      * Disallow changing of read-only attribute pools
2224      */
2225     if(stuff->type == XPPrinterAttr || stuff->type == XPServerAttr)
2226         return BadMatch;
2227
2228     if((pContext = (XpContextPtr)SecurityLookupIDByType(
2229                                         client,
2230                                         stuff->printContext,
2231                                         RTcontext,
2232                                         SecurityWriteAccess))
2233        == (XpContextPtr)NULL)
2234     {
2235         client->errorValue = stuff->printContext;
2236         return XpErrorBase+XPBadContext;
2237     }
2238
2239     if(pContext->funcs.SetAttributes == (int (*)())NULL)
2240         return BadImplementation;
2241     
2242     /* 
2243      * Check for attributes being set after their relevant phase
2244      * has already begun (e.g. Job attributes set after StartJob).
2245      */
2246     if((pContext->state & JOB_STARTED) && stuff->type == XPJobAttr)
2247         return XpErrorBase+XPBadSequence;
2248     if(((pContext->state & DOC_RAW_STARTED) || 
2249        (pContext->state & DOC_COOKED_STARTED)) && stuff->type == XPDocAttr)
2250         return XpErrorBase+XPBadSequence;
2251     if((pContext->state & PAGE_STARTED) && stuff->type == XPPageAttr)
2252         return XpErrorBase+XPBadSequence;
2253
2254     if((attr = (char *)malloc(stuff->stringLen + 1)) == (char *)NULL)
2255         return BadAlloc;
2256
2257     strncpy(attr, (char *)(stuff + 1), stuff->stringLen);
2258     attr[stuff->stringLen] = (char)'\0';
2259
2260     if(stuff->rule == XPAttrReplace)
2261         (*pContext->funcs.SetAttributes)(pContext, stuff->type, attr);
2262     else if(stuff->rule == XPAttrMerge)
2263         (*pContext->funcs.AugmentAttributes)(pContext, stuff->type, attr);
2264     else
2265     {
2266         client->errorValue = stuff->rule;
2267         result = BadValue;
2268     }
2269
2270     xfree(attr);
2271
2272     SendAttributeNotify(pContext, stuff->type);
2273
2274     return result;
2275 }
2276
2277 static int 
2278 ProcXpGetOneAttribute(client)
2279     ClientPtr client;
2280 {
2281     REQUEST(xPrintGetOneAttributeReq);
2282     XpContextPtr pContext;
2283     char *value, *attrName;
2284     xPrintGetOneAttributeReply *pRep;
2285     int totalSize, n;
2286     unsigned long l;
2287
2288     REQUEST_AT_LEAST_SIZE(xPrintGetOneAttributeReq);
2289
2290     totalSize = ((sz_xPrintGetOneAttributeReq) >> 2) +
2291                 ((stuff->nameLen + 3) >> 2);
2292     if(totalSize != client->req_len)
2293          return BadLength;
2294
2295     if(stuff->type < XPJobAttr || stuff->type > XPServerAttr)
2296     {
2297         client->errorValue = stuff->type;
2298         return BadValue;
2299     }
2300     
2301     if((attrName = (char *)malloc(stuff->nameLen + 1)) == (char *)NULL)
2302         return BadAlloc;
2303     strncpy(attrName, (char *)(stuff+1), stuff->nameLen);
2304     attrName[stuff->nameLen] = (char)'\0';
2305
2306     if(stuff->type != XPServerAttr)
2307     {
2308         if((pContext = (XpContextPtr)SecurityLookupIDByType(
2309                                                 client,
2310                                                 stuff->printContext, 
2311                                                 RTcontext,
2312                                                 SecurityReadAccess))
2313            == (XpContextPtr)NULL)
2314         {
2315             client->errorValue = stuff->printContext;
2316             return XpErrorBase+XPBadContext;
2317         }
2318
2319         if(pContext->funcs.GetOneAttribute == (char *(*)())NULL)
2320             return BadImplementation;
2321         if((value = (*pContext->funcs.GetOneAttribute)(pContext, stuff->type,
2322            attrName)) == (char *)NULL) 
2323             return BadAlloc;
2324     }
2325     else
2326     {
2327         if((value = XpGetOneAttribute((XpContextPtr)NULL, XPServerAttr,
2328             attrName)) == (char *)NULL)
2329             return BadAlloc;
2330     }
2331
2332     free(attrName);
2333
2334     totalSize = sz_xPrintGetOneAttributeReply + QUADPAD(strlen(value));
2335     if((pRep = (xPrintGetOneAttributeReply *)malloc(totalSize)) ==
2336        (xPrintGetOneAttributeReply *)NULL)
2337         return BadAlloc;
2338
2339     pRep->type = X_Reply;
2340     pRep->length = (totalSize - sz_xPrintGetOneAttributeReply) >> 2;
2341     pRep->sequenceNumber = client->sequence;
2342     pRep->valueLen = strlen(value);
2343
2344     if (client->swapped) {
2345         swaps(&pRep->sequenceNumber, n);
2346         swapl(&pRep->length, l);
2347         swapl(&pRep->valueLen, l);
2348     }
2349
2350     strncpy((char*)(pRep + 1), value, strlen(value));
2351
2352     WriteToClient(client, totalSize, (char *)pRep);
2353
2354     xfree(pRep);
2355
2356     return client->noClientException;
2357 }
2358
2359 /*******************************************************************************
2360  *
2361  * Print Event requests: SelectInput InputSelected, SendXpNotify
2362  *
2363  ******************************************************************************/
2364
2365
2366 static int
2367 ProcXpSelectInput(client)
2368     ClientPtr client;
2369 {
2370     REQUEST(xPrintSelectInputReq);
2371     int result = Success;
2372     XpContextPtr pContext;
2373     XpClientPtr pPrintClient;
2374
2375     REQUEST_SIZE_MATCH(xPrintSelectInputReq);
2376
2377     /*
2378      * Check to see that the supplied XID is really a valid print context
2379      * in this server.
2380      */
2381     if((pContext=(XpContextPtr)SecurityLookupIDByType(client,
2382                                                       stuff->printContext,
2383                                                       RTcontext,
2384                                                       SecurityWriteAccess))
2385        == (XpContextPtr)NULL)
2386     {
2387         client->errorValue = stuff->printContext;
2388         return XpErrorBase+XPBadContext;
2389     }
2390
2391     if(stuff->eventMask & ~allEvents)
2392     {
2393         client->errorValue = stuff->eventMask;
2394         return BadValue; /* bogus event mask bits */
2395     }
2396
2397     if((pPrintClient = AcquireClient(pContext, client)) == (XpClientPtr)NULL)
2398         return BadAlloc;
2399
2400     pPrintClient->eventMask = stuff->eventMask;
2401
2402     return result;
2403 }
2404
2405 static int
2406 ProcXpInputSelected(client)
2407     ClientPtr client;
2408 {
2409     REQUEST(xPrintInputSelectedReq);
2410     xPrintInputSelectedReply rep;
2411     register int n;
2412     long l, allMask;
2413     WindowPtr pWin;
2414     XpClientPtr pXpClient;
2415     XpContextPtr pContext;
2416
2417     REQUEST_SIZE_MATCH(xPrintInputSelectedReq);
2418
2419     if((pContext=(XpContextPtr)SecurityLookupIDByType(client,
2420                                                       stuff->printContext,
2421                                                       RTcontext,
2422                                                       SecurityReadAccess))
2423        == (XpContextPtr)NULL)
2424     {
2425         client->errorValue = stuff->printContext;
2426         return XpErrorBase+XPBadContext;
2427     }
2428
2429     pXpClient = FindClient(pContext, client);
2430
2431     rep.type = X_Reply;
2432     rep.length = 0;
2433     rep.sequenceNumber = client->sequence;
2434     rep.eventMask = (pXpClient != (XpClientPtr)NULL)? pXpClient->eventMask : 0;
2435     rep.allEventsMask = GetAllEventMasks(pContext);
2436
2437     if (client->swapped) {
2438         swaps(&rep.sequenceNumber, n);
2439         swapl(&rep.length, l);
2440         swapl(&rep.eventMask, l);
2441         swapl(&rep.allEventsMask, l);
2442     }
2443
2444     WriteToClient(client, sz_xPrintInputSelectedReply, (char *)&rep);
2445     return client->noClientException;
2446 }
2447
2448 static void
2449 SendAttributeNotify(pContext, which)
2450     XpContextPtr pContext;
2451     int which;
2452 {
2453     XpClientPtr        pXpClient;
2454     xPrintAttributeEvent   ae;
2455     ClientPtr   client;
2456
2457     pXpClient = pContext->clientHead;
2458     if(pXpClient == (XpClientPtr)NULL) 
2459         return; /* Nobody's interested in the events (or this context). */
2460
2461     for (pXpClient = pContext->clientHead; 
2462          pXpClient != (XpClientPtr)NULL; 
2463          pXpClient = pXpClient->pNext)
2464     {
2465         client = pXpClient->client;
2466         if (client == serverClient || client->clientGone || 
2467             !(pXpClient->eventMask & XPAttributeMask))
2468             continue;
2469         ae.type = XPAttributeNotify + XpEventBase;
2470         ae.detail = which;
2471         ae.printContext = pContext->contextID;
2472         ae.sequenceNumber = client->sequence;
2473         WriteEventsToClient (client, 1, (xEvent *) &ae);
2474     }
2475 }
2476 static void
2477 SendXpNotify(pContext, which, val)
2478     XpContextPtr pContext;
2479     int which;
2480     int val;
2481 {
2482     XpClientPtr        pXpClient;
2483     xPrintPrintEvent   pe;
2484     ClientPtr   client;
2485
2486     pXpClient = pContext->clientHead;
2487     if(pXpClient == (XpClientPtr)NULL) 
2488         return; /* Nobody's interested in the events (or this context). */
2489
2490     for (pXpClient = pContext->clientHead; 
2491          pXpClient != (XpClientPtr)NULL; 
2492          pXpClient = pXpClient->pNext)
2493     {
2494         client = pXpClient->client;
2495         if (client == serverClient || client->clientGone || 
2496             !(pXpClient->eventMask & XPPrintMask))
2497             continue;
2498         pe.type = XPPrintNotify + XpEventBase;
2499         pe.detail = which;
2500         pe.printContext = pContext->contextID;
2501         pe.cancel = (Bool)val;
2502         pe.sequenceNumber = client->sequence;
2503         WriteEventsToClient (client, 1, (xEvent *) &pe);
2504     }
2505 }
2506
2507 static CARD32
2508 GetAllEventMasks(pContext)
2509     XpContextPtr pContext;
2510 {
2511     XpClientPtr pPrintClient;
2512     CARD32 totalMask = (CARD32)0;
2513     
2514     for (pPrintClient = pContext->clientHead;
2515          pPrintClient != (XpClientPtr)NULL;
2516          pPrintClient = pPrintClient->pNext)
2517     {
2518         totalMask |= pPrintClient->eventMask;
2519     }
2520     return totalMask;
2521 }
2522
2523 /*
2524  * XpContextOfClient - returns the XpContextPtr to the context
2525  * associated with the specified client, or NULL if the client
2526  * does not currently have a context set.
2527  */
2528 XpContextPtr
2529 XpContextOfClient(client)
2530     ClientPtr client;
2531 {
2532     XpContextPtr pContext;
2533
2534     return (XpContextPtr)client->devPrivates[XpClientPrivateIndex].ptr;
2535 }
2536
2537
2538 /*******************************************************************************
2539  *
2540  * Swap-request functions
2541  *
2542  ******************************************************************************/
2543
2544 static int
2545 SProcXpCreateContext(client)
2546     ClientPtr client;
2547 {
2548     int i;
2549     long n;
2550
2551     REQUEST(xPrintCreateContextReq);
2552
2553     swaps(&stuff->length, i);
2554     swapl(&stuff->contextID, n);
2555     swapl(&stuff->printerNameLen, n);
2556     swapl(&stuff->localeLen, n);
2557     return ProcXpCreateContext(client);
2558 }
2559
2560 static int
2561 SProcXpGetPrinterList(client)
2562     ClientPtr client;
2563 {
2564     int i;
2565     long n;
2566
2567     REQUEST(xPrintGetPrinterListReq);
2568
2569     swaps(&stuff->length, i);
2570     swapl(&stuff->printerNameLen, n);
2571     swapl(&stuff->localeLen, n);
2572     return ProcXpGetPrinterList(client);
2573 }
2574
2575 static int
2576 SProcXpRehashPrinterList(client)
2577     ClientPtr client;
2578 {
2579     int i;
2580     long n;
2581
2582     REQUEST(xPrintRehashPrinterListReq);
2583     swaps(&stuff->length, i);
2584     return ProcXpRehashPrinterList(client);
2585 }
2586
2587 static int
2588 SProcXpSetContext(client)
2589     ClientPtr client;
2590 {
2591     int i;
2592     long n;
2593
2594     REQUEST(xPrintSetContextReq);
2595     swaps(&stuff->length, i);
2596     swapl(&stuff->printContext, i);
2597     return ProcXpSetContext(client);
2598 }
2599
2600 static int
2601 SProcXpGetContext(client)
2602     ClientPtr client;
2603 {
2604     int i;
2605
2606     REQUEST(xPrintGetContextReq);
2607     swaps(&stuff->length, i);
2608     return ProcXpGetContext(client);
2609 }
2610
2611 static int
2612 SProcXpDestroyContext(client)
2613     ClientPtr client;
2614 {
2615     int i;
2616     long n;
2617
2618     REQUEST(xPrintDestroyContextReq);
2619     swaps(&stuff->length, i);
2620     swapl(&stuff->printContext, n);
2621     return ProcXpDestroyContext(client);
2622 }
2623
2624 static int
2625 SProcXpGetContextScreen(client)
2626     ClientPtr client;
2627 {
2628     int i;
2629     long n;
2630
2631     REQUEST(xPrintGetContextScreenReq);
2632     swaps(&stuff->length, i);
2633     swapl(&stuff->printContext, n);
2634     return ProcXpGetContextScreen(client);
2635 }
2636
2637 static int
2638 SProcXpInputSelected(client)
2639     ClientPtr client;
2640 {
2641     int i;
2642     long n;
2643
2644     REQUEST(xPrintInputSelectedReq);
2645     swaps(&stuff->length, i);
2646     swapl(&stuff->printContext, n);
2647     return ProcXpInputSelected(client);
2648 }
2649
2650 static int
2651 SProcXpStartJob(client)
2652     ClientPtr client;
2653 {
2654     int i;
2655
2656     REQUEST(xPrintStartJobReq);
2657     swaps(&stuff->length, i);
2658     return ProcXpStartJob(client);
2659 }
2660
2661 static int
2662 SProcXpEndJob(client)
2663     ClientPtr client;
2664 {
2665     int i;
2666
2667     REQUEST(xPrintEndJobReq);
2668     swaps(&stuff->length, i);
2669     return ProcXpEndJob(client);
2670 }
2671
2672 static int
2673 SProcXpStartDoc(client)
2674     ClientPtr client;
2675 {
2676     int i;
2677
2678     REQUEST(xPrintStartDocReq);
2679     swaps(&stuff->length, i);
2680     return ProcXpStartDoc(client);
2681 }
2682
2683 static int
2684 SProcXpEndDoc(client)
2685     ClientPtr client;
2686 {
2687     int i;
2688
2689     REQUEST(xPrintEndDocReq);
2690     swaps(&stuff->length, i);
2691     return ProcXpEndDoc(client);
2692 }
2693
2694 static int
2695 SProcXpStartPage(client)
2696     ClientPtr client;
2697 {
2698     int i;
2699     long n;
2700
2701     REQUEST(xPrintStartPageReq);
2702     swaps(&stuff->length, i);
2703     swapl(&stuff->window, n);
2704     return ProcXpStartPage(client);
2705 }
2706
2707 static int
2708 SProcXpEndPage(client)
2709     ClientPtr client;
2710 {
2711     int i;
2712
2713     REQUEST(xPrintEndPageReq);
2714     swaps(&stuff->length, i);
2715     return ProcXpEndPage(client);
2716 }
2717
2718 static int
2719 SProcXpPutDocumentData(client)
2720     ClientPtr client;
2721 {
2722     long n;
2723     int i;
2724
2725     REQUEST(xPrintPutDocumentDataReq);
2726     swaps(&stuff->length, i);
2727     swapl(&stuff->drawable, n);
2728     swapl(&stuff->len_data, n);
2729     swaps(&stuff->len_fmt, i);
2730     swaps(&stuff->len_options, i);
2731     return ProcXpPutDocumentData(client);
2732 }
2733
2734 static int
2735 SProcXpGetDocumentData(client)
2736     ClientPtr client;
2737 {
2738     long n;
2739     int i;
2740
2741     REQUEST(xPrintGetDocumentDataReq);
2742     swaps(&stuff->length, i);
2743     swapl(&stuff->printContext, n);
2744     swapl(&stuff->maxBufferSize, n);
2745     return ProcXpGetDocumentData(client);
2746 }
2747
2748 static int
2749 SProcXpGetAttributes(client)
2750     ClientPtr client;
2751 {
2752     long n;
2753     int i;
2754
2755     REQUEST(xPrintGetAttributesReq);
2756     swaps(&stuff->length, i);
2757     swapl(&stuff->printContext, n);
2758     return ProcXpGetAttributes(client);
2759 }
2760
2761 static int
2762 SProcXpSetAttributes(client)
2763     ClientPtr client;
2764 {
2765     long n;
2766     int i;
2767
2768     REQUEST(xPrintSetAttributesReq);
2769     swaps(&stuff->length, i);
2770     swapl(&stuff->printContext, n);
2771     swapl(&stuff->stringLen, n);
2772     return ProcXpSetAttributes(client);
2773 }
2774
2775 static int
2776 SProcXpGetOneAttribute(client)
2777     ClientPtr client;
2778 {
2779     long n;
2780     int i;
2781
2782     REQUEST(xPrintGetOneAttributeReq);
2783     swaps(&stuff->length, i);
2784     swapl(&stuff->printContext, n);
2785     swapl(&stuff->nameLen, n);
2786     return ProcXpGetOneAttribute(client);
2787 }
2788
2789 static int
2790 SProcXpSelectInput(client)
2791     ClientPtr client;
2792 {
2793     long n;
2794     int i;
2795
2796     REQUEST(xPrintSelectInputReq);
2797     swaps(&stuff->length, i);
2798     swapl(&stuff->eventMask, n);
2799     swapl(&stuff->printContext, n);
2800     return ProcXpSelectInput(client);
2801 }
2802 static int 
2803 SProcXpGetPageDimensions(client)
2804     ClientPtr client;
2805 {
2806     long n;
2807     int i;
2808
2809     REQUEST(xPrintGetPageDimensionsReq);
2810     swaps(&stuff->length, i);
2811     swapl(&stuff->printContext, n);
2812     return ProcXpGetPageDimensions(client);
2813 }
2814 static int 
2815 SProcXpSetImageResolution(client)
2816     ClientPtr client;
2817 {
2818     long n;
2819     int i;
2820
2821     REQUEST(xPrintSetImageResolutionReq);
2822     swaps(&stuff->length, i);
2823     swapl(&stuff->printContext, n);
2824     swaps(&stuff->imageRes, i);
2825     return ProcXpSetImageResolution(client);
2826 }
2827 static int 
2828 SProcXpGetImageResolution(client)
2829     ClientPtr client;
2830 {
2831     long n;
2832     int i;
2833
2834     REQUEST(xPrintGetImageResolutionReq);
2835     swaps(&stuff->length, i);
2836     swapl(&stuff->printContext, n);
2837     return ProcXpGetImageResolution(client);
2838 }
2839
2840 static void
2841 SwapXpNotifyEvent(src, dst)
2842     xPrintPrintEvent *src, *dst;
2843 {
2844     /*
2845      * Swap the sequence number and context fields.
2846      */
2847     cpswaps(src->sequenceNumber, dst->sequenceNumber);
2848     cpswapl(src->printContext, dst->printContext);
2849
2850     /*
2851      * Copy the byte-long fields.
2852      */
2853     dst->type = src->type;
2854     dst->detail = src->detail;
2855     dst->cancel = src->cancel;
2856 }
2857
2858 static void
2859 SwapXpAttributeEvent(src, dst)
2860     xPrintAttributeEvent *src, *dst;
2861 {
2862     /*
2863      * Swap the sequence number and context fields.
2864      */
2865     cpswaps(src->sequenceNumber, dst->sequenceNumber);
2866     cpswapl(src->printContext, dst->printContext);
2867
2868     /*
2869      * Copy the byte-long fields.
2870      */
2871     dst->type = src->type;
2872     dst->detail = src->detail;
2873 }