summaryrefslogtreecommitdiff
path: root/hw/xprint/Init.c
diff options
context:
space:
mode:
Diffstat (limited to 'hw/xprint/Init.c')
-rw-r--r--hw/xprint/Init.c1921
1 files changed, 1921 insertions, 0 deletions
diff --git a/hw/xprint/Init.c b/hw/xprint/Init.c
new file mode 100644
index 000000000..0f1be6791
--- /dev/null
+++ b/hw/xprint/Init.c
@@ -0,0 +1,1921 @@
+/* $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
+** *
+** *********************************************************
+**
+********************************************************************/
+
+#ifdef HAVE_DIX_CONFIG_H
+#include <dix-config.h>
+#endif
+
+#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 <X11/X.h>
+#define NEED_EVENTS 1
+#include <X11/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 <X11/fonts/fontstruct.h>
+#include "errno.h"
+
+typedef char *XPointer;
+#define HAVE_XPointer 1
+
+#define Status int
+#include <X11/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 },
+ { 12, 16, BITMAP_SCANLINE_PAD },
+ { 14, 16, BITMAP_SCANLINE_PAD },
+ { 16, 16, 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 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 PrinterInitGlobals(void)
+{
+ xprintInitGlobalsCalled = TRUE;
+
+#ifdef DAMAGE
+ /* Disable DAMAGE extension for now as it does not work with
+ * the Postscript DDX yet (see
+ * https://bugs.freedesktop.org/show_bug.cgi?id=1660) ...
+ * (you can enable the DAMAGE extension explicitly via
+ * % X +extension DAMAGE ... #) ;-( */
+ noDamageExtension = TRUE;
+#endif /* DAMAGE */
+
+#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;
+}
+
+/*
+ * PrinterUseMsg() prints usage for the Xprint-specific options
+ */
+void PrinterUseMsg(void)
+{
+ 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);
+}
+
+/*
+ * PrinterOptions 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
+PrinterOptions(
+ int argc,
+ char **argv,
+ int i)
+{
+ 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(void)
+{
+ 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)
+{
+ 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: 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 *modelID, **allIDs = (char **)NULL;
+ PrinterDbPtr 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-modes document/page attribute to
+ * see if xp-list-glyph-fonts has been left out of the mode list. Only
+ * if the xp-listfonts-modes 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-modes");
+ if(!mode || !strlen(mode))
+ {
+ mode = XpGetOneAttribute(pContext, XPDocAttr, "xp-listfonts-modes");
+ 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 at the value of the xp-listfonts-modes
+ * document/page attribute to see if xp-list-internal-printer-fonts has
+ * been left out of the mode list.
+ * If the xp-listfonts-modes attribute exists, and it does not contain
+ * xp-list-internal-printer-fonts this function returns FALSE.
+ * Otherwise it 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 *mode;
+ char *modelID, *fontDir;
+
+ if(!(pContext = XpContextOfClient(client)))
+ return FALSE;
+
+ /*
+ * Check the page attributes, and if it's not defined there, then
+ * check the document attributes.
+ */
+ mode = XpGetOneAttribute(pContext, XPPageAttr, "xp-listfonts-modes");
+ if(!mode || !strlen(mode))
+ {
+ mode = XpGetOneAttribute(pContext, XPDocAttr, "xp-listfonts-modes");
+ }
+
+ if(mode && strlen(mode))
+ {
+ if(!strstr(mode, "xp-list-internal-printer-fonts"))
+ 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: PrinterInitGlobals() not called.");
+ }
+#ifdef SMART_SCHEDULE
+ /* |PrinterInitGlobals| 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")
+ * |PrinterInitGlobals| 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)(BFuncArgs);
+ 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)
+{
+ float fWidth, fHeight, maxWidth, maxHeight;
+ unsigned short width, height;
+ PrinterDbPtr pDb;
+ 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);
+}
+
+#if 0 /* No one uses this anymore... */
+/*
+ * 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(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;
+}
+#endif
+
+/*
+ * 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;
+
+ 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;
+
+ 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;
+
+ 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? */
+}
+