ad6b9644a3
for the issue that GetPrinterList does not return printer descriptions on Solaris. The patch implements a framework which allows the printer enumerator scripts to pass additional printer attributes to the information pool (currently only "xp-printerattr.descriptor" is implemented).
1892 lines
51 KiB
C
1892 lines
51 KiB
C
/* $Xorg: Init.c,v 1.5 2001/03/07 17:31:33 pookie Exp $ */
|
||
/*
|
||
(c) Copyright 1996 Hewlett-Packard Company
|
||
(c) Copyright 1996 International Business Machines Corp.
|
||
(c) Copyright 1996-2004 Sun Microsystems, Inc.
|
||
(c) Copyright 1996 Novell, Inc.
|
||
(c) Copyright 1996 Digital Equipment Corp.
|
||
(c) Copyright 1996 Fujitsu Limited
|
||
(c) Copyright 1996 Hitachi, Ltd.
|
||
(c) Copyright 2003-2004 Roland Mainz <roland.mainz@nrubsig.org>
|
||
|
||
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: printer/Init.c
|
||
** *
|
||
** * Contents:
|
||
** * The InitOutput routine here would presumably
|
||
** * be called from the normal server's InitOutput
|
||
** * after all display screens have been added.
|
||
** * There is are ifdef'd routines suitable for
|
||
** * use in building a printer-only server. Turn
|
||
** * on the "PRINTER_ONLY_SERVER" define if this is
|
||
** * to be the only ddx-level driver.
|
||
** *
|
||
** * Copyright: Copyright 1993,1995 Hewlett-Packard Company
|
||
** *
|
||
** *********************************************************
|
||
**
|
||
********************************************************************/
|
||
|
||
#include <unistd.h>
|
||
#include <stdlib.h>
|
||
#include <stdio.h>
|
||
#include <ctype.h>
|
||
#include <signal.h>
|
||
#include <sys/types.h>
|
||
#include <sys/stat.h>
|
||
#include <string.h>
|
||
#include <locale.h>
|
||
#ifdef __hpux
|
||
#include <sys/sysmacros.h>
|
||
#endif
|
||
|
||
#include "X.h"
|
||
#define NEED_EVENTS 1
|
||
#include "Xproto.h"
|
||
#include <servermd.h>
|
||
|
||
#include "screenint.h"
|
||
#include "input.h"
|
||
#include "cursor.h"
|
||
#include "misc.h"
|
||
#include "windowstr.h"
|
||
#include "inputstr.h"
|
||
|
||
#include "gcstruct.h"
|
||
#include "fonts/fontstruct.h"
|
||
#include "errno.h"
|
||
|
||
typedef char *XPointer;
|
||
#define HAVE_XPointer 1
|
||
|
||
#define Status int
|
||
#include <Xresource.h>
|
||
|
||
#include "DiPrint.h"
|
||
#include "attributes.h"
|
||
|
||
#include "os.h"
|
||
#include "spooler.h"
|
||
|
||
static void GenericScreenInit(
|
||
int index,
|
||
ScreenPtr pScreen,
|
||
int argc,
|
||
char **argv);
|
||
static Bool InitPrintDrivers(
|
||
int index,
|
||
ScreenPtr pScreen,
|
||
int argc,
|
||
char **argv);
|
||
|
||
/*
|
||
* The following two defines are used to build the name "X*printers", where
|
||
* the "*" is replaced by the display number. This is used to construct
|
||
* the name of the default printers configuration file if the -XpFile
|
||
* command line option was not specified.
|
||
*/
|
||
#define XNPRINTERSFILEPREFIX "/X"
|
||
#define XNPRINTERSFILESUFFIX "printers"
|
||
#define XPRINTERSFILENAME "Xprinters"
|
||
|
||
#define MODELDIRNAME "/models"
|
||
#define FONTDIRNAME "/fonts"
|
||
|
||
#ifdef XPRASTERDDX
|
||
|
||
static
|
||
PixmapFormatRec RasterPixmapFormats[] = {
|
||
{ 1, 1, BITMAP_SCANLINE_PAD }
|
||
};
|
||
#define NUMRASTFORMATS (sizeof RasterPixmapFormats)/(sizeof RasterPixmapFormats[0])
|
||
|
||
#include "raster/Raster.h"
|
||
|
||
#endif
|
||
|
||
#ifdef XPPCLDDX
|
||
|
||
static
|
||
PixmapFormatRec ColorPclPixmapFormats[] = {
|
||
{ 1, 1, BITMAP_SCANLINE_PAD },
|
||
{ 8, 8, BITMAP_SCANLINE_PAD },
|
||
{ 24, 32, BITMAP_SCANLINE_PAD }
|
||
};
|
||
|
||
#define NUMCPCLFORMATS (sizeof ColorPclPixmapFormats)/(sizeof ColorPclPixmapFormats[0])
|
||
|
||
#endif
|
||
|
||
#ifdef XPMONOPCLDDX
|
||
|
||
static
|
||
PixmapFormatRec MonoPclPixmapFormats[] = {
|
||
{ 1, 1, BITMAP_SCANLINE_PAD }
|
||
};
|
||
|
||
#define NUMMPCLFORMATS (sizeof MonoPclPixmapFormats)/(sizeof MonoPclPixmapFormats[0])
|
||
|
||
#endif
|
||
|
||
#if defined(XPPCLDDX) || defined(XPMONOPCLDDX)
|
||
#include "pcl/Pcl.h"
|
||
#endif
|
||
|
||
#ifdef XPPSDDX
|
||
|
||
static
|
||
PixmapFormatRec PSPixmapFormats[] = {
|
||
{ 1, 1, BITMAP_SCANLINE_PAD },
|
||
{ 8, 8, BITMAP_SCANLINE_PAD },
|
||
{ 24, 32, BITMAP_SCANLINE_PAD }
|
||
};
|
||
|
||
#define NUMPSFORMATS (sizeof PSPixmapFormats)/(sizeof PSPixmapFormats[0])
|
||
|
||
#include "ps/Ps.h"
|
||
|
||
#endif
|
||
|
||
/*
|
||
* The driverInitArray contains an entry for each driver the
|
||
* server knows about. Each element contains pointers to pixmap formats, the
|
||
* driver's initialization routine, and pointers to the driver's
|
||
* attribute validation rec, and/or a driver function which
|
||
* returns the maximum medium width&height, and maximum resolution
|
||
* given a printer name. Either the validation rec OR the dimension
|
||
* function can be NULL. If the function is non-NULL then it
|
||
* will be called, and will be passed the (possibly NULL) validation rec.
|
||
* If the function is NULL, then XpGetMaxWidthHeightRes() is called.
|
||
*/
|
||
typedef struct _driverInitRec {
|
||
char *driverName;
|
||
pBFunc initFunc;
|
||
XpValidatePoolsRec *pValRec;
|
||
pVFunc dimensionsFunc;
|
||
PixmapFormatRec *pFmts;
|
||
int numFmts;
|
||
} driverInitRec;
|
||
|
||
static driverInitRec driverInits[] = {
|
||
#ifdef XPRASTERDDX
|
||
{
|
||
"XP-RASTER",
|
||
InitializeRasterDriver,
|
||
&RasterValidatePoolsRec,
|
||
(pVFunc) NULL,
|
||
RasterPixmapFormats,
|
||
NUMRASTFORMATS
|
||
},
|
||
#endif
|
||
#ifdef XPPCLDDX
|
||
{
|
||
"XP-PCL-COLOR",
|
||
InitializeColorPclDriver,
|
||
&PclValidatePoolsRec,
|
||
(pVFunc) NULL,
|
||
ColorPclPixmapFormats,
|
||
NUMCPCLFORMATS
|
||
},
|
||
#endif
|
||
#ifdef XPMONOPCLDDX
|
||
{
|
||
"XP-PCL-MONO",
|
||
InitializeMonoPclDriver,
|
||
&PclValidatePoolsRec,
|
||
(pVFunc) NULL,
|
||
MonoPclPixmapFormats,
|
||
NUMMPCLFORMATS
|
||
},
|
||
#endif
|
||
#ifdef XPPSDDX
|
||
{
|
||
"XP-POSTSCRIPT",
|
||
InitializePsDriver,
|
||
&PsValidatePoolsRec,
|
||
(pVFunc) NULL,
|
||
PSPixmapFormats,
|
||
NUMPSFORMATS
|
||
},
|
||
#endif
|
||
};
|
||
|
||
|
||
/*
|
||
* The printerDb variable points to a list of PrinterDbEntry structs
|
||
* which map printer names with screen numbers and driver names.
|
||
*/
|
||
typedef struct _printerDbEntry {
|
||
struct _printerDbEntry *next;
|
||
char *name;
|
||
char *qualifier;
|
||
int screenNum;
|
||
char *driverName;
|
||
char *desc;
|
||
} PrinterDbEntry, *PrinterDbPtr;
|
||
|
||
static PrinterDbPtr printerDb = (PrinterDbPtr)NULL;
|
||
|
||
/*
|
||
* The nameMap is a list used in initializing the attribute store
|
||
* for each printer. The list is freed once the printerDb is built
|
||
* and the attribute stores for all printers have been initialized.
|
||
*/
|
||
typedef struct _nameMapEntry {
|
||
struct _nameMapEntry *next;
|
||
char *name;
|
||
char *qualifier;
|
||
} NameMapEntry, *NameMapPtr;
|
||
|
||
static NameMapPtr nameMap = (NameMapPtr)NULL;
|
||
|
||
/*
|
||
* The driverMap is a list which provides the mapping between driver names
|
||
* and screen numbers. It is built and used
|
||
* by RehashPrinterList to correctly fill in the screenNum field in the
|
||
* printerDb entries. The list is freed before RehashPrinterList terminates.
|
||
*/
|
||
typedef struct _driverMapping {
|
||
struct _driverMapping *next;
|
||
char *driverName;
|
||
int screenNum;
|
||
} DriverMapEntry, *DriverMapPtr;
|
||
|
||
static const char configFilePath[] =
|
||
"/etc/dt/config/print:/usr/dt/config/print";
|
||
|
||
static const char printServerConfigDir[] = "XPSERVERCONFIGDIR";
|
||
|
||
static int printScreenPrivIndex,
|
||
printWindowPrivIndex,
|
||
printGCPrivIndex;
|
||
static unsigned long printGeneration = 0;
|
||
static char *configFileName = (char *)NULL;
|
||
static Bool freeDefaultFontPath = FALSE;
|
||
static char *origFontPath = (char *)NULL;
|
||
|
||
static Bool xprintInitGlobalsCalled = FALSE;
|
||
/*
|
||
* This function is responsible for doing initalisation of any global
|
||
* variables at an very early point of server startup (even before
|
||
* |ProcessCommandLine()|.
|
||
*/
|
||
void XprintInitGlobals(void)
|
||
{
|
||
extern char dispatchExceptionAtReset; /* defined in Xserver/dix/dispatch.c */
|
||
|
||
xprintInitGlobalsCalled = TRUE;
|
||
|
||
#ifdef SMART_SCHEDULE
|
||
/* Somehow the XF86 "smart scheduler" completely kills the Xprint DDX
|
||
* (see http://xprint.freedesktop.org/cgi-bin/bugzilla/show_bug.cgi?id=467
|
||
* ("Xfree86's "smart scheduler" breaks Xprt") */
|
||
SmartScheduleDisable = TRUE;
|
||
#endif /* SMART_SCHEDULE */
|
||
|
||
/* Disable internal screensaver for Xprint (workaround for
|
||
* http://pdx.freedesktop.org/cgi-bin/bugzilla/show_bug.cgi?id=567 ("Xorg
|
||
* Xprt starts to consume 100% CPU when being idle for some time")) */
|
||
defaultScreenSaverTime = 0;
|
||
|
||
/* Ensure that the maximum request size for the BIGREQUESTS extension
|
||
* is at least 8MB (see
|
||
* http://xprint.freedesktop.org/cgi-bin/bugzilla/show_bug.cgi?id=622 - "RFE:
|
||
* Xprt's default BIGREQUESTS extension buffer size should be 8MB")
|
||
*/
|
||
maxBigRequestSize = (8*1048576)-1;
|
||
|
||
/* Xprt should not reset by default when the last client exists
|
||
* (default for Xprt is |0|, video Xservers use |DE_RESET|) */
|
||
dispatchExceptionAtReset = 0;
|
||
}
|
||
|
||
/*
|
||
* XprintUseMsg() prints usage for the Xprint-specific options
|
||
*/
|
||
void XprintUseMsg()
|
||
{
|
||
XpSpoolerTypePtr curr = xpstm;
|
||
|
||
/* Option '-XpFile' */
|
||
ErrorF("-XpFile file specifies an alternate `Xprinters' file, rather\n");
|
||
ErrorF(" than the default one (e.g.\n");
|
||
ErrorF(" `${XPCONFIGDIR}/${LANG}/print/Xprinters') or\n");
|
||
ErrorF(" `${XPCONFIGDIR}/C/print/Xprinters'.\n");
|
||
|
||
/* Option '-XpSpoolerType' */
|
||
ErrorF("-XpSpoolerType string specifies a spooler type.\n");
|
||
ErrorF(" Supported values are:\n");
|
||
|
||
while( curr->name != NULL )
|
||
{
|
||
ErrorF(" - '%s'\n", curr->name);
|
||
curr++;
|
||
}
|
||
ErrorF(" (multiple values can be specified, seperated by ':',\n");
|
||
ErrorF(" the first active spooler will be chosen).\n");
|
||
ErrorF(" default is '%s'.\n", XPDEFAULTSPOOLERNAMELIST);
|
||
}
|
||
|
||
/*
|
||
* XprintOptions checks argv[i] to see if it is our command line
|
||
* option specifying a configuration file name. It returns the index
|
||
* of the next option to process.
|
||
*/
|
||
int
|
||
XprintOptions(
|
||
int argc,
|
||
char **argv,
|
||
int i)
|
||
{
|
||
extern void ddxUseMsg();
|
||
if(strcmp(argv[i], "-XpFile") == 0)
|
||
{
|
||
if ((i + 1) >= argc) {
|
||
ddxUseMsg ();
|
||
return i + 2;
|
||
}
|
||
configFileName = argv[i + 1];
|
||
return i + 2;
|
||
}
|
||
else if(strcmp(argv[i], "-XpSpoolerType") == 0)
|
||
{
|
||
if ((i + 1) >= argc) {
|
||
ddxUseMsg ();
|
||
return i + 2;
|
||
}
|
||
XpSetSpoolerTypeNameList(argv[i + 1]);
|
||
return i + 2;
|
||
}
|
||
else
|
||
{
|
||
return i;
|
||
}
|
||
}
|
||
|
||
/************************************************************
|
||
* GetInitFunc --
|
||
*
|
||
* This routine is called from the InitPrintDrivers function.
|
||
* Given the name of a driver, return a pointer to the driver's
|
||
* initialization function.
|
||
*
|
||
* Results:
|
||
* Returns a pointer to the initialization function for the driver.
|
||
*
|
||
*
|
||
************************************************************/
|
||
|
||
/*
|
||
typedef Bool (*pIFunc)();
|
||
static pIFunc
|
||
GetInitFunc(driverName)
|
||
*/
|
||
|
||
static pBFunc GetInitFunc(char *driverName)
|
||
{
|
||
driverInitRec *pInitRec;
|
||
int numDrivers = sizeof(driverInits)/sizeof(driverInitRec);
|
||
int i;
|
||
|
||
for(pInitRec = driverInits, i = 0; i < numDrivers; pInitRec++, i++)
|
||
{
|
||
if( !strcmp( driverName, pInitRec->driverName ) )
|
||
return pInitRec->initFunc;
|
||
}
|
||
|
||
return 0;
|
||
}
|
||
|
||
static void
|
||
GetDimFuncAndRec(
|
||
char *driverName,
|
||
XpValidatePoolsRec **pValRec,
|
||
pVFunc *dimensionsFunc)
|
||
{
|
||
driverInitRec *pInitRec;
|
||
int numDrivers = sizeof(driverInits)/sizeof(driverInitRec);
|
||
int i;
|
||
|
||
for(pInitRec = driverInits, i = 0; i < numDrivers; pInitRec++, i++)
|
||
{
|
||
if( !strcmp( driverName, pInitRec->driverName ) )
|
||
{
|
||
*dimensionsFunc = pInitRec->dimensionsFunc;
|
||
*pValRec = pInitRec->pValRec;
|
||
return ;
|
||
}
|
||
}
|
||
|
||
*dimensionsFunc = 0;
|
||
*pValRec = 0;
|
||
return;
|
||
}
|
||
|
||
static void
|
||
FreePrinterDb(void)
|
||
{
|
||
PrinterDbPtr pCurEntry, pNextEntry;
|
||
|
||
for(pCurEntry = printerDb, pNextEntry = (PrinterDbPtr)NULL;
|
||
pCurEntry != (PrinterDbPtr)NULL; pCurEntry = pNextEntry)
|
||
{
|
||
pNextEntry = pCurEntry->next;
|
||
if(pCurEntry->name != (char *)NULL)
|
||
xfree(pCurEntry->name);
|
||
if(pCurEntry->desc != (char *)NULL)
|
||
xfree(pCurEntry->desc);
|
||
/*
|
||
* We don't free the driver name, because it's expected to simply
|
||
* be a pointer into the xrm database.
|
||
*/
|
||
xfree(pCurEntry);
|
||
}
|
||
printerDb = (PrinterDbPtr)NULL;
|
||
}
|
||
|
||
/*
|
||
* AddPrinterDbName allocates an entry in the printerDb list, and
|
||
* initializes the "name". It returns TRUE if the element was
|
||
* successfully added, and FALSE if an allocation error ocurred.
|
||
* XXX AddPrinterDbName needs to check for (and not add) duplicate names.
|
||
*/
|
||
static Bool
|
||
AddPrinterDbName(char *name, char *desc)
|
||
{
|
||
PrinterDbPtr pEntry = (PrinterDbPtr)xalloc(sizeof(PrinterDbEntry));
|
||
|
||
if(pEntry == (PrinterDbPtr)NULL) return FALSE;
|
||
pEntry->name = (name != NULL) ? strdup(name) : NULL;
|
||
pEntry->desc = (desc != NULL) ? strdup(desc) : NULL;
|
||
pEntry->qualifier = (char *)NULL;
|
||
|
||
if(printerDb == (PrinterDbPtr)NULL)
|
||
{
|
||
pEntry->next = (PrinterDbPtr)NULL;
|
||
printerDb = pEntry;
|
||
}
|
||
else
|
||
{
|
||
pEntry->next = printerDb;
|
||
printerDb = pEntry;
|
||
}
|
||
return TRUE;
|
||
}
|
||
|
||
static int
|
||
AugmentPrinterDb(const char *command)
|
||
{
|
||
FILE *fp;
|
||
char name[256];
|
||
int num_printers = 0; /* Number of printers we found */
|
||
size_t namelen;
|
||
char *desc = NULL;
|
||
|
||
fp = popen(command, "r");
|
||
/* XXX is a 256 character limit overly restrictive for printer names? */
|
||
while(fgets(name, 256, fp) != (char *)NULL && (namelen=strlen(name)))
|
||
{
|
||
char *option = name;
|
||
|
||
name[namelen-1] = (char)'\0'; /* strip the \n */
|
||
|
||
#define XP_DESCRIPTOR "xp-printerattr.descriptor="
|
||
#define XP_DESCRIPTOR_LEN (sizeof(XP_DESCRIPTOR)-1)
|
||
while (option = strchr(option, '\t')) {
|
||
option++; /* Skip the '\t' */
|
||
if (!strncmp(option, XP_DESCRIPTOR, XP_DESCRIPTOR_LEN)) {
|
||
*(option-1) = '\0'; /* Kill the '\t' (only if we found a valid option) */
|
||
option += XP_DESCRIPTOR_LEN;
|
||
if (*option != '\0') {
|
||
desc = option;
|
||
}
|
||
}
|
||
else
|
||
{
|
||
/* Unknown option */
|
||
ErrorF("AugmentPrinterDb: Unknown option '%s'\n", option);
|
||
}
|
||
}
|
||
AddPrinterDbName(name, desc);
|
||
num_printers++;
|
||
}
|
||
pclose(fp);
|
||
return num_printers;
|
||
}
|
||
|
||
/*
|
||
* FreeNameMap frees all remaining memory associated with the nameMap.
|
||
*/
|
||
static void
|
||
FreeNameMap(void)
|
||
{
|
||
NameMapPtr pEntry, pTmp;
|
||
|
||
for(pEntry = nameMap, pTmp = (NameMapPtr)NULL;
|
||
pEntry != (NameMapPtr)NULL;
|
||
pEntry = pTmp)
|
||
{
|
||
if(pEntry->name != (char *)NULL)
|
||
xfree(pEntry->name);
|
||
if(pEntry->qualifier != (char *)NULL)
|
||
xfree(pEntry->qualifier);
|
||
pTmp = pEntry->next;
|
||
xfree(pEntry);
|
||
}
|
||
nameMap = (NameMapPtr)NULL;
|
||
}
|
||
|
||
/*
|
||
* AddNameMap adds an element to the nameMap linked list.
|
||
*/
|
||
static Bool
|
||
AddNameMap(char *name, char *qualifier)
|
||
{
|
||
NameMapPtr pEntry;
|
||
|
||
if((pEntry = (NameMapPtr)xalloc(sizeof(NameMapEntry))) == (NameMapPtr)NULL)
|
||
return FALSE;
|
||
pEntry->name = name;
|
||
pEntry->qualifier = qualifier;
|
||
pEntry->next = nameMap;
|
||
nameMap = pEntry;
|
||
return TRUE;
|
||
}
|
||
|
||
/*
|
||
* MergeNameMap - puts the "map" names (aka qualifiers, aliases) into
|
||
* the printerDb. This should be called once, after both the printerDb
|
||
* and nameMap lists are complete. When/if MergeNameMap finds a map for
|
||
* an entry in the printerDb, the qualifier is _moved_ (not copied) to
|
||
* the printerDb. This means that the qualifier pointer in the nameMap
|
||
* is NULLed out.
|
||
*/
|
||
static void
|
||
MergeNameMap(void)
|
||
{
|
||
NameMapPtr pMap;
|
||
PrinterDbPtr pDb;
|
||
|
||
for(pMap = nameMap; pMap != (NameMapPtr)NULL; pMap = pMap->next)
|
||
{
|
||
for(pDb = printerDb; pDb != (PrinterDbPtr)NULL; pDb = pDb->next)
|
||
{
|
||
if(!strcmp(pMap->name, pDb->name))
|
||
{
|
||
pDb->qualifier = pMap->qualifier;
|
||
pMap->qualifier = (char *)NULL;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
/*
|
||
* CreatePrinterAttrs causes the attribute stores to be built for
|
||
* each printer in the printerDb.
|
||
*/
|
||
static void
|
||
CreatePrinterAttrs(void)
|
||
{
|
||
PrinterDbPtr pDb;
|
||
|
||
for(pDb = printerDb; pDb != (PrinterDbPtr)NULL; pDb = pDb->next)
|
||
{
|
||
XpBuildAttributeStore(pDb->name, (pDb->qualifier)?
|
||
pDb->qualifier : pDb->name);
|
||
}
|
||
}
|
||
|
||
#ifdef XPPSDDX
|
||
#define defaultDriver "XP-POSTSCRIPT"
|
||
#else
|
||
#ifdef XPPCLDDX
|
||
#define defaultDriver "XP-PCL-COLOR"
|
||
#else
|
||
#ifdef XPMONOPCLDDX
|
||
#define defaultDriver "XP-PCL-MONO"
|
||
#else
|
||
#define defaultDriver "XP-RASTER"
|
||
#endif
|
||
#endif
|
||
#endif
|
||
|
||
/*
|
||
* StoreDriverNames - queries the attribute store for the ddx-identifier.
|
||
* if the ddx-identifier is not in the attribute database, then a default
|
||
* ddx-identifier is store in both the attribute store for the printer,
|
||
* and in the printerDb.
|
||
* The ddx-identifier is stored in the printerDb for use in initializing
|
||
* the screens.
|
||
*/
|
||
static void
|
||
StoreDriverNames(void)
|
||
{
|
||
PrinterDbPtr pEntry;
|
||
|
||
for(pEntry = printerDb; pEntry != (PrinterDbPtr)NULL;
|
||
pEntry = pEntry->next)
|
||
{
|
||
pEntry->driverName = (char*)XpGetPrinterAttribute(pEntry->name,
|
||
"xp-ddx-identifier");
|
||
if(pEntry->driverName == (char *)NULL ||
|
||
strlen(pEntry->driverName) == 0 ||
|
||
GetInitFunc(pEntry->driverName) == (Bool(*)())NULL)
|
||
{
|
||
if (pEntry->driverName && (strlen(pEntry->driverName) != 0)) {
|
||
ErrorF("Xp Extension: Can't load driver %s\n",
|
||
pEntry->driverName);
|
||
ErrorF(" init function missing\n");
|
||
}
|
||
|
||
pEntry->driverName = defaultDriver;
|
||
XpAddPrinterAttribute(pEntry->name,
|
||
(pEntry->qualifier != (char *)NULL)?
|
||
pEntry->qualifier : pEntry->name,
|
||
"*xp-ddx-identifier", pEntry->driverName);
|
||
}
|
||
}
|
||
}
|
||
|
||
/*
|
||
* StoreDescriptors - queries the attribute store for the descriptor.
|
||
* if the descriptor is not in the attribute database, then the descriptor
|
||
* from the printerDb is store in the attribute store for the printer.
|
||
*/
|
||
static void
|
||
StoreDescriptors()
|
||
{
|
||
PrinterDbPtr pEntry;
|
||
|
||
for(pEntry = printerDb; pEntry != (PrinterDbPtr)NULL;
|
||
pEntry = pEntry->next)
|
||
{
|
||
if (pEntry->desc != NULL)
|
||
{
|
||
XpAddPrinterAttribute(pEntry->name,
|
||
(pEntry->qualifier != (char *)NULL)?
|
||
pEntry->qualifier : pEntry->name,
|
||
"*descriptor", pEntry->desc);
|
||
}
|
||
}
|
||
}
|
||
|
||
static char *
|
||
MbStrchr(
|
||
char *str,
|
||
int ch)
|
||
{
|
||
size_t mbCurMax = MB_CUR_MAX;
|
||
wchar_t targetChar, curChar;
|
||
char tmpChar;
|
||
int i, numBytes, byteLen;
|
||
|
||
if(mbCurMax <= 1) return strchr(str, ch);
|
||
|
||
tmpChar = (char)ch;
|
||
mbtowc(&targetChar, &tmpChar, mbCurMax);
|
||
for(i = 0, numBytes = 0, byteLen = strlen(str); i < byteLen; i += numBytes)
|
||
{
|
||
numBytes = mbtowc(&curChar, &str[i], mbCurMax);
|
||
if(curChar == targetChar) return &str[i];
|
||
}
|
||
return (char *)NULL;
|
||
}
|
||
|
||
/*
|
||
* GetConfigFileName - Looks for a "Xprinters" file in
|
||
* $(XPRINTDIR)/$LANG/print, and then in $(XPRINTDIR)/C/print. If it
|
||
* finds such a file, it returns the path to the file. The returned
|
||
* string must be freed by the caller.
|
||
*/
|
||
static char *
|
||
GetConfigFileName(void)
|
||
{
|
||
/*
|
||
* We need to find the system-wide file, if one exists. This
|
||
* file can be in either $(XPRINTDIR)/$LANG/print, or in
|
||
* $(PRINTDIR)/C/print, and the file itself is named "Xprinters".
|
||
*/
|
||
char *dirName, *filePath;
|
||
|
||
/*
|
||
* Check for a LANG-specific file.
|
||
*/
|
||
if(dirName = XpGetConfigDir(TRUE))
|
||
{
|
||
filePath = (char *)xalloc(strlen(dirName) +
|
||
strlen(XPRINTERSFILENAME) + 2);
|
||
|
||
if(filePath == (char *)NULL)
|
||
{
|
||
xfree(dirName);
|
||
return (char *)NULL;
|
||
}
|
||
|
||
sprintf(filePath, "%s/%s", dirName, XPRINTERSFILENAME);
|
||
xfree(dirName);
|
||
if(access(filePath, R_OK) == 0)
|
||
return filePath;
|
||
|
||
xfree(filePath);
|
||
}
|
||
|
||
if(dirName = XpGetConfigDir(FALSE))
|
||
{
|
||
filePath = (char *)xalloc(strlen(dirName) +
|
||
strlen(XPRINTERSFILENAME) + 2);
|
||
if(filePath == (char *)NULL)
|
||
{
|
||
xfree(dirName);
|
||
return (char *)NULL;
|
||
}
|
||
sprintf(filePath, "%s/%s", dirName, XPRINTERSFILENAME);
|
||
xfree(dirName);
|
||
if(access(filePath, R_OK) == 0)
|
||
return filePath;
|
||
xfree(filePath);
|
||
}
|
||
return (char *)NULL;
|
||
}
|
||
|
||
/*
|
||
* BuildPrinterDb - reads the config file if it exists, and if necessary
|
||
* executes a command such as lpstat to generate a list of printers.
|
||
* XXX
|
||
* XXX BuildPrinterDb must be rewritten to allow 16-bit characters in
|
||
* XXX printer names. The will involve replacing the use of strtok() and its
|
||
* XXX related functions.
|
||
* XXX At the same time, BuildPrinterDb and it's support routines should have
|
||
* XXX allocation error checking added.
|
||
* XXX
|
||
*/
|
||
static PrinterDbPtr
|
||
BuildPrinterDb(void)
|
||
{
|
||
char *printerList, *augmentCmd = (char *)NULL;
|
||
Bool defaultAugment = TRUE, freeConfigFileName;
|
||
|
||
if(configFileName && access(configFileName, R_OK) != 0)
|
||
{
|
||
ErrorF("Xp Extension: Can't open file %s\n", configFileName);
|
||
}
|
||
if(!configFileName && (configFileName = GetConfigFileName()))
|
||
freeConfigFileName = TRUE;
|
||
else
|
||
freeConfigFileName = FALSE;
|
||
|
||
if(configFileName != (char *)NULL && access(configFileName, R_OK) == 0)
|
||
{
|
||
char line[256];
|
||
FILE *fp = fopen(configFileName, "r");
|
||
|
||
while(fgets(line, 256, fp) != (char *)NULL)
|
||
{
|
||
char *tok, *ptr;
|
||
if((tok = strtok(line, " \t\012")) != (char *)NULL)
|
||
{
|
||
if(tok[0] == (char)'#') continue;
|
||
if(strcmp(tok, "Printer") == 0)
|
||
{
|
||
while((tok = strtok((char *)NULL, " \t")) != (char *)NULL)
|
||
{
|
||
if(ptr = MbStrchr(tok, '\012'))
|
||
*ptr = (char)'\0';
|
||
AddPrinterDbName(tok, NULL);
|
||
}
|
||
}
|
||
else if(strcmp(tok, "Map") == 0)
|
||
{
|
||
char *name, *qualifier;
|
||
|
||
if((tok = strtok((char *)NULL, " \t\012")) == (char *)NULL)
|
||
continue;
|
||
name = strdup(tok);
|
||
if((tok = strtok((char *)NULL, " \t\012")) == (char *)NULL)
|
||
{
|
||
xfree(name);
|
||
continue;
|
||
}
|
||
qualifier = strdup(tok);
|
||
AddNameMap(name, qualifier);
|
||
}
|
||
else if(strcmp(tok, "Augment_Printer_List") == 0)
|
||
{
|
||
if((tok = strtok((char *)NULL, " \t\012")) == (char *)NULL)
|
||
continue;
|
||
|
||
if(strcmp(tok, "%default%") == 0)
|
||
continue;
|
||
defaultAugment = FALSE;
|
||
if(strcmp(tok, "%none%") == 0)
|
||
continue;
|
||
AugmentPrinterDb(tok);
|
||
}
|
||
else
|
||
break; /* XXX Generate an error? */
|
||
}
|
||
}
|
||
fclose(fp);
|
||
}
|
||
|
||
if(defaultAugment == TRUE)
|
||
{
|
||
XpSpoolerTypePtr curr_spooler_type; /* spooler we are currently probing for queues */
|
||
int num_printers_found; /* number of printers found by |AugmentPrinterDb()| */
|
||
char *tok_lasts; /* strtok_r() position token */
|
||
char *spnamelist; /* list of spooler names, seperated by ":" */
|
||
char *spname; /* spooler name */
|
||
|
||
spnamelist = strdup(XpGetSpoolerTypeNameList()); /* strtok_r() modifies string so dup' it first */
|
||
|
||
for( spname = strtok_r(spnamelist, ":", &tok_lasts) ;
|
||
spname != NULL ;
|
||
spname = strtok_r(NULL, ":", &tok_lasts) )
|
||
{
|
||
curr_spooler_type = XpSpoolerNameToXpSpoolerType(spname);
|
||
if(!curr_spooler_type)
|
||
{
|
||
FatalError("BuildPrinterDb:<3A>No spooler type entry found for '%s'.\n", spname);
|
||
}
|
||
|
||
if(curr_spooler_type->list_queues_command == NULL ||
|
||
strlen(curr_spooler_type->list_queues_command) == 0)
|
||
{
|
||
continue;
|
||
}
|
||
|
||
num_printers_found = AugmentPrinterDb(curr_spooler_type->list_queues_command);
|
||
/* Did we found a spooler which works ? */
|
||
if(num_printers_found > 0)
|
||
{
|
||
spooler_type = curr_spooler_type;
|
||
#ifdef DEBUG_gisburn
|
||
fprintf(stderr, "BuildPrinterDb: using '%s'.\n", spooler_type->name);
|
||
#endif /* DEBUG_gisburn */
|
||
break;
|
||
}
|
||
}
|
||
|
||
free(spnamelist);
|
||
}
|
||
|
||
MergeNameMap();
|
||
FreeNameMap();
|
||
|
||
/* Create the attribute stores for all printers */
|
||
CreatePrinterAttrs();
|
||
|
||
/*
|
||
* Find the drivers for each printers, and store the driver names
|
||
* in the printerDb
|
||
*/
|
||
StoreDriverNames();
|
||
StoreDescriptors();
|
||
|
||
if(freeConfigFileName)
|
||
{
|
||
xfree(configFileName);
|
||
configFileName = (char *)NULL;
|
||
}
|
||
|
||
return printerDb;
|
||
}
|
||
|
||
static void
|
||
FreeDriverMap(DriverMapPtr driverMap)
|
||
{
|
||
DriverMapPtr pCurEntry, pNextEntry;
|
||
|
||
for(pCurEntry = driverMap, pNextEntry = (DriverMapPtr)NULL;
|
||
pCurEntry != (DriverMapPtr)NULL; pCurEntry = pNextEntry)
|
||
{
|
||
pNextEntry = pCurEntry->next;
|
||
if(pCurEntry->driverName != (char *)NULL)
|
||
xfree(pCurEntry->driverName);
|
||
xfree(pCurEntry);
|
||
}
|
||
}
|
||
|
||
/*
|
||
* XpRehashPrinterList rebuilds the list of printers known to the
|
||
* server. It first walks the printerDb to build a table mapping
|
||
* driver names and screen numbers, since this is not an easy mapping
|
||
* to change in the sample server. The normal configuration files are
|
||
* then read & parsed to create the new list of printers. Printers
|
||
* which require drivers other than those already initialized are
|
||
* deleted from the printerDb. This leaves attribute stores in place
|
||
* for inaccessible printers, but those stores will be cleaned up in
|
||
* the next rehash or server recycle.
|
||
*/
|
||
int
|
||
XpRehashPrinterList(void)
|
||
{
|
||
PrinterDbPtr pEntry, pPrev;
|
||
DriverMapPtr driverMap = (DriverMapPtr)NULL, pDrvEnt;
|
||
int result;
|
||
|
||
/* Build driverMap */
|
||
for(pEntry = printerDb; pEntry != (PrinterDbPtr)NULL; pEntry = pEntry->next)
|
||
{
|
||
for(pDrvEnt = driverMap; pDrvEnt != (DriverMapPtr)NULL;
|
||
pDrvEnt = pDrvEnt->next)
|
||
{
|
||
if(!strcmp(pEntry->driverName, pDrvEnt->driverName))
|
||
break;
|
||
}
|
||
|
||
if(pDrvEnt != (DriverMapPtr)NULL)
|
||
continue;
|
||
|
||
if((pDrvEnt = (DriverMapPtr)xalloc(sizeof(DriverMapEntry))) ==
|
||
(DriverMapPtr)NULL)
|
||
{
|
||
FreeDriverMap(driverMap);
|
||
return BadAlloc;
|
||
}
|
||
pDrvEnt->driverName = strdup(pEntry->driverName);
|
||
pDrvEnt->screenNum = pEntry->screenNum;
|
||
pDrvEnt->next = driverMap;
|
||
driverMap = pDrvEnt;
|
||
}
|
||
|
||
/* Free the old printerDb */
|
||
FreePrinterDb();
|
||
|
||
/* Free/Rehash attribute stores */
|
||
if((result = XpRehashAttributes()) != Success)
|
||
return result;
|
||
|
||
/* Build a new printerDb */
|
||
if(BuildPrinterDb() == (PrinterDbPtr)NULL)
|
||
return BadAlloc;
|
||
|
||
/* Walk PrinterDb & either store screenNum, or delete printerDb entry */
|
||
for(pEntry = printerDb, pPrev = (PrinterDbPtr)NULL;
|
||
pEntry != (PrinterDbPtr)NULL; pEntry = pEntry->next)
|
||
{
|
||
for(pDrvEnt = driverMap; pDrvEnt != (DriverMapPtr)NULL;
|
||
pDrvEnt = pDrvEnt->next)
|
||
{
|
||
if(!strcmp(printerDb->driverName, pDrvEnt->driverName))
|
||
break;
|
||
}
|
||
|
||
/*
|
||
* Either store the screen number, or delete the printerDb entry.
|
||
* Deleting the entry leaves orphaned attribute stores, but they'll
|
||
* get cleaned up at the next rehash or server recycle.
|
||
*/
|
||
if(pDrvEnt != (DriverMapPtr)NULL)
|
||
{
|
||
pEntry->screenNum = pDrvEnt->screenNum;
|
||
pPrev = pEntry;
|
||
}
|
||
else {
|
||
if(pPrev)
|
||
pPrev->next = pEntry->next;
|
||
else
|
||
pPrev = pEntry->next;
|
||
if(pEntry->name != (char *)NULL)
|
||
xfree(pEntry->name);
|
||
xfree(pEntry);
|
||
pEntry = pPrev;
|
||
}
|
||
}
|
||
|
||
FreeDriverMap(driverMap);
|
||
|
||
return Success;
|
||
}
|
||
|
||
/*
|
||
* ValidateFontDir looks for a valid font directory for the specified
|
||
* printer model within the specified configuration directory. It returns
|
||
* the directory name, or NULL if no valid font directory was found.
|
||
* It is the caller's responsibility to free the returned font directory
|
||
* name.
|
||
*/
|
||
static char *
|
||
ValidateFontDir(
|
||
char *configDir,
|
||
char *modelName)
|
||
{
|
||
char *pathName;
|
||
|
||
if(!configDir || !modelName)
|
||
return (char *)NULL;
|
||
|
||
pathName = (char *)xalloc(strlen(configDir) + strlen(MODELDIRNAME) +
|
||
strlen(modelName) + strlen(FONTDIRNAME) +
|
||
strlen("fonts.dir") + 5);
|
||
if(!pathName)
|
||
return (char *)NULL;
|
||
sprintf(pathName, "%s/%s/%s/%s/%s", configDir, MODELDIRNAME, modelName,
|
||
FONTDIRNAME, "fonts.dir");
|
||
if(access(pathName, R_OK) != 0)
|
||
{
|
||
xfree(pathName);
|
||
return (char *)NULL;
|
||
}
|
||
pathName[strlen(pathName) - 9] = (char)'\0'; /* erase fonts.dir */
|
||
return pathName;
|
||
}
|
||
|
||
/*
|
||
* FindFontDir returns a pointer to the path name of the font directory
|
||
* for the specified printer model name, if such a directory exists.
|
||
* The directory contents are superficially checked for validity.
|
||
* The caller must free the returned char *.
|
||
*
|
||
* We first look in the locale-specific model-config directory, and
|
||
* then fall back to the C language model-config directory.
|
||
*/
|
||
static char *
|
||
FindFontDir(
|
||
char *modelName)
|
||
{
|
||
char *configDir, *fontDir;
|
||
|
||
if(!modelName || !strlen(modelName))
|
||
return (char *)NULL;
|
||
|
||
configDir = XpGetConfigDir(TRUE);
|
||
if(fontDir = ValidateFontDir(configDir, modelName))
|
||
{
|
||
xfree(configDir);
|
||
return fontDir;
|
||
}
|
||
|
||
if(configDir)
|
||
xfree(configDir);
|
||
configDir = XpGetConfigDir(FALSE);
|
||
fontDir = ValidateFontDir(configDir, modelName);
|
||
|
||
xfree(configDir);
|
||
|
||
return fontDir;
|
||
}
|
||
|
||
/*
|
||
* AddToFontPath adds the specified font path element to the global
|
||
* defaultFontPath string. It adds the keyword "PRINTER:" to the front
|
||
* of the path to denote that this is a printer-specific font path
|
||
* element.
|
||
*/
|
||
static char PATH_PREFIX[] = "PRINTER:";
|
||
static int PATH_PREFIX_LEN = sizeof(PATH_PREFIX) - 1; /* same as strlen() */
|
||
|
||
static void
|
||
AddToFontPath(
|
||
char *pathName)
|
||
{
|
||
char *newPath;
|
||
Bool freeOldPath;
|
||
|
||
if(defaultFontPath == origFontPath)
|
||
freeOldPath = FALSE;
|
||
else
|
||
freeOldPath = TRUE;
|
||
|
||
newPath = (char *)xalloc(strlen(defaultFontPath) + strlen(pathName) +
|
||
PATH_PREFIX_LEN + 2);
|
||
|
||
sprintf(newPath, "%s%s,%s", PATH_PREFIX, pathName, defaultFontPath);
|
||
|
||
if(freeOldPath)
|
||
xfree(defaultFontPath);
|
||
|
||
defaultFontPath = newPath;
|
||
return;
|
||
}
|
||
|
||
/*
|
||
* AugmentFontPath adds printer-model-specific font path elements to
|
||
* the front of the font path global variable "defaultFontPath" (dix/globals.c).
|
||
* We can't call SetFontPath() because the font code has not yet been
|
||
* initialized when InitOutput is called (from whence this routine is called).
|
||
*
|
||
* This utilizes the static variables origFontPath and
|
||
* freeDefaultFontPath to track the original contents of defaultFontPath,
|
||
* and to properly free the modified version upon server recycle.
|
||
*/
|
||
static void
|
||
AugmentFontPath(void)
|
||
{
|
||
char *newPath, *modelID, **allIDs = (char **)NULL;
|
||
PrinterDbPtr pDb, pDbEntry;
|
||
int numModels, i;
|
||
|
||
if(!origFontPath)
|
||
origFontPath = defaultFontPath;
|
||
|
||
if(freeDefaultFontPath)
|
||
{
|
||
xfree(defaultFontPath);
|
||
defaultFontPath = origFontPath;
|
||
freeDefaultFontPath = FALSE;
|
||
}
|
||
|
||
/*
|
||
* Build a list of printer models to check for internal fonts.
|
||
*/
|
||
for(pDbEntry = printerDb, numModels = 0;
|
||
pDbEntry != (PrinterDbPtr)NULL;
|
||
pDbEntry = pDbEntry->next)
|
||
{
|
||
modelID =
|
||
(char*)XpGetPrinterAttribute(pDbEntry->name,
|
||
"xp-model-identifier");
|
||
|
||
if(modelID && strlen(modelID) != 0)
|
||
{
|
||
/* look for current model in the list of allIDs */
|
||
for(i = 0; i < numModels; i++)
|
||
{
|
||
if(!strcmp(modelID, allIDs[i]))
|
||
{
|
||
modelID = (char *)NULL;
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
|
||
/*
|
||
* If this printer's model-identifier isn't in the allIDs list,
|
||
* then add it to allIDs.
|
||
*/
|
||
if(modelID && strlen(modelID) != 0)
|
||
{
|
||
allIDs = (char **)xrealloc(allIDs, (numModels+2) * sizeof(char *));
|
||
if(allIDs == (char **)NULL)
|
||
return;
|
||
allIDs[numModels] = modelID;
|
||
allIDs[numModels + 1] = (char *)NULL;
|
||
numModels++;
|
||
}
|
||
}
|
||
|
||
/* for each model, check for a valid font directory, and add it to
|
||
* the front of defaultFontPath.
|
||
*/
|
||
for(i = 0; allIDs != (char **)NULL && allIDs[i] != (char *)NULL; i ++)
|
||
{
|
||
char *fontDir;
|
||
if(fontDir = FindFontDir(allIDs[i]))
|
||
{
|
||
AddToFontPath(fontDir);
|
||
xfree(fontDir);
|
||
freeDefaultFontPath = TRUE;
|
||
}
|
||
}
|
||
|
||
if(allIDs)
|
||
xfree(allIDs);
|
||
|
||
return;
|
||
}
|
||
|
||
/*
|
||
* XpClientIsBitmapClient is called by the font code to find out if
|
||
* a particular client should be granted access to bitmap fonts.
|
||
* This function works by
|
||
* calling XpContextOfClient (in Xserver/Xext/xprint.c) to determine
|
||
* the context associated with the client, and then queries the context's
|
||
* attributes to determine whether the bitmap fonts should be visible.
|
||
* It looks at the value of the xp-listfonts-mode document/page attribute to
|
||
* see if xp-list-glyph-fonts has been left out of the mode list. Only
|
||
* if the xp-listfonts-mode attribute exists, and it does not contain
|
||
* xp-list-glyph-fonts does this function return FALSE. In any other
|
||
* case the funtion returns TRUE, indicating that the bitmap fonts
|
||
* should be visible to the client.
|
||
*/
|
||
Bool
|
||
XpClientIsBitmapClient(
|
||
ClientPtr client)
|
||
{
|
||
XpContextPtr pContext;
|
||
char *mode;
|
||
|
||
if(!(pContext = XpContextOfClient(client)))
|
||
return TRUE;
|
||
|
||
/*
|
||
* Check the page attributes, and if it's not defined there, then
|
||
* check the document attributes.
|
||
*/
|
||
mode = XpGetOneAttribute(pContext, XPPageAttr, "xp-listfonts-mode");
|
||
if(!mode || !strlen(mode))
|
||
{
|
||
mode = XpGetOneAttribute(pContext, XPDocAttr, "xp-listfonts-mode");
|
||
if(!mode || !strlen(mode))
|
||
return TRUE;
|
||
}
|
||
|
||
if(!strstr(mode, "xp-list-glyph-fonts"))
|
||
return FALSE;
|
||
|
||
return TRUE;
|
||
}
|
||
/*
|
||
* XpClientIsPrintClient is called by the font code to find out if
|
||
* a particular client has set a context which references a printer
|
||
* which utilizes a particular font path. This function works by
|
||
* calling XpContextOfClient (in Xserver/Xext/xprint.c) to determine
|
||
* the context associated with the client, and then looks up the
|
||
* font directory for the context. The font directory is then compared
|
||
* with the directory specified in the FontPathElement which is passed in.
|
||
*/
|
||
Bool
|
||
XpClientIsPrintClient(
|
||
ClientPtr client,
|
||
FontPathElementPtr fpe)
|
||
{
|
||
XpContextPtr pContext;
|
||
char *modelID, *fontDir;
|
||
|
||
if(!(pContext = XpContextOfClient(client)))
|
||
return FALSE;
|
||
|
||
if (!fpe)
|
||
return TRUE;
|
||
|
||
modelID = XpGetOneAttribute(pContext, XPPrinterAttr, "xp-model-identifier");
|
||
if(!modelID || !strlen(modelID))
|
||
return FALSE;
|
||
|
||
if(!(fontDir = FindFontDir(modelID)))
|
||
return FALSE;
|
||
|
||
/*
|
||
* The grunge here is to ignore the PATH_PREFIX at the front of the
|
||
* fpe->name.
|
||
*/
|
||
if(fpe->name_length < PATH_PREFIX_LEN ||
|
||
(strlen(fontDir) != (fpe->name_length - PATH_PREFIX_LEN)) ||
|
||
strncmp(fontDir, fpe->name + PATH_PREFIX_LEN,
|
||
fpe->name_length - PATH_PREFIX_LEN))
|
||
{
|
||
xfree(fontDir);
|
||
return FALSE;
|
||
}
|
||
xfree(fontDir);
|
||
return TRUE;
|
||
}
|
||
|
||
static void
|
||
AddFormats(ScreenInfo *pScreenInfo, char *driverName)
|
||
{
|
||
int i, j;
|
||
driverInitRec *pInitRec;
|
||
int numDrivers = sizeof(driverInits)/sizeof(driverInitRec);
|
||
PixmapFormatRec *formats;
|
||
int numfmts;
|
||
|
||
for (pInitRec = driverInits, i = 0; i < numDrivers; pInitRec++, i++)
|
||
{
|
||
if ( !strcmp( driverName, pInitRec->driverName ) )
|
||
break;
|
||
}
|
||
if (i >= numDrivers)
|
||
return;
|
||
formats = pInitRec->pFmts;
|
||
numfmts = pInitRec->numFmts;
|
||
for (i = 0; i < numfmts && pScreenInfo->numPixmapFormats < MAXFORMATS; i++)
|
||
{
|
||
for (j = 0; j < pScreenInfo->numPixmapFormats; j++) {
|
||
if (pScreenInfo->formats[j].depth == formats[i].depth &&
|
||
pScreenInfo->formats[j].bitsPerPixel == formats[i].bitsPerPixel &&
|
||
pScreenInfo->formats[j].scanlinePad == formats[i].scanlinePad)
|
||
break;
|
||
}
|
||
if (j == pScreenInfo->numPixmapFormats) {
|
||
pScreenInfo->formats[j] = formats[i];
|
||
pScreenInfo->numPixmapFormats++;
|
||
}
|
||
}
|
||
}
|
||
|
||
/************************************************************
|
||
* PrinterInitOutput --
|
||
* This routine is to be called from a ddx's InitOutput
|
||
* during the server startup initialization, and when
|
||
* the server is to be reset. The routine creates the
|
||
* screens associated with configured printers by calling
|
||
* dix:AddScreen. The configuration information comes from a
|
||
* database read from the X*printers file.
|
||
*
|
||
* Results:
|
||
* The array of ScreenRec pointers referenced by
|
||
* pScreenInfo->screen is increased by the addition
|
||
* of the printer screen(s), as is the value of
|
||
* pScreenInfo->numScreens. This is done via calls
|
||
* to AddScreen() in dix.
|
||
*
|
||
************************************************************/
|
||
|
||
void
|
||
PrinterInitOutput(
|
||
ScreenInfo *pScreenInfo,
|
||
int argc,
|
||
char **argv)
|
||
{
|
||
PrinterDbPtr pDb, pDbEntry;
|
||
int driverCount = 0, i;
|
||
char **driverNames;
|
||
char *configDir;
|
||
|
||
/* This should NEVER happen, but... */
|
||
if( !xprintInitGlobalsCalled )
|
||
{
|
||
FatalError("Internal error: XprintInitGlobals() not called.");
|
||
}
|
||
#ifdef SMART_SCHEDULE
|
||
/* |XprintInitGlobals| should have set |SmartScheduleDisable| to
|
||
* |TRUE| - if not we will trigger this safeguard. */
|
||
if( SmartScheduleDisable != TRUE )
|
||
{
|
||
FatalError("Internal error: XF86 smart scheduler incompatible to Xprint DDX.");
|
||
}
|
||
#endif /* SMART_SCHEDULE */
|
||
/* Safeguard for
|
||
* http://pdx.freedesktop.org/cgi-bin/bugzilla/show_bug.cgi?id=567 ("Xorg
|
||
* Xprt starts to consume 100% CPU when being idle for some time")
|
||
* |XprintInitGlobals| should have set |defaultScreenSaverTime| to
|
||
* |0| - if not we will trigger this trap. */
|
||
if( defaultScreenSaverTime != 0 )
|
||
{
|
||
FatalError("Internal screen saver must be OFF for printing.");
|
||
}
|
||
|
||
/* Print a warnung when the maximum request size of the BIGREQUESTS
|
||
* extension is smaller than 8MB (see
|
||
* http://xprint.freedesktop.org/cgi-bin/bugzilla/show_bug.cgi?id=622)
|
||
*/
|
||
if (maxBigRequestSize < (8*1048576)-1) {
|
||
ErrorF("Xp Extension: BIGREQUESTS max. request is currently %ld bytes "
|
||
", recommemded minimum for Xprint is 8MB.\n", (long)maxBigRequestSize);
|
||
}
|
||
|
||
/*
|
||
* this little test is just a warning at startup to make sure
|
||
* that the config directory exists.
|
||
*
|
||
* what this ugly looking if says is that if both ways of
|
||
* calling configDir works and both directories don't exist,
|
||
* then print an error saying we can't find the non-lang one.
|
||
*/
|
||
if (((configDir = XpGetConfigDir(TRUE)) != NULL) &&
|
||
(access(configDir, F_OK) == 0))
|
||
{
|
||
xfree(configDir);
|
||
}
|
||
else if (((configDir = XpGetConfigDir(FALSE)) != NULL) &&
|
||
(access(configDir, F_OK) == 0))
|
||
{
|
||
xfree(configDir);
|
||
}
|
||
else {
|
||
/* Refuse to start when we do not have our config dir... */
|
||
FatalError("Xp Extension: could not find config dir %s\n",
|
||
configDir ? configDir : XPRINTDIR);
|
||
}
|
||
|
||
if(printerDb != (PrinterDbPtr)NULL)
|
||
FreePrinterDb();
|
||
|
||
/*
|
||
* Calling BuildPrinterDb serves to build the printer database,
|
||
* and to initialize the attribute store for each printer.
|
||
* The driver can, if it so desires, modify the attribute
|
||
* store at a later time.
|
||
*/
|
||
if((pDb = BuildPrinterDb()) == (PrinterDbPtr)NULL) return;
|
||
|
||
/*
|
||
* We now have to decide how many screens to initialize, and call
|
||
* AddScreen for each one. The printerDb must be properly initialized
|
||
* for at least one screen's worth of printers prior to calling AddScreen
|
||
* because InitPrintDrivers reads the printerDb to determine which
|
||
* driver(s) to init on a particular screen.
|
||
* We put each driver's printers on a different
|
||
* screen, and call AddScreen for each screen/driver pair.
|
||
*/
|
||
/* count the number of printers */
|
||
for(pDbEntry = pDb, driverCount = 0; pDbEntry != (PrinterDbPtr)NULL;
|
||
pDbEntry = pDbEntry->next, driverCount++)
|
||
;
|
||
/*
|
||
* Allocate memory for the worst case - a driver per printer
|
||
*/
|
||
driverNames = (char **)xalloc(sizeof(char *) * driverCount);
|
||
|
||
/*
|
||
* Assign the driver for the first printer to the first screen
|
||
*/
|
||
pDb->screenNum = screenInfo.numScreens;
|
||
driverNames[0] = pDb->driverName;
|
||
driverCount = 1;
|
||
AddFormats(pScreenInfo, pDb->driverName);
|
||
|
||
/*
|
||
* For each printer, look to see if its driver is already assigned
|
||
* to a screen, and if so copy that screen number into the printerDb.
|
||
* Otherwise, assign a new screen number to the driver for this
|
||
* printer.
|
||
*/
|
||
for(pDbEntry = pDb; pDbEntry != (PrinterDbPtr)NULL;
|
||
pDbEntry = pDbEntry->next)
|
||
{
|
||
Bool foundMatch;
|
||
|
||
for(i = 0, foundMatch = FALSE; i < driverCount; i++)
|
||
{
|
||
if(!strcmp(driverNames[i], pDbEntry->driverName))
|
||
{
|
||
foundMatch = TRUE;
|
||
pDbEntry->screenNum = screenInfo.numScreens + i;
|
||
break;
|
||
}
|
||
}
|
||
if(foundMatch == FALSE)
|
||
{
|
||
driverNames[driverCount] = pDbEntry->driverName;
|
||
pDbEntry->screenNum = screenInfo.numScreens + driverCount;
|
||
AddFormats(pScreenInfo, pDbEntry->driverName);
|
||
driverCount++;
|
||
}
|
||
}
|
||
|
||
for(i = 0; i < driverCount; i++)
|
||
{
|
||
int curScreen = screenInfo.numScreens;
|
||
if(AddScreen(InitPrintDrivers, argc, argv) < 0)
|
||
{
|
||
PrinterDbPtr pPrev;
|
||
/*
|
||
* AddScreen failed, so we pull the associated printers
|
||
* from the list.
|
||
*/
|
||
ErrorF("Xp Extension: Could not add screen for driver %s\n",
|
||
driverNames[i]);
|
||
for(pPrev = pDbEntry = printerDb; pDbEntry != (PrinterDbPtr)NULL;
|
||
pDbEntry = pDbEntry->next)
|
||
{
|
||
if(pDbEntry->screenNum == curScreen)
|
||
{
|
||
if(pPrev == printerDb)
|
||
{
|
||
printerDb = pDbEntry->next;
|
||
pPrev = printerDb;
|
||
}
|
||
else
|
||
pPrev->next = pDbEntry->next;
|
||
|
||
xfree(pDbEntry->name);
|
||
xfree(pDbEntry);
|
||
pDbEntry = pPrev;
|
||
}
|
||
else
|
||
{
|
||
if(pDbEntry->screenNum > curScreen)
|
||
pDbEntry->screenNum--;
|
||
pPrev = pDbEntry;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
xfree(driverNames);
|
||
|
||
AugmentFontPath();
|
||
|
||
if(pScreenInfo->numScreens > MAXSCREENS)
|
||
{
|
||
ErrorF("The number of printer screens requested ");
|
||
ErrorF("exceeds the allowable limit of %d screens.\n", MAXSCREENS);
|
||
ErrorF("Please reduce the number of requested printers in your ");
|
||
ErrorF("\nX%sprinters file.", display);
|
||
ErrorF("Server exiting...\n");
|
||
exit(-1);
|
||
}
|
||
}
|
||
|
||
/*
|
||
* InitPrintDrivers is called from dix:AddScreen. It in turn calls the
|
||
* driver initialization routine for any and all drivers which are
|
||
* implicated in supporting printers on the particular screen number
|
||
* specified by the "index" parameter. The printerDb variable is used
|
||
* to determine which printers are to be associated with a particular
|
||
* screen.
|
||
*/
|
||
static Bool
|
||
InitPrintDrivers(
|
||
int index,
|
||
ScreenPtr pScreen,
|
||
int argc,
|
||
char **argv)
|
||
{
|
||
PrinterDbPtr pDb, pDb2;
|
||
|
||
GenericScreenInit(index, pScreen, argc, argv);
|
||
|
||
for(pDb = printerDb; pDb != (PrinterDbPtr)NULL; pDb = pDb->next)
|
||
{
|
||
if(pDb->screenNum == index)
|
||
{
|
||
Bool callInit = TRUE;
|
||
for(pDb2 = printerDb; pDb2 != pDb; pDb2 = pDb2->next)
|
||
{
|
||
if(!strcmp(pDb->driverName, pDb2->driverName))
|
||
{
|
||
callInit = FALSE;
|
||
break;
|
||
}
|
||
}
|
||
if(callInit == TRUE)
|
||
{
|
||
Bool (*initFunc)();
|
||
initFunc = GetInitFunc(pDb->driverName);
|
||
if(initFunc(index, pScreen, argc, argv) == FALSE)
|
||
{
|
||
/* XXX - What do I do if the driver's init fails? */
|
||
}
|
||
}
|
||
}
|
||
}
|
||
return TRUE;
|
||
}
|
||
|
||
void
|
||
_XpVoidNoop(void)
|
||
{
|
||
return;
|
||
}
|
||
|
||
Bool
|
||
_XpBoolNoop(void)
|
||
{
|
||
return TRUE;
|
||
}
|
||
|
||
/*
|
||
* GenericScreenInit - The common initializations required by all
|
||
* printer screens and drivers. It sets the screen's cursor functions
|
||
* to Noops, and computes the maximum screen (i.e. medium) dimensions.
|
||
*/
|
||
|
||
static void
|
||
GenericScreenInit(
|
||
int index,
|
||
ScreenPtr pScreen,
|
||
int argc,
|
||
char **argv)
|
||
{
|
||
int i;
|
||
float fWidth, fHeight, maxWidth, maxHeight;
|
||
unsigned short width, height;
|
||
PrinterDbPtr pDb, pDb2;
|
||
int res, maxRes;
|
||
|
||
/*
|
||
* Set the cursor ops to no-op functions.
|
||
*/
|
||
pScreen->DisplayCursor = (DisplayCursorProcPtr)_XpBoolNoop;
|
||
pScreen->RealizeCursor = (RealizeCursorProcPtr)_XpBoolNoop;
|
||
pScreen->UnrealizeCursor = (UnrealizeCursorProcPtr)_XpBoolNoop;
|
||
pScreen->SetCursorPosition = (SetCursorPositionProcPtr)_XpBoolNoop;
|
||
pScreen->ConstrainCursor = (ConstrainCursorProcPtr)_XpVoidNoop;
|
||
pScreen->CursorLimits = (CursorLimitsProcPtr)_XpVoidNoop;
|
||
pScreen->RecolorCursor = (RecolorCursorProcPtr)_XpVoidNoop;
|
||
|
||
/*
|
||
* Find the largest paper size for all the printers on the given
|
||
* screen.
|
||
*/
|
||
maxRes = 0;
|
||
maxWidth = maxHeight = 0.0;
|
||
for( pDb = printerDb; pDb != (PrinterDbPtr)NULL; pDb = pDb->next)
|
||
{
|
||
if(pDb->screenNum == index)
|
||
{
|
||
|
||
XpValidatePoolsRec *pValRec;
|
||
pVFunc dimensionsFunc;
|
||
|
||
GetDimFuncAndRec(pDb->driverName, &pValRec, &dimensionsFunc);
|
||
if(dimensionsFunc != (pVFunc)NULL)
|
||
dimensionsFunc(pDb->name, pValRec, &fWidth, &fHeight, &res);
|
||
else
|
||
XpGetMaxWidthHeightRes(pDb->name, pValRec, &fWidth,
|
||
&fHeight, &res);
|
||
if( res > maxRes )
|
||
maxRes = res;
|
||
if( fWidth > maxWidth )
|
||
maxWidth = fWidth;
|
||
if( fHeight > maxHeight )
|
||
maxHeight = fHeight;
|
||
}
|
||
}
|
||
|
||
width = (unsigned short) (maxWidth * maxRes / 25.4);
|
||
height = (unsigned short) (maxHeight * maxRes / 25.4);
|
||
pScreen->width = pScreen->height = ( width > height ) ? width :
|
||
height;
|
||
|
||
pScreen->mmWidth = pScreen->mmHeight = ( maxWidth > maxHeight ) ?
|
||
(unsigned short)(maxWidth + 0.5) :
|
||
(unsigned short)(maxHeight + 0.5);
|
||
}
|
||
|
||
/*
|
||
* QualifyName - takes an unqualified file name such as X6printers and
|
||
* a colon-separated list of directory path names such as
|
||
* /etc/opt/dt:/opt/dt/config.
|
||
*
|
||
* Returns a fully qualified file path name such as /etc/opt/dt/X6printers.
|
||
* The returned value is malloc'd, and the caller is responsible for
|
||
* freeing the associated memory.
|
||
*/
|
||
static char *
|
||
QualifyName(fileName, searchPath)
|
||
char *fileName;
|
||
char *searchPath;
|
||
{
|
||
char * curPath = searchPath;
|
||
char * nextPath;
|
||
char * chance;
|
||
FILE *pFile;
|
||
|
||
if (fileName == NULL || searchPath == NULL)
|
||
return NULL;
|
||
|
||
while (1) {
|
||
if ((nextPath = strchr(curPath, ':')) != NULL)
|
||
*nextPath = 0;
|
||
|
||
chance = (char *)xalloc(strlen(curPath) + strlen(fileName) + 2);
|
||
sprintf(chance,"%s/%s",curPath,fileName);
|
||
|
||
/* see if we can read from the file */
|
||
if((pFile = fopen(chance, "r")) != (FILE *)NULL)
|
||
{
|
||
fclose(pFile);
|
||
/* ... restore the colon, .... */
|
||
if (nextPath)
|
||
*nextPath = ':';
|
||
|
||
return chance;
|
||
}
|
||
|
||
xfree(chance);
|
||
|
||
if (nextPath == NULL) /* End of path list? */
|
||
break;
|
||
|
||
/* try the next path */
|
||
curPath = nextPath + 1;
|
||
}
|
||
return NULL;
|
||
}
|
||
|
||
/*
|
||
* FillPrinterListEntry fills in a single XpDiListEntry element with data
|
||
* derived from the supplied PrinterDbPtr element.
|
||
*
|
||
* XXX A smarter (i.e. future) version of this routine might inspect the
|
||
* XXX "locale" parameter and attempt to match the "description" and
|
||
* XXX "localeName" elements of the XpDiListEntry to the specified locale.
|
||
*/
|
||
static void
|
||
FillPrinterListEntry(
|
||
XpDiListEntry *pEntry,
|
||
PrinterDbPtr pDb,
|
||
int localeLen,
|
||
char *locale)
|
||
{
|
||
static char *localeStr = (char *)NULL;
|
||
|
||
if(localeStr == (char *)NULL)
|
||
localeStr = strdup(setlocale(LC_ALL, (const char *)NULL));
|
||
|
||
pEntry->name = pDb->name;
|
||
pEntry->description =
|
||
(char*)XpGetPrinterAttribute(pDb->name, "descriptor");
|
||
pEntry->localeName = localeStr;
|
||
pEntry->rootWinId = WindowTable[pDb->screenNum]->drawable.id;
|
||
}
|
||
|
||
/*
|
||
* GetPrinterListInfo fills in the XpDiListEntry struct pointed to by the
|
||
* parameter pEntry with the information regarding the printer specified
|
||
* by the name and nameLen parameters. The pointers placed in the
|
||
* XpDiListEntry structure MUST NOT be freed by the caller. They are
|
||
* pointers into existing long-lived databases.
|
||
*
|
||
*/
|
||
static Bool
|
||
GetPrinterListInfo(
|
||
XpDiListEntry *pEntry,
|
||
int nameLen,
|
||
char *name,
|
||
int localeLen,
|
||
char *locale)
|
||
{
|
||
PrinterDbPtr pDb, pDb2;
|
||
|
||
for(pDb = printerDb; pDb != (PrinterDbPtr)NULL; pDb = pDb->next)
|
||
{
|
||
if(strlen(pDb->name) == nameLen && !strncmp(pDb->name, name, nameLen))
|
||
{
|
||
FillPrinterListEntry(pEntry, pDb, localeLen, locale);
|
||
return TRUE;
|
||
}
|
||
}
|
||
return FALSE;
|
||
}
|
||
|
||
/*
|
||
* XpDiFreePrinterList is the approved method of releasing memory used
|
||
* for a printer list.
|
||
*/
|
||
void
|
||
XpDiFreePrinterList(XpDiListEntry **list)
|
||
{
|
||
int i;
|
||
|
||
for(i = 0; list[i] != (XpDiListEntry *)NULL; i++)
|
||
xfree(list[i]);
|
||
xfree(list);
|
||
}
|
||
|
||
/*
|
||
* XpDiGetPrinterList returns a pointer to a NULL-terminated array of
|
||
* XpDiListEntry pointers. Each entry structure contains the name,
|
||
* description, root window, and locale of a printer. The call returns
|
||
* either a list of all printers configured on the server, or it returns
|
||
* the information for one specific printer depending on the values passed
|
||
* in. Non-NULL values passed in indicate that only the information for
|
||
* the one specific printer is desired, while NULL values indicate that
|
||
* the information for all printers is desired.
|
||
*/
|
||
XpDiListEntry **
|
||
XpDiGetPrinterList(
|
||
int nameLen,
|
||
char *name,
|
||
int localeLen,
|
||
char *locale)
|
||
{
|
||
XpDiListEntry **pList;
|
||
|
||
if(!nameLen || name == (char *)NULL)
|
||
{
|
||
int i;
|
||
PrinterDbPtr pDb, pDb2;
|
||
|
||
for(pDb = printerDb, i = 0; pDb != (PrinterDbPtr)NULL;
|
||
pDb = pDb->next, i++)
|
||
;
|
||
|
||
if((pList = (XpDiListEntry **)xalloc((i+1) * sizeof(XpDiListEntry *)))
|
||
== (XpDiListEntry **)NULL)
|
||
return pList;
|
||
|
||
pList[i] = (XpDiListEntry *)NULL;
|
||
for(pDb = printerDb, i = 0; pDb != (PrinterDbPtr)NULL;
|
||
pDb = pDb->next, i++)
|
||
{
|
||
if((pList[i] = (XpDiListEntry *)xalloc(sizeof(XpDiListEntry)))==
|
||
(XpDiListEntry *)NULL)
|
||
{
|
||
XpDiFreePrinterList(pList);
|
||
return (XpDiListEntry **)NULL;
|
||
}
|
||
FillPrinterListEntry(pList[i], pDb, localeLen, locale);
|
||
}
|
||
}
|
||
else
|
||
{
|
||
if((pList = (XpDiListEntry **)xalloc(2 * sizeof(XpDiListEntry *))) ==
|
||
(XpDiListEntry **)NULL)
|
||
return pList;
|
||
|
||
if((pList[0] = (XpDiListEntry *)xalloc(sizeof(XpDiListEntry))) ==
|
||
(XpDiListEntry *)NULL)
|
||
{
|
||
xfree(pList);
|
||
return (XpDiListEntry **)NULL;
|
||
}
|
||
pList[1] = (XpDiListEntry *)NULL;
|
||
if(GetPrinterListInfo(pList[0], nameLen, name, localeLen, locale) ==
|
||
FALSE)
|
||
{
|
||
xfree(pList[0]);
|
||
pList[0] = (XpDiListEntry *)NULL;
|
||
}
|
||
}
|
||
return pList;
|
||
}
|
||
|
||
WindowPtr
|
||
XpDiValidatePrinter(char *printerName, int printerNameLen)
|
||
{
|
||
PrinterDbPtr pCurEntry;
|
||
WindowPtr pWin;
|
||
|
||
for(pCurEntry = printerDb;
|
||
pCurEntry != (PrinterDbPtr)NULL; pCurEntry = pCurEntry->next)
|
||
{
|
||
if(strlen(pCurEntry->name) == printerNameLen &&
|
||
!strncmp(pCurEntry->name, printerName, printerNameLen))
|
||
return WindowTable[pCurEntry->screenNum];
|
||
}
|
||
return (WindowPtr)NULL;
|
||
}
|
||
|
||
/*
|
||
* XpDiGetDriverName takes a screen index and a printer name, and returns
|
||
* a pointer to the name of the driver to be used for the specified printer
|
||
* on the specified screen.
|
||
*/
|
||
char *
|
||
XpDiGetDriverName(int index, char *printerName)
|
||
{
|
||
|
||
PrinterDbPtr pCurEntry;
|
||
|
||
for(pCurEntry = printerDb;
|
||
pCurEntry != (PrinterDbPtr)NULL; pCurEntry = pCurEntry->next)
|
||
{
|
||
if(pCurEntry->screenNum == index &&
|
||
!strcmp(pCurEntry->name, printerName))
|
||
return pCurEntry->driverName;
|
||
}
|
||
|
||
return (char *)NULL; /* XXX Should we supply a default driverName? */
|
||
}
|
||
|