Implemented /etc/printcap based printing support.

Changed 'CUPS:printername' to 'LPR:printername'.
Some fixes in AddPrinterW().
This commit is contained in:
Marcus Meissner 2001-05-09 17:10:41 +00:00 committed by Alexandre Julliard
parent b7c2f2ff68
commit 0c63012b6d
4 changed files with 241 additions and 62 deletions

View File

@ -384,7 +384,7 @@ INT16 WINAPI InsertPQ16(HPQ16 hPQ, INT16 tag, INT16 key)
{ {
struct hpq *queueItem = HeapAlloc(GetProcessHeap(), 0, sizeof(struct hpq)); struct hpq *queueItem = HeapAlloc(GetProcessHeap(), 0, sizeof(struct hpq));
if(queueItem == NULL) { if(queueItem == NULL) {
ERR("Memory exausted!"); ERR("Memory exausted!\n");
return FALSE; return FALSE;
} }
queueItem->next = hpqueue; queueItem->next = hpqueue;
@ -456,8 +456,8 @@ static int CreateSpoolFile(LPCSTR pszOutput)
if (pszOutput == NULL || *pszOutput == '\0') if (pszOutput == NULL || *pszOutput == '\0')
return -1; return -1;
if (!strncmp("CUPS:",pszOutput,5)) if (!strncmp("LPR:",pszOutput,4))
sprintf(psCmd,"|lpr -P%s",pszOutput+5); sprintf(psCmd,"|lpr -P%s",pszOutput+4);
else else
PROFILE_GetWineIniString("spooler",pszOutput,"",psCmd,sizeof(psCmd)); PROFILE_GetWineIniString("spooler",pszOutput,"",psCmd,sizeof(psCmd));
TRACE("Got printerSpoolCommand '%s' for output device '%s'\n", TRACE("Got printerSpoolCommand '%s' for output device '%s'\n",
@ -555,7 +555,7 @@ HPJOB16 WINAPI OpenJob16(LPCSTR lpOutput, LPCSTR lpTitle, HDC16 hDC)
{ {
pPrintJob = HeapAlloc(GetProcessHeap(), 0, sizeof(PRINTJOB)); pPrintJob = HeapAlloc(GetProcessHeap(), 0, sizeof(PRINTJOB));
if(pPrintJob == NULL) { if(pPrintJob == NULL) {
WARN("Memory exausted!"); WARN("Memory exausted!\n");
return hHandle; return hHandle;
} }

View File

@ -522,9 +522,9 @@ PRINTERINFO *PSDRV_FindPrinterInfo(LPCSTR name)
strncpy(ppdFileName, ppd, sizeof(ppdFileName)); strncpy(ppdFileName, ppd, sizeof(ppdFileName));
res = ERROR_SUCCESS; res = ERROR_SUCCESS;
/* we should unlink() that file later */ /* we should unlink() that file later */
} } else {
else { res = ERROR_FILE_NOT_FOUND;
ERR("Did not find ppd for %s\n",name); WARN("Did not find ppd for %s\n",name);
} }
} }
#endif #endif
@ -533,7 +533,17 @@ PRINTERINFO *PSDRV_FindPrinterInfo(LPCSTR name)
res = GetPrinterDataA (hPrinter, "PPD File", NULL, ppdFileName, res = GetPrinterDataA (hPrinter, "PPD File", NULL, ppdFileName,
sizeof(ppdFileName), &needed); sizeof(ppdFileName), &needed);
} }
/* Look for a ppd file for this printer in the config file.
* First look for the names of the printer, then for 'generic'
*/
if ((res!=ERROR_SUCCESS) &&
!PROFILE_GetWineIniString("ppd",name,"",ppdFileName,sizeof(ppdFileName)) &&
!PROFILE_GetWineIniString("ppd","generic","",ppdFileName,sizeof(ppdFileName))
)
res = ERROR_FILE_NOT_FOUND;
else
res = ERROR_SUCCESS;
if (res != ERROR_SUCCESS) { if (res != ERROR_SUCCESS) {
ERR ("Error %li getting PPD file name for printer '%s'\n", res, name); ERR ("Error %li getting PPD file name for printer '%s'\n", res, name);
goto closeprinter; goto closeprinter;

View File

@ -76,46 +76,37 @@ static WCHAR Share_NameW[] = {'S','h','a','r','e',' ','N','a','m','e',0};
static WCHAR WinPrintW[] = {'W','i','n','P','r','i','n','t',0}; static WCHAR WinPrintW[] = {'W','i','n','P','r','i','n','t',0};
static HKEY WINSPOOL_OpenDriverReg( LPVOID pEnvironment, BOOL unicode); static HKEY WINSPOOL_OpenDriverReg( LPVOID pEnvironment, BOOL unicode);
static BOOL WINSPOOL_GetPrinterDriver(HANDLE hPrinter, LPWSTR pEnvironment,
DWORD Level, LPBYTE pDriverInfo,
DWORD cbBuf, LPDWORD pcbNeeded,
BOOL unicode);
#ifdef HAVE_CUPS #ifdef HAVE_CUPS
void BOOL
CUPS_LoadPrinters(void) { CUPS_LoadPrinters(void) {
cups_dest_t *dests; cups_dest_t *dests;
int i,nrofdests; int i,nrofdests,hadprinter = FALSE;
PRINTER_INFO_2A pinfo2a; PRINTER_INFO_2A pinfo2a;
DRIVER_INFO_3A di3a;
const char* def = cupsGetDefault(); const char* def = cupsGetDefault();
nrofdests = cupsGetDests(&dests); nrofdests = cupsGetDests(&dests);
di3a.cVersion = 0x400;
di3a.pName = "PS Driver";
di3a.pEnvironment = NULL; /* NULL means auto */
di3a.pDriverPath = "wineps.drv";
di3a.pDataFile = "<datafile?>";
di3a.pConfigFile = "wineps.drv";
di3a.pHelpFile = "<helpfile?>";
di3a.pDependentFiles = "<dependend files?>";
di3a.pMonitorName = "<monitor name?>";
di3a.pDefaultDataType = "RAW";
if (!AddPrinterDriverA(NULL,3,(LPBYTE)&di3a)) {
ERR("Failed adding PS Driver (%ld)\n",GetLastError());
return;
}
for (i=0;i<nrofdests;i++) { for (i=0;i<nrofdests;i++) {
const char *ppd = cupsGetPPD(dests[i].name); const char *ppd = cupsGetPPD(dests[i].name);
char *port,*devline; char *port,*devline;
if (!ppd) if (!ppd) {
continue; WARN("No ppd file for %s.\n",dests[i].name);
continue;
}
unlink(ppd); unlink(ppd);
if (!strcmp(def,dests[i].name)) { hadprinter = TRUE;
char *buf = HeapAlloc(GetProcessHeap(),0,2*strlen(dests[i].name)+strlen(",WINEPS,CUPS:")+1);
sprintf(buf,"%s,WINEPS,CUPS:%s",dests[i].name,dests[i].name); if (!strcmp(def,dests[i].name)) {
char *buf = HeapAlloc(GetProcessHeap(),0,2*strlen(dests[i].name)+strlen(",WINEPS,LPR:")+1);
sprintf(buf,"%s,WINEPS,LPR:%s",dests[i].name,dests[i].name);
WriteProfileStringA("windows","device",buf); WriteProfileStringA("windows","device",buf);
HeapFree(GetProcessHeap(),0,buf); HeapFree(GetProcessHeap(),0,buf);
} }
@ -126,8 +117,8 @@ CUPS_LoadPrinters(void) {
pinfo2a.pDriverName = "PS Driver"; pinfo2a.pDriverName = "PS Driver";
pinfo2a.pComment = "WINEPS Printer using CUPS"; pinfo2a.pComment = "WINEPS Printer using CUPS";
pinfo2a.pLocation = "<physical location of printer>"; pinfo2a.pLocation = "<physical location of printer>";
port = HeapAlloc(GetProcessHeap(),0,strlen("CUPS:")+strlen(dests[i].name)+1); port = HeapAlloc(GetProcessHeap(),0,strlen("LPR:")+strlen(dests[i].name)+1);
sprintf(port,"CUPS:%s",dests[i].name); sprintf(port,"LPR:%s",dests[i].name);
pinfo2a.pPortName = port; pinfo2a.pPortName = port;
pinfo2a.pParameters = "<parameters?>"; pinfo2a.pParameters = "<parameters?>";
pinfo2a.pShareName = "<share name?>"; pinfo2a.pShareName = "<share name?>";
@ -144,9 +135,170 @@ CUPS_LoadPrinters(void) {
} }
HeapFree(GetProcessHeap(),0,port); HeapFree(GetProcessHeap(),0,port);
} }
return hadprinter;
} }
#endif #endif
static BOOL
PRINTCAP_ParseEntry(char *pent,BOOL isfirst) {
PRINTER_INFO_2A pinfo2a;
char *s,*name,*prettyname,*devname;
BOOL isps = FALSE;
char *port,*devline;
s = strchr(pent,':');
if (!s) return FALSE;
*s='\0';
name = pent;
pent = s+1;
TRACE("%s\n",name);
/* Determine whether this is a postscript printer. */
/* 1. Check if name or aliases contain trigger phrases like 'ps' */
if (strstr(name,"ps") ||
strstr(name,"pd") || /* postscript double page */
strstr(name,"postscript") ||
strstr(name,"PostScript")
) {
TRACE("%s has 'ps' style name, assuming postscript.\n",name);
isps = TRUE;
}
/* 2. Check if this is a remote printer. These usually are postscript
* capable
*/
if (strstr(pent,":rm")) {
isps = TRUE;
TRACE("%s is remote, assuming postscript.\n",name);
}
/* 3. Check if we have an input filter program. If we have one, it
* most likely is one capable of converting postscript.
* (Could probably check for occurence of 'gs' or 'ghostscript'
* in the if file itself.)
*/
if (strstr(pent,":if=/")) {
isps = TRUE;
TRACE("%s has inputfilter program, assuming postscript.\n",name);
}
/* If it is not a postscript printer, we cannot use it. */
if (!isps)
return FALSE;
prettyname = name;
/* Get longest name, usually the one at the right for later display. */
while ((s=strchr(prettyname,'|'))) prettyname = s+1;
s=strchr(name,'|');if (s) *s='\0';
/* prettyname must fit into the dmDeviceName member of DEVMODE struct,
* if it is too long, we use it as comment below. */
devname = prettyname;
if (strlen(devname)>=CCHDEVICENAME-1)
devname = name;
if (strlen(devname)>=CCHDEVICENAME-1)
return FALSE;
if (isfirst) {
char *buf = HeapAlloc(GetProcessHeap(),0,strlen(name)+strlen(devname)+strlen(",WINEPS,LPR:")+1);
sprintf(buf,"%s,WINEPS,LPR:%s",devname,name);
WriteProfileStringA("windows","device",buf);
HeapFree(GetProcessHeap(),0,buf);
}
memset(&pinfo2a,0,sizeof(pinfo2a));
pinfo2a.pPrinterName = devname;
pinfo2a.pDatatype = "RAW";
pinfo2a.pPrintProcessor = "WinPrint";
pinfo2a.pDriverName = "PS Driver";
pinfo2a.pComment = "WINEPS Printer using LPR";
pinfo2a.pLocation = prettyname;
port = HeapAlloc(GetProcessHeap(),0,strlen("LPR:")+strlen(name)+1);
sprintf(port,"LPR:%s",name);
pinfo2a.pPortName = port;
pinfo2a.pParameters = "<parameters?>";
pinfo2a.pShareName = "<share name?>";
pinfo2a.pSepFile = "<sep file?>";
devline=HeapAlloc(GetProcessHeap(),0,strlen("WINEPS,")+strlen(port)+1);
sprintf(devline,"WINEPS,%s",port);
WriteProfileStringA("devices",devname,devline);
HeapFree(GetProcessHeap(),0,devline);
if (!AddPrinterA(NULL,2,(LPBYTE)&pinfo2a)) {
if (GetLastError()!=ERROR_PRINTER_ALREADY_EXISTS)
ERR("%s not added by AddPrinterA (%ld)\n",name,GetLastError());
}
HeapFree(GetProcessHeap(),0,port);
return TRUE;
}
static BOOL
PRINTCAP_LoadPrinters(void) {
BOOL hadprinter = FALSE, isfirst = TRUE;
char buf[200];
FILE *f;
f = fopen("/etc/printcap","r");
if (!f)
return FALSE;
while (fgets(buf,sizeof(buf),f)) {
char *pent = NULL;
do {
char *s;
s=strchr(buf,'\n'); if (s) *s='\0';
if ((buf[0]=='#') || (buf[0]=='\0'))
continue;
if (pent) {
pent=HeapReAlloc(GetProcessHeap(),0,pent,strlen(pent)+strlen(buf)+2);
strcat(pent,buf);
} else {
pent=HeapAlloc(GetProcessHeap(),0,strlen(buf)+1);
strcpy(pent,buf);
}
if (strlen(pent) && (pent[strlen(pent)-1] == '\\'))
pent[strlen(pent)-1] = '\0';
else
break;
} while (fgets(buf,sizeof(buf),f));
if (pent)
hadprinter |= PRINTCAP_ParseEntry(pent,isfirst);
isfirst = FALSE;
if (pent) HeapFree(GetProcessHeap(),0,pent);
pent = NULL;
if (feof(f)) break;
}
fclose(f);
return hadprinter;
}
void
WINSPOOL_LoadSystemPrinters() {
DRIVER_INFO_3A di3a;
di3a.cVersion = 0x400;
di3a.pName = "PS Driver";
di3a.pEnvironment = NULL; /* NULL means auto */
di3a.pDriverPath = "wineps.drv";
di3a.pDataFile = "<datafile?>";
di3a.pConfigFile = "wineps.drv";
di3a.pHelpFile = "<helpfile?>";
di3a.pDependentFiles = "<dependend files?>";
di3a.pMonitorName = "<monitor name?>";
di3a.pDefaultDataType = "RAW";
if (!AddPrinterDriverA(NULL,3,(LPBYTE)&di3a)) {
ERR("Failed adding PS Driver (%ld)\n",GetLastError());
return;
}
#ifdef HAVE_CUPS
/* If we have any CUPS based printers, skip looking for printcap printers */
if (CUPS_LoadPrinters())
return;
#endif
PRINTCAP_LoadPrinters();
}
/****************************************************************** /******************************************************************
* WINSPOOL_GetOpenedPrinterEntry * WINSPOOL_GetOpenedPrinterEntry
@ -792,6 +944,13 @@ HANDLE WINAPI AddPrinterW(LPWSTR pName, DWORD Level, LPBYTE pPrinter)
SetLastError(ERROR_INVALID_LEVEL); SetLastError(ERROR_INVALID_LEVEL);
return 0; return 0;
} }
if (strlenW(pi->pPrinterName) >= CCHDEVICENAME) {
ERR("Printername %s must not exceed length of DEVMODE.dmDeviceName !\n",
debugstr_w(pi->pPrinterName)
);
SetLastError(ERROR_INVALID_LEVEL);
return 0;
}
if(!pPrinter) { if(!pPrinter) {
SetLastError(ERROR_INVALID_PARAMETER); SetLastError(ERROR_INVALID_PARAMETER);
return 0; return 0;
@ -801,12 +960,14 @@ HANDLE WINAPI AddPrinterW(LPWSTR pName, DWORD Level, LPBYTE pPrinter)
ERR("Can't create Printers key\n"); ERR("Can't create Printers key\n");
return 0; return 0;
} }
if(RegOpenKeyW(hkeyPrinters, pi->pPrinterName, &hkeyPrinter) == if(!RegOpenKeyW(hkeyPrinters, pi->pPrinterName, &hkeyPrinter)) {
ERROR_SUCCESS) { if (!RegQueryValueA(hkeyPrinter,"Attributes",NULL,NULL)) {
SetLastError(ERROR_PRINTER_ALREADY_EXISTS); SetLastError(ERROR_PRINTER_ALREADY_EXISTS);
RegCloseKey(hkeyPrinter);
RegCloseKey(hkeyPrinters);
return 0;
}
RegCloseKey(hkeyPrinter); RegCloseKey(hkeyPrinter);
RegCloseKey(hkeyPrinters);
return 0;
} }
hkeyDrivers = WINSPOOL_OpenDriverReg( NULL, TRUE); hkeyDrivers = WINSPOOL_OpenDriverReg( NULL, TRUE);
if(!hkeyDrivers) { if(!hkeyDrivers) {
@ -832,34 +993,44 @@ HANDLE WINAPI AddPrinterW(LPWSTR pName, DWORD Level, LPBYTE pPrinter)
return 0; return 0;
} }
/* See if we can load the driver. We may need the devmode structure anyway
*/
size = DocumentPropertiesW(0, -1, pi->pPrinterName, NULL, NULL, 0);
if(size < 0) {
FIXME("DocumentProperties fails\n");
size = sizeof(DEVMODEW);
}
if(pi->pDevMode) {
dmW = pi->pDevMode;
} else {
dmW = HeapAlloc(GetProcessHeap(), 0, size);
dmW->dmSize = size;
DocumentPropertiesW(0, -1, pi->pPrinterName, dmW, NULL, DM_OUT_BUFFER);
}
if(RegCreateKeyW(hkeyPrinters, pi->pPrinterName, &hkeyPrinter) != if(RegCreateKeyW(hkeyPrinters, pi->pPrinterName, &hkeyPrinter) !=
ERROR_SUCCESS) { ERROR_SUCCESS) {
FIXME("Can't create printer %s\n", debugstr_w(pi->pPrinterName)); FIXME("Can't create printer %s\n", debugstr_w(pi->pPrinterName));
SetLastError(ERROR_INVALID_PRINTER_NAME); SetLastError(ERROR_INVALID_PRINTER_NAME);
RegCloseKey(hkeyPrinters); RegCloseKey(hkeyPrinters);
if(!pi->pDevMode)
HeapFree(GetProcessHeap(), 0, dmW);
return 0; return 0;
} }
RegSetValueExA(hkeyPrinter, "Attributes", 0, REG_DWORD, RegSetValueExA(hkeyPrinter, "Attributes", 0, REG_DWORD,
(LPBYTE)&pi->Attributes, sizeof(DWORD)); (LPBYTE)&pi->Attributes, sizeof(DWORD));
RegSetValueExW(hkeyPrinter, DatatypeW, 0, REG_SZ, (LPBYTE)pi->pDatatype, RegSetValueExW(hkeyPrinter, DatatypeW, 0, REG_SZ, (LPBYTE)pi->pDatatype,
0); 0);
/* See if we can load the driver. We may need the devmode structure anyway
*
* FIXME:
* Note that DocumentPropertiesW will briefly try to open the printer we
* just create to find a DEVMODEA struct (it will use the WINEPS default
* one in case it is not there, so we are ok).
*/
size = DocumentPropertiesW(0, -1, pi->pPrinterName, NULL, NULL, 0);
if(size < 0) {
FIXME("DocumentProperties fails\n");
size = sizeof(DEVMODEW);
}
if(pi->pDevMode)
dmW = pi->pDevMode;
else {
dmW = HeapAlloc(GetProcessHeap(), 0, size);
dmW->dmSize = size;
if (0>DocumentPropertiesW(0,-1,pi->pPrinterName,dmW,NULL,DM_OUT_BUFFER)) {
ERR("DocumentPropertiesW failed!\n");
SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER);
return 0;
}
/* set devmode to printer name */
strcpyW(dmW->dmDeviceName,pi->pPrinterName);
}
/* Write DEVMODEA not DEVMODEW into reg. This is what win9x does /* Write DEVMODEA not DEVMODEW into reg. This is what win9x does
and we support these drivers. NT writes DEVMODEW so somehow and we support these drivers. NT writes DEVMODEW so somehow
we'll need to distinguish between these when we support NT we'll need to distinguish between these when we support NT
@ -1165,7 +1336,7 @@ static BOOL WINSPOOL_GetDevModeFromReg(HKEY hkey, LPCWSTR ValueName,
if (sz < sizeof(DEVMODEA)) if (sz < sizeof(DEVMODEA))
{ {
ERR("corrupted registry for %s ( size %ld)\n",debugstr_w(ValueName),sz); ERR("corrupted registry for %s ( size %ld)\n",debugstr_w(ValueName),sz);
sz = sizeof(DEVMODEA); return FALSE;
} }
/* ensures that dmSize is not erratically bogus if registry is invalid */ /* ensures that dmSize is not erratically bogus if registry is invalid */
if (ptr && ((DEVMODEA*)ptr)->dmSize < sizeof(DEVMODEA)) if (ptr && ((DEVMODEA*)ptr)->dmSize < sizeof(DEVMODEA))
@ -2123,7 +2294,7 @@ BOOL WINAPI AddPrinterDriverA(LPSTR pName, DWORD level, LPBYTE pDriverInfo)
return FALSE; return FALSE;
} }
if(!pDriverInfo) { if(!pDriverInfo) {
WARN("pDriverInfo == NULL"); WARN("pDriverInfo == NULL\n");
SetLastError(ERROR_INVALID_PARAMETER); SetLastError(ERROR_INVALID_PARAMETER);
return FALSE; return FALSE;
} }

View File

@ -26,10 +26,8 @@ BOOL WINAPI WINSPOOL_EntryPoint(HINSTANCE hInstance,
switch (reason) switch (reason)
{ {
case DLL_PROCESS_ATTACH: { case DLL_PROCESS_ATTACH: {
#ifdef HAVE_CUPS extern void WINSPOOL_LoadSystemPrinters();
extern void CUPS_LoadPrinters(); WINSPOOL_LoadSystemPrinters();
CUPS_LoadPrinters();
#endif
break; break;
} }
case DLL_PROCESS_DETACH: case DLL_PROCESS_DETACH: