winspool: Move CUPS printer enumeration to cups.c.

Signed-off-by: Huw Davies <huw@codeweavers.com>
Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
Huw Davies 2021-10-26 11:18:10 +01:00 committed by Alexandre Julliard
parent 9d8bf3bf96
commit 5a163d5537
3 changed files with 185 additions and 96 deletions

View File

@ -41,11 +41,22 @@
#include "winspool.h"
#include "ddk/winsplp.h"
#include "wine/debug.h"
#include "wine/unicode.h"
#include "wspool.h"
WINE_DEFAULT_DEBUG_CHANNEL(winspool);
/* Temporary helpers until switch to unixlib */
#include "winnls.h"
#include "wine/heap.h"
#define malloc( sz ) heap_alloc( sz )
#define free( ptr ) heap_free( ptr )
static DWORD ntdll_umbstowcs( const char *src, DWORD srclen, WCHAR *dst, DWORD dstlen )
{
return MultiByteToWideChar( CP_UNIXCP, 0, src, srclen, dst, dstlen );
}
#ifdef SONAME_LIBCUPS
void *libcups_handle = NULL;
@ -99,3 +110,109 @@ NTSTATUS unix_process_attach( void *arg )
return STATUS_NOT_SUPPORTED;
#endif /* SONAME_LIBCUPS */
}
#ifdef SONAME_LIBCUPS
static WCHAR *cups_get_optionW( const char *opt_name, int num_options, cups_option_t *options )
{
const char *value;
WCHAR *ret;
int len;
value = pcupsGetOption( opt_name, num_options, options );
if (!value) return NULL;
len = strlen( value ) + 1;
ret = malloc( len * sizeof(WCHAR) );
if (ret) ntdll_umbstowcs( value, len, ret, len );
return ret;
}
static cups_ptype_t cups_get_printer_type( const cups_dest_t *dest )
{
const char *value;
cups_ptype_t ret;
char *end;
value = pcupsGetOption( "printer-type", dest->num_options, dest->options );
if (!value) return 0;
ret = (cups_ptype_t)strtoul( value, &end, 10 );
if (*end) ret = 0;
return ret;
}
static BOOL cups_is_scanner( cups_dest_t *dest )
{
return cups_get_printer_type( dest ) & 0x2000000 /* CUPS_PRINTER_SCANNER */;
}
#endif /* SONAME_LIBCUPS */
NTSTATUS unix_enum_printers( void *args )
{
struct enum_printers_params *params = args;
#ifdef SONAME_LIBCUPS
unsigned int num, i, name_len, comment_len, location_len, needed;
WCHAR *comment, *location, *ptr;
struct printer_info *info;
cups_dest_t *dests;
params->num = 0;
if (!pcupsGetDests) return STATUS_NOT_SUPPORTED;
num = pcupsGetDests( &dests );
for (i = 0; i < num; i++)
{
if (cups_is_scanner( dests + i ))
{
TRACE( "Printer %d: %s - skipping scanner\n", i, debugstr_a( dests[i].name ) );
continue;
}
TRACE( "Printer %d: %s\n", i, debugstr_a( dests[i].name ) );
params->num++;
}
needed = sizeof( *info ) * params->num;
info = params->printers;
ptr = (WCHAR *)(info + params->num);
for (i = 0; i < num; i++)
{
if (cups_is_scanner( dests + i )) continue;
comment = cups_get_optionW( "printer-info", dests[i].num_options, dests[i].options );
location = cups_get_optionW( "printer-location", dests[i].num_options, dests[i].options );
name_len = strlen( dests[i].name ) + 1;
comment_len = comment ? strlenW( comment ) + 1 : 0;
location_len = location ? strlenW( location ) + 1 : 0;
needed += (name_len + comment_len + location_len) * sizeof(WCHAR);
if (needed <= params->size)
{
info->name = ptr;
ntdll_umbstowcs( dests[i].name, name_len, info->name, name_len );
info->comment = comment ? ptr + name_len : NULL;
memcpy( info->comment, comment, comment_len * sizeof(WCHAR) );
info->location = location ? ptr + name_len + comment_len : NULL;
memcpy( info->location, location, location_len * sizeof(WCHAR) );
info->is_default = dests[i].is_default;
info++;
ptr += name_len + comment_len + location_len;
}
free( comment );
free( location );
}
pcupsFreeDests( num, dests );
if (needed > params->size)
{
params->size = needed;
return STATUS_BUFFER_OVERFLOW;
}
return STATUS_SUCCESS;
#else
params->num = 0;
return STATUS_NOT_SUPPORTED;
#endif /* SONAME_LIBCUPS */
}

View File

@ -107,6 +107,8 @@
#define NONAMELESSSTRUCT
#define NONAMELESSUNION
#include "ntstatus.h"
#define WIN32_NO_STATUS
#include "windef.h"
#include "winbase.h"
#include "winuser.h"
@ -917,7 +919,6 @@ extern void *libcups_handle;
DO_FUNC(cupsAddOption); \
DO_FUNC(cupsFreeDests); \
DO_FUNC(cupsFreeOptions); \
DO_FUNC(cupsGetDests); \
DO_FUNC(cupsGetOption); \
DO_FUNC(cupsParseOptions); \
DO_FUNC(cupsPrintFile)
@ -981,137 +982,96 @@ static BOOL get_cups_ppd( const char *printer_name, const WCHAR *ppd )
return http_status == HTTP_OK;
}
#endif
static WCHAR *get_cups_option( const char *name, int num_options, cups_option_t *options )
static BOOL init_unix_printers( void )
{
const char *value;
WCHAR *ret;
int len;
WCHAR *port, *ppd_dir = NULL, *default_printer = NULL;
struct enum_printers_params enum_params;
HKEY printer_key, printers_key;
HANDLE added_printer;
PRINTER_INFO_2W pi2;
NTSTATUS status;
int i;
value = pcupsGetOption( name, num_options, options );
if (!value) return NULL;
len = MultiByteToWideChar( CP_UNIXCP, 0, value, -1, NULL, 0 );
ret = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) );
if (ret) MultiByteToWideChar( CP_UNIXCP, 0, value, -1, ret, len );
return ret;
}
static cups_ptype_t get_cups_printer_type( const cups_dest_t *dest )
{
WCHAR *type = get_cups_option( "printer-type", dest->num_options, dest->options ), *end;
cups_ptype_t ret = 0;
if (type && *type)
if (RegCreateKeyW( HKEY_LOCAL_MACHINE, PrintersW, &printers_key ) != ERROR_SUCCESS)
{
ret = (cups_ptype_t)strtoulW( type, &end, 10 );
if (*end) ret = 0;
}
HeapFree( GetProcessHeap(), 0, type );
return ret;
}
static BOOL CUPS_LoadPrinters(void)
{
int i, nrofdests;
BOOL hadprinter = FALSE, haddefault = FALSE;
cups_dest_t *dests;
PRINTER_INFO_2W pi2;
WCHAR *port, *ppd_dir = NULL;
HKEY hkeyPrinter, hkeyPrinters;
WCHAR nameW[MAX_PATH];
HANDLE added_printer;
cups_ptype_t printer_type;
if (!libcups_handle) return FALSE;
if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
ERROR_SUCCESS) {
ERR("Can't create Printers key\n");
return FALSE;
ERR( "Can't create Printers key\n" );
return FALSE;
}
nrofdests = pcupsGetDests(&dests);
TRACE("Found %d CUPS %s:\n", nrofdests, (nrofdests == 1) ? "printer" : "printers");
for (i=0;i<nrofdests;i++) {
MultiByteToWideChar(CP_UNIXCP, 0, dests[i].name, -1, nameW, ARRAY_SIZE(nameW));
printer_type = get_cups_printer_type( dests + i );
enum_params.size = 10000;
enum_params.printers = NULL;
do
{
enum_params.size *= 2;
heap_free( enum_params.printers );
enum_params.printers = heap_alloc( enum_params.size );
status = UNIX_CALL( enum_printers, &enum_params );
} while (status == STATUS_BUFFER_OVERFLOW);
if (status) goto end;
TRACE( "Printer %d: %s. printer_type %x\n", i, debugstr_w(nameW), printer_type );
TRACE( "Found %d CUPS %s:\n", enum_params.num, (enum_params.num == 1) ? "printer" : "printers" );
for (i = 0; i < enum_params.num; i++)
{
struct printer_info *printer = enum_params.printers + i;
if (printer_type & 0x2000000 /* CUPS_PRINTER_SCANNER */)
if (RegOpenKeyW( printers_key, printer->name, &printer_key ) == ERROR_SUCCESS)
{
TRACE( "skipping scanner-only device\n" );
continue;
}
if (RegOpenKeyW( hkeyPrinters, nameW, &hkeyPrinter ) == ERROR_SUCCESS)
{
DWORD status = get_dword_from_reg( hkeyPrinter, StatusW );
DWORD status = get_dword_from_reg( printer_key, StatusW );
/* Printer already in registry, delete the tag added in WINSPOOL_LoadSystemPrinters
and continue */
TRACE("Printer already exists\n");
RegDeleteValueW(hkeyPrinter, May_Delete_Value);
RegDeleteValueW( printer_key, May_Delete_Value );
/* flag that the PPD file should be checked for an update */
set_reg_DWORD( hkeyPrinter, StatusW, status | PRINTER_STATUS_DRIVER_UPDATE_NEEDED );
RegCloseKey(hkeyPrinter);
set_reg_DWORD( printer_key, StatusW, status | PRINTER_STATUS_DRIVER_UPDATE_NEEDED );
RegCloseKey( printer_key );
}
else
{
if (!ppd_dir && !(ppd_dir = get_ppd_dir())) break;
if (!add_printer_driver( nameW, ppd_dir )) continue;
if (!add_printer_driver( printer->name, ppd_dir )) continue;
port = heap_alloc( sizeof(CUPS_Port) + lstrlenW( nameW ) * sizeof(WCHAR) );
port = heap_alloc( sizeof(CUPS_Port) + lstrlenW( printer->name ) * sizeof(WCHAR) );
lstrcpyW( port, CUPS_Port );
lstrcatW( port, nameW );
lstrcatW( port, printer->name );
memset(&pi2, 0, sizeof(PRINTER_INFO_2W));
pi2.pPrinterName = nameW;
memset( &pi2, 0, sizeof(PRINTER_INFO_2W) );
pi2.pPrinterName = printer->name;
pi2.pDatatype = rawW;
pi2.pPrintProcessor = WinPrintW;
pi2.pDriverName = nameW;
pi2.pComment = get_cups_option( "printer-info", dests[i].num_options, dests[i].options );
pi2.pLocation = get_cups_option( "printer-location", dests[i].num_options, dests[i].options );
pi2.pDriverName = printer->name;
pi2.pComment = printer->comment;
pi2.pLocation = printer->location;
pi2.pPortName = port;
pi2.pParameters = emptyStringW;
pi2.pShareName = emptyStringW;
pi2.pSepFile = emptyStringW;
added_printer = AddPrinterW( NULL, 2, (LPBYTE)&pi2 );
added_printer = AddPrinterW( NULL, 2, (BYTE *)&pi2 );
if (added_printer) ClosePrinter( added_printer );
else if (GetLastError() != ERROR_PRINTER_ALREADY_EXISTS)
ERR( "printer '%s' not added by AddPrinter (error %d)\n", debugstr_w(nameW), GetLastError() );
ERR( "printer '%s' not added by AddPrinter (error %d)\n", debugstr_w( printer->name ), GetLastError() );
heap_free( port );
HeapFree( GetProcessHeap(), 0, pi2.pComment );
HeapFree( GetProcessHeap(), 0, pi2.pLocation );
}
hadprinter = TRUE;
if (dests[i].is_default) {
SetDefaultPrinterW(nameW);
haddefault = TRUE;
}
if (printer->is_default) default_printer = printer->name;
}
if (!default_printer && enum_params.num) default_printer = enum_params.printers[0].name;
if (default_printer) SetDefaultPrinterW( default_printer );
if (ppd_dir)
{
RemoveDirectoryW( ppd_dir );
HeapFree( GetProcessHeap(), 0, ppd_dir );
heap_free( ppd_dir );
}
if (hadprinter && !haddefault) {
MultiByteToWideChar(CP_UNIXCP, 0, dests[0].name, -1, nameW, ARRAY_SIZE(nameW));
SetDefaultPrinterW(nameW);
}
pcupsFreeDests(nrofdests, dests);
RegCloseKey(hkeyPrinters);
end:
heap_free( enum_params.printers );
RegCloseKey( printers_key );
return TRUE;
}
#endif
static void set_ppd_overrides( HANDLE printer )
{
WCHAR *wstr = NULL;
@ -1493,11 +1453,7 @@ void WINSPOOL_LoadSystemPrinters(void)
}
old_printer_check( FALSE );
#ifdef SONAME_LIBCUPS
CUPS_LoadPrinters();
#endif
init_unix_printers();
old_printer_check( TRUE );
ReleaseMutex( init_mutex );

View File

@ -37,6 +37,22 @@ extern void WINSPOOL_LoadSystemPrinters(void) DECLSPEC_HIDDEN;
#define FILENAME_DIALOG 100
#define EDITBOX 201
struct printer_info
{
WCHAR *name;
WCHAR *comment;
WCHAR *location;
BOOL is_default;
};
struct enum_printers_params
{
struct printer_info *printers;
unsigned int size;
unsigned int num;
};
#define UNIX_CALL( func, params ) unix_ ## func( params )
NTSTATUS unix_process_attach( void * ) DECLSPEC_HIDDEN;
NTSTATUS unix_enum_printers( void * ) DECLSPEC_HIDDEN;