1736 lines
		
	
	
		
			47 KiB
		
	
	
	
		
			C
		
	
	
	
			
		
		
	
	
			1736 lines
		
	
	
		
			47 KiB
		
	
	
	
		
			C
		
	
	
	
/*
 | 
						|
(c) Copyright 1996 Hewlett-Packard Company
 | 
						|
(c) Copyright 1996 International Business Machines Corp.
 | 
						|
(c) Copyright 1996 Sun Microsystems, Inc.
 | 
						|
(c) Copyright 1996 Novell, Inc.
 | 
						|
(c) Copyright 1996 Digital Equipment Corp.
 | 
						|
(c) Copyright 1996 Fujitsu Limited
 | 
						|
(c) Copyright 1996 Hitachi, Ltd.
 | 
						|
 | 
						|
Permission is hereby granted, free of charge, to any person obtaining a copy
 | 
						|
of this software and associated documentation files (the "Software"), to deal
 | 
						|
in the Software without restriction, including without limitation the rights
 | 
						|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 | 
						|
copies of the Software, and to permit persons to whom the Software is
 | 
						|
furnished to do so, subject to the following conditions:
 | 
						|
 | 
						|
The above copyright notice and this permission notice shall be included in
 | 
						|
all copies or substantial portions of the Software.
 | 
						|
 | 
						|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 | 
						|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 | 
						|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
 | 
						|
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
 | 
						|
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
 | 
						|
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 | 
						|
 | 
						|
Except as contained in this notice, the names of the copyright holders shall
 | 
						|
not be used in advertising or otherwise to promote the sale, use or other
 | 
						|
dealings in this Software without prior written authorization from said
 | 
						|
copyright holders.
 | 
						|
*/
 | 
						|
/*******************************************************************
 | 
						|
**
 | 
						|
**    *********************************************************
 | 
						|
**    *
 | 
						|
**    *  File:		attributes.c
 | 
						|
**    *
 | 
						|
**    *  Contents:
 | 
						|
**    *                 Implementation of the attribute store for Xp.
 | 
						|
**    *
 | 
						|
**    *  Copyright:	Copyright 1995 Hewlett-Packard Company
 | 
						|
**    *
 | 
						|
**    *********************************************************
 | 
						|
** 
 | 
						|
********************************************************************/
 | 
						|
 | 
						|
#ifdef HAVE_DIX_CONFIG_H
 | 
						|
#include <dix-config.h>
 | 
						|
#endif
 | 
						|
 | 
						|
#include <X11/Xproto.h>
 | 
						|
#include <stdio.h>
 | 
						|
#include <ctype.h>
 | 
						|
#include <string.h>
 | 
						|
#include <stdlib.h>
 | 
						|
#include <sys/wait.h>
 | 
						|
#include <pwd.h>
 | 
						|
#include <grp.h>
 | 
						|
#include <sys/types.h>
 | 
						|
#include <sys/stat.h>
 | 
						|
#include <unistd.h>
 | 
						|
 | 
						|
#if (defined(sun) && defined(SVR4)) || defined(__SCO__) || defined(__UNIXWARE__)
 | 
						|
#include <wchar.h>
 | 
						|
#endif
 | 
						|
#include "scrnintstr.h"
 | 
						|
 | 
						|
#include <X11/extensions/Printstr.h>
 | 
						|
 | 
						|
#include "attributes.h"
 | 
						|
 | 
						|
#include <X11/Xlib.h>
 | 
						|
#include <X11/Xresource.h>
 | 
						|
 | 
						|
#include "spooler.h"
 | 
						|
 | 
						|
#ifndef MIN
 | 
						|
#define MIN(a,b) (((a)<(b))?(a):(b))
 | 
						|
#endif
 | 
						|
#ifndef MAX
 | 
						|
#define MAX(a,b) (((a)>(b))?(a):(b))
 | 
						|
#endif
 | 
						|
 | 
						|
 | 
						|
static XrmDatabase CopyDb(XrmDatabase inDb);
 | 
						|
 | 
						|
extern XrmDatabase XpSpoolerGetServerAttributes(void);
 | 
						|
 | 
						|
static int attrGeneration = 0;
 | 
						|
 | 
						|
typedef struct {
 | 
						|
    XrmDatabase *pDb;
 | 
						|
    char *qualifier;
 | 
						|
    char *modelId;
 | 
						|
} DbEnumStruct;
 | 
						|
 | 
						|
typedef struct {
 | 
						|
    char *stringDb;
 | 
						|
    int nextPos;
 | 
						|
    int space;
 | 
						|
} StringDbStruct;
 | 
						|
 | 
						|
typedef struct _printerAttrs {
 | 
						|
    struct _printerAttrs *next;
 | 
						|
    char *name;
 | 
						|
    char *qualifier;
 | 
						|
    XrmDatabase printerAttrs;
 | 
						|
    XrmDatabase docAttrs;
 | 
						|
    XrmDatabase jobAttrs;
 | 
						|
} PrAttrs, *PrAttrPtr;
 | 
						|
 | 
						|
static PrAttrPtr attrList = (PrAttrPtr)NULL;
 | 
						|
 | 
						|
typedef struct _systemAttrs {
 | 
						|
    XrmDatabase doc;
 | 
						|
    XrmDatabase job;
 | 
						|
    XrmDatabase printers;
 | 
						|
    XrmDatabase server;
 | 
						|
} SysAttrs, *SysAttrsPtr;
 | 
						|
 | 
						|
SysAttrs systemAttributes;
 | 
						|
 | 
						|
/*
 | 
						|
 * attrCtxtPrivIndex hold the attribute store's context private index.
 | 
						|
 * This index is allocated at the time the attribute store is initialized.
 | 
						|
 */
 | 
						|
static int attrCtxtPrivIndex;
 | 
						|
 | 
						|
/*
 | 
						|
 * The ContextAttrs structure descibes the context private space reserved
 | 
						|
 * by the attribute store.
 | 
						|
 */
 | 
						|
typedef struct _contextAttrs {
 | 
						|
    XrmDatabase printerAttrs;
 | 
						|
    XrmDatabase docAttrs;
 | 
						|
    XrmDatabase jobAttrs;
 | 
						|
    XrmDatabase pageAttrs;
 | 
						|
} ContextAttrs, *ContextAttrPtr;
 | 
						|
 | 
						|
/*
 | 
						|
 * XPDIR is relative to (i.e. is a subdir of) XPRINTDIR/$LANG.
 | 
						|
 */
 | 
						|
static const char XPDIR[] = "/print";
 | 
						|
/*
 | 
						|
 * The following files/directories define or are within subdirectories of the 
 | 
						|
 * above-defined XPDIR.
 | 
						|
 */
 | 
						|
static const char XPPRINTERATTRFILE[] = "/attributes/printer";
 | 
						|
static const char XPJOBATTRFILE[] = "/attributes/job";
 | 
						|
static const char XPDOCATTRFILE[] = "/attributes/document";
 | 
						|
static const char XPMODELDIR[] = "/models";
 | 
						|
 | 
						|
static char NULL_STRING[] = "\0";
 | 
						|
 | 
						|
/*
 | 
						|
 * XpGetConfigDirBase returns a string containing the path name of the base
 | 
						|
 * where the print server configuration directory is localed.
 | 
						|
 */
 | 
						|
static
 | 
						|
char *XpGetConfigDirBase(void)
 | 
						|
{
 | 
						|
    char *configDir;
 | 
						|
 | 
						|
    /*
 | 
						|
     * If the XPCONFIGDIR environment variable is not set, then use the
 | 
						|
     * compile-time constant XPRINTDIR.  XPRINTDIR is passed in on the
 | 
						|
     * compile command line, and is defined in $(TOP)/config/cf/Project.tmpl.
 | 
						|
     */
 | 
						|
    if((configDir = getenv("XPCONFIGDIR")) == (char *)NULL)
 | 
						|
	configDir = XPRINTDIR;
 | 
						|
 | 
						|
    return configDir;
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
 * XpGetConfigDir returns a string containing the path name of the print
 | 
						|
 * server configuration directory.  If the useLocale parameter is False
 | 
						|
 * the it returns the path to the "/C" directory.  If the useLocale
 | 
						|
 * parameter is True it returns the path to the directory associated with
 | 
						|
 * $LANG.  It makes no attempt to ensure that the directory actually exists.
 | 
						|
 */
 | 
						|
char *
 | 
						|
XpGetConfigDir(Bool useLocale)
 | 
						|
{ 
 | 
						|
    char *dirName, *langName, *langDir, *configDir;
 | 
						|
    Bool freeLangDir = False;
 | 
						|
 | 
						|
    if(useLocale == False) langDir = "/C";
 | 
						|
    else 
 | 
						|
    {
 | 
						|
        langName = getenv("LC_ALL");
 | 
						|
        if (langName == NULL) {
 | 
						|
            langName = getenv("LANG");
 | 
						|
        }
 | 
						|
        
 | 
						|
	if(langName == (char *)NULL)
 | 
						|
	    return (char *)NULL;
 | 
						|
	else
 | 
						|
	{
 | 
						|
	    if(strcmp(langName, "C") == 0)
 | 
						|
		return (char *)NULL;
 | 
						|
	    langDir = (char *)xalloc(strlen(langName) + 2);
 | 
						|
	    sprintf(langDir, "/%s", langName);
 | 
						|
	    freeLangDir = True;
 | 
						|
	}
 | 
						|
    }
 | 
						|
    
 | 
						|
    configDir = XpGetConfigDirBase();
 | 
						|
 | 
						|
    dirName = (char *)xalloc(strlen(configDir) + strlen(XPDIR) + 
 | 
						|
			      strlen(langDir) + 1);
 | 
						|
    sprintf(dirName, "%s%s%s", configDir, langDir, XPDIR);
 | 
						|
 | 
						|
    if(freeLangDir == True)
 | 
						|
	xfree(langDir);
 | 
						|
 | 
						|
    return dirName;
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
 * GetMergedDatabase reads and merges xrmdb files from the top-level printer
 | 
						|
 * config directory, and from the directory associated with the current
 | 
						|
 * locale (if other than the top-level).
 | 
						|
 */
 | 
						|
static XrmDatabase
 | 
						|
GetMergedDatabase(const char *attrName)
 | 
						|
{
 | 
						|
    char *dirName, *fileName;
 | 
						|
    XrmDatabase db;
 | 
						|
 | 
						|
    if((dirName = XpGetConfigDir(False)) == (char *)NULL)
 | 
						|
	return (XrmDatabase)NULL;
 | 
						|
    if((fileName = (char *)xalloc(strlen(dirName) + strlen(attrName) + 1)) ==
 | 
						|
       (char *)NULL)
 | 
						|
	return (XrmDatabase)NULL;
 | 
						|
    sprintf(fileName, "%s%s", dirName, attrName);
 | 
						|
    db = XrmGetFileDatabase(fileName);
 | 
						|
    xfree(fileName);
 | 
						|
    xfree(dirName);
 | 
						|
 | 
						|
    if((dirName = XpGetConfigDir(True)) == (char *)NULL) 
 | 
						|
	return db;
 | 
						|
    if((fileName = (char *)xalloc(strlen(dirName) + strlen(attrName) + 1)) ==
 | 
						|
       (char *)NULL)
 | 
						|
	return db;
 | 
						|
    sprintf(fileName, "%s%s", dirName, attrName);
 | 
						|
    (void)XrmCombineFileDatabase(fileName, &db, True);
 | 
						|
    xfree(fileName);
 | 
						|
    xfree(dirName);
 | 
						|
 | 
						|
    return db;
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
 * BuildSystemAttributes reads the on-disk configuration files for printers,
 | 
						|
 * initial job, and initial document attributes.  The resulting xrm 
 | 
						|
 * databases are then dissected as needed for each printer.
 | 
						|
 * It also allocates a contextPrivate space for the attributes,
 | 
						|
 * reserving space to store pointers to the attribute stores for
 | 
						|
 * the context.
 | 
						|
 */
 | 
						|
static void
 | 
						|
BuildSystemAttributes(void)
 | 
						|
{
 | 
						|
    if(systemAttributes.printers != (XrmDatabase)NULL)
 | 
						|
	XrmDestroyDatabase(systemAttributes.printers);
 | 
						|
    systemAttributes.printers = GetMergedDatabase(XPPRINTERATTRFILE);
 | 
						|
    if(systemAttributes.job != (XrmDatabase)NULL)
 | 
						|
	XrmDestroyDatabase(systemAttributes.job);
 | 
						|
    systemAttributes.job = GetMergedDatabase(XPJOBATTRFILE);
 | 
						|
    if(systemAttributes.doc != (XrmDatabase)NULL)
 | 
						|
	XrmDestroyDatabase(systemAttributes.doc);
 | 
						|
    systemAttributes.doc = GetMergedDatabase(XPDOCATTRFILE);
 | 
						|
    if(systemAttributes.server != (XrmDatabase)NULL)
 | 
						|
	XrmDestroyDatabase(systemAttributes.server);
 | 
						|
    systemAttributes.server = XpSpoolerGetServerAttributes();
 | 
						|
    return;
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
 * AddDbEntry is called by XrmEnumerateDatabase, and adds the supplied
 | 
						|
 * database entry to the database pointed to within the "DbEnumStruct"
 | 
						|
 * passed as the client_data (aka "closure").
 | 
						|
 */
 | 
						|
static Bool
 | 
						|
AddDbEntry(
 | 
						|
    XrmDatabase *sourceDB,
 | 
						|
    XrmBindingList bindings,
 | 
						|
    XrmQuarkList quarks,
 | 
						|
    XrmRepresentation *type,
 | 
						|
    XrmValue *value,
 | 
						|
    XPointer client_data)
 | 
						|
{
 | 
						|
    DbEnumStruct *pEnumStruct = (DbEnumStruct *)client_data;
 | 
						|
    XrmName xrm_name[5];
 | 
						|
    XrmClass xrm_class[5];
 | 
						|
    XrmBinding xrm_bind[3];
 | 
						|
    XrmValue realVal;
 | 
						|
    XrmRepresentation rep_type;
 | 
						|
 | 
						|
    xrm_name[0] = XrmStringToQuark (pEnumStruct->qualifier);
 | 
						|
    xrm_class[0] = XrmStringToQuark (pEnumStruct->modelId);
 | 
						|
 | 
						|
    for(;*quarks; quarks++)
 | 
						|
	xrm_name[1] = xrm_class[1] = *quarks;
 | 
						|
 | 
						|
    xrm_name[2] = (XrmQuark)NULL;
 | 
						|
    xrm_class[2] = (XrmQuark)NULL;
 | 
						|
 | 
						|
    if(XrmQGetResource (*sourceDB, xrm_name, xrm_class, &rep_type, &realVal))
 | 
						|
    {
 | 
						|
        xrm_bind[0] = XrmBindLoosely;
 | 
						|
 | 
						|
	xrm_name[0] = xrm_name[1];
 | 
						|
	xrm_name[1] = NULLQUARK;
 | 
						|
 | 
						|
        XrmQPutStringResource(pEnumStruct->pDb, xrm_bind, xrm_name, 
 | 
						|
			      (char *)realVal.addr);
 | 
						|
    }
 | 
						|
    
 | 
						|
    return FALSE;
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
 * BuildPrinterAttrs - builds and returns an XrmDatabase for the printer
 | 
						|
 * of the specified name/qualifier, if we have enough information.
 | 
						|
 * If we don't have a model-config
 | 
						|
 * file, then just enumerate the systemAttributes->printers database, 
 | 
						|
 * otherwise read in the model-config database and merge into it the
 | 
						|
 * systemAttributes->printers database.  This database is then enumerated
 | 
						|
 * with the printer qualifier (and the model name as class if we have it), and
 | 
						|
 * the resulting elements are stored into the database for this particular
 | 
						|
 * printer.
 | 
						|
 */
 | 
						|
static XrmDatabase
 | 
						|
BuildPrinterAttrs(
 | 
						|
    char *printerName,
 | 
						|
    char *qualifierName)
 | 
						|
{
 | 
						|
    XrmDatabase printerDB = (XrmDatabase)NULL;
 | 
						|
 | 
						|
    if(systemAttributes.printers != (XrmDatabase)NULL)
 | 
						|
    {
 | 
						|
        char *fileName;
 | 
						|
        XrmDatabase modelDB = (XrmDatabase)NULL;
 | 
						|
        XrmName xrm_name[5], xrm_class[2];
 | 
						|
        XrmRepresentation rep_type;
 | 
						|
        XrmValue value;
 | 
						|
        DbEnumStruct enumStruct;
 | 
						|
        Bool freeModelDB = False;
 | 
						|
        /*
 | 
						|
         * Build the initial db based on the model-config files
 | 
						|
         */
 | 
						|
        xrm_name[0] = XrmStringToQuark (qualifierName);
 | 
						|
        xrm_name[1] = XrmStringToQuark ("xp-model-identifier");
 | 
						|
        xrm_name[2] = (XrmQuark)NULL;
 | 
						|
        XrmQGetResource (systemAttributes.printers, xrm_name, xrm_name, 
 | 
						|
			 &rep_type, &value);
 | 
						|
 | 
						|
        if(value.addr != (XPointer)NULL)
 | 
						|
        {
 | 
						|
            fileName = (char *)xalloc(strlen(XPMODELDIR) + 
 | 
						|
				      strlen((char *)value.addr) + 
 | 
						|
				      strlen("model-config") + 3);
 | 
						|
	    sprintf(fileName, "%s/%s/%s", XPMODELDIR, value.addr,
 | 
						|
		    "model-config");
 | 
						|
	    modelDB = GetMergedDatabase(fileName);
 | 
						|
            xfree(fileName);
 | 
						|
	    if(modelDB != (XrmDatabase)NULL)
 | 
						|
	    {
 | 
						|
		XrmDatabase tempDB = (XrmDatabase)NULL;
 | 
						|
		/*
 | 
						|
		 * have to make a temp copy because MergeDatabase destroys
 | 
						|
		 * the "source" database. Merge in the printers DB
 | 
						|
		 */
 | 
						|
		tempDB = CopyDb(systemAttributes.printers);
 | 
						|
		XrmMergeDatabases(tempDB, &modelDB);
 | 
						|
		freeModelDB = True;
 | 
						|
	    }
 | 
						|
        }
 | 
						|
 | 
						|
	/*
 | 
						|
	 * Check to see if we knew the name AND found a database file
 | 
						|
	 */
 | 
						|
	if(modelDB == (XrmDatabase)NULL)
 | 
						|
	     modelDB = systemAttributes.printers;
 | 
						|
 | 
						|
        xrm_name[0] = XrmStringToQuark (qualifierName);
 | 
						|
	xrm_name[1] = (XrmQuark)NULL;
 | 
						|
	xrm_class[0] = XrmStringToQuark((char *)value.addr);
 | 
						|
	xrm_class[1] = (XrmQuark)NULL;
 | 
						|
	enumStruct.pDb = &printerDB;
 | 
						|
	enumStruct.qualifier = (char *)qualifierName;
 | 
						|
	enumStruct.modelId = (char *)value.addr;
 | 
						|
	XrmEnumerateDatabase(modelDB, xrm_name, xrm_class, XrmEnumAllLevels,
 | 
						|
			     AddDbEntry, (XPointer) &enumStruct);
 | 
						|
 | 
						|
        if(freeModelDB == True) XrmDestroyDatabase(modelDB);
 | 
						|
    }
 | 
						|
    XrmPutStringResource(&printerDB, "*printer-name", printerName);
 | 
						|
    XrmPutStringResource(&printerDB, "*qualifier", qualifierName);
 | 
						|
    return printerDB;
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
 * BuildABase - builds an XrmDatabase by enumerating the supplied sourceBase
 | 
						|
 * database for elements relevant for the printer named by printerName,
 | 
						|
 * and deriving a class for printerName from the model declared in the
 | 
						|
 * systemAttributes.printers database.  If no model is defined for this
 | 
						|
 * printer then the printerName is used as the class as well.
 | 
						|
 * 
 | 
						|
 * This is used to build the initial value document and initial value
 | 
						|
 * job attribute databases for each printer by searching the system
 | 
						|
 * level doc and job databases.
 | 
						|
 */
 | 
						|
static XrmDatabase
 | 
						|
BuildABase(
 | 
						|
    char *printerName,
 | 
						|
    char *qualifierName,
 | 
						|
    XrmDatabase sourceBase)
 | 
						|
{
 | 
						|
    XrmDatabase builtDB = (XrmDatabase)NULL;
 | 
						|
 | 
						|
    if(sourceBase != (XrmDatabase)NULL)
 | 
						|
    {
 | 
						|
        XrmName xrm_name[5], xrm_class[2];
 | 
						|
        XrmRepresentation rep_type;
 | 
						|
        XrmValue value;
 | 
						|
        DbEnumStruct enumStruct;
 | 
						|
 | 
						|
        /*
 | 
						|
         * Retrieve the model name for use as the class.
 | 
						|
         */
 | 
						|
        xrm_name[0] = XrmStringToQuark (printerName);
 | 
						|
        xrm_name[1] = XrmStringToQuark ("xp-model-identifier");
 | 
						|
        xrm_name[2] = (XrmQuark)NULL;
 | 
						|
        XrmQGetResource (systemAttributes.printers, xrm_name, xrm_name, 
 | 
						|
			 &rep_type, &value);
 | 
						|
	/*
 | 
						|
	 * if we have a model name then use it as the class, otherwise
 | 
						|
	 * just use the printer name as the class as well as the name.
 | 
						|
	 */
 | 
						|
        if(value.addr != (XPointer)NULL)
 | 
						|
	    xrm_class[0] = XrmStringToQuark((char *)value.addr);
 | 
						|
	else
 | 
						|
	    xrm_class[0] = xrm_name[0];
 | 
						|
	xrm_class[1] = (XrmQuark)NULL;
 | 
						|
 | 
						|
	xrm_name[1] = (XrmQuark)NULL;
 | 
						|
 | 
						|
	enumStruct.pDb = &builtDB;
 | 
						|
	enumStruct.qualifier = (char *)qualifierName;
 | 
						|
	enumStruct.modelId = (char *)value.addr;
 | 
						|
	XrmEnumerateDatabase(sourceBase, xrm_name, xrm_class, XrmEnumAllLevels,
 | 
						|
			     AddDbEntry, (XPointer) &enumStruct);
 | 
						|
    }
 | 
						|
 | 
						|
    XrmPutStringResource(&builtDB, "*qualifier", qualifierName);
 | 
						|
 | 
						|
    return builtDB;
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
 * FreeAttrList is called upon server recycle, and frees the printer
 | 
						|
 * databases stored in the global attrList.
 | 
						|
 */
 | 
						|
static void
 | 
						|
FreeAttrList(void)
 | 
						|
{
 | 
						|
    PrAttrPtr pAttr, pNext;
 | 
						|
 | 
						|
    for(pAttr = attrList, pNext = attrList; 
 | 
						|
	pAttr != (PrAttrPtr)NULL; 
 | 
						|
	pAttr = pNext)
 | 
						|
    {
 | 
						|
	pNext = pAttr->next;
 | 
						|
	if(pAttr->printerAttrs != (XrmDatabase)NULL)
 | 
						|
	    XrmDestroyDatabase(pAttr->printerAttrs);
 | 
						|
	if(pAttr->docAttrs != (XrmDatabase)NULL)
 | 
						|
	    XrmDestroyDatabase(pAttr->docAttrs);
 | 
						|
	if(pAttr->jobAttrs != (XrmDatabase)NULL)
 | 
						|
	    XrmDestroyDatabase(pAttr->jobAttrs);
 | 
						|
	xfree(pAttr->name);
 | 
						|
	xfree(pAttr->qualifier);
 | 
						|
	xfree(pAttr);
 | 
						|
    }
 | 
						|
    attrList = (PrAttrPtr)NULL;
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
 * XpRehashAttributes - frees the per-printer attribute list and
 | 
						|
 * calls BuildSystemAttributes to rebuild the overall attribute
 | 
						|
 * store.  It is expected that a caller of this will follow it
 | 
						|
 * by calling XpBuildAttributeStore for a new list of printers.
 | 
						|
 */
 | 
						|
int
 | 
						|
XpRehashAttributes(void)
 | 
						|
{
 | 
						|
    if(attrList != (PrAttrPtr)NULL)
 | 
						|
        FreeAttrList();
 | 
						|
    BuildSystemAttributes();
 | 
						|
    return Success;
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
 * XpBuildAttributeStore - creates the attribute database associated
 | 
						|
 * with the specified printer.  The first time this is called it
 | 
						|
 * calls BuildSystemAttributes to create the system-level databases.
 | 
						|
 */
 | 
						|
void
 | 
						|
XpBuildAttributeStore(
 | 
						|
    char *printerName,
 | 
						|
    char *qualifierName)
 | 
						|
{
 | 
						|
    PrAttrPtr pAttr;
 | 
						|
 | 
						|
    if((pAttr = (PrAttrPtr)xalloc(sizeof(PrAttrs))) == (PrAttrPtr)NULL)
 | 
						|
	return;
 | 
						|
 | 
						|
    if(attrGeneration != serverGeneration)
 | 
						|
    {
 | 
						|
	if(attrList != (PrAttrPtr)NULL)
 | 
						|
	    FreeAttrList();
 | 
						|
        attrCtxtPrivIndex = XpAllocateContextPrivateIndex();
 | 
						|
        XpAllocateContextPrivate(attrCtxtPrivIndex, sizeof(ContextAttrs));
 | 
						|
	BuildSystemAttributes();
 | 
						|
 | 
						|
	attrGeneration = serverGeneration;
 | 
						|
    }
 | 
						|
 | 
						|
    if(attrList == (PrAttrPtr)NULL)
 | 
						|
    {
 | 
						|
	pAttr->next = (PrAttrPtr)NULL;
 | 
						|
	attrList = pAttr;
 | 
						|
    }
 | 
						|
    else
 | 
						|
    {
 | 
						|
	pAttr->next = attrList;
 | 
						|
	attrList = pAttr;
 | 
						|
    }
 | 
						|
 | 
						|
    pAttr->name = strdup(printerName);
 | 
						|
    pAttr->qualifier = strdup(qualifierName);
 | 
						|
    pAttr->printerAttrs = BuildPrinterAttrs(printerName, qualifierName);
 | 
						|
    pAttr->docAttrs = BuildABase(printerName, qualifierName, 
 | 
						|
				 systemAttributes.doc);
 | 
						|
    pAttr->jobAttrs = BuildABase(printerName, qualifierName,
 | 
						|
				 systemAttributes.job);
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
static Bool
 | 
						|
StoreEntry(
 | 
						|
    XrmDatabase *sourceDB,
 | 
						|
    XrmBindingList bindings,
 | 
						|
    XrmQuarkList quarks,
 | 
						|
    XrmRepresentation *type,
 | 
						|
    XrmValue *value,
 | 
						|
    XPointer client_data)
 | 
						|
{
 | 
						|
    XrmDatabase *outDb = (XrmDatabase *)client_data;
 | 
						|
 | 
						|
    XrmQPutStringResource(outDb, bindings, quarks, (char *)value->addr);
 | 
						|
    
 | 
						|
    return FALSE;
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
 * XpCopyDb - makes a copy of the specified XrmDatabase and returns
 | 
						|
 * the copy.
 | 
						|
 */
 | 
						|
static XrmDatabase
 | 
						|
CopyDb(XrmDatabase inDb)
 | 
						|
{
 | 
						|
    XrmDatabase outDb = (XrmDatabase)NULL;
 | 
						|
    XrmQuark empty = NULLQUARK;
 | 
						|
 | 
						|
    (void)XrmEnumerateDatabase(inDb, &empty, &empty, XrmEnumAllLevels,
 | 
						|
			       StoreEntry, (XPointer) &outDb);
 | 
						|
    return outDb;
 | 
						|
}
 | 
						|
 | 
						|
/* 
 | 
						|
 * XpInitAttributes - initializes the attribute store for the specified
 | 
						|
 * context.  It does this by making copies of the printer, doc, and job
 | 
						|
 * attributes databases for the printer associated with the context.
 | 
						|
 */
 | 
						|
void
 | 
						|
XpInitAttributes(XpContextPtr pContext)
 | 
						|
{
 | 
						|
    ContextAttrPtr pCtxtAttrs;
 | 
						|
    PrAttrPtr pPrAttr = attrList;
 | 
						|
 | 
						|
    /* Initialize all the pointers to NULL */
 | 
						|
    pCtxtAttrs = (ContextAttrPtr)pContext->devPrivates[attrCtxtPrivIndex].ptr;
 | 
						|
    (void)memset((void *)pCtxtAttrs, 0, (size_t) sizeof(ContextAttrs));
 | 
						|
 | 
						|
    for(pPrAttr = attrList; pPrAttr != (PrAttrPtr)NULL; pPrAttr = pPrAttr->next)
 | 
						|
	if(!strcmp(pPrAttr->name, pContext->printerName)) break;
 | 
						|
 | 
						|
    if(pPrAttr != (PrAttrPtr)NULL)
 | 
						|
    {
 | 
						|
	pCtxtAttrs->printerAttrs = CopyDb(pPrAttr->printerAttrs);
 | 
						|
	pCtxtAttrs->docAttrs = CopyDb(pPrAttr->docAttrs);
 | 
						|
	pCtxtAttrs->jobAttrs = CopyDb(pPrAttr->jobAttrs);
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
void
 | 
						|
XpDestroyAttributes(
 | 
						|
    XpContextPtr pContext)
 | 
						|
{
 | 
						|
    ContextAttrPtr pCtxtAttrs;
 | 
						|
 | 
						|
    pCtxtAttrs = (ContextAttrPtr)pContext->devPrivates[attrCtxtPrivIndex].ptr;
 | 
						|
 | 
						|
    if(pCtxtAttrs->printerAttrs != (XrmDatabase)NULL)
 | 
						|
	XrmDestroyDatabase(pCtxtAttrs->printerAttrs);
 | 
						|
    if(pCtxtAttrs->docAttrs != (XrmDatabase)NULL)
 | 
						|
	XrmDestroyDatabase(pCtxtAttrs->docAttrs);
 | 
						|
    if(pCtxtAttrs->jobAttrs != (XrmDatabase)NULL)
 | 
						|
	XrmDestroyDatabase(pCtxtAttrs->jobAttrs);
 | 
						|
    if(pCtxtAttrs->pageAttrs != (XrmDatabase)NULL)
 | 
						|
	XrmDestroyDatabase(pCtxtAttrs->pageAttrs);
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
 * XpGetOneAttribute returns the string value of the specified attribute
 | 
						|
 * in the specified class for the specified print context.  If the attribute
 | 
						|
 * doesn't exist in the database for this context, or if the class database
 | 
						|
 * doesn't exist for this context, then NULL is returned.  The caller must
 | 
						|
 * not free the returned string, as the returned pointer points into the
 | 
						|
 * database.  This function can also return a value from the server attributes,
 | 
						|
 * in which case the pContext parameter is ignored.
 | 
						|
 */
 | 
						|
char *
 | 
						|
XpGetOneAttribute(
 | 
						|
     XpContextPtr pContext,
 | 
						|
     XPAttributes class,
 | 
						|
     char *attributeName)
 | 
						|
{
 | 
						|
    ContextAttrPtr pCtxtAttrs;
 | 
						|
    XrmDatabase db = (XrmDatabase)NULL;
 | 
						|
    XrmName xrm_name[3];
 | 
						|
    XrmRepresentation rep_type;
 | 
						|
    XrmValue value;
 | 
						|
 | 
						|
    if(class == XPServerAttr)
 | 
						|
    {
 | 
						|
        if(systemAttributes.server == (XrmDatabase)NULL) 
 | 
						|
	    return NULL_STRING;
 | 
						|
 | 
						|
        xrm_name[0] = XrmStringToQuark (attributeName);
 | 
						|
        xrm_name[1] = (XrmQuark)NULL;
 | 
						|
        XrmQGetResource(systemAttributes.server, xrm_name, xrm_name, 
 | 
						|
			&rep_type, &value);
 | 
						|
 | 
						|
        if(value.addr == (char *)NULL) 
 | 
						|
	    return NULL_STRING;
 | 
						|
        return (char *)value.addr;
 | 
						|
    }
 | 
						|
    else
 | 
						|
    {
 | 
						|
        pCtxtAttrs=(ContextAttrPtr)pContext->devPrivates[attrCtxtPrivIndex].ptr;
 | 
						|
        switch(class)
 | 
						|
        {
 | 
						|
	    case XPPrinterAttr:
 | 
						|
	        db = pCtxtAttrs->printerAttrs;
 | 
						|
	        break;
 | 
						|
	    case XPDocAttr:
 | 
						|
	        db = pCtxtAttrs->docAttrs;
 | 
						|
	        break;
 | 
						|
	    case XPJobAttr:
 | 
						|
	        db = pCtxtAttrs->jobAttrs;
 | 
						|
	        break;
 | 
						|
	    case XPPageAttr:
 | 
						|
	        db = pCtxtAttrs->pageAttrs;
 | 
						|
	        break;
 | 
						|
	    default:
 | 
						|
	        break;
 | 
						|
        }
 | 
						|
    }
 | 
						|
    if(db == (XrmDatabase)NULL) 
 | 
						|
	return NULL_STRING;
 | 
						|
 | 
						|
    xrm_name[0] = XrmStringToQuark ("qualifier");
 | 
						|
    xrm_name[1] = (XrmQuark)NULL;
 | 
						|
    XrmQGetResource(db, xrm_name, xrm_name, &rep_type, &value);
 | 
						|
 | 
						|
    xrm_name[0] = XrmStringToQuark (value.addr);
 | 
						|
    xrm_name[1] = XrmStringToQuark (attributeName);
 | 
						|
    xrm_name[2] = (XrmQuark)NULL;
 | 
						|
    if(XrmQGetResource(db, xrm_name, xrm_name, &rep_type, &value))
 | 
						|
	return (char *)value.addr;
 | 
						|
    else
 | 
						|
        return NULL_STRING;
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
 * XpPutOneAttribute updates one attribute for the specified
 | 
						|
 * context and class. This function is intended for use by the attribute
 | 
						|
 * validation module which updates the XrmDatabases directly. This
 | 
						|
 * function does not recognize XPServerAttr.
 | 
						|
 */
 | 
						|
void
 | 
						|
XpPutOneAttribute(
 | 
						|
       XpContextPtr pContext,
 | 
						|
       XPAttributes class,
 | 
						|
       const char* attributeName,
 | 
						|
       const char* value)
 | 
						|
{
 | 
						|
    ContextAttrPtr pCtxtAttrs;
 | 
						|
    XrmDatabase db;
 | 
						|
    XrmBinding bindings[1];
 | 
						|
    XrmQuark quarks[2];
 | 
						|
    
 | 
						|
    pCtxtAttrs = (ContextAttrPtr)pContext->devPrivates[attrCtxtPrivIndex].ptr;
 | 
						|
    switch(class)
 | 
						|
    {
 | 
						|
    case XPPrinterAttr:
 | 
						|
	db = pCtxtAttrs->printerAttrs;
 | 
						|
	break;
 | 
						|
    case XPDocAttr:
 | 
						|
	db = pCtxtAttrs->docAttrs;
 | 
						|
	break;
 | 
						|
    case XPJobAttr:
 | 
						|
	db = pCtxtAttrs->jobAttrs;
 | 
						|
	break;
 | 
						|
    case XPPageAttr:
 | 
						|
	db =  pCtxtAttrs->pageAttrs;
 | 
						|
	break;
 | 
						|
    default:
 | 
						|
	return;
 | 
						|
    }
 | 
						|
    bindings[0] = XrmBindLoosely;
 | 
						|
    quarks[0] = XrmStringToQuark(attributeName);
 | 
						|
    quarks[1] = (XrmQuark)NULL;
 | 
						|
    XrmQPutStringResource(&db, bindings, quarks, value ? value : "");
 | 
						|
}
 | 
						|
 | 
						|
    
 | 
						|
 | 
						|
/*******************************************************************************
 | 
						|
 *
 | 
						|
 * The following routines: ExpandSpace, PutString, PutByte, and AppendEntry
 | 
						|
 * form the functional core of the GetAttributes routine.  Xrm does not
 | 
						|
 * supply a routine to form a string database from an XrmDatabase, except
 | 
						|
 * by writing the database to a file.  This code avoids the file system
 | 
						|
 * overhead, but is a bit clunky in its memory management.
 | 
						|
 *
 | 
						|
 ******************************************************************************/
 | 
						|
 | 
						|
/*
 | 
						|
 * ExpandSpace expands the memory allocated for the string database in
 | 
						|
 * the StringDbStruct passed in, and updates the "space" field of the
 | 
						|
 * struct to indicate the new amount of space available.
 | 
						|
 */
 | 
						|
static Bool
 | 
						|
ExpandSpace(
 | 
						|
    StringDbStruct *pStr)
 | 
						|
{
 | 
						|
    char *newSpace;
 | 
						|
 | 
						|
    if((newSpace = (char *)xrealloc(pStr->stringDb, pStr->nextPos + pStr->space
 | 
						|
				    + 1024)) == (char *)NULL)
 | 
						|
	return False;
 | 
						|
    pStr->space += 1024;
 | 
						|
    pStr->stringDb = newSpace;
 | 
						|
    return True;
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
 * PutString puts the contents of a null-terminated string into the string
 | 
						|
 * database in the StringDbStruct passed in.  If there is insufficient room
 | 
						|
 * for the string, ExpandSpace is called, and the nextPos and space fields
 | 
						|
 * are updated.
 | 
						|
 */
 | 
						|
static void
 | 
						|
PutString(
 | 
						|
    StringDbStruct *pStr,
 | 
						|
    char *pString)
 | 
						|
{
 | 
						|
    int len = strlen(pString);
 | 
						|
 | 
						|
    if(len >= pStr->space)
 | 
						|
	if(!ExpandSpace(pStr))
 | 
						|
	    return;
 | 
						|
    strcpy(&pStr->stringDb[pStr->nextPos], pString);
 | 
						|
    pStr->nextPos += len;
 | 
						|
    pStr->space -= len;
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
 * PutByte puts a single byte value in to the string database in the passed-in
 | 
						|
 * StringDbStruct.  ExpandSpace is called if there is insufficient room for
 | 
						|
 * the byte, and the nextPos and space fields are updated.
 | 
						|
 */
 | 
						|
static void
 | 
						|
PutByte(
 | 
						|
    StringDbStruct *pStr,
 | 
						|
    char byte)
 | 
						|
{
 | 
						|
    if(pStr->space <= 1)
 | 
						|
	if(!ExpandSpace(pStr))
 | 
						|
	    return;
 | 
						|
    pStr->stringDb[pStr->nextPos] = byte;
 | 
						|
    pStr->nextPos++;
 | 
						|
    pStr->space--;
 | 
						|
}
 | 
						|
 | 
						|
#define XrmQString XrmPermStringToQuark("String")
 | 
						|
 | 
						|
/*
 | 
						|
 * AppendEntry is called by XrmEnumerateDatabase, and serves to append
 | 
						|
 * a database entry onto a string database.  The passed-in "closure"
 | 
						|
 * struct contains a pointer to the string, and a count of the remaining
 | 
						|
 * bytes.  If there are insufficient remaining bytes then the struct
 | 
						|
 * is realloced, and the count of the space remaining is updated.
 | 
						|
 * Database elements of types other than String are ignored!
 | 
						|
 * This code is based directly on that in "DumpEntry" in Xrm.c.
 | 
						|
 */
 | 
						|
static Bool
 | 
						|
AppendEntry(
 | 
						|
    XrmDatabase         *db,
 | 
						|
    XrmBindingList      bindings,
 | 
						|
    XrmQuarkList        quarks,
 | 
						|
    XrmRepresentation   *type,
 | 
						|
    XrmValuePtr         value,
 | 
						|
    XPointer            data)
 | 
						|
{
 | 
						|
    StringDbStruct *pEnumStr = (StringDbStruct *)data;
 | 
						|
    Bool        firstNameSeen;
 | 
						|
    unsigned int i;
 | 
						|
    char *s, c;
 | 
						|
 | 
						|
    if (*type != XrmQString)
 | 
						|
	return False;
 | 
						|
 | 
						|
    for (firstNameSeen = False; *quarks; bindings++, quarks++) {
 | 
						|
        if (*bindings == XrmBindLoosely) {
 | 
						|
	    PutString(pEnumStr, "*");
 | 
						|
        } else if (firstNameSeen) {
 | 
						|
	    PutString(pEnumStr, ".");
 | 
						|
        }
 | 
						|
        firstNameSeen = True;
 | 
						|
	PutString(pEnumStr, XrmQuarkToString(*quarks));
 | 
						|
    }
 | 
						|
    s = value->addr;
 | 
						|
    i = value->size;
 | 
						|
    PutString(pEnumStr, ":\t");
 | 
						|
    if(i) i--;
 | 
						|
 | 
						|
    if (i && (*s == ' ' || *s == '\t'))
 | 
						|
        PutByte(pEnumStr, '\\'); /* preserve leading whitespace */
 | 
						|
 | 
						|
    while (i--) {
 | 
						|
        c = *s++;
 | 
						|
        if (c == '\n') {
 | 
						|
            if (i)
 | 
						|
                PutString(pEnumStr, "\\n\\\n");
 | 
						|
            else
 | 
						|
                PutString(pEnumStr, "\\n");
 | 
						|
        } else if (c == '\\')
 | 
						|
            PutString(pEnumStr, "\\\\");
 | 
						|
        else if ((c < ' ' && c != '\t') ||
 | 
						|
                 ((unsigned char)c >= 0x7f && (unsigned char)c < 0xa0))
 | 
						|
	{
 | 
						|
	    char temp[4];
 | 
						|
            (void) sprintf(temp, "\\%03o", (unsigned char)c);
 | 
						|
	    PutString(pEnumStr, temp);
 | 
						|
	}
 | 
						|
        else
 | 
						|
            PutByte(pEnumStr, c);
 | 
						|
    }
 | 
						|
    PutByte(pEnumStr, '\n');
 | 
						|
    pEnumStr->stringDb[pEnumStr->nextPos] = (char)'\0';
 | 
						|
    return False;
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
 * XpGetAttributes returns a string database version of the Xrm database
 | 
						|
 * for the specified context and class.  This function can also return the
 | 
						|
 * contents of the server attributes, in which case the pContext parameter
 | 
						|
 * is ignored. 
 | 
						|
 *
 | 
						|
 * The caller is responsible for freeing the returned string, 
 | 
						|
 * unlike XpGetOneAttribute, where the caller must not free the string.
 | 
						|
 */
 | 
						|
char *
 | 
						|
XpGetAttributes(
 | 
						|
     XpContextPtr pContext,
 | 
						|
     XPAttributes class)
 | 
						|
{
 | 
						|
    ContextAttrPtr pCtxtAttrs;
 | 
						|
    XrmDatabase db = (XrmDatabase)NULL;
 | 
						|
    StringDbStruct enumStruct;
 | 
						|
    XrmQuark empty = NULLQUARK;
 | 
						|
 | 
						|
    if(class == XPServerAttr)
 | 
						|
	db = systemAttributes.server;
 | 
						|
    else
 | 
						|
    {
 | 
						|
        pCtxtAttrs=(ContextAttrPtr)pContext->devPrivates[attrCtxtPrivIndex].ptr;
 | 
						|
        switch(class)
 | 
						|
        {
 | 
						|
	    case XPServerAttr:
 | 
						|
	        db = systemAttributes.server;
 | 
						|
	        break;
 | 
						|
	    case XPPrinterAttr:
 | 
						|
	        db = pCtxtAttrs->printerAttrs;
 | 
						|
	        break;
 | 
						|
	    case XPDocAttr:
 | 
						|
	        db = pCtxtAttrs->docAttrs;
 | 
						|
	        break;
 | 
						|
	    case XPJobAttr:
 | 
						|
	        db = pCtxtAttrs->jobAttrs;
 | 
						|
	        break;
 | 
						|
	    case XPPageAttr:
 | 
						|
	        db = pCtxtAttrs->pageAttrs;
 | 
						|
	        break;
 | 
						|
	    default:
 | 
						|
	        break;
 | 
						|
        }
 | 
						|
    }
 | 
						|
    if(db == (XrmDatabase)NULL) 
 | 
						|
    {
 | 
						|
	char *retval = (char *)xalloc(1);
 | 
						|
	retval[0] = (char)'\0';
 | 
						|
	return retval;
 | 
						|
    }
 | 
						|
 | 
						|
    if((enumStruct.stringDb = (char *)xalloc(1024)) == (char *)NULL)
 | 
						|
	return (char *)NULL;
 | 
						|
    enumStruct.stringDb[0] = (char)'\0';
 | 
						|
    enumStruct.nextPos = 0;
 | 
						|
    enumStruct.space = 1024;
 | 
						|
    (void)XrmEnumerateDatabase(db, &empty, &empty, XrmEnumAllLevels,
 | 
						|
			       AppendEntry, (XPointer) &enumStruct);
 | 
						|
 | 
						|
    return enumStruct.stringDb;
 | 
						|
}
 | 
						|
 | 
						|
int
 | 
						|
XpAugmentAttributes(
 | 
						|
     XpContextPtr pContext,
 | 
						|
     XPAttributes class,
 | 
						|
     char *attributes)
 | 
						|
{
 | 
						|
    XrmDatabase db;
 | 
						|
    ContextAttrPtr pCtxtAttrs;
 | 
						|
 | 
						|
    db = XrmGetStringDatabase(attributes);
 | 
						|
    if(db == (XrmDatabase)NULL) return BadAlloc;
 | 
						|
 | 
						|
    pCtxtAttrs = (ContextAttrPtr)pContext->devPrivates[attrCtxtPrivIndex].ptr;
 | 
						|
    switch(class)
 | 
						|
    {
 | 
						|
	case XPPrinterAttr:
 | 
						|
	    XrmMergeDatabases(db, &pCtxtAttrs->printerAttrs);
 | 
						|
	    break;
 | 
						|
	case XPDocAttr:
 | 
						|
	    XrmMergeDatabases(db, &pCtxtAttrs->docAttrs);
 | 
						|
	    break;
 | 
						|
	case XPJobAttr:
 | 
						|
	    XrmMergeDatabases(db, &pCtxtAttrs->jobAttrs);
 | 
						|
	    break;
 | 
						|
	case XPPageAttr:
 | 
						|
	    XrmMergeDatabases(db, &pCtxtAttrs->pageAttrs);
 | 
						|
	    break;
 | 
						|
	default:
 | 
						|
	    break;
 | 
						|
    }
 | 
						|
    return Success;
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
 * XpSetAttributes - sets the attribute stores for a specified context.
 | 
						|
 */
 | 
						|
int
 | 
						|
XpSetAttributes(
 | 
						|
     XpContextPtr pContext,
 | 
						|
     XPAttributes class,
 | 
						|
     char *attributes)
 | 
						|
{
 | 
						|
    XrmDatabase db;
 | 
						|
    ContextAttrPtr pCtxtAttrs;
 | 
						|
 | 
						|
    db = XrmGetStringDatabase(attributes);
 | 
						|
    if(db == (XrmDatabase)NULL) return BadAlloc;
 | 
						|
 | 
						|
    pCtxtAttrs=(ContextAttrPtr)pContext->devPrivates[attrCtxtPrivIndex].ptr;
 | 
						|
    switch(class)
 | 
						|
    {
 | 
						|
	case XPPrinterAttr:
 | 
						|
	    if(pCtxtAttrs->printerAttrs != (XrmDatabase)NULL)
 | 
						|
	        XrmDestroyDatabase(pCtxtAttrs->printerAttrs);
 | 
						|
	    pCtxtAttrs->printerAttrs = db;
 | 
						|
	    break;
 | 
						|
	case XPDocAttr:
 | 
						|
	    if(pCtxtAttrs->docAttrs != (XrmDatabase)NULL)
 | 
						|
	        XrmDestroyDatabase(pCtxtAttrs->docAttrs);
 | 
						|
	    pCtxtAttrs->docAttrs = db;
 | 
						|
	    break;
 | 
						|
	case XPJobAttr:
 | 
						|
	    if(pCtxtAttrs->jobAttrs != (XrmDatabase)NULL)
 | 
						|
	        XrmDestroyDatabase(pCtxtAttrs->jobAttrs);
 | 
						|
	    pCtxtAttrs->jobAttrs = db;
 | 
						|
	    break;
 | 
						|
	case XPPageAttr:
 | 
						|
	    if(pCtxtAttrs->pageAttrs != (XrmDatabase)NULL)
 | 
						|
	        XrmDestroyDatabase(pCtxtAttrs->pageAttrs);
 | 
						|
	    pCtxtAttrs->pageAttrs = db;
 | 
						|
	    break;
 | 
						|
	default:
 | 
						|
	    break;
 | 
						|
    }
 | 
						|
    return Success;
 | 
						|
}
 | 
						|
 | 
						|
void
 | 
						|
XpAddPrinterAttribute(
 | 
						|
    char *printerName,
 | 
						|
    char *printerQualifier,
 | 
						|
    char *attributeName,
 | 
						|
    char *attributeValue)
 | 
						|
{
 | 
						|
    PrAttrPtr pAttr;
 | 
						|
 | 
						|
    for(pAttr = attrList; pAttr != (PrAttrPtr)NULL; pAttr = pAttr->next)
 | 
						|
    {
 | 
						|
	if(!strcmp(printerQualifier, pAttr->qualifier))
 | 
						|
	{
 | 
						|
            XrmPutStringResource(&pAttr->printerAttrs, attributeName, 
 | 
						|
				 attributeValue);
 | 
						|
	    break;
 | 
						|
	}
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
const char *
 | 
						|
XpGetPrinterAttribute(const char *printerName,
 | 
						|
		      const char *attribute)
 | 
						|
{
 | 
						|
    PrAttrPtr pAttr;
 | 
						|
    XrmValue value;
 | 
						|
    char *type;
 | 
						|
 | 
						|
    for(pAttr = attrList; pAttr != (PrAttrPtr)NULL; pAttr = pAttr->next)
 | 
						|
    {
 | 
						|
        if(!strcmp(printerName, pAttr->qualifier))
 | 
						|
        {
 | 
						|
	    char *attrStr;
 | 
						|
 | 
						|
	    attrStr = (char *)xalloc(strlen(printerName) + strlen(attribute) +
 | 
						|
				     2);
 | 
						|
	    sprintf(attrStr, "%s.%s", printerName, attribute);
 | 
						|
            XrmGetResource(pAttr->printerAttrs, attrStr, attrStr,
 | 
						|
                           &type, &value);
 | 
						|
	    xfree(attrStr);
 | 
						|
            break;
 | 
						|
        }
 | 
						|
    }
 | 
						|
    if(value.addr != (XPointer)NULL && strlen(value.addr) != 0)
 | 
						|
	return value.addr;
 | 
						|
    else
 | 
						|
      return "";
 | 
						|
}
 | 
						|
 | 
						|
/*******************************************************************************
 | 
						|
 *
 | 
						|
 * The following routines are not attribute routines, but are rather
 | 
						|
 * spooler interface functions.  They should presumably move to 
 | 
						|
 * a SpoolerIf.c of some similarly named file.
 | 
						|
 *
 | 
						|
 ******************************************************************************/
 | 
						|
#include <locale.h>
 | 
						|
 | 
						|
static char serverAttrStr[] = "*document-attributes-supported:	copy-count\n\
 | 
						|
*job-attributes-supported:	job-name job-owner\
 | 
						|
 notification-profile xp-spooler-command-options\n\
 | 
						|
*multiple-documents-supported:	False";
 | 
						|
 | 
						|
XrmDatabase
 | 
						|
XpSpoolerGetServerAttributes(void)
 | 
						|
{
 | 
						|
    char *totalAttrs, *localeName;
 | 
						|
    XrmDatabase db;
 | 
						|
 | 
						|
    localeName = setlocale(LC_CTYPE, (char *)NULL);
 | 
						|
    if(!localeName || strlen(localeName) == 0)
 | 
						|
	localeName = "C";
 | 
						|
 | 
						|
    if((totalAttrs = (char *)xalloc(strlen(serverAttrStr) + strlen(localeName)
 | 
						|
				    + 11)) == (char *)NULL)
 | 
						|
	return (XrmDatabase)NULL;
 | 
						|
    sprintf(totalAttrs, "%s\n%s\t%s", serverAttrStr, "*locale:", localeName);
 | 
						|
 | 
						|
    db =  XrmGetStringDatabase(totalAttrs);
 | 
						|
    xfree(totalAttrs);
 | 
						|
    return db;
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
 * Tailf() works similar to "/bin/tail -f fd_in >fd_out" until
 | 
						|
 * the process |child| terminates (the child status is
 | 
						|
 * returned in |child_status|).
 | 
						|
 * This function is used to copy the stdout/stderr output of a
 | 
						|
 * child to fd_out until the child terminates.
 | 
						|
 */
 | 
						|
static
 | 
						|
void Tailf(int fd_in, int fd_out, pid_t child, int *child_status)
 | 
						|
{
 | 
						|
    char           b[256];
 | 
						|
    ssize_t        sz;
 | 
						|
    Bool           childDone = FALSE;
 | 
						|
    struct timeval timeout;
 | 
						|
    long           fpos = 0; /* XXX: this is not correct for largefile support */
 | 
						|
 | 
						|
    timeout.tv_sec  = 0;
 | 
						|
    timeout.tv_usec = 100000;
 | 
						|
 | 
						|
    for(;;)
 | 
						|
    {
 | 
						|
        /* Check whether the child is still alive or not */
 | 
						|
        if (waitpid(child, child_status, WNOHANG) == child)
 | 
						|
            childDone = TRUE;
 | 
						|
 | 
						|
        /* Copy traffic from |fd_in| to |fd_out|
 | 
						|
         * (Note we have to use |pread()| here to avoid race conditions
 | 
						|
         * between a child process writing to the same file using the
 | 
						|
         * same file pointer (|dup(2)| and |fork(2)| just duplicate the
 | 
						|
         * file handle but not the pointer)).
 | 
						|
         */
 | 
						|
        while ((sz = pread(fd_in, b, sizeof(b), fpos)) > 0)
 | 
						|
        {
 | 
						|
            fpos += sz;
 | 
						|
            write(fd_out, b, sz);
 | 
						|
        }
 | 
						|
 | 
						|
        if (childDone)
 | 
						|
            break;
 | 
						|
 | 
						|
        (void)select(0, NULL, NULL, NULL, &timeout);
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
 * SendFileToCommand takes three character pointers - the file name,
 | 
						|
 * the command to execute,
 | 
						|
 * and the "argv" style NULL-terminated vector of arguments for the command.
 | 
						|
 * The command is exec'd, and the file contents are sent to the command
 | 
						|
 * via stdin.
 | 
						|
 *
 | 
						|
 * WARNING:  This function will try to adopt the userId of the supplied
 | 
						|
 *           user name prior to exec'ing the supplied command.
 | 
						|
 */
 | 
						|
static void
 | 
						|
SendFileToCommand(
 | 
						|
    XpContextPtr pContext,
 | 
						|
    char *fileName,
 | 
						|
    char *pCommand,
 | 
						|
    char **argVector,
 | 
						|
    char *userName)
 | 
						|
{
 | 
						|
    pid_t childPid;
 | 
						|
    int pipefd[2];
 | 
						|
    int status;
 | 
						|
    struct stat statBuf;
 | 
						|
    FILE *fp, *outPipe;
 | 
						|
    FILE *resFp; /* output from launched command */
 | 
						|
    int   resfd;
 | 
						|
    
 | 
						|
    resFp = tmpfile();
 | 
						|
    if (resFp == NULL)
 | 
						|
    {
 | 
						|
        ErrorF("SendFileToCommand: Cannot open temporary file for command output\n");
 | 
						|
        return;
 | 
						|
    }
 | 
						|
    resfd = fileno(resFp);
 | 
						|
 | 
						|
    if(pipe(pipefd))
 | 
						|
    {
 | 
						|
        ErrorF("SendFileToCommand: Cannot open pipe\n");
 | 
						|
        fclose(resFp);
 | 
						|
        return;
 | 
						|
    }
 | 
						|
 | 
						|
    if(stat(fileName, &statBuf) < 0 || (int)statBuf.st_size == 0)
 | 
						|
    {
 | 
						|
        close(pipefd[0]);
 | 
						|
        close(pipefd[1]);
 | 
						|
        fclose(resFp);
 | 
						|
        return;
 | 
						|
    }
 | 
						|
 | 
						|
    fp = fopen(fileName, "r");
 | 
						|
    if(fp == (FILE *)NULL)
 | 
						|
    {
 | 
						|
        ErrorF("SendFileToCommand: Cannot open scratch spool file '%s'\n", fileName);
 | 
						|
        close(pipefd[0]);
 | 
						|
        close(pipefd[1]);
 | 
						|
        fclose(resFp);
 | 
						|
        return;
 | 
						|
    }
 | 
						|
    
 | 
						|
    if((childPid = fork()) == 0)
 | 
						|
    {
 | 
						|
        close(pipefd[1]);
 | 
						|
 | 
						|
        /* Replace current stdin with input from the pipe */
 | 
						|
	close(STDIN_FILENO);
 | 
						|
	dup(pipefd[0]);
 | 
						|
	close(pipefd[0]);
 | 
						|
 | 
						|
        /* Close current stdout and redirect it to resfd */
 | 
						|
        close(STDOUT_FILENO);
 | 
						|
        dup(resfd);
 | 
						|
 | 
						|
        /* Close current stderr and redirect it to resfd
 | 
						|
         * (valgrind may not like that, in this case simply start it using
 | 
						|
         * % valgrind 50>/dev/tty --logfile-fd=50 <more-options> ./Xprt ... #)
 | 
						|
         */
 | 
						|
        close(STDERR_FILENO);
 | 
						|
        dup(resfd);
 | 
						|
 | 
						|
        fclose(resFp);
 | 
						|
        
 | 
						|
	/*
 | 
						|
	 * If a user name is specified, try to set our uid to match that
 | 
						|
	 * user name.  This is to allow e.g. a banner page to show the
 | 
						|
	 * name of the printing user rather than the user who started
 | 
						|
	 * the print server.
 | 
						|
	 */
 | 
						|
	if(userName)
 | 
						|
	{
 | 
						|
	    uid_t myUid;
 | 
						|
 | 
						|
	    if((myUid = geteuid()) == (uid_t)0)
 | 
						|
	    {
 | 
						|
	        struct passwd *pPasswd;
 | 
						|
 | 
						|
	        if((pPasswd = getpwnam(userName)))
 | 
						|
	        {
 | 
						|
                    if (setgid((gid_t)pPasswd->pw_gid) != 0)
 | 
						|
                        perror("SendFileToCommand: setgid() failure.");
 | 
						|
 | 
						|
                    if (initgroups(userName, (gid_t)pPasswd->pw_gid) != 0)
 | 
						|
                        perror("SendFileToCommand: initgroups() failure.");
 | 
						|
 | 
						|
                    if (setuid((uid_t)pPasswd->pw_uid) != 0)
 | 
						|
                        perror("SendFileToCommand: setuid() failure.");
 | 
						|
	        }
 | 
						|
	    }
 | 
						|
	}
 | 
						|
	/* return BadAlloc? */
 | 
						|
	if (execv(pCommand, argVector) == -1) {
 | 
						|
	    FatalError("unable to exec '%s'", pCommand);
 | 
						|
	}
 | 
						|
    }
 | 
						|
    else
 | 
						|
    {
 | 
						|
	(void) close(pipefd[0]);
 | 
						|
 | 
						|
 	outPipe = fdopen(pipefd[1], "w");
 | 
						|
	(void) TransferBytes(fp, outPipe, (int)statBuf.st_size);
 | 
						|
	
 | 
						|
	(void) fclose(outPipe);
 | 
						|
	(void) fclose(fp);
 | 
						|
 | 
						|
        /* Wait for spooler child (and send all it's output to stderr) */
 | 
						|
        Tailf(resfd, STDERR_FILENO, childPid, &status);
 | 
						|
        
 | 
						|
        if (status != EXIT_SUCCESS)
 | 
						|
        {
 | 
						|
            ErrorF("SendFileToCommand: spooler command returned non-zero status %d.\n", status);
 | 
						|
        }
 | 
						|
 | 
						|
        /* Store "xp-spooler-command-results" XPJobAttr that the
 | 
						|
         * client can fetch it on demand */
 | 
						|
        if ((fstat(resfd, &statBuf) >= 0) && (statBuf.st_size >= 0))
 | 
						|
        {
 | 
						|
            long  bufSize;
 | 
						|
            char *buf;
 | 
						|
 | 
						|
            bufSize = statBuf.st_size;
 | 
						|
 | 
						|
            /* Clamp buffer size to 4MB to prevent that we allocate giant 
 | 
						|
             * buffers if the spooler goes mad and spams it's stdout/stderr
 | 
						|
             * channel. */
 | 
						|
            bufSize = MIN(bufSize, 4*1024*1024);
 | 
						|
 | 
						|
            buf = xalloc(bufSize+1);
 | 
						|
            if (buf != NULL)
 | 
						|
            {
 | 
						|
                bufSize = pread(resfd, buf, bufSize, 0);
 | 
						|
                buf[bufSize]='\0';
 | 
						|
 | 
						|
                /* XXX: This should be converted from local multibyte encoding to
 | 
						|
                 * Compound Text encoding first */
 | 
						|
                XpPutOneAttribute(pContext, XPJobAttr, "xp-spooler-command-results", buf);
 | 
						|
 | 
						|
                xfree(buf);
 | 
						|
            }
 | 
						|
        }
 | 
						|
        else
 | 
						|
        {
 | 
						|
            ErrorF("SendFileToCommand: fstat() failed.\n");
 | 
						|
        }
 | 
						|
 | 
						|
        fclose(resFp);
 | 
						|
    }
 | 
						|
    return;
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
 * ReplaceAllKeywords causes all the predefined keywords (e.g. %options%)
 | 
						|
 * to be replaced with the appropriate values derived from the attribute
 | 
						|
 * store for the supplied print context.  The ReplaceAnyString utility
 | 
						|
 * routine is used to perform the actual replacements.
 | 
						|
 */
 | 
						|
 | 
						|
static char *
 | 
						|
ReplaceAllKeywords(
 | 
						|
    XpContextPtr pContext,
 | 
						|
    char *command)
 | 
						|
{
 | 
						|
    char *cmdOpt;
 | 
						|
 | 
						|
    cmdOpt = XpGetOneAttribute(pContext, XPPrinterAttr, 
 | 
						|
			       "xp-spooler-printer-name");
 | 
						|
    if(cmdOpt != (char *)NULL && strlen(cmdOpt) != 0)
 | 
						|
        command = ReplaceAnyString(command, "%printer-name%", cmdOpt);
 | 
						|
    else
 | 
						|
        command = ReplaceAnyString(command, "%printer-name%", 
 | 
						|
			           pContext->printerName);
 | 
						|
 | 
						|
    cmdOpt = XpGetOneAttribute(pContext, XPDocAttr, "copy-count");
 | 
						|
    if(cmdOpt != (char *)NULL && strlen(cmdOpt) != 0)
 | 
						|
        command = ReplaceAnyString(command, "%copy-count%", cmdOpt);
 | 
						|
    else
 | 
						|
        command = ReplaceAnyString(command, "%copy-count%", "1");
 | 
						|
 | 
						|
    cmdOpt = XpGetOneAttribute(pContext, XPJobAttr, "job-name");
 | 
						|
    if(cmdOpt != (char *)NULL && strlen(cmdOpt) != 0)
 | 
						|
        command = ReplaceAnyString(command, "%job-name%", cmdOpt);
 | 
						|
    else
 | 
						|
        command = ReplaceAnyString(command, "%job-name%", "");
 | 
						|
 | 
						|
    cmdOpt = XpGetOneAttribute(pContext, XPJobAttr, "job-owner");
 | 
						|
    if(cmdOpt != (char *)NULL && strlen(cmdOpt) != 0)
 | 
						|
        command = ReplaceAnyString(command, "%job-owner%", cmdOpt);
 | 
						|
    else
 | 
						|
        command = ReplaceAnyString(command, "%job-owner%", "");
 | 
						|
 | 
						|
    cmdOpt = XpGetOneAttribute(pContext, XPJobAttr, 
 | 
						|
			       "xp-spooler-command-options");
 | 
						|
    if(cmdOpt != (char *)NULL && strlen(cmdOpt) != 0)
 | 
						|
        command = ReplaceAnyString(command, "%options%", cmdOpt);
 | 
						|
    else
 | 
						|
        command = ReplaceAnyString(command, "%options%", "");
 | 
						|
 | 
						|
    /* New in xprint.mozdev.org release 007 - replace "%xpconfigdir%" with
 | 
						|
     * location of $XPCONFIGDIR */
 | 
						|
    command = ReplaceAnyString(command, "%xpconfigdir%", XpGetConfigDirBase());
 | 
						|
 | 
						|
    return command;
 | 
						|
}
 | 
						|
 | 
						|
#ifdef __QNX__
 | 
						|
#define toascii( c ) ((unsigned)(c) & 0x007f)
 | 
						|
#endif
 | 
						|
 | 
						|
#if defined(CSRG_BASED) || \
 | 
						|
    defined(linux) || \
 | 
						|
    defined(__CYGWIN__) || \
 | 
						|
    (defined(sun) && !defined(SVR4)) || \
 | 
						|
    (defined(SVR4) && !defined(sun) && !defined(__UNIXWARE__)) || \
 | 
						|
    defined(ISC) || \
 | 
						|
    defined(Lynx) || \
 | 
						|
    defined(__QNX__) || \
 | 
						|
    defined(__DARWIN__)
 | 
						|
#define iswspace(c) (isascii(c) && isspace(toascii(c)))
 | 
						|
#endif
 | 
						|
 | 
						|
/*
 | 
						|
 * GetToken - takes in a string and returns a malloc'd copy of the
 | 
						|
 * first non-white-space sequence of characters in the string.
 | 
						|
 * It returns the number of _bytes_ (NOT characters) parsed through 
 | 
						|
 * the inStr to get to the end of the returned token.
 | 
						|
 */
 | 
						|
static int
 | 
						|
GetToken(
 | 
						|
    char *inStr,
 | 
						|
    char **outStr)
 | 
						|
{
 | 
						|
    size_t mbCurMax = MB_CUR_MAX;
 | 
						|
    wchar_t curChar;
 | 
						|
    int i, numBytes, byteLen = strlen(inStr);
 | 
						|
    char *tok;
 | 
						|
 | 
						|
    /*
 | 
						|
     * read through any leading white space.
 | 
						|
     */
 | 
						|
    for(i = 0, numBytes = 0; i < byteLen; i += numBytes)
 | 
						|
    {
 | 
						|
        numBytes = mbtowc(&curChar, &inStr[i], mbCurMax);
 | 
						|
        if(!iswspace(curChar))
 | 
						|
	    break;
 | 
						|
    }
 | 
						|
    tok = inStr + i;
 | 
						|
 | 
						|
    /*
 | 
						|
     * find the end of the token.
 | 
						|
     */
 | 
						|
    byteLen = strlen(tok);
 | 
						|
    for(i = 0, numBytes = 0; i < byteLen; i += numBytes)
 | 
						|
    {
 | 
						|
        numBytes = mbtowc(&curChar, &tok[i], mbCurMax);
 | 
						|
        if(iswspace(curChar))
 | 
						|
	    break;
 | 
						|
    }
 | 
						|
 | 
						|
    if((*outStr = (char *)xalloc(i + 1)) == (char *)NULL)
 | 
						|
	return 0;
 | 
						|
    strncpy(*outStr, tok, i);
 | 
						|
    (*outStr)[i] = (char)'\0';
 | 
						|
    return (tok + i) - inStr;
 | 
						|
}
 | 
						|
 | 
						|
static void
 | 
						|
FreeVector(
 | 
						|
    char **vector)
 | 
						|
{
 | 
						|
    int i;
 | 
						|
 | 
						|
    if(vector == (char **)NULL) return;
 | 
						|
 | 
						|
    for(i = 0; vector[i] != (char *)NULL; i++)
 | 
						|
	xfree(vector[i]);
 | 
						|
    xfree(vector);
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/*
 | 
						|
 * AddVector appends the pAddition arg vector to the pTarget arg vector.
 | 
						|
 * If the pTarget cannot be realloc'd, then pTarget is set to NULL.
 | 
						|
 */
 | 
						|
static void
 | 
						|
AddVector(
 | 
						|
    char ***pTarget,
 | 
						|
    char **pAddition)
 | 
						|
{
 | 
						|
    int numTarget, numAdd, i;
 | 
						|
 | 
						|
    for(numTarget = 0; (*pTarget)[numTarget] != (char *)NULL; numTarget++)
 | 
						|
	;
 | 
						|
    for(numAdd = 0; pAddition[numAdd] != (char *)NULL; numAdd++)
 | 
						|
	;
 | 
						|
 | 
						|
    *pTarget = (char **)xrealloc((void *)*pTarget, (numTarget + numAdd + 1) * 
 | 
						|
	       sizeof(char *));
 | 
						|
    if(*pTarget == (char **)NULL)
 | 
						|
	return;
 | 
						|
    for(i = 0; i < numAdd; i++)
 | 
						|
	(*pTarget)[numTarget + i] = pAddition[i];
 | 
						|
 | 
						|
    (*pTarget)[numTarget + numAdd] = (char *)NULL;
 | 
						|
}
 | 
						|
 | 
						|
static char **
 | 
						|
BuildArgVector(
 | 
						|
    char *argString,
 | 
						|
    XpContextPtr pContext)
 | 
						|
{
 | 
						|
    char **pVector;
 | 
						|
    char *curTok;
 | 
						|
    int numChars, i;
 | 
						|
    static int beenHere = 0; /* prevent recursion on embedded %options%
 | 
						|
			     */
 | 
						|
 | 
						|
    pVector = (char **)xalloc(sizeof(char *));
 | 
						|
    pVector[0] = (char *)NULL;
 | 
						|
    for(i = 0; (numChars = GetToken(argString, &curTok)) != 0; 
 | 
						|
	i++, argString += numChars)
 | 
						|
    {
 | 
						|
	if(beenHere || strcmp(curTok, "%options%"))
 | 
						|
	{
 | 
						|
	    if(curTok[0] == (char)'\0')
 | 
						|
	    {
 | 
						|
		xfree(curTok);
 | 
						|
	    }
 | 
						|
	    else
 | 
						|
	    {
 | 
						|
	        pVector = (char **)xrealloc((void *)pVector,
 | 
						|
					    (i + 2)*sizeof(char *));
 | 
						|
	        if(pVector == (char **)NULL)
 | 
						|
	            return (char **)NULL;
 | 
						|
	        pVector[i] = curTok;
 | 
						|
	        pVector[i + 1] = (char *)NULL;
 | 
						|
	    }
 | 
						|
	}
 | 
						|
	else if(!beenHere)
 | 
						|
	{
 | 
						|
	    char **optionsVec;
 | 
						|
 | 
						|
	    curTok = ReplaceAllKeywords(pContext, curTok);
 | 
						|
	    beenHere = 1;
 | 
						|
	    optionsVec = BuildArgVector(curTok, pContext);
 | 
						|
	    xfree(curTok);
 | 
						|
	    beenHere = 0;
 | 
						|
	    AddVector(&pVector, optionsVec);
 | 
						|
	    xfree(optionsVec);
 | 
						|
	}
 | 
						|
    }
 | 
						|
    if(numChars == 0 && curTok != (char *)NULL)
 | 
						|
	xfree(curTok);
 | 
						|
    return pVector;
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
 * VectorizeCommand takes a string and breaks it into a command name and
 | 
						|
 * an array of character pointers suitable for handing to execv.  The
 | 
						|
 * array is NULL-terminated.
 | 
						|
 * The returned char * is the command name, and should be freed when no
 | 
						|
 * longer needed.  The array elements returned in the pVector parameter 
 | 
						|
 * should be individually freed, and the array itself should also be
 | 
						|
 * freed when no longer needed.
 | 
						|
 */
 | 
						|
static char *
 | 
						|
VectorizeCommand(
 | 
						|
    char *command,
 | 
						|
    char ***pVector,
 | 
						|
    XpContextPtr pContext)
 | 
						|
{
 | 
						|
    char *cmdName;
 | 
						|
    int numChars;
 | 
						|
 | 
						|
    if(command == (char *)NULL)
 | 
						|
	return (char *)NULL;
 | 
						|
    
 | 
						|
    numChars = GetToken(command, &cmdName);
 | 
						|
 | 
						|
    if(cmdName == (char *)NULL)
 | 
						|
	return (char *)NULL;
 | 
						|
 | 
						|
    /* Mangle the command name, too... */
 | 
						|
    cmdName = ReplaceAllKeywords(pContext, cmdName);
 | 
						|
 | 
						|
    if(cmdName == (char *)NULL)
 | 
						|
	return (char *)NULL;
 | 
						|
 | 
						|
    *pVector = BuildArgVector(command, pContext);
 | 
						|
    
 | 
						|
    return cmdName;
 | 
						|
}
 | 
						|
 | 
						|
int
 | 
						|
XpSubmitJob(fileName, pContext)
 | 
						|
     char *fileName;
 | 
						|
     XpContextPtr pContext;
 | 
						|
{
 | 
						|
    char **vector, *cmdNam, *command, *userName;
 | 
						|
    int i;
 | 
						|
 | 
						|
    command = XpGetOneAttribute(pContext, XPPrinterAttr, "xp-spooler-command");
 | 
						|
    if(command == (char *)NULL || strlen(command) == 0)
 | 
						|
    {
 | 
						|
        if( spooler_type )
 | 
						|
        {
 | 
						|
	    command = strdup(spooler_type->spool_command);
 | 
						|
        }
 | 
						|
        else
 | 
						|
        {
 | 
						|
            ErrorF("XpSubmitJob: No default spool command defined.\n");
 | 
						|
        }
 | 
						|
    }
 | 
						|
    else
 | 
						|
    {
 | 
						|
	command = strdup(command);
 | 
						|
    }
 | 
						|
    if(command == (char *)NULL)
 | 
						|
    {
 | 
						|
        ErrorF("XpSubmitJob: No spooler command found, cannot submit job.\n");
 | 
						|
	return BadAlloc;
 | 
						|
    }
 | 
						|
    
 | 
						|
    cmdNam = VectorizeCommand(command, &vector, pContext);
 | 
						|
    xfree(command);
 | 
						|
 | 
						|
    if(cmdNam == (char *)NULL)
 | 
						|
	return BadAlloc;
 | 
						|
 | 
						|
    for(i = 0; vector[i] != (char *)NULL; i++)
 | 
						|
    {
 | 
						|
        vector[i] = ReplaceAllKeywords(pContext, vector[i]);
 | 
						|
	if(vector[i] == (char *)NULL)
 | 
						|
	{
 | 
						|
	    xfree(cmdNam);
 | 
						|
	    for(i = 0; vector[i] != (char *)NULL; i++)
 | 
						|
		xfree(vector[i]);
 | 
						|
	    xfree(vector);
 | 
						|
	    return BadAlloc;
 | 
						|
	}
 | 
						|
    }
 | 
						|
 | 
						|
    userName = XpGetOneAttribute(pContext, XPJobAttr, "job-owner");
 | 
						|
    if(userName != (char *)NULL && strlen(userName) == 0)
 | 
						|
	userName = (char *)NULL;
 | 
						|
 | 
						|
    SendFileToCommand(pContext, fileName, cmdNam, vector, userName);
 | 
						|
 | 
						|
    FreeVector(vector);
 | 
						|
    xfree(cmdNam);
 | 
						|
    
 | 
						|
    return Success;
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
 * SearchInputTrays()
 | 
						|
 *
 | 
						|
 * Given a tray, return the medium in the tray.  Conversely, given a
 | 
						|
 * medium, return a tray in which it can be found.  In either case,
 | 
						|
 * return NULL if the given tray or medium cannot be found.
 | 
						|
 */
 | 
						|
#define TRAY 0
 | 
						|
#define MEDIUM 1
 | 
						|
 | 
						|
static char *
 | 
						|
SearchInputTrays(XpContextPtr pCon,
 | 
						|
		 int which,
 | 
						|
		 char *val)
 | 
						|
{
 | 
						|
    char *inputTraysMedium, tray[80], medium[80], *copy;
 | 
						|
    char *pS, *pE, *pLast;
 | 
						|
    
 | 
						|
    inputTraysMedium = XpGetOneAttribute( pCon, XPPrinterAttr,
 | 
						|
					 "input-trays-medium" );
 | 
						|
    
 | 
						|
    copy = strdup( inputTraysMedium );
 | 
						|
    pS = copy;
 | 
						|
    pLast = copy + strlen( copy );
 | 
						|
    
 | 
						|
    while( pS < pLast )
 | 
						|
      {
 | 
						|
	  while( *pS && *pS != '{' )
 | 
						|
	    pS++;
 | 
						|
	  
 | 
						|
	  pE = ++pS;
 | 
						|
	  while( *pE && *pE != '}' )
 | 
						|
	    pE++;
 | 
						|
	  *pE = '\0';
 | 
						|
 | 
						|
	  sscanf( pS, "%s %s", tray, medium );
 | 
						|
 | 
						|
	  if( which == MEDIUM && !strcmp( val, medium ) )
 | 
						|
	    {
 | 
						|
		xfree( copy );
 | 
						|
		return strdup( tray );
 | 
						|
	    }
 | 
						|
 | 
						|
	  if( which == TRAY && !strcmp( val, tray ) )
 | 
						|
	    {
 | 
						|
		xfree( copy );
 | 
						|
		return strdup( medium );
 | 
						|
	    }
 | 
						|
	  
 | 
						|
	  pS = pE + 1;
 | 
						|
      }
 | 
						|
 | 
						|
    xfree( copy );
 | 
						|
    return strdup( NULL_STRING );
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
 * XpGetTrayMediumFromContext()
 | 
						|
 *
 | 
						|
 * Given a print context, hit the input-trays-medium,
 | 
						|
 * default-input-tray and default-medium attributes to find the
 | 
						|
 * appropriate tray to use, and the medium in that tray.
 | 
						|
 */
 | 
						|
void
 | 
						|
XpGetTrayMediumFromContext(XpContextPtr pCon,
 | 
						|
			   char **medium,
 | 
						|
			   char **tray)
 | 
						|
{
 | 
						|
    char *defMedium, *defTray;
 | 
						|
    char *t, *m;
 | 
						|
    
 | 
						|
    defMedium = XpGetOneAttribute( pCon, XPPageAttr, 
 | 
						|
				  "default-medium" );
 | 
						|
    if( *defMedium == '\0' )
 | 
						|
      defMedium = XpGetOneAttribute( pCon, XPDocAttr,
 | 
						|
				    "default-medium" );
 | 
						|
 | 
						|
    defTray = XpGetOneAttribute( pCon, XPPageAttr,
 | 
						|
				"default-input-tray" );
 | 
						|
    if( *defTray == '\0' )
 | 
						|
      defTray = XpGetOneAttribute( pCon, XPDocAttr,
 | 
						|
				  "default-input-tray" );
 | 
						|
 | 
						|
    /*
 | 
						|
     * First, check to see if the default tray has the default medium
 | 
						|
     * installed.  This is the ideal case.
 | 
						|
     */
 | 
						|
    m = SearchInputTrays( pCon, TRAY, defTray );
 | 
						|
    if( !strcmp( m, defMedium ) )
 | 
						|
      {
 | 
						|
	  xfree( m );
 | 
						|
	  *tray = strdup( defTray );
 | 
						|
	  *medium = strdup( defMedium );
 | 
						|
	  return;
 | 
						|
      }
 | 
						|
 | 
						|
    /*
 | 
						|
     * If the default tray doesn't have the default medium, search for
 | 
						|
     * a tray which has the default medium.
 | 
						|
     */
 | 
						|
    t = SearchInputTrays( pCon, MEDIUM, defMedium );
 | 
						|
    if( t )
 | 
						|
      {
 | 
						|
	  *tray = t;
 | 
						|
	  *medium = strdup( defMedium );
 | 
						|
	  return;
 | 
						|
      }
 | 
						|
    
 | 
						|
    /*
 | 
						|
     * If all else fails, just return the default tray, and whatever
 | 
						|
     * medium happens to be there.  Note that we simply return
 | 
						|
     * whatever is in the attribute store.  Any further correction is
 | 
						|
     * left up to the DDX driver.
 | 
						|
     */
 | 
						|
    *tray = strdup( defTray );
 | 
						|
    *medium = m;
 | 
						|
    xfree( t );
 | 
						|
}
 |