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
32 /*******************************************************************
34 ** *********************************************************
36 ** * File: attributes.c
39 ** * Implementation of the attribute store for Xp.
41 ** * Copyright: Copyright 1995 Hewlett-Packard Company
43 ** *********************************************************
45 ********************************************************************/
47 #ifdef HAVE_DIX_CONFIG_H
48 #include <dix-config.h>
51 #include <X11/Xproto.h>
59 #include <sys/types.h>
63 #if (defined(sun) && defined(SVR4)) || defined(__SCO__) || defined(__UNIXWARE__)
66 #include "scrnintstr.h"
68 #include <X11/extensions/Printstr.h>
70 #include "attributes.h"
73 #include <X11/Xresource.h>
78 #define MIN(a,b) (((a)<(b))?(a):(b))
81 #define MAX(a,b) (((a)>(b))?(a):(b))
85 static XrmDatabase
CopyDb(XrmDatabase inDb
);
87 extern XrmDatabase
XpSpoolerGetServerAttributes(void);
89 static int attrGeneration
= 0;
103 typedef struct _printerAttrs
{
104 struct _printerAttrs
*next
;
107 XrmDatabase printerAttrs
;
108 XrmDatabase docAttrs
;
109 XrmDatabase jobAttrs
;
110 } PrAttrs
, *PrAttrPtr
;
112 static PrAttrPtr attrList
= (PrAttrPtr
)NULL
;
114 typedef struct _systemAttrs
{
117 XrmDatabase printers
;
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.
160 char *XpGetConfigDirBase(void)
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
;
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.
183 XpGetConfigDir(Bool useLocale
)
185 char *dirName
, *langName
, *langDir
, *configDir
;
186 Bool freeLangDir
= False
;
188 if(useLocale
== False
) langDir
= "/C";
191 langName
= getenv("LC_ALL");
192 if (langName
== NULL
) {
193 langName
= getenv("LANG");
196 if(langName
== (char *)NULL
)
200 if(strcmp(langName
, "C") == 0)
202 langDir
= (char *)xalloc(strlen(langName
) + 2);
203 sprintf(langDir
, "/%s", langName
);
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
)
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).
226 GetMergedDatabase(const char *attrName
)
228 char *dirName
, *fileName
;
231 if((dirName
= XpGetConfigDir(False
)) == (char *)NULL
)
232 return (XrmDatabase
)NULL
;
233 if((fileName
= (char *)xalloc(strlen(dirName
) + strlen(attrName
) + 1)) ==
235 return (XrmDatabase
)NULL
;
236 sprintf(fileName
, "%s%s", dirName
, attrName
);
237 db
= XrmGetFileDatabase(fileName
);
241 if((dirName
= XpGetConfigDir(True
)) == (char *)NULL
)
243 if((fileName
= (char *)xalloc(strlen(dirName
) + strlen(attrName
) + 1)) ==
246 sprintf(fileName
, "%s%s", dirName
, attrName
);
247 (void)XrmCombineFileDatabase(fileName
, &db
, True
);
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
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();
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").
287 XrmDatabase
*sourceDB
,
288 XrmBindingList bindings
,
290 XrmRepresentation
*type
,
292 XPointer client_data
)
294 DbEnumStruct
*pEnumStruct
= (DbEnumStruct
*)client_data
;
296 XrmClass xrm_class
[5];
297 XrmBinding xrm_bind
[3];
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
);
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
340 XrmDatabase printerDB
= (XrmDatabase
)NULL
;
342 if(systemAttributes
.printers
!= (XrmDatabase
)NULL
)
345 XrmDatabase modelDB
= (XrmDatabase
)NULL
;
346 XrmName xrm_name
[5], xrm_class
[2];
347 XrmRepresentation rep_type
;
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
,
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
,
367 modelDB
= GetMergedDatabase(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
);
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
);
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.
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
;
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
,
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
);
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
);
464 * FreeAttrList is called upon server recycle, and frees the printer
465 * databases stored in the global attrList.
470 PrAttrPtr pAttr
, pNext
;
472 for(pAttr
= attrList
, pNext
= attrList
;
473 pAttr
!= (PrAttrPtr
)NULL
;
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
);
484 xfree(pAttr
->qualifier
);
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
)
501 BuildSystemAttributes();
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.
511 XpBuildAttributeStore(
517 if((pAttr
= (PrAttrPtr
)xalloc(sizeof(PrAttrs
))) == (PrAttrPtr
)NULL
)
520 if(attrGeneration
!= serverGeneration
)
522 if(attrList
!= (PrAttrPtr
)NULL
)
524 attrCtxtPrivIndex
= XpAllocateContextPrivateIndex();
525 XpAllocateContextPrivate(attrCtxtPrivIndex
, sizeof(ContextAttrs
));
526 BuildSystemAttributes();
528 attrGeneration
= serverGeneration
;
531 if(attrList
== (PrAttrPtr
)NULL
)
533 pAttr
->next
= (PrAttrPtr
)NULL
;
538 pAttr
->next
= attrList
;
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
);
554 XrmDatabase
*sourceDB
,
555 XrmBindingList bindings
,
557 XrmRepresentation
*type
,
559 XPointer client_data
)
561 XrmDatabase
*outDb
= (XrmDatabase
*)client_data
;
563 XrmQPutStringResource(outDb
, bindings
, quarks
, (char *)value
->addr
);
569 * XpCopyDb - makes a copy of the specified XrmDatabase and returns
573 CopyDb(XrmDatabase inDb
)
575 XrmDatabase outDb
= (XrmDatabase
)NULL
;
576 XrmQuark empty
= NULLQUARK
;
578 (void)XrmEnumerateDatabase(inDb
, &empty
, &empty
, XrmEnumAllLevels
,
579 StoreEntry
, (XPointer
) &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.
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
);
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.
638 XpContextPtr pContext
,
642 ContextAttrPtr pCtxtAttrs
;
643 XrmDatabase db
= (XrmDatabase
)NULL
;
645 XrmRepresentation rep_type
;
648 if(class == XPServerAttr
)
650 if(systemAttributes
.server
== (XrmDatabase
)NULL
)
653 xrm_name
[0] = XrmStringToQuark (attributeName
);
654 xrm_name
[1] = (XrmQuark
)NULL
;
655 XrmQGetResource(systemAttributes
.server
, xrm_name
, xrm_name
,
658 if(value
.addr
== (char *)NULL
)
660 return (char *)value
.addr
;
664 pCtxtAttrs
=(ContextAttrPtr
)pContext
->devPrivates
[attrCtxtPrivIndex
].ptr
;
668 db
= pCtxtAttrs
->printerAttrs
;
671 db
= pCtxtAttrs
->docAttrs
;
674 db
= pCtxtAttrs
->jobAttrs
;
677 db
= pCtxtAttrs
->pageAttrs
;
683 if(db
== (XrmDatabase
)NULL
)
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
;
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.
707 XpContextPtr pContext
,
709 const char* attributeName
,
712 ContextAttrPtr pCtxtAttrs
;
714 XrmBinding bindings
[1];
717 pCtxtAttrs
= (ContextAttrPtr
)pContext
->devPrivates
[attrCtxtPrivIndex
].ptr
;
721 db
= pCtxtAttrs
->printerAttrs
;
724 db
= pCtxtAttrs
->docAttrs
;
727 db
= pCtxtAttrs
->jobAttrs
;
730 db
= pCtxtAttrs
->pageAttrs
;
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.
760 StringDbStruct
*pStr
)
764 if((newSpace
= (char *)xrealloc(pStr
->stringDb
, pStr
->nextPos
+ pStr
->space
765 + 1024)) == (char *)NULL
)
768 pStr
->stringDb
= newSpace
;
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
780 StringDbStruct
*pStr
,
783 int len
= strlen(pString
);
785 if(len
>= pStr
->space
)
786 if(!ExpandSpace(pStr
))
788 strcpy(&pStr
->stringDb
[pStr
->nextPos
], pString
);
789 pStr
->nextPos
+= 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.
800 StringDbStruct
*pStr
,
804 if(!ExpandSpace(pStr
))
806 pStr
->stringDb
[pStr
->nextPos
] = byte
;
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.
825 XrmBindingList bindings
,
827 XrmRepresentation
*type
,
831 StringDbStruct
*pEnumStr
= (StringDbStruct
*)data
;
836 if (*type
!= XrmQString
)
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
));
850 PutString(pEnumStr
, ":\t");
853 if (i
&& (*s
== ' ' || *s
== '\t'))
854 PutByte(pEnumStr
, '\\'); /* preserve leading whitespace */
860 PutString(pEnumStr
, "\\n\\\n");
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))
869 (void) sprintf(temp
, "\\%03o", (unsigned char)c
);
870 PutString(pEnumStr
, temp
);
873 PutByte(pEnumStr
, c
);
875 PutByte(pEnumStr
, '\n');
876 pEnumStr
->stringDb
[pEnumStr
->nextPos
] = (char)'\0';
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
886 * The caller is responsible for freeing the returned string,
887 * unlike XpGetOneAttribute, where the caller must not free the string.
891 XpContextPtr pContext
,
894 ContextAttrPtr pCtxtAttrs
;
895 XrmDatabase db
= (XrmDatabase
)NULL
;
896 StringDbStruct enumStruct
;
897 XrmQuark empty
= NULLQUARK
;
899 if(class == XPServerAttr
)
900 db
= systemAttributes
.server
;
903 pCtxtAttrs
=(ContextAttrPtr
)pContext
->devPrivates
[attrCtxtPrivIndex
].ptr
;
907 db
= systemAttributes
.server
;
910 db
= pCtxtAttrs
->printerAttrs
;
913 db
= pCtxtAttrs
->docAttrs
;
916 db
= pCtxtAttrs
->jobAttrs
;
919 db
= pCtxtAttrs
->pageAttrs
;
925 if(db
== (XrmDatabase
)NULL
)
927 char *retval
= (char *)xalloc(1);
928 retval
[0] = (char)'\0';
932 if((enumStruct
.stringDb
= (char *)xalloc(1024)) == (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
;
945 XpContextPtr pContext
,
950 ContextAttrPtr pCtxtAttrs
;
952 db
= XrmGetStringDatabase(attributes
);
953 if(db
== (XrmDatabase
)NULL
) return BadAlloc
;
955 pCtxtAttrs
= (ContextAttrPtr
)pContext
->devPrivates
[attrCtxtPrivIndex
].ptr
;
959 XrmMergeDatabases(db
, &pCtxtAttrs
->printerAttrs
);
962 XrmMergeDatabases(db
, &pCtxtAttrs
->docAttrs
);
965 XrmMergeDatabases(db
, &pCtxtAttrs
->jobAttrs
);
968 XrmMergeDatabases(db
, &pCtxtAttrs
->pageAttrs
);
977 * XpSetAttributes - sets the attribute stores for a specified context.
981 XpContextPtr pContext
,
986 ContextAttrPtr pCtxtAttrs
;
988 db
= XrmGetStringDatabase(attributes
);
989 if(db
== (XrmDatabase
)NULL
) return BadAlloc
;
991 pCtxtAttrs
=(ContextAttrPtr
)pContext
->devPrivates
[attrCtxtPrivIndex
].ptr
;
995 if(pCtxtAttrs
->printerAttrs
!= (XrmDatabase
)NULL
)
996 XrmDestroyDatabase(pCtxtAttrs
->printerAttrs
);
997 pCtxtAttrs
->printerAttrs
= db
;
1000 if(pCtxtAttrs
->docAttrs
!= (XrmDatabase
)NULL
)
1001 XrmDestroyDatabase(pCtxtAttrs
->docAttrs
);
1002 pCtxtAttrs
->docAttrs
= db
;
1005 if(pCtxtAttrs
->jobAttrs
!= (XrmDatabase
)NULL
)
1006 XrmDestroyDatabase(pCtxtAttrs
->jobAttrs
);
1007 pCtxtAttrs
->jobAttrs
= db
;
1010 if(pCtxtAttrs
->pageAttrs
!= (XrmDatabase
)NULL
)
1011 XrmDestroyDatabase(pCtxtAttrs
->pageAttrs
);
1012 pCtxtAttrs
->pageAttrs
= db
;
1021 XpAddPrinterAttribute(
1023 char *printerQualifier
,
1024 char *attributeName
,
1025 char *attributeValue
)
1029 for(pAttr
= attrList
; pAttr
!= (PrAttrPtr
)NULL
; pAttr
= pAttr
->next
)
1031 if(!strcmp(printerQualifier
, pAttr
->qualifier
))
1033 XrmPutStringResource(&pAttr
->printerAttrs
, attributeName
,
1041 XpGetPrinterAttribute(const char *printerName
,
1042 const char *attribute
)
1048 for(pAttr
= attrList
; pAttr
!= (PrAttrPtr
)NULL
; pAttr
= pAttr
->next
)
1050 if(!strcmp(printerName
, pAttr
->qualifier
))
1054 attrStr
= (char *)xalloc(strlen(printerName
) + strlen(attribute
) +
1056 sprintf(attrStr
, "%s.%s", printerName
, attribute
);
1057 XrmGetResource(pAttr
->printerAttrs
, attrStr
, attrStr
,
1063 if(value
.addr
!= (XPointer
)NULL
&& strlen(value
.addr
) != 0)
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 ******************************************************************************/
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";
1084 XpSpoolerGetServerAttributes(void)
1086 char *totalAttrs
, *localeName
;
1089 localeName
= setlocale(LC_CTYPE
, (char *)NULL
);
1090 if(!localeName
|| strlen(localeName
) == 0)
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
);
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.
1111 void Tailf(int fd_in
, int fd_out
, pid_t child
, int *child_status
)
1115 Bool childDone
= FALSE
;
1116 struct timeval timeout
;
1117 long fpos
= 0; /* XXX: this is not correct for largefile support */
1120 timeout
.tv_usec
= 100000;
1124 /* Check whether the child is still alive or not */
1125 if (waitpid(child
, child_status
, WNOHANG
) == child
)
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)
1137 write(fd_out
, b
, sz
);
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
1154 * WARNING: This function will try to adopt the userId of the supplied
1155 * user name prior to exec'ing the supplied command.
1159 XpContextPtr pContext
,
1168 struct stat statBuf
;
1170 FILE *resFp
; /* output from launched command */
1176 ErrorF("SendFileToCommand: Cannot open temporary file for command output\n");
1179 resfd
= fileno(resFp
);
1183 ErrorF("SendFileToCommand: Cannot open pipe\n");
1188 if(stat(fileName
, &statBuf
) < 0 || (int)statBuf
.st_size
== 0)
1196 fp
= fopen(fileName
, "r");
1197 if(fp
== (FILE *)NULL
)
1199 ErrorF("SendFileToCommand: Cannot open scratch spool file '%s'\n", fileName
);
1206 if((childPid
= fork()) == 0)
1210 /* Replace current stdin with input from the pipe */
1211 close(STDIN_FILENO
);
1215 /* Close current stdout and redirect it to resfd */
1216 close(STDOUT_FILENO
);
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
);
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
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
);
1262 (void) close(pipefd
[0]);
1264 outPipe
= fdopen(pipefd
[1], "w");
1265 (void) TransferBytes(fp
, outPipe
, (int)statBuf
.st_size
);
1267 (void) fclose(outPipe
);
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))
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
1290 bufSize
= MIN(bufSize
, 4*1024*1024);
1292 buf
= xalloc(bufSize
+1);
1295 bufSize
= pread(resfd
, 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
);
1307 ErrorF("SendFileToCommand: fstat() failed.\n");
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.
1324 XpContextPtr pContext
,
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
);
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
);
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
);
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
);
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
);
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());
1370 #define toascii( c ) ((unsigned)(c) & 0x007f)
1373 #if defined(CSRG_BASED) || \
1375 defined(__CYGWIN__) || \
1376 (defined(sun) && !defined(SVR4)) || \
1377 (defined(SVR4) && !defined(sun) && !defined(__UNIXWARE__)) || \
1380 defined(__QNX__) || \
1382 #define iswspace(c) (isascii(c) && isspace(toascii(c)))
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.
1396 size_t mbCurMax
= MB_CUR_MAX
;
1398 int i
, numBytes
, byteLen
= strlen(inStr
);
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
))
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
))
1423 if((*outStr
= (char *)xalloc(i
+ 1)) == (char *)NULL
)
1425 strncpy(*outStr
, tok
, i
);
1426 (*outStr
)[i
] = (char)'\0';
1427 return (tok
+ i
) - inStr
;
1436 if(vector
== (char **)NULL
) return;
1438 for(i
= 0; vector
[i
] != (char *)NULL
; i
++)
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.
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) *
1462 if(*pTarget
== (char **)NULL
)
1464 for(i
= 0; i
< numAdd
; i
++)
1465 (*pTarget
)[numTarget
+ i
] = pAddition
[i
];
1467 (*pTarget
)[numTarget
+ numAdd
] = (char *)NULL
;
1473 XpContextPtr pContext
)
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')
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
;
1506 curTok
= ReplaceAllKeywords(pContext
, curTok
);
1508 optionsVec
= BuildArgVector(curTok
, pContext
);
1511 AddVector(&pVector
, optionsVec
);
1515 if(numChars
== 0 && curTok
!= (char *)NULL
)
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.
1533 XpContextPtr pContext
)
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
);
1558 XpSubmitJob(fileName
, pContext
)
1560 XpContextPtr pContext
;
1562 char **vector
, *cmdNam
, *command
, *userName
;
1565 command
= XpGetOneAttribute(pContext
, XPPrinterAttr
, "xp-spooler-command");
1566 if(command
== (char *)NULL
|| strlen(command
) == 0)
1570 command
= strdup(spooler_type
->spool_command
);
1574 ErrorF("XpSubmitJob: No default spool command defined.\n");
1579 command
= strdup(command
);
1581 if(command
== (char *)NULL
)
1583 ErrorF("XpSubmitJob: No spooler command found, cannot submit job.\n");
1587 cmdNam
= VectorizeCommand(command
, &vector
, pContext
);
1590 if(cmdNam
== (char *)NULL
)
1593 for(i
= 0; vector
[i
] != (char *)NULL
; i
++)
1595 vector
[i
] = ReplaceAllKeywords(pContext
, vector
[i
]);
1596 if(vector
[i
] == (char *)NULL
)
1599 for(i
= 0; vector
[i
] != (char *)NULL
; i
++)
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
);
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.
1629 SearchInputTrays(XpContextPtr pCon
,
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
);
1641 pLast
= copy
+ strlen( copy
);
1645 while( *pS
&& *pS
!= '{' )
1649 while( *pE
&& *pE
!= '}' )
1653 sscanf( pS
, "%s %s", tray
, medium
);
1655 if( which
== MEDIUM
&& !strcmp( val
, medium
) )
1658 return strdup( tray
);
1661 if( which
== TRAY
&& !strcmp( val
, tray
) )
1664 return strdup( medium
);
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.
1682 XpGetTrayMediumFromContext(XpContextPtr pCon
,
1686 char *defMedium
, *defTray
;
1689 defMedium
= XpGetOneAttribute( pCon
, XPPageAttr
,
1691 if( *defMedium
== '\0' )
1692 defMedium
= XpGetOneAttribute( pCon
, XPDocAttr
,
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
) )
1709 *tray
= strdup( defTray
);
1710 *medium
= strdup( defMedium
);
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
);
1722 *medium
= strdup( defMedium
);
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
);