Signed-off-by: Huw Davies huw@codeweavers.com --- dlls/winspool.drv/cups.c | 117 +++++++++++++++++++++++++++++ dlls/winspool.drv/info.c | 148 +++++++++++++------------------------ dlls/winspool.drv/wspool.h | 16 ++++ 3 files changed, 185 insertions(+), 96 deletions(-)
diff --git a/dlls/winspool.drv/cups.c b/dlls/winspool.drv/cups.c index 207c95c568a..7aeb68d4f8d 100644 --- a/dlls/winspool.drv/cups.c +++ b/dlls/winspool.drv/cups.c @@ -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 */ +} diff --git a/dlls/winspool.drv/info.c b/dlls/winspool.drv/info.c index 9d2af8cec94..a3fcb32641a 100644 --- a/dlls/winspool.drv/info.c +++ b/dlls/winspool.drv/info.c @@ -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 ) -{ - const char *value; - WCHAR *ret; - int len; - - 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 ) +static BOOL init_unix_printers( void ) { - WCHAR *type = get_cups_option( "printer-type", dest->num_options, dest->options ), *end; - cups_ptype_t ret = 0; + 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;
- 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 ); - - TRACE( "Printer %d: %s. printer_type %x\n", i, debugstr_w(nameW), printer_type ); + 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;
- if (printer_type & 0x2000000 /* CUPS_PRINTER_SCANNER */) - { - TRACE( "skipping scanner-only device\n" ); - continue; - } + 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 (RegOpenKeyW( hkeyPrinters, nameW, &hkeyPrinter ) == ERROR_SUCCESS) + if (RegOpenKeyW( printers_key, printer->name, &printer_key ) == 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 ); diff --git a/dlls/winspool.drv/wspool.h b/dlls/winspool.drv/wspool.h index bca4a5ea02d..5a1f1038995 100644 --- a/dlls/winspool.drv/wspool.h +++ b/dlls/winspool.drv/wspool.h @@ -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;