Signed-off-by: Huw Davies <huw(a)codeweavers.com>
---
dlls/winspool.drv/cups.c | 125 +++++++++++++++++++++++++++++++++++++
dlls/winspool.drv/info.c | 107 +++----------------------------
dlls/winspool.drv/wspool.h | 7 +++
3 files changed, 142 insertions(+), 97 deletions(-)
diff --git a/dlls/winspool.drv/cups.c b/dlls/winspool.drv/cups.c
index 7aeb68d4f8d..2ce5f43fa8f 100644
--- a/dlls/winspool.drv/cups.c
+++ b/dlls/winspool.drv/cups.c
@@ -22,6 +22,9 @@
#include <stdarg.h>
#include <string.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <fcntl.h>
#ifdef HAVE_CUPS_CUPS_H
#include <cups/cups.h>
#endif
@@ -56,6 +59,11 @@ static DWORD ntdll_umbstowcs( const char *src, DWORD srclen, WCHAR *dst, DWORD d
{
return MultiByteToWideChar( CP_UNIXCP, 0, src, srclen, dst, dstlen );
}
+static int ntdll_wcstoumbs( const WCHAR *src, DWORD srclen, char *dst, DWORD dstlen, BOOL strict )
+{
+ /* FIXME: strict */
+ return WideCharToMultiByte( CP_UNIXCP, 0, src, srclen, dst, dstlen, NULL, NULL );
+}
#ifdef SONAME_LIBCUPS
@@ -111,6 +119,56 @@ NTSTATUS unix_process_attach( void *arg )
#endif /* SONAME_LIBCUPS */
}
+static BOOL copy_file( const char *src, const char *dst )
+{
+ int fds[2] = { -1, -1 }, num;
+ char buf[1024];
+ BOOL ret = FALSE;
+
+ fds[0] = open( src, O_RDONLY );
+ fds[1] = open( dst, O_CREAT | O_TRUNC | O_WRONLY, 0666 );
+ if (fds[0] == -1 || fds[1] == -1) goto fail;
+
+ while ((num = read( fds[0], buf, sizeof(buf) )) != 0)
+ {
+ if (num == -1) goto fail;
+ if (write( fds[1], buf, num ) != num) goto fail;
+ }
+ ret = TRUE;
+
+fail:
+ if (fds[1] != -1) close( fds[1] );
+ if (fds[0] != -1) close( fds[0] );
+ return ret;
+}
+
+static char *get_unix_file_name( LPCWSTR path )
+{
+ UNICODE_STRING nt_name;
+ OBJECT_ATTRIBUTES attr;
+ NTSTATUS status;
+ ULONG size = 256;
+ char *buffer;
+
+ nt_name.Buffer = (WCHAR *)path;
+ nt_name.MaximumLength = nt_name.Length = lstrlenW( path ) * sizeof(WCHAR);
+ InitializeObjectAttributes( &attr, &nt_name, 0, 0, NULL );
+ for (;;)
+ {
+ if (!(buffer = malloc( size ))) return NULL;
+ status = wine_nt_to_unix_file_name( &attr, buffer, &size, FILE_OPEN_IF );
+ if (status != STATUS_BUFFER_TOO_SMALL) break;
+ free( buffer );
+ }
+ if (status && status != STATUS_NO_SUCH_FILE)
+ {
+ free( buffer );
+ return NULL;
+ }
+ return buffer;
+}
+
+
#ifdef SONAME_LIBCUPS
static WCHAR *cups_get_optionW( const char *opt_name, int num_options, cups_option_t *options )
{
@@ -145,6 +203,32 @@ static BOOL cups_is_scanner( cups_dest_t *dest )
{
return cups_get_printer_type( dest ) & 0x2000000 /* CUPS_PRINTER_SCANNER */;
}
+
+static http_status_t cupsGetPPD3_wrapper( http_t *http, const char *name, time_t *modtime,
+ char *buffer, size_t bufsize )
+{
+ const char *ppd;
+
+ if (pcupsGetPPD3) return pcupsGetPPD3( http, name, modtime, buffer, bufsize );
+ if (!pcupsGetPPD) return HTTP_NOT_FOUND;
+
+ TRACE( "No cupsGetPPD3 implementation, so calling cupsGetPPD\n" );
+
+ *modtime = 0;
+ ppd = pcupsGetPPD( name );
+
+ TRACE( "cupsGetPPD returns %s\n", debugstr_a(ppd) );
+
+ if (!ppd) return HTTP_NOT_FOUND;
+
+ if (rename( ppd, buffer ) == -1)
+ {
+ BOOL res = copy_file( ppd, buffer );
+ unlink( ppd );
+ if (!res) return HTTP_NOT_FOUND;
+ }
+ return HTTP_OK;
+}
#endif /* SONAME_LIBCUPS */
NTSTATUS unix_enum_printers( void *args )
@@ -216,3 +300,44 @@ NTSTATUS unix_enum_printers( void *args )
return STATUS_NOT_SUPPORTED;
#endif /* SONAME_LIBCUPS */
}
+
+NTSTATUS unix_get_ppd( void *args )
+{
+ struct get_ppd_params *params = args;
+ char *unix_ppd = get_unix_file_name( params->ppd );
+ NTSTATUS status = STATUS_SUCCESS;
+
+ TRACE( "(%s, %s)\n", debugstr_w( params->printer ), debugstr_w( params->ppd ) );
+
+ if (!unix_ppd) return STATUS_NO_SUCH_FILE;
+
+ if (!params->printer) /* unlink */
+ {
+ unlink( unix_ppd );
+ }
+ else
+ {
+#ifdef SONAME_LIBCUPS
+ http_status_t http_status;
+ time_t modtime = 0;
+ char *printer_name;
+ int len;
+
+ len = strlenW( params->printer );
+ printer_name = malloc( len * 3 + 1 );
+ ntdll_wcstoumbs( params->printer, len + 1, printer_name, len * 3 + 1, FALSE );
+
+ http_status = cupsGetPPD3_wrapper( 0, printer_name, &modtime, unix_ppd, strlen( unix_ppd ) + 1 );
+ if (http_status != HTTP_OK)
+ {
+ unlink( unix_ppd );
+ status = STATUS_DEVICE_UNREACHABLE;
+ }
+ free( printer_name );
+#else
+ status = STATUS_NOT_SUPPORTED;
+#endif
+ }
+ free( unix_ppd );
+ return status;
+}
diff --git a/dlls/winspool.drv/info.c b/dlls/winspool.drv/info.c
index a3fcb32641a..5deab0083d3 100644
--- a/dlls/winspool.drv/info.c
+++ b/dlls/winspool.drv/info.c
@@ -752,29 +752,6 @@ static DWORD WINSPOOL_GetOpenedPrinterRegKey(HANDLE hPrinter, HKEY *phkey)
return open_printer_reg_key( name, phkey );
}
-static BOOL copy_file( const char *src, const char *dst )
-{
- int fds[2] = {-1, -1}, num;
- char buf[1024];
- BOOL ret = FALSE;
-
- fds[0] = open( src, O_RDONLY );
- fds[1] = open( dst, O_CREAT | O_TRUNC | O_WRONLY, 0666 );
- if (fds[0] == -1 || fds[1] == -1) goto fail;
-
- while ((num = read( fds[0], buf, sizeof(buf) )) != 0)
- {
- if (num == -1) goto fail;
- if (write( fds[1], buf, num ) != num) goto fail;
- }
- ret = TRUE;
-
-fail:
- if (fds[1] != -1) close( fds[1] );
- if (fds[0] != -1) close( fds[0] );
- return ret;
-}
-
static BOOL get_internal_fallback_ppd( const WCHAR *ppd )
{
static const WCHAR typeW[] = {'P','P','D','F','I','L','E',0};
@@ -817,31 +794,22 @@ static WCHAR *get_ppd_filename( const WCHAR *dir, const WCHAR *file_name )
return ppd;
}
-static char *get_dest_name( const WCHAR *printer )
-{
- int len = WideCharToMultiByte( CP_UNIXCP, 0, printer, -1, NULL, 0, NULL, NULL );
- char *dest = heap_alloc( len );
-
- if (dest) WideCharToMultiByte( CP_UNIXCP, 0, printer, -1, dest, len, NULL, NULL );
- return dest;
-}
-
-static BOOL get_cups_ppd( const char *printer_name, const WCHAR *ppd );
-static void unlink_ppd( const WCHAR *ppd );
-
static BOOL add_printer_driver( const WCHAR *name, const WCHAR *ppd_dir )
{
WCHAR *ppd = get_ppd_filename( ppd_dir, name );
- char *dest_name;
+ struct get_ppd_params ppd_params;
+ UNICODE_STRING nt_ppd;
DRIVER_INFO_3W di3;
unsigned int i;
BOOL res = FALSE;
if (!ppd) return FALSE;
- dest_name = get_dest_name( name );
- if (!dest_name) goto end;
+ RtlInitUnicodeString( &nt_ppd, NULL );
+ if (!RtlDosPathNameToNtPathName_U( ppd, &nt_ppd, NULL, NULL )) goto end;
- res = get_cups_ppd( dest_name, ppd ) || get_internal_fallback_ppd( ppd );
+ ppd_params.printer = name;
+ ppd_params.ppd = nt_ppd.Buffer;
+ res = !UNIX_CALL( get_ppd, &ppd_params ) || get_internal_fallback_ppd( ppd );
if (!res) goto end;
memset( &di3, 0, sizeof(DRIVER_INFO_3W) );
@@ -872,10 +840,11 @@ static BOOL add_printer_driver( const WCHAR *name, const WCHAR *ppd_dir )
}
res = TRUE;
}
- unlink_ppd( ppd );
+ ppd_params.printer = NULL; /* unlink the ppd */
+ UNIX_CALL( get_ppd, &ppd_params );
end:
- heap_free( dest_name );
+ RtlFreeUnicodeString( &nt_ppd );
heap_free( ppd );
return res;
}
@@ -904,13 +873,6 @@ static WCHAR *get_ppd_dir( void )
return dir;
}
-static void unlink_ppd( const WCHAR *ppd )
-{
- char *unix_name = wine_get_unix_file_name( ppd );
- unlink( unix_name );
- HeapFree( GetProcessHeap(), 0, unix_name );
-}
-
#ifdef SONAME_LIBCUPS
extern void *libcups_handle;
@@ -932,56 +894,7 @@ extern void *libcups_handle;
CUPS_FUNCS;
#undef DO_FUNC
extern cups_dest_t * (*pcupsGetNamedDest)(http_t *, const char *, const char *);
-extern const char * (*pcupsGetPPD)(const char *);
-extern http_status_t (*pcupsGetPPD3)(http_t *, const char *, time_t *, char *, size_t);
extern const char * (*pcupsLastErrorString)(void);
-
-static http_status_t cupsGetPPD3_wrapper( http_t *http, const char *name,
- time_t *modtime, char *buffer,
- size_t bufsize )
-{
- const char *ppd;
-
- if (pcupsGetPPD3) return pcupsGetPPD3( http, name, modtime, buffer, bufsize );
-
- if (!pcupsGetPPD) return HTTP_NOT_FOUND;
-
- TRACE( "No cupsGetPPD3 implementation, so calling cupsGetPPD\n" );
-
- *modtime = 0;
- ppd = pcupsGetPPD( name );
-
- TRACE( "cupsGetPPD returns %s\n", debugstr_a(ppd) );
-
- if (!ppd) return HTTP_NOT_FOUND;
-
- if (rename( ppd, buffer ) == -1)
- {
- BOOL res = copy_file( ppd, buffer );
- unlink( ppd );
- if (!res) return HTTP_NOT_FOUND;
- }
- return HTTP_OK;
-}
-
-static BOOL get_cups_ppd( const char *printer_name, const WCHAR *ppd )
-{
- time_t modtime = 0;
- http_status_t http_status;
- char *unix_name = wine_get_unix_file_name( ppd );
-
- TRACE( "(%s, %s)\n", debugstr_a(printer_name), debugstr_w(ppd) );
-
- if (!unix_name) return FALSE;
-
- http_status = cupsGetPPD3_wrapper( 0, printer_name, &modtime,
- unix_name, strlen( unix_name ) + 1 );
-
- if (http_status != HTTP_OK) unlink( unix_name );
- HeapFree( GetProcessHeap(), 0, unix_name );
-
- return http_status == HTTP_OK;
-}
#endif
static BOOL init_unix_printers( void )
diff --git a/dlls/winspool.drv/wspool.h b/dlls/winspool.drv/wspool.h
index 5a1f1038995..e66e08bfee0 100644
--- a/dlls/winspool.drv/wspool.h
+++ b/dlls/winspool.drv/wspool.h
@@ -52,7 +52,14 @@ struct enum_printers_params
unsigned int num;
};
+struct get_ppd_params
+{
+ const WCHAR *printer; /* set to NULL to unlink */
+ const WCHAR *ppd;
+};
+
#define UNIX_CALL( func, params ) unix_ ## func( params )
NTSTATUS unix_process_attach( void * ) DECLSPEC_HIDDEN;
NTSTATUS unix_enum_printers( void * ) DECLSPEC_HIDDEN;
+NTSTATUS unix_get_ppd( void * ) DECLSPEC_HIDDEN;
--
2.23.0