First import
[xorg_rtime.git] / xorg-server-1.4 / hw / xprint / attributes.c
blobd8ee5adf882e2bbe3b7a1937213d5dc49169364a
1 /*
2 (c) Copyright 1996 Hewlett-Packard Company
3 (c) Copyright 1996 International Business Machines Corp.
4 (c) Copyright 1996 Sun Microsystems, Inc.
5 (c) Copyright 1996 Novell, Inc.
6 (c) Copyright 1996 Digital Equipment Corp.
7 (c) Copyright 1996 Fujitsu Limited
8 (c) Copyright 1996 Hitachi, Ltd.
10 Permission is hereby granted, free of charge, to any person obtaining a copy
11 of this software and associated documentation files (the "Software"), to deal
12 in the Software without restriction, including without limitation the rights
13 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
14 copies of the Software, and to permit persons to whom the Software is
15 furnished to do so, subject to the following conditions:
17 The above copyright notice and this permission notice shall be included in
18 all copies or substantial portions of the Software.
20 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
21 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
23 COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
24 IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
25 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
27 Except as contained in this notice, the names of the copyright holders shall
28 not be used in advertising or otherwise to promote the sale, use or other
29 dealings in this Software without prior written authorization from said
30 copyright holders.
32 /*******************************************************************
34 ** *********************************************************
35 ** *
36 ** * File: attributes.c
37 ** *
38 ** * Contents:
39 ** * Implementation of the attribute store for Xp.
40 ** *
41 ** * Copyright: Copyright 1995 Hewlett-Packard Company
42 ** *
43 ** *********************************************************
44 **
45 ********************************************************************/
47 #ifdef HAVE_DIX_CONFIG_H
48 #include <dix-config.h>
49 #endif
51 #include <X11/Xproto.h>
52 #include <stdio.h>
53 #include <ctype.h>
54 #include <string.h>
55 #include <stdlib.h>
56 #include <sys/wait.h>
57 #include <pwd.h>
58 #include <grp.h>
59 #include <sys/types.h>
60 #include <sys/stat.h>
61 #include <unistd.h>
63 #if (defined(sun) && defined(SVR4)) || defined(__SCO__) || defined(__UNIXWARE__)
64 #include <wchar.h>
65 #endif
66 #include "scrnintstr.h"
68 #include <X11/extensions/Printstr.h>
70 #include "attributes.h"
72 #include <X11/Xlib.h>
73 #include <X11/Xresource.h>
75 #include "spooler.h"
77 #ifndef MIN
78 #define MIN(a,b) (((a)<(b))?(a):(b))
79 #endif
80 #ifndef MAX
81 #define MAX(a,b) (((a)>(b))?(a):(b))
82 #endif
85 static XrmDatabase CopyDb(XrmDatabase inDb);
87 extern XrmDatabase XpSpoolerGetServerAttributes(void);
89 static int attrGeneration = 0;
91 typedef struct {
92 XrmDatabase *pDb;
93 char *qualifier;
94 char *modelId;
95 } DbEnumStruct;
97 typedef struct {
98 char *stringDb;
99 int nextPos;
100 int space;
101 } StringDbStruct;
103 typedef struct _printerAttrs {
104 struct _printerAttrs *next;
105 char *name;
106 char *qualifier;
107 XrmDatabase printerAttrs;
108 XrmDatabase docAttrs;
109 XrmDatabase jobAttrs;
110 } PrAttrs, *PrAttrPtr;
112 static PrAttrPtr attrList = (PrAttrPtr)NULL;
114 typedef struct _systemAttrs {
115 XrmDatabase doc;
116 XrmDatabase job;
117 XrmDatabase printers;
118 XrmDatabase server;
119 } SysAttrs, *SysAttrsPtr;
121 SysAttrs systemAttributes;
124 * attrCtxtPrivIndex hold the attribute store's context private index.
125 * This index is allocated at the time the attribute store is initialized.
127 static int attrCtxtPrivIndex;
130 * The ContextAttrs structure descibes the context private space reserved
131 * by the attribute store.
133 typedef struct _contextAttrs {
134 XrmDatabase printerAttrs;
135 XrmDatabase docAttrs;
136 XrmDatabase jobAttrs;
137 XrmDatabase pageAttrs;
138 } ContextAttrs, *ContextAttrPtr;
141 * XPDIR is relative to (i.e. is a subdir of) XPRINTDIR/$LANG.
143 static const char XPDIR[] = "/print";
145 * The following files/directories define or are within subdirectories of the
146 * above-defined XPDIR.
148 static const char XPPRINTERATTRFILE[] = "/attributes/printer";
149 static const char XPJOBATTRFILE[] = "/attributes/job";
150 static const char XPDOCATTRFILE[] = "/attributes/document";
151 static const char XPMODELDIR[] = "/models";
153 static char NULL_STRING[] = "\0";
156 * XpGetConfigDirBase returns a string containing the path name of the base
157 * where the print server configuration directory is localed.
159 static
160 char *XpGetConfigDirBase(void)
162 char *configDir;
165 * If the XPCONFIGDIR environment variable is not set, then use the
166 * compile-time constant XPRINTDIR. XPRINTDIR is passed in on the
167 * compile command line, and is defined in $(TOP)/config/cf/Project.tmpl.
169 if((configDir = getenv("XPCONFIGDIR")) == (char *)NULL)
170 configDir = XPRINTDIR;
172 return configDir;
176 * XpGetConfigDir returns a string containing the path name of the print
177 * server configuration directory. If the useLocale parameter is False
178 * the it returns the path to the "/C" directory. If the useLocale
179 * parameter is True it returns the path to the directory associated with
180 * $LANG. It makes no attempt to ensure that the directory actually exists.
182 char *
183 XpGetConfigDir(Bool useLocale)
185 char *dirName, *langName, *langDir, *configDir;
186 Bool freeLangDir = False;
188 if(useLocale == False) langDir = "/C";
189 else
191 langName = getenv("LC_ALL");
192 if (langName == NULL) {
193 langName = getenv("LANG");
196 if(langName == (char *)NULL)
197 return (char *)NULL;
198 else
200 if(strcmp(langName, "C") == 0)
201 return (char *)NULL;
202 langDir = (char *)xalloc(strlen(langName) + 2);
203 sprintf(langDir, "/%s", langName);
204 freeLangDir = True;
208 configDir = XpGetConfigDirBase();
210 dirName = (char *)xalloc(strlen(configDir) + strlen(XPDIR) +
211 strlen(langDir) + 1);
212 sprintf(dirName, "%s%s%s", configDir, langDir, XPDIR);
214 if(freeLangDir == True)
215 xfree(langDir);
217 return dirName;
221 * GetMergedDatabase reads and merges xrmdb files from the top-level printer
222 * config directory, and from the directory associated with the current
223 * locale (if other than the top-level).
225 static XrmDatabase
226 GetMergedDatabase(const char *attrName)
228 char *dirName, *fileName;
229 XrmDatabase db;
231 if((dirName = XpGetConfigDir(False)) == (char *)NULL)
232 return (XrmDatabase)NULL;
233 if((fileName = (char *)xalloc(strlen(dirName) + strlen(attrName) + 1)) ==
234 (char *)NULL)
235 return (XrmDatabase)NULL;
236 sprintf(fileName, "%s%s", dirName, attrName);
237 db = XrmGetFileDatabase(fileName);
238 xfree(fileName);
239 xfree(dirName);
241 if((dirName = XpGetConfigDir(True)) == (char *)NULL)
242 return db;
243 if((fileName = (char *)xalloc(strlen(dirName) + strlen(attrName) + 1)) ==
244 (char *)NULL)
245 return db;
246 sprintf(fileName, "%s%s", dirName, attrName);
247 (void)XrmCombineFileDatabase(fileName, &db, True);
248 xfree(fileName);
249 xfree(dirName);
251 return db;
255 * BuildSystemAttributes reads the on-disk configuration files for printers,
256 * initial job, and initial document attributes. The resulting xrm
257 * databases are then dissected as needed for each printer.
258 * It also allocates a contextPrivate space for the attributes,
259 * reserving space to store pointers to the attribute stores for
260 * the context.
262 static void
263 BuildSystemAttributes(void)
265 if(systemAttributes.printers != (XrmDatabase)NULL)
266 XrmDestroyDatabase(systemAttributes.printers);
267 systemAttributes.printers = GetMergedDatabase(XPPRINTERATTRFILE);
268 if(systemAttributes.job != (XrmDatabase)NULL)
269 XrmDestroyDatabase(systemAttributes.job);
270 systemAttributes.job = GetMergedDatabase(XPJOBATTRFILE);
271 if(systemAttributes.doc != (XrmDatabase)NULL)
272 XrmDestroyDatabase(systemAttributes.doc);
273 systemAttributes.doc = GetMergedDatabase(XPDOCATTRFILE);
274 if(systemAttributes.server != (XrmDatabase)NULL)
275 XrmDestroyDatabase(systemAttributes.server);
276 systemAttributes.server = XpSpoolerGetServerAttributes();
277 return;
281 * AddDbEntry is called by XrmEnumerateDatabase, and adds the supplied
282 * database entry to the database pointed to within the "DbEnumStruct"
283 * passed as the client_data (aka "closure").
285 static Bool
286 AddDbEntry(
287 XrmDatabase *sourceDB,
288 XrmBindingList bindings,
289 XrmQuarkList quarks,
290 XrmRepresentation *type,
291 XrmValue *value,
292 XPointer client_data)
294 DbEnumStruct *pEnumStruct = (DbEnumStruct *)client_data;
295 XrmName xrm_name[5];
296 XrmClass xrm_class[5];
297 XrmBinding xrm_bind[3];
298 XrmValue realVal;
299 XrmRepresentation rep_type;
301 xrm_name[0] = XrmStringToQuark (pEnumStruct->qualifier);
302 xrm_class[0] = XrmStringToQuark (pEnumStruct->modelId);
304 for(;*quarks; quarks++)
305 xrm_name[1] = xrm_class[1] = *quarks;
307 xrm_name[2] = (XrmQuark)NULL;
308 xrm_class[2] = (XrmQuark)NULL;
310 if(XrmQGetResource (*sourceDB, xrm_name, xrm_class, &rep_type, &realVal))
312 xrm_bind[0] = XrmBindLoosely;
314 xrm_name[0] = xrm_name[1];
315 xrm_name[1] = NULLQUARK;
317 XrmQPutStringResource(pEnumStruct->pDb, xrm_bind, xrm_name,
318 (char *)realVal.addr);
321 return FALSE;
325 * BuildPrinterAttrs - builds and returns an XrmDatabase for the printer
326 * of the specified name/qualifier, if we have enough information.
327 * If we don't have a model-config
328 * file, then just enumerate the systemAttributes->printers database,
329 * otherwise read in the model-config database and merge into it the
330 * systemAttributes->printers database. This database is then enumerated
331 * with the printer qualifier (and the model name as class if we have it), and
332 * the resulting elements are stored into the database for this particular
333 * printer.
335 static XrmDatabase
336 BuildPrinterAttrs(
337 char *printerName,
338 char *qualifierName)
340 XrmDatabase printerDB = (XrmDatabase)NULL;
342 if(systemAttributes.printers != (XrmDatabase)NULL)
344 char *fileName;
345 XrmDatabase modelDB = (XrmDatabase)NULL;
346 XrmName xrm_name[5], xrm_class[2];
347 XrmRepresentation rep_type;
348 XrmValue value;
349 DbEnumStruct enumStruct;
350 Bool freeModelDB = False;
352 * Build the initial db based on the model-config files
354 xrm_name[0] = XrmStringToQuark (qualifierName);
355 xrm_name[1] = XrmStringToQuark ("xp-model-identifier");
356 xrm_name[2] = (XrmQuark)NULL;
357 XrmQGetResource (systemAttributes.printers, xrm_name, xrm_name,
358 &rep_type, &value);
360 if(value.addr != (XPointer)NULL)
362 fileName = (char *)xalloc(strlen(XPMODELDIR) +
363 strlen((char *)value.addr) +
364 strlen("model-config") + 3);
365 sprintf(fileName, "%s/%s/%s", XPMODELDIR, value.addr,
366 "model-config");
367 modelDB = GetMergedDatabase(fileName);
368 xfree(fileName);
369 if(modelDB != (XrmDatabase)NULL)
371 XrmDatabase tempDB = (XrmDatabase)NULL;
373 * have to make a temp copy because MergeDatabase destroys
374 * the "source" database. Merge in the printers DB
376 tempDB = CopyDb(systemAttributes.printers);
377 XrmMergeDatabases(tempDB, &modelDB);
378 freeModelDB = True;
383 * Check to see if we knew the name AND found a database file
385 if(modelDB == (XrmDatabase)NULL)
386 modelDB = systemAttributes.printers;
388 xrm_name[0] = XrmStringToQuark (qualifierName);
389 xrm_name[1] = (XrmQuark)NULL;
390 xrm_class[0] = XrmStringToQuark((char *)value.addr);
391 xrm_class[1] = (XrmQuark)NULL;
392 enumStruct.pDb = &printerDB;
393 enumStruct.qualifier = (char *)qualifierName;
394 enumStruct.modelId = (char *)value.addr;
395 XrmEnumerateDatabase(modelDB, xrm_name, xrm_class, XrmEnumAllLevels,
396 AddDbEntry, (XPointer) &enumStruct);
398 if(freeModelDB == True) XrmDestroyDatabase(modelDB);
400 XrmPutStringResource(&printerDB, "*printer-name", printerName);
401 XrmPutStringResource(&printerDB, "*qualifier", qualifierName);
402 return printerDB;
406 * BuildABase - builds an XrmDatabase by enumerating the supplied sourceBase
407 * database for elements relevant for the printer named by printerName,
408 * and deriving a class for printerName from the model declared in the
409 * systemAttributes.printers database. If no model is defined for this
410 * printer then the printerName is used as the class as well.
412 * This is used to build the initial value document and initial value
413 * job attribute databases for each printer by searching the system
414 * level doc and job databases.
416 static XrmDatabase
417 BuildABase(
418 char *printerName,
419 char *qualifierName,
420 XrmDatabase sourceBase)
422 XrmDatabase builtDB = (XrmDatabase)NULL;
424 if(sourceBase != (XrmDatabase)NULL)
426 XrmName xrm_name[5], xrm_class[2];
427 XrmRepresentation rep_type;
428 XrmValue value;
429 DbEnumStruct enumStruct;
432 * Retrieve the model name for use as the class.
434 xrm_name[0] = XrmStringToQuark (printerName);
435 xrm_name[1] = XrmStringToQuark ("xp-model-identifier");
436 xrm_name[2] = (XrmQuark)NULL;
437 XrmQGetResource (systemAttributes.printers, xrm_name, xrm_name,
438 &rep_type, &value);
440 * if we have a model name then use it as the class, otherwise
441 * just use the printer name as the class as well as the name.
443 if(value.addr != (XPointer)NULL)
444 xrm_class[0] = XrmStringToQuark((char *)value.addr);
445 else
446 xrm_class[0] = xrm_name[0];
447 xrm_class[1] = (XrmQuark)NULL;
449 xrm_name[1] = (XrmQuark)NULL;
451 enumStruct.pDb = &builtDB;
452 enumStruct.qualifier = (char *)qualifierName;
453 enumStruct.modelId = (char *)value.addr;
454 XrmEnumerateDatabase(sourceBase, xrm_name, xrm_class, XrmEnumAllLevels,
455 AddDbEntry, (XPointer) &enumStruct);
458 XrmPutStringResource(&builtDB, "*qualifier", qualifierName);
460 return builtDB;
464 * FreeAttrList is called upon server recycle, and frees the printer
465 * databases stored in the global attrList.
467 static void
468 FreeAttrList(void)
470 PrAttrPtr pAttr, pNext;
472 for(pAttr = attrList, pNext = attrList;
473 pAttr != (PrAttrPtr)NULL;
474 pAttr = pNext)
476 pNext = pAttr->next;
477 if(pAttr->printerAttrs != (XrmDatabase)NULL)
478 XrmDestroyDatabase(pAttr->printerAttrs);
479 if(pAttr->docAttrs != (XrmDatabase)NULL)
480 XrmDestroyDatabase(pAttr->docAttrs);
481 if(pAttr->jobAttrs != (XrmDatabase)NULL)
482 XrmDestroyDatabase(pAttr->jobAttrs);
483 xfree(pAttr->name);
484 xfree(pAttr->qualifier);
485 xfree(pAttr);
487 attrList = (PrAttrPtr)NULL;
491 * XpRehashAttributes - frees the per-printer attribute list and
492 * calls BuildSystemAttributes to rebuild the overall attribute
493 * store. It is expected that a caller of this will follow it
494 * by calling XpBuildAttributeStore for a new list of printers.
497 XpRehashAttributes(void)
499 if(attrList != (PrAttrPtr)NULL)
500 FreeAttrList();
501 BuildSystemAttributes();
502 return Success;
506 * XpBuildAttributeStore - creates the attribute database associated
507 * with the specified printer. The first time this is called it
508 * calls BuildSystemAttributes to create the system-level databases.
510 void
511 XpBuildAttributeStore(
512 char *printerName,
513 char *qualifierName)
515 PrAttrPtr pAttr;
517 if((pAttr = (PrAttrPtr)xalloc(sizeof(PrAttrs))) == (PrAttrPtr)NULL)
518 return;
520 if(attrGeneration != serverGeneration)
522 if(attrList != (PrAttrPtr)NULL)
523 FreeAttrList();
524 attrCtxtPrivIndex = XpAllocateContextPrivateIndex();
525 XpAllocateContextPrivate(attrCtxtPrivIndex, sizeof(ContextAttrs));
526 BuildSystemAttributes();
528 attrGeneration = serverGeneration;
531 if(attrList == (PrAttrPtr)NULL)
533 pAttr->next = (PrAttrPtr)NULL;
534 attrList = pAttr;
536 else
538 pAttr->next = attrList;
539 attrList = pAttr;
542 pAttr->name = strdup(printerName);
543 pAttr->qualifier = strdup(qualifierName);
544 pAttr->printerAttrs = BuildPrinterAttrs(printerName, qualifierName);
545 pAttr->docAttrs = BuildABase(printerName, qualifierName,
546 systemAttributes.doc);
547 pAttr->jobAttrs = BuildABase(printerName, qualifierName,
548 systemAttributes.job);
552 static Bool
553 StoreEntry(
554 XrmDatabase *sourceDB,
555 XrmBindingList bindings,
556 XrmQuarkList quarks,
557 XrmRepresentation *type,
558 XrmValue *value,
559 XPointer client_data)
561 XrmDatabase *outDb = (XrmDatabase *)client_data;
563 XrmQPutStringResource(outDb, bindings, quarks, (char *)value->addr);
565 return FALSE;
569 * XpCopyDb - makes a copy of the specified XrmDatabase and returns
570 * the copy.
572 static XrmDatabase
573 CopyDb(XrmDatabase inDb)
575 XrmDatabase outDb = (XrmDatabase)NULL;
576 XrmQuark empty = NULLQUARK;
578 (void)XrmEnumerateDatabase(inDb, &empty, &empty, XrmEnumAllLevels,
579 StoreEntry, (XPointer) &outDb);
580 return outDb;
584 * XpInitAttributes - initializes the attribute store for the specified
585 * context. It does this by making copies of the printer, doc, and job
586 * attributes databases for the printer associated with the context.
588 void
589 XpInitAttributes(XpContextPtr pContext)
591 ContextAttrPtr pCtxtAttrs;
592 PrAttrPtr pPrAttr = attrList;
594 /* Initialize all the pointers to NULL */
595 pCtxtAttrs = (ContextAttrPtr)pContext->devPrivates[attrCtxtPrivIndex].ptr;
596 (void)memset((void *)pCtxtAttrs, 0, (size_t) sizeof(ContextAttrs));
598 for(pPrAttr = attrList; pPrAttr != (PrAttrPtr)NULL; pPrAttr = pPrAttr->next)
599 if(!strcmp(pPrAttr->name, pContext->printerName)) break;
601 if(pPrAttr != (PrAttrPtr)NULL)
603 pCtxtAttrs->printerAttrs = CopyDb(pPrAttr->printerAttrs);
604 pCtxtAttrs->docAttrs = CopyDb(pPrAttr->docAttrs);
605 pCtxtAttrs->jobAttrs = CopyDb(pPrAttr->jobAttrs);
609 void
610 XpDestroyAttributes(
611 XpContextPtr pContext)
613 ContextAttrPtr pCtxtAttrs;
615 pCtxtAttrs = (ContextAttrPtr)pContext->devPrivates[attrCtxtPrivIndex].ptr;
617 if(pCtxtAttrs->printerAttrs != (XrmDatabase)NULL)
618 XrmDestroyDatabase(pCtxtAttrs->printerAttrs);
619 if(pCtxtAttrs->docAttrs != (XrmDatabase)NULL)
620 XrmDestroyDatabase(pCtxtAttrs->docAttrs);
621 if(pCtxtAttrs->jobAttrs != (XrmDatabase)NULL)
622 XrmDestroyDatabase(pCtxtAttrs->jobAttrs);
623 if(pCtxtAttrs->pageAttrs != (XrmDatabase)NULL)
624 XrmDestroyDatabase(pCtxtAttrs->pageAttrs);
628 * XpGetOneAttribute returns the string value of the specified attribute
629 * in the specified class for the specified print context. If the attribute
630 * doesn't exist in the database for this context, or if the class database
631 * doesn't exist for this context, then NULL is returned. The caller must
632 * not free the returned string, as the returned pointer points into the
633 * database. This function can also return a value from the server attributes,
634 * in which case the pContext parameter is ignored.
636 char *
637 XpGetOneAttribute(
638 XpContextPtr pContext,
639 XPAttributes class,
640 char *attributeName)
642 ContextAttrPtr pCtxtAttrs;
643 XrmDatabase db = (XrmDatabase)NULL;
644 XrmName xrm_name[3];
645 XrmRepresentation rep_type;
646 XrmValue value;
648 if(class == XPServerAttr)
650 if(systemAttributes.server == (XrmDatabase)NULL)
651 return NULL_STRING;
653 xrm_name[0] = XrmStringToQuark (attributeName);
654 xrm_name[1] = (XrmQuark)NULL;
655 XrmQGetResource(systemAttributes.server, xrm_name, xrm_name,
656 &rep_type, &value);
658 if(value.addr == (char *)NULL)
659 return NULL_STRING;
660 return (char *)value.addr;
662 else
664 pCtxtAttrs=(ContextAttrPtr)pContext->devPrivates[attrCtxtPrivIndex].ptr;
665 switch(class)
667 case XPPrinterAttr:
668 db = pCtxtAttrs->printerAttrs;
669 break;
670 case XPDocAttr:
671 db = pCtxtAttrs->docAttrs;
672 break;
673 case XPJobAttr:
674 db = pCtxtAttrs->jobAttrs;
675 break;
676 case XPPageAttr:
677 db = pCtxtAttrs->pageAttrs;
678 break;
679 default:
680 break;
683 if(db == (XrmDatabase)NULL)
684 return NULL_STRING;
686 xrm_name[0] = XrmStringToQuark ("qualifier");
687 xrm_name[1] = (XrmQuark)NULL;
688 XrmQGetResource(db, xrm_name, xrm_name, &rep_type, &value);
690 xrm_name[0] = XrmStringToQuark (value.addr);
691 xrm_name[1] = XrmStringToQuark (attributeName);
692 xrm_name[2] = (XrmQuark)NULL;
693 if(XrmQGetResource(db, xrm_name, xrm_name, &rep_type, &value))
694 return (char *)value.addr;
695 else
696 return NULL_STRING;
700 * XpPutOneAttribute updates one attribute for the specified
701 * context and class. This function is intended for use by the attribute
702 * validation module which updates the XrmDatabases directly. This
703 * function does not recognize XPServerAttr.
705 void
706 XpPutOneAttribute(
707 XpContextPtr pContext,
708 XPAttributes class,
709 const char* attributeName,
710 const char* value)
712 ContextAttrPtr pCtxtAttrs;
713 XrmDatabase db;
714 XrmBinding bindings[1];
715 XrmQuark quarks[2];
717 pCtxtAttrs = (ContextAttrPtr)pContext->devPrivates[attrCtxtPrivIndex].ptr;
718 switch(class)
720 case XPPrinterAttr:
721 db = pCtxtAttrs->printerAttrs;
722 break;
723 case XPDocAttr:
724 db = pCtxtAttrs->docAttrs;
725 break;
726 case XPJobAttr:
727 db = pCtxtAttrs->jobAttrs;
728 break;
729 case XPPageAttr:
730 db = pCtxtAttrs->pageAttrs;
731 break;
732 default:
733 return;
735 bindings[0] = XrmBindLoosely;
736 quarks[0] = XrmStringToQuark(attributeName);
737 quarks[1] = (XrmQuark)NULL;
738 XrmQPutStringResource(&db, bindings, quarks, value ? value : "");
743 /*******************************************************************************
745 * The following routines: ExpandSpace, PutString, PutByte, and AppendEntry
746 * form the functional core of the GetAttributes routine. Xrm does not
747 * supply a routine to form a string database from an XrmDatabase, except
748 * by writing the database to a file. This code avoids the file system
749 * overhead, but is a bit clunky in its memory management.
751 ******************************************************************************/
754 * ExpandSpace expands the memory allocated for the string database in
755 * the StringDbStruct passed in, and updates the "space" field of the
756 * struct to indicate the new amount of space available.
758 static Bool
759 ExpandSpace(
760 StringDbStruct *pStr)
762 char *newSpace;
764 if((newSpace = (char *)xrealloc(pStr->stringDb, pStr->nextPos + pStr->space
765 + 1024)) == (char *)NULL)
766 return False;
767 pStr->space += 1024;
768 pStr->stringDb = newSpace;
769 return True;
773 * PutString puts the contents of a null-terminated string into the string
774 * database in the StringDbStruct passed in. If there is insufficient room
775 * for the string, ExpandSpace is called, and the nextPos and space fields
776 * are updated.
778 static void
779 PutString(
780 StringDbStruct *pStr,
781 char *pString)
783 int len = strlen(pString);
785 if(len >= pStr->space)
786 if(!ExpandSpace(pStr))
787 return;
788 strcpy(&pStr->stringDb[pStr->nextPos], pString);
789 pStr->nextPos += len;
790 pStr->space -= len;
794 * PutByte puts a single byte value in to the string database in the passed-in
795 * StringDbStruct. ExpandSpace is called if there is insufficient room for
796 * the byte, and the nextPos and space fields are updated.
798 static void
799 PutByte(
800 StringDbStruct *pStr,
801 char byte)
803 if(pStr->space <= 1)
804 if(!ExpandSpace(pStr))
805 return;
806 pStr->stringDb[pStr->nextPos] = byte;
807 pStr->nextPos++;
808 pStr->space--;
811 #define XrmQString XrmPermStringToQuark("String")
814 * AppendEntry is called by XrmEnumerateDatabase, and serves to append
815 * a database entry onto a string database. The passed-in "closure"
816 * struct contains a pointer to the string, and a count of the remaining
817 * bytes. If there are insufficient remaining bytes then the struct
818 * is realloced, and the count of the space remaining is updated.
819 * Database elements of types other than String are ignored!
820 * This code is based directly on that in "DumpEntry" in Xrm.c.
822 static Bool
823 AppendEntry(
824 XrmDatabase *db,
825 XrmBindingList bindings,
826 XrmQuarkList quarks,
827 XrmRepresentation *type,
828 XrmValuePtr value,
829 XPointer data)
831 StringDbStruct *pEnumStr = (StringDbStruct *)data;
832 Bool firstNameSeen;
833 unsigned int i;
834 char *s, c;
836 if (*type != XrmQString)
837 return False;
839 for (firstNameSeen = False; *quarks; bindings++, quarks++) {
840 if (*bindings == XrmBindLoosely) {
841 PutString(pEnumStr, "*");
842 } else if (firstNameSeen) {
843 PutString(pEnumStr, ".");
845 firstNameSeen = True;
846 PutString(pEnumStr, XrmQuarkToString(*quarks));
848 s = value->addr;
849 i = value->size;
850 PutString(pEnumStr, ":\t");
851 if(i) i--;
853 if (i && (*s == ' ' || *s == '\t'))
854 PutByte(pEnumStr, '\\'); /* preserve leading whitespace */
856 while (i--) {
857 c = *s++;
858 if (c == '\n') {
859 if (i)
860 PutString(pEnumStr, "\\n\\\n");
861 else
862 PutString(pEnumStr, "\\n");
863 } else if (c == '\\')
864 PutString(pEnumStr, "\\\\");
865 else if ((c < ' ' && c != '\t') ||
866 ((unsigned char)c >= 0x7f && (unsigned char)c < 0xa0))
868 char temp[4];
869 (void) sprintf(temp, "\\%03o", (unsigned char)c);
870 PutString(pEnumStr, temp);
872 else
873 PutByte(pEnumStr, c);
875 PutByte(pEnumStr, '\n');
876 pEnumStr->stringDb[pEnumStr->nextPos] = (char)'\0';
877 return False;
881 * XpGetAttributes returns a string database version of the Xrm database
882 * for the specified context and class. This function can also return the
883 * contents of the server attributes, in which case the pContext parameter
884 * is ignored.
886 * The caller is responsible for freeing the returned string,
887 * unlike XpGetOneAttribute, where the caller must not free the string.
889 char *
890 XpGetAttributes(
891 XpContextPtr pContext,
892 XPAttributes class)
894 ContextAttrPtr pCtxtAttrs;
895 XrmDatabase db = (XrmDatabase)NULL;
896 StringDbStruct enumStruct;
897 XrmQuark empty = NULLQUARK;
899 if(class == XPServerAttr)
900 db = systemAttributes.server;
901 else
903 pCtxtAttrs=(ContextAttrPtr)pContext->devPrivates[attrCtxtPrivIndex].ptr;
904 switch(class)
906 case XPServerAttr:
907 db = systemAttributes.server;
908 break;
909 case XPPrinterAttr:
910 db = pCtxtAttrs->printerAttrs;
911 break;
912 case XPDocAttr:
913 db = pCtxtAttrs->docAttrs;
914 break;
915 case XPJobAttr:
916 db = pCtxtAttrs->jobAttrs;
917 break;
918 case XPPageAttr:
919 db = pCtxtAttrs->pageAttrs;
920 break;
921 default:
922 break;
925 if(db == (XrmDatabase)NULL)
927 char *retval = (char *)xalloc(1);
928 retval[0] = (char)'\0';
929 return retval;
932 if((enumStruct.stringDb = (char *)xalloc(1024)) == (char *)NULL)
933 return (char *)NULL;
934 enumStruct.stringDb[0] = (char)'\0';
935 enumStruct.nextPos = 0;
936 enumStruct.space = 1024;
937 (void)XrmEnumerateDatabase(db, &empty, &empty, XrmEnumAllLevels,
938 AppendEntry, (XPointer) &enumStruct);
940 return enumStruct.stringDb;
944 XpAugmentAttributes(
945 XpContextPtr pContext,
946 XPAttributes class,
947 char *attributes)
949 XrmDatabase db;
950 ContextAttrPtr pCtxtAttrs;
952 db = XrmGetStringDatabase(attributes);
953 if(db == (XrmDatabase)NULL) return BadAlloc;
955 pCtxtAttrs = (ContextAttrPtr)pContext->devPrivates[attrCtxtPrivIndex].ptr;
956 switch(class)
958 case XPPrinterAttr:
959 XrmMergeDatabases(db, &pCtxtAttrs->printerAttrs);
960 break;
961 case XPDocAttr:
962 XrmMergeDatabases(db, &pCtxtAttrs->docAttrs);
963 break;
964 case XPJobAttr:
965 XrmMergeDatabases(db, &pCtxtAttrs->jobAttrs);
966 break;
967 case XPPageAttr:
968 XrmMergeDatabases(db, &pCtxtAttrs->pageAttrs);
969 break;
970 default:
971 break;
973 return Success;
977 * XpSetAttributes - sets the attribute stores for a specified context.
980 XpSetAttributes(
981 XpContextPtr pContext,
982 XPAttributes class,
983 char *attributes)
985 XrmDatabase db;
986 ContextAttrPtr pCtxtAttrs;
988 db = XrmGetStringDatabase(attributes);
989 if(db == (XrmDatabase)NULL) return BadAlloc;
991 pCtxtAttrs=(ContextAttrPtr)pContext->devPrivates[attrCtxtPrivIndex].ptr;
992 switch(class)
994 case XPPrinterAttr:
995 if(pCtxtAttrs->printerAttrs != (XrmDatabase)NULL)
996 XrmDestroyDatabase(pCtxtAttrs->printerAttrs);
997 pCtxtAttrs->printerAttrs = db;
998 break;
999 case XPDocAttr:
1000 if(pCtxtAttrs->docAttrs != (XrmDatabase)NULL)
1001 XrmDestroyDatabase(pCtxtAttrs->docAttrs);
1002 pCtxtAttrs->docAttrs = db;
1003 break;
1004 case XPJobAttr:
1005 if(pCtxtAttrs->jobAttrs != (XrmDatabase)NULL)
1006 XrmDestroyDatabase(pCtxtAttrs->jobAttrs);
1007 pCtxtAttrs->jobAttrs = db;
1008 break;
1009 case XPPageAttr:
1010 if(pCtxtAttrs->pageAttrs != (XrmDatabase)NULL)
1011 XrmDestroyDatabase(pCtxtAttrs->pageAttrs);
1012 pCtxtAttrs->pageAttrs = db;
1013 break;
1014 default:
1015 break;
1017 return Success;
1020 void
1021 XpAddPrinterAttribute(
1022 char *printerName,
1023 char *printerQualifier,
1024 char *attributeName,
1025 char *attributeValue)
1027 PrAttrPtr pAttr;
1029 for(pAttr = attrList; pAttr != (PrAttrPtr)NULL; pAttr = pAttr->next)
1031 if(!strcmp(printerQualifier, pAttr->qualifier))
1033 XrmPutStringResource(&pAttr->printerAttrs, attributeName,
1034 attributeValue);
1035 break;
1040 const char *
1041 XpGetPrinterAttribute(const char *printerName,
1042 const char *attribute)
1044 PrAttrPtr pAttr;
1045 XrmValue value;
1046 char *type;
1048 for(pAttr = attrList; pAttr != (PrAttrPtr)NULL; pAttr = pAttr->next)
1050 if(!strcmp(printerName, pAttr->qualifier))
1052 char *attrStr;
1054 attrStr = (char *)xalloc(strlen(printerName) + strlen(attribute) +
1056 sprintf(attrStr, "%s.%s", printerName, attribute);
1057 XrmGetResource(pAttr->printerAttrs, attrStr, attrStr,
1058 &type, &value);
1059 xfree(attrStr);
1060 break;
1063 if(value.addr != (XPointer)NULL && strlen(value.addr) != 0)
1064 return value.addr;
1065 else
1066 return "";
1069 /*******************************************************************************
1071 * The following routines are not attribute routines, but are rather
1072 * spooler interface functions. They should presumably move to
1073 * a SpoolerIf.c of some similarly named file.
1075 ******************************************************************************/
1076 #include <locale.h>
1078 static char serverAttrStr[] = "*document-attributes-supported: copy-count\n\
1079 *job-attributes-supported: job-name job-owner\
1080 notification-profile xp-spooler-command-options\n\
1081 *multiple-documents-supported: False";
1083 XrmDatabase
1084 XpSpoolerGetServerAttributes(void)
1086 char *totalAttrs, *localeName;
1087 XrmDatabase db;
1089 localeName = setlocale(LC_CTYPE, (char *)NULL);
1090 if(!localeName || strlen(localeName) == 0)
1091 localeName = "C";
1093 if((totalAttrs = (char *)xalloc(strlen(serverAttrStr) + strlen(localeName)
1094 + 11)) == (char *)NULL)
1095 return (XrmDatabase)NULL;
1096 sprintf(totalAttrs, "%s\n%s\t%s", serverAttrStr, "*locale:", localeName);
1098 db = XrmGetStringDatabase(totalAttrs);
1099 xfree(totalAttrs);
1100 return db;
1104 * Tailf() works similar to "/bin/tail -f fd_in >fd_out" until
1105 * the process |child| terminates (the child status is
1106 * returned in |child_status|).
1107 * This function is used to copy the stdout/stderr output of a
1108 * child to fd_out until the child terminates.
1110 static
1111 void Tailf(int fd_in, int fd_out, pid_t child, int *child_status)
1113 char b[256];
1114 ssize_t sz;
1115 Bool childDone = FALSE;
1116 struct timeval timeout;
1117 long fpos = 0; /* XXX: this is not correct for largefile support */
1119 timeout.tv_sec = 0;
1120 timeout.tv_usec = 100000;
1122 for(;;)
1124 /* Check whether the child is still alive or not */
1125 if (waitpid(child, child_status, WNOHANG) == child)
1126 childDone = TRUE;
1128 /* Copy traffic from |fd_in| to |fd_out|
1129 * (Note we have to use |pread()| here to avoid race conditions
1130 * between a child process writing to the same file using the
1131 * same file pointer (|dup(2)| and |fork(2)| just duplicate the
1132 * file handle but not the pointer)).
1134 while ((sz = pread(fd_in, b, sizeof(b), fpos)) > 0)
1136 fpos += sz;
1137 write(fd_out, b, sz);
1140 if (childDone)
1141 break;
1143 (void)select(0, NULL, NULL, NULL, &timeout);
1148 * SendFileToCommand takes three character pointers - the file name,
1149 * the command to execute,
1150 * and the "argv" style NULL-terminated vector of arguments for the command.
1151 * The command is exec'd, and the file contents are sent to the command
1152 * via stdin.
1154 * WARNING: This function will try to adopt the userId of the supplied
1155 * user name prior to exec'ing the supplied command.
1157 static void
1158 SendFileToCommand(
1159 XpContextPtr pContext,
1160 char *fileName,
1161 char *pCommand,
1162 char **argVector,
1163 char *userName)
1165 pid_t childPid;
1166 int pipefd[2];
1167 int status;
1168 struct stat statBuf;
1169 FILE *fp, *outPipe;
1170 FILE *resFp; /* output from launched command */
1171 int resfd;
1173 resFp = tmpfile();
1174 if (resFp == NULL)
1176 ErrorF("SendFileToCommand: Cannot open temporary file for command output\n");
1177 return;
1179 resfd = fileno(resFp);
1181 if(pipe(pipefd))
1183 ErrorF("SendFileToCommand: Cannot open pipe\n");
1184 fclose(resFp);
1185 return;
1188 if(stat(fileName, &statBuf) < 0 || (int)statBuf.st_size == 0)
1190 close(pipefd[0]);
1191 close(pipefd[1]);
1192 fclose(resFp);
1193 return;
1196 fp = fopen(fileName, "r");
1197 if(fp == (FILE *)NULL)
1199 ErrorF("SendFileToCommand: Cannot open scratch spool file '%s'\n", fileName);
1200 close(pipefd[0]);
1201 close(pipefd[1]);
1202 fclose(resFp);
1203 return;
1206 if((childPid = fork()) == 0)
1208 close(pipefd[1]);
1210 /* Replace current stdin with input from the pipe */
1211 close(STDIN_FILENO);
1212 dup(pipefd[0]);
1213 close(pipefd[0]);
1215 /* Close current stdout and redirect it to resfd */
1216 close(STDOUT_FILENO);
1217 dup(resfd);
1219 /* Close current stderr and redirect it to resfd
1220 * (valgrind may not like that, in this case simply start it using
1221 * % valgrind 50>/dev/tty --logfile-fd=50 <more-options> ./Xprt ... #)
1223 close(STDERR_FILENO);
1224 dup(resfd);
1226 fclose(resFp);
1229 * If a user name is specified, try to set our uid to match that
1230 * user name. This is to allow e.g. a banner page to show the
1231 * name of the printing user rather than the user who started
1232 * the print server.
1234 if(userName)
1236 uid_t myUid;
1238 if((myUid = geteuid()) == (uid_t)0)
1240 struct passwd *pPasswd;
1242 if((pPasswd = getpwnam(userName)))
1244 if (setgid((gid_t)pPasswd->pw_gid) != 0)
1245 perror("SendFileToCommand: setgid() failure.");
1247 if (initgroups(userName, (gid_t)pPasswd->pw_gid) != 0)
1248 perror("SendFileToCommand: initgroups() failure.");
1250 if (setuid((uid_t)pPasswd->pw_uid) != 0)
1251 perror("SendFileToCommand: setuid() failure.");
1255 /* return BadAlloc? */
1256 if (execv(pCommand, argVector) == -1) {
1257 FatalError("unable to exec '%s'", pCommand);
1260 else
1262 (void) close(pipefd[0]);
1264 outPipe = fdopen(pipefd[1], "w");
1265 (void) TransferBytes(fp, outPipe, (int)statBuf.st_size);
1267 (void) fclose(outPipe);
1268 (void) fclose(fp);
1270 /* Wait for spooler child (and send all it's output to stderr) */
1271 Tailf(resfd, STDERR_FILENO, childPid, &status);
1273 if (status != EXIT_SUCCESS)
1275 ErrorF("SendFileToCommand: spooler command returned non-zero status %d.\n", status);
1278 /* Store "xp-spooler-command-results" XPJobAttr that the
1279 * client can fetch it on demand */
1280 if ((fstat(resfd, &statBuf) >= 0) && (statBuf.st_size >= 0))
1282 long bufSize;
1283 char *buf;
1285 bufSize = statBuf.st_size;
1287 /* Clamp buffer size to 4MB to prevent that we allocate giant
1288 * buffers if the spooler goes mad and spams it's stdout/stderr
1289 * channel. */
1290 bufSize = MIN(bufSize, 4*1024*1024);
1292 buf = xalloc(bufSize+1);
1293 if (buf != NULL)
1295 bufSize = pread(resfd, buf, bufSize, 0);
1296 buf[bufSize]='\0';
1298 /* XXX: This should be converted from local multibyte encoding to
1299 * Compound Text encoding first */
1300 XpPutOneAttribute(pContext, XPJobAttr, "xp-spooler-command-results", buf);
1302 xfree(buf);
1305 else
1307 ErrorF("SendFileToCommand: fstat() failed.\n");
1310 fclose(resFp);
1312 return;
1316 * ReplaceAllKeywords causes all the predefined keywords (e.g. %options%)
1317 * to be replaced with the appropriate values derived from the attribute
1318 * store for the supplied print context. The ReplaceAnyString utility
1319 * routine is used to perform the actual replacements.
1322 static char *
1323 ReplaceAllKeywords(
1324 XpContextPtr pContext,
1325 char *command)
1327 char *cmdOpt;
1329 cmdOpt = XpGetOneAttribute(pContext, XPPrinterAttr,
1330 "xp-spooler-printer-name");
1331 if(cmdOpt != (char *)NULL && strlen(cmdOpt) != 0)
1332 command = ReplaceAnyString(command, "%printer-name%", cmdOpt);
1333 else
1334 command = ReplaceAnyString(command, "%printer-name%",
1335 pContext->printerName);
1337 cmdOpt = XpGetOneAttribute(pContext, XPDocAttr, "copy-count");
1338 if(cmdOpt != (char *)NULL && strlen(cmdOpt) != 0)
1339 command = ReplaceAnyString(command, "%copy-count%", cmdOpt);
1340 else
1341 command = ReplaceAnyString(command, "%copy-count%", "1");
1343 cmdOpt = XpGetOneAttribute(pContext, XPJobAttr, "job-name");
1344 if(cmdOpt != (char *)NULL && strlen(cmdOpt) != 0)
1345 command = ReplaceAnyString(command, "%job-name%", cmdOpt);
1346 else
1347 command = ReplaceAnyString(command, "%job-name%", "");
1349 cmdOpt = XpGetOneAttribute(pContext, XPJobAttr, "job-owner");
1350 if(cmdOpt != (char *)NULL && strlen(cmdOpt) != 0)
1351 command = ReplaceAnyString(command, "%job-owner%", cmdOpt);
1352 else
1353 command = ReplaceAnyString(command, "%job-owner%", "");
1355 cmdOpt = XpGetOneAttribute(pContext, XPJobAttr,
1356 "xp-spooler-command-options");
1357 if(cmdOpt != (char *)NULL && strlen(cmdOpt) != 0)
1358 command = ReplaceAnyString(command, "%options%", cmdOpt);
1359 else
1360 command = ReplaceAnyString(command, "%options%", "");
1362 /* New in xprint.mozdev.org release 007 - replace "%xpconfigdir%" with
1363 * location of $XPCONFIGDIR */
1364 command = ReplaceAnyString(command, "%xpconfigdir%", XpGetConfigDirBase());
1366 return command;
1369 #ifdef __QNX__
1370 #define toascii( c ) ((unsigned)(c) & 0x007f)
1371 #endif
1373 #if defined(CSRG_BASED) || \
1374 defined(linux) || \
1375 defined(__CYGWIN__) || \
1376 (defined(sun) && !defined(SVR4)) || \
1377 (defined(SVR4) && !defined(sun) && !defined(__UNIXWARE__)) || \
1378 defined(ISC) || \
1379 defined(Lynx) || \
1380 defined(__QNX__) || \
1381 defined(__DARWIN__)
1382 #define iswspace(c) (isascii(c) && isspace(toascii(c)))
1383 #endif
1386 * GetToken - takes in a string and returns a malloc'd copy of the
1387 * first non-white-space sequence of characters in the string.
1388 * It returns the number of _bytes_ (NOT characters) parsed through
1389 * the inStr to get to the end of the returned token.
1391 static int
1392 GetToken(
1393 char *inStr,
1394 char **outStr)
1396 size_t mbCurMax = MB_CUR_MAX;
1397 wchar_t curChar;
1398 int i, numBytes, byteLen = strlen(inStr);
1399 char *tok;
1402 * read through any leading white space.
1404 for(i = 0, numBytes = 0; i < byteLen; i += numBytes)
1406 numBytes = mbtowc(&curChar, &inStr[i], mbCurMax);
1407 if(!iswspace(curChar))
1408 break;
1410 tok = inStr + i;
1413 * find the end of the token.
1415 byteLen = strlen(tok);
1416 for(i = 0, numBytes = 0; i < byteLen; i += numBytes)
1418 numBytes = mbtowc(&curChar, &tok[i], mbCurMax);
1419 if(iswspace(curChar))
1420 break;
1423 if((*outStr = (char *)xalloc(i + 1)) == (char *)NULL)
1424 return 0;
1425 strncpy(*outStr, tok, i);
1426 (*outStr)[i] = (char)'\0';
1427 return (tok + i) - inStr;
1430 static void
1431 FreeVector(
1432 char **vector)
1434 int i;
1436 if(vector == (char **)NULL) return;
1438 for(i = 0; vector[i] != (char *)NULL; i++)
1439 xfree(vector[i]);
1440 xfree(vector);
1445 * AddVector appends the pAddition arg vector to the pTarget arg vector.
1446 * If the pTarget cannot be realloc'd, then pTarget is set to NULL.
1448 static void
1449 AddVector(
1450 char ***pTarget,
1451 char **pAddition)
1453 int numTarget, numAdd, i;
1455 for(numTarget = 0; (*pTarget)[numTarget] != (char *)NULL; numTarget++)
1457 for(numAdd = 0; pAddition[numAdd] != (char *)NULL; numAdd++)
1460 *pTarget = (char **)xrealloc((void *)*pTarget, (numTarget + numAdd + 1) *
1461 sizeof(char *));
1462 if(*pTarget == (char **)NULL)
1463 return;
1464 for(i = 0; i < numAdd; i++)
1465 (*pTarget)[numTarget + i] = pAddition[i];
1467 (*pTarget)[numTarget + numAdd] = (char *)NULL;
1470 static char **
1471 BuildArgVector(
1472 char *argString,
1473 XpContextPtr pContext)
1475 char **pVector;
1476 char *curTok;
1477 int numChars, i;
1478 static int beenHere = 0; /* prevent recursion on embedded %options%
1481 pVector = (char **)xalloc(sizeof(char *));
1482 pVector[0] = (char *)NULL;
1483 for(i = 0; (numChars = GetToken(argString, &curTok)) != 0;
1484 i++, argString += numChars)
1486 if(beenHere || strcmp(curTok, "%options%"))
1488 if(curTok[0] == (char)'\0')
1490 xfree(curTok);
1492 else
1494 pVector = (char **)xrealloc((void *)pVector,
1495 (i + 2)*sizeof(char *));
1496 if(pVector == (char **)NULL)
1497 return (char **)NULL;
1498 pVector[i] = curTok;
1499 pVector[i + 1] = (char *)NULL;
1502 else if(!beenHere)
1504 char **optionsVec;
1506 curTok = ReplaceAllKeywords(pContext, curTok);
1507 beenHere = 1;
1508 optionsVec = BuildArgVector(curTok, pContext);
1509 xfree(curTok);
1510 beenHere = 0;
1511 AddVector(&pVector, optionsVec);
1512 xfree(optionsVec);
1515 if(numChars == 0 && curTok != (char *)NULL)
1516 xfree(curTok);
1517 return pVector;
1521 * VectorizeCommand takes a string and breaks it into a command name and
1522 * an array of character pointers suitable for handing to execv. The
1523 * array is NULL-terminated.
1524 * The returned char * is the command name, and should be freed when no
1525 * longer needed. The array elements returned in the pVector parameter
1526 * should be individually freed, and the array itself should also be
1527 * freed when no longer needed.
1529 static char *
1530 VectorizeCommand(
1531 char *command,
1532 char ***pVector,
1533 XpContextPtr pContext)
1535 char *cmdName;
1536 int numChars;
1538 if(command == (char *)NULL)
1539 return (char *)NULL;
1541 numChars = GetToken(command, &cmdName);
1543 if(cmdName == (char *)NULL)
1544 return (char *)NULL;
1546 /* Mangle the command name, too... */
1547 cmdName = ReplaceAllKeywords(pContext, cmdName);
1549 if(cmdName == (char *)NULL)
1550 return (char *)NULL;
1552 *pVector = BuildArgVector(command, pContext);
1554 return cmdName;
1558 XpSubmitJob(fileName, pContext)
1559 char *fileName;
1560 XpContextPtr pContext;
1562 char **vector, *cmdNam, *command, *userName;
1563 int i;
1565 command = XpGetOneAttribute(pContext, XPPrinterAttr, "xp-spooler-command");
1566 if(command == (char *)NULL || strlen(command) == 0)
1568 if( spooler_type )
1570 command = strdup(spooler_type->spool_command);
1572 else
1574 ErrorF("XpSubmitJob: No default spool command defined.\n");
1577 else
1579 command = strdup(command);
1581 if(command == (char *)NULL)
1583 ErrorF("XpSubmitJob: No spooler command found, cannot submit job.\n");
1584 return BadAlloc;
1587 cmdNam = VectorizeCommand(command, &vector, pContext);
1588 xfree(command);
1590 if(cmdNam == (char *)NULL)
1591 return BadAlloc;
1593 for(i = 0; vector[i] != (char *)NULL; i++)
1595 vector[i] = ReplaceAllKeywords(pContext, vector[i]);
1596 if(vector[i] == (char *)NULL)
1598 xfree(cmdNam);
1599 for(i = 0; vector[i] != (char *)NULL; i++)
1600 xfree(vector[i]);
1601 xfree(vector);
1602 return BadAlloc;
1606 userName = XpGetOneAttribute(pContext, XPJobAttr, "job-owner");
1607 if(userName != (char *)NULL && strlen(userName) == 0)
1608 userName = (char *)NULL;
1610 SendFileToCommand(pContext, fileName, cmdNam, vector, userName);
1612 FreeVector(vector);
1613 xfree(cmdNam);
1615 return Success;
1619 * SearchInputTrays()
1621 * Given a tray, return the medium in the tray. Conversely, given a
1622 * medium, return a tray in which it can be found. In either case,
1623 * return NULL if the given tray or medium cannot be found.
1625 #define TRAY 0
1626 #define MEDIUM 1
1628 static char *
1629 SearchInputTrays(XpContextPtr pCon,
1630 int which,
1631 char *val)
1633 char *inputTraysMedium, tray[80], medium[80], *copy;
1634 char *pS, *pE, *pLast;
1636 inputTraysMedium = XpGetOneAttribute( pCon, XPPrinterAttr,
1637 "input-trays-medium" );
1639 copy = strdup( inputTraysMedium );
1640 pS = copy;
1641 pLast = copy + strlen( copy );
1643 while( pS < pLast )
1645 while( *pS && *pS != '{' )
1646 pS++;
1648 pE = ++pS;
1649 while( *pE && *pE != '}' )
1650 pE++;
1651 *pE = '\0';
1653 sscanf( pS, "%s %s", tray, medium );
1655 if( which == MEDIUM && !strcmp( val, medium ) )
1657 xfree( copy );
1658 return strdup( tray );
1661 if( which == TRAY && !strcmp( val, tray ) )
1663 xfree( copy );
1664 return strdup( medium );
1667 pS = pE + 1;
1670 xfree( copy );
1671 return strdup( NULL_STRING );
1675 * XpGetTrayMediumFromContext()
1677 * Given a print context, hit the input-trays-medium,
1678 * default-input-tray and default-medium attributes to find the
1679 * appropriate tray to use, and the medium in that tray.
1681 void
1682 XpGetTrayMediumFromContext(XpContextPtr pCon,
1683 char **medium,
1684 char **tray)
1686 char *defMedium, *defTray;
1687 char *t, *m;
1689 defMedium = XpGetOneAttribute( pCon, XPPageAttr,
1690 "default-medium" );
1691 if( *defMedium == '\0' )
1692 defMedium = XpGetOneAttribute( pCon, XPDocAttr,
1693 "default-medium" );
1695 defTray = XpGetOneAttribute( pCon, XPPageAttr,
1696 "default-input-tray" );
1697 if( *defTray == '\0' )
1698 defTray = XpGetOneAttribute( pCon, XPDocAttr,
1699 "default-input-tray" );
1702 * First, check to see if the default tray has the default medium
1703 * installed. This is the ideal case.
1705 m = SearchInputTrays( pCon, TRAY, defTray );
1706 if( !strcmp( m, defMedium ) )
1708 xfree( m );
1709 *tray = strdup( defTray );
1710 *medium = strdup( defMedium );
1711 return;
1715 * If the default tray doesn't have the default medium, search for
1716 * a tray which has the default medium.
1718 t = SearchInputTrays( pCon, MEDIUM, defMedium );
1719 if( t )
1721 *tray = t;
1722 *medium = strdup( defMedium );
1723 return;
1727 * If all else fails, just return the default tray, and whatever
1728 * medium happens to be there. Note that we simply return
1729 * whatever is in the attribute store. Any further correction is
1730 * left up to the DDX driver.
1732 *tray = strdup( defTray );
1733 *medium = m;
1734 xfree( t );