winspool: Move the unix job schedulers to cups.c.
Signed-off-by: Huw Davies <huw@codeweavers.com> Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
parent
097bde4691
commit
8ecd220c8e
|
@ -23,8 +23,15 @@
|
||||||
#include <stdarg.h>
|
#include <stdarg.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <sys/types.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <signal.h>
|
||||||
|
#ifdef HAVE_SYS_WAIT_H
|
||||||
|
#include <sys/wait.h>
|
||||||
|
#endif
|
||||||
#ifdef HAVE_CUPS_CUPS_H
|
#ifdef HAVE_CUPS_CUPS_H
|
||||||
#include <cups/cups.h>
|
#include <cups/cups.h>
|
||||||
#endif
|
#endif
|
||||||
|
@ -106,6 +113,9 @@
|
||||||
|
|
||||||
WINE_DEFAULT_DEBUG_CHANNEL(winspool);
|
WINE_DEFAULT_DEBUG_CHANNEL(winspool);
|
||||||
|
|
||||||
|
static const WCHAR CUPS_Port[] = { 'C','U','P','S',':',0 };
|
||||||
|
static const WCHAR LPR_Port[] = { 'L','P','R',':',0 };
|
||||||
|
|
||||||
/* Temporary helpers until switch to unixlib */
|
/* Temporary helpers until switch to unixlib */
|
||||||
#include "winnls.h"
|
#include "winnls.h"
|
||||||
#include "wine/heap.h"
|
#include "wine/heap.h"
|
||||||
|
@ -123,7 +133,7 @@ static int ntdll_wcstoumbs( const WCHAR *src, DWORD srclen, char *dst, DWORD dst
|
||||||
|
|
||||||
#ifdef SONAME_LIBCUPS
|
#ifdef SONAME_LIBCUPS
|
||||||
|
|
||||||
void *libcups_handle = NULL;
|
static void *libcups_handle;
|
||||||
|
|
||||||
#define CUPS_FUNCS \
|
#define CUPS_FUNCS \
|
||||||
DO_FUNC(cupsAddOption); \
|
DO_FUNC(cupsAddOption); \
|
||||||
|
@ -139,13 +149,13 @@ void *libcups_handle = NULL;
|
||||||
DO_FUNC(cupsGetPPD3); \
|
DO_FUNC(cupsGetPPD3); \
|
||||||
DO_FUNC(cupsLastErrorString)
|
DO_FUNC(cupsLastErrorString)
|
||||||
|
|
||||||
#define DO_FUNC(f) typeof(f) *p##f = NULL
|
#define DO_FUNC(f) static typeof(f) *p##f
|
||||||
CUPS_FUNCS;
|
CUPS_FUNCS;
|
||||||
#undef DO_FUNC
|
#undef DO_FUNC
|
||||||
cups_dest_t * (*pcupsGetNamedDest)(http_t *, const char *, const char *) = NULL;
|
static cups_dest_t * (*pcupsGetNamedDest)(http_t *, const char *, const char *);
|
||||||
const char * (*pcupsGetPPD)(const char *) = NULL;
|
static const char * (*pcupsGetPPD)(const char *);
|
||||||
http_status_t (*pcupsGetPPD3)(http_t *, const char *, time_t *, char *, size_t) = NULL;
|
static http_status_t (*pcupsGetPPD3)(http_t *, const char *, time_t *, char *, size_t);
|
||||||
const char * (*pcupsLastErrorString)(void) = NULL;
|
static const char * (*pcupsLastErrorString)(void);
|
||||||
|
|
||||||
#endif /* SONAME_LIBCUPS */
|
#endif /* SONAME_LIBCUPS */
|
||||||
|
|
||||||
|
@ -285,6 +295,56 @@ static http_status_t cupsGetPPD3_wrapper( http_t *http, const char *name, time_t
|
||||||
}
|
}
|
||||||
return HTTP_OK;
|
return HTTP_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*****************************************************************************
|
||||||
|
* get_cups_jobs_ticket_options
|
||||||
|
*
|
||||||
|
* Explicitly set CUPS options based on any %cupsJobTicket lines.
|
||||||
|
* The CUPS scheduler only looks for these in Print-File requests, and since
|
||||||
|
* cupsPrintFile uses Create-Job / Send-Document, the ticket lines don't get
|
||||||
|
* parsed.
|
||||||
|
*/
|
||||||
|
static int get_cups_job_ticket_options( const char *file, int num_options, cups_option_t **options )
|
||||||
|
{
|
||||||
|
FILE *fp = fopen( file, "r" );
|
||||||
|
char buf[257]; /* DSC max of 256 + '\0' */
|
||||||
|
const char *ps_adobe = "%!PS-Adobe-";
|
||||||
|
const char *cups_job = "%cupsJobTicket:";
|
||||||
|
|
||||||
|
if (!fp) return num_options;
|
||||||
|
if (!fgets( buf, sizeof(buf), fp )) goto end;
|
||||||
|
if (strncmp( buf, ps_adobe, strlen( ps_adobe ) )) goto end;
|
||||||
|
while (fgets( buf, sizeof(buf), fp ))
|
||||||
|
{
|
||||||
|
if (strncmp( buf, cups_job, strlen( cups_job ) )) break;
|
||||||
|
num_options = pcupsParseOptions( buf + strlen( cups_job ), num_options, options );
|
||||||
|
}
|
||||||
|
|
||||||
|
end:
|
||||||
|
fclose( fp );
|
||||||
|
return num_options;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int get_cups_default_options( const char *printer, int num_options, cups_option_t **options )
|
||||||
|
{
|
||||||
|
cups_dest_t *dest;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
if (!pcupsGetNamedDest) return num_options;
|
||||||
|
|
||||||
|
dest = pcupsGetNamedDest( NULL, printer, NULL );
|
||||||
|
if (!dest) return num_options;
|
||||||
|
|
||||||
|
for (i = 0; i < dest->num_options; i++)
|
||||||
|
{
|
||||||
|
if (!pcupsGetOption( dest->options[i].name, num_options, *options ))
|
||||||
|
num_options = pcupsAddOption( dest->options[i].name, dest->options[i].value,
|
||||||
|
num_options, options );
|
||||||
|
}
|
||||||
|
|
||||||
|
pcupsFreeDests( 1, dest );
|
||||||
|
return num_options;
|
||||||
|
}
|
||||||
#endif /* SONAME_LIBCUPS */
|
#endif /* SONAME_LIBCUPS */
|
||||||
|
|
||||||
NTSTATUS unix_enum_printers( void *args )
|
NTSTATUS unix_enum_printers( void *args )
|
||||||
|
@ -438,3 +498,200 @@ end:
|
||||||
return STATUS_NOT_IMPLEMENTED;
|
return STATUS_NOT_IMPLEMENTED;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*****************************************************************************
|
||||||
|
* schedule_pipe
|
||||||
|
*/
|
||||||
|
static BOOL schedule_pipe( const WCHAR *cmd, const WCHAR *filename )
|
||||||
|
{
|
||||||
|
#ifdef HAVE_FORK
|
||||||
|
char *unixname, *cmdA;
|
||||||
|
DWORD len;
|
||||||
|
int fds[2] = { -1, -1 }, file_fd = -1, no_read;
|
||||||
|
BOOL ret = FALSE;
|
||||||
|
char buf[1024];
|
||||||
|
pid_t pid, wret;
|
||||||
|
int status;
|
||||||
|
|
||||||
|
if (!(unixname = get_unix_file_name( filename ))) return FALSE;
|
||||||
|
|
||||||
|
len = strlenW( cmd );
|
||||||
|
cmdA = malloc( len * 3 + 1);
|
||||||
|
ntdll_wcstoumbs( cmd, len + 1, cmdA, len * 3 + 1, FALSE );
|
||||||
|
|
||||||
|
TRACE( "printing with: %s\n", cmdA );
|
||||||
|
|
||||||
|
if ((file_fd = open( unixname, O_RDONLY )) == -1) goto end;
|
||||||
|
|
||||||
|
if (pipe( fds ))
|
||||||
|
{
|
||||||
|
ERR( "pipe() failed!\n" );
|
||||||
|
goto end;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((pid = fork()) == 0)
|
||||||
|
{
|
||||||
|
close( 0 );
|
||||||
|
dup2( fds[0], 0 );
|
||||||
|
close( fds[1] );
|
||||||
|
|
||||||
|
/* reset signals that we previously set to SIG_IGN */
|
||||||
|
signal( SIGPIPE, SIG_DFL );
|
||||||
|
|
||||||
|
execl( "/bin/sh", "/bin/sh", "-c", cmdA, NULL );
|
||||||
|
_exit( 1 );
|
||||||
|
}
|
||||||
|
else if (pid == -1)
|
||||||
|
{
|
||||||
|
ERR( "fork() failed!\n" );
|
||||||
|
goto end;
|
||||||
|
}
|
||||||
|
|
||||||
|
close( fds[0] );
|
||||||
|
fds[0] = -1;
|
||||||
|
while ((no_read = read( file_fd, buf, sizeof(buf) )) > 0)
|
||||||
|
write( fds[1], buf, no_read );
|
||||||
|
|
||||||
|
close( fds[1] );
|
||||||
|
fds[1] = -1;
|
||||||
|
|
||||||
|
/* reap child */
|
||||||
|
do {
|
||||||
|
wret = waitpid( pid, &status, 0 );
|
||||||
|
} while (wret < 0 && errno == EINTR);
|
||||||
|
if (wret < 0)
|
||||||
|
{
|
||||||
|
ERR( "waitpid() failed!\n" );
|
||||||
|
goto end;
|
||||||
|
}
|
||||||
|
if (!WIFEXITED(status) || WEXITSTATUS(status))
|
||||||
|
{
|
||||||
|
ERR( "child process failed! %d\n", status );
|
||||||
|
goto end;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = TRUE;
|
||||||
|
|
||||||
|
end:
|
||||||
|
if (file_fd != -1) close( file_fd );
|
||||||
|
if (fds[0] != -1) close( fds[0] );
|
||||||
|
if (fds[1] != -1) close( fds[1] );
|
||||||
|
|
||||||
|
free( cmdA );
|
||||||
|
free( unixname );
|
||||||
|
return ret;
|
||||||
|
#else
|
||||||
|
return FALSE;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
/*****************************************************************************
|
||||||
|
* schedule_unixfile
|
||||||
|
*/
|
||||||
|
static BOOL schedule_unixfile( const WCHAR *output, const WCHAR *filename )
|
||||||
|
{
|
||||||
|
char *unixname, *outputA;
|
||||||
|
DWORD len;
|
||||||
|
BOOL ret;
|
||||||
|
|
||||||
|
if (!(unixname = get_unix_file_name( filename ))) return FALSE;
|
||||||
|
|
||||||
|
len = strlenW( output );
|
||||||
|
outputA = malloc( len * 3 + 1);
|
||||||
|
ntdll_wcstoumbs( output, len + 1, outputA, len * 3 + 1, FALSE );
|
||||||
|
|
||||||
|
ret = copy_file( unixname, outputA );
|
||||||
|
|
||||||
|
free( outputA );
|
||||||
|
free( unixname );
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*****************************************************************************
|
||||||
|
* schedule_lpr
|
||||||
|
*/
|
||||||
|
static BOOL schedule_lpr( const WCHAR *printer_name, const WCHAR *filename )
|
||||||
|
{
|
||||||
|
static const WCHAR lpr[] = { 'l','p','r',' ','-','P','\'' };
|
||||||
|
static const WCHAR quote[] = { '\'',0 };
|
||||||
|
int printer_len = strlenW( printer_name );
|
||||||
|
WCHAR *cmd;
|
||||||
|
BOOL ret;
|
||||||
|
|
||||||
|
cmd = malloc( printer_len * sizeof(WCHAR) + sizeof(lpr) + sizeof(quote) );
|
||||||
|
memcpy( cmd, lpr, sizeof(lpr) );
|
||||||
|
memcpy( cmd + ARRAY_SIZE(lpr), printer_name, printer_len * sizeof(WCHAR) );
|
||||||
|
memcpy( cmd + ARRAY_SIZE(lpr) + printer_len, quote, sizeof(quote) );
|
||||||
|
|
||||||
|
ret = schedule_pipe( cmd, filename );
|
||||||
|
|
||||||
|
free( cmd );
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*****************************************************************************
|
||||||
|
* schedule_cups
|
||||||
|
*/
|
||||||
|
static BOOL schedule_cups( const WCHAR *printer_name, const WCHAR *filename, const WCHAR *document_title )
|
||||||
|
{
|
||||||
|
#ifdef SONAME_LIBCUPS
|
||||||
|
if (pcupsPrintFile)
|
||||||
|
{
|
||||||
|
char *unixname, *queue, *unix_doc_title;
|
||||||
|
cups_option_t *options = NULL;
|
||||||
|
int num_options = 0, i;
|
||||||
|
DWORD len;
|
||||||
|
BOOL ret;
|
||||||
|
|
||||||
|
if (!(unixname = get_unix_file_name( filename ))) return FALSE;
|
||||||
|
len = strlenW( printer_name );
|
||||||
|
queue = malloc( len * 3 + 1);
|
||||||
|
ntdll_wcstoumbs( printer_name, len + 1, queue, len * 3 + 1, FALSE );
|
||||||
|
|
||||||
|
len = strlenW( document_title );
|
||||||
|
unix_doc_title = malloc( len * 3 + 1 );
|
||||||
|
ntdll_wcstoumbs( document_title, len + 1, unix_doc_title, len + 3 + 1, FALSE );
|
||||||
|
|
||||||
|
num_options = get_cups_job_ticket_options( unixname, num_options, &options );
|
||||||
|
num_options = get_cups_default_options( queue, num_options, &options );
|
||||||
|
|
||||||
|
TRACE( "printing via cups with options:\n" );
|
||||||
|
for (i = 0; i < num_options; i++)
|
||||||
|
TRACE( "\t%d: %s = %s\n", i, options[i].name, options[i].value );
|
||||||
|
|
||||||
|
ret = pcupsPrintFile( queue, unixname, unix_doc_title, num_options, options );
|
||||||
|
if (ret == 0 && pcupsLastErrorString)
|
||||||
|
WARN( "cupsPrintFile failed with error %s\n", debugstr_a( pcupsLastErrorString() ) );
|
||||||
|
|
||||||
|
pcupsFreeOptions( num_options, options );
|
||||||
|
|
||||||
|
free( unix_doc_title );
|
||||||
|
free( queue );
|
||||||
|
free( unixname );
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
#endif
|
||||||
|
{
|
||||||
|
return schedule_lpr( printer_name, filename );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOL unix_schedule_job( void *args )
|
||||||
|
{
|
||||||
|
struct schedule_job_params *params = args;
|
||||||
|
|
||||||
|
if (params->wine_port[0] == '|')
|
||||||
|
return schedule_pipe( params->wine_port + 1, params->filename );
|
||||||
|
|
||||||
|
if (params->wine_port[0])
|
||||||
|
return schedule_unixfile( params->wine_port, params->filename );
|
||||||
|
|
||||||
|
if (!strncmpW( params->port, LPR_Port, ARRAY_SIZE(LPR_Port) - 1 ))
|
||||||
|
return schedule_lpr( params->port + ARRAY_SIZE(LPR_Port) - 1, params->filename );
|
||||||
|
|
||||||
|
if (!strncmpW( params->port, CUPS_Port, ARRAY_SIZE(CUPS_Port) - 1 ))
|
||||||
|
return schedule_cups( params->port + ARRAY_SIZE(CUPS_Port) - 1, params->filename, params->document_title );
|
||||||
|
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
|
@ -25,7 +25,6 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
#include "wine/port.h"
|
|
||||||
|
|
||||||
#include <stdarg.h>
|
#include <stdarg.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
@ -33,20 +32,6 @@
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
#include <errno.h>
|
|
||||||
#ifdef HAVE_SYS_WAIT_H
|
|
||||||
#include <sys/wait.h>
|
|
||||||
#endif
|
|
||||||
#ifdef HAVE_UNISTD_H
|
|
||||||
# include <unistd.h>
|
|
||||||
#endif
|
|
||||||
#include <signal.h>
|
|
||||||
#ifdef HAVE_CUPS_CUPS_H
|
|
||||||
# include <cups/cups.h>
|
|
||||||
#endif
|
|
||||||
#ifdef HAVE_CUPS_PPD_H
|
|
||||||
# include <cups/ppd.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#define NONAMELESSSTRUCT
|
#define NONAMELESSSTRUCT
|
||||||
#define NONAMELESSUNION
|
#define NONAMELESSUNION
|
||||||
|
@ -817,30 +802,6 @@ static WCHAR *get_ppd_dir( void )
|
||||||
return dir;
|
return dir;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef SONAME_LIBCUPS
|
|
||||||
|
|
||||||
extern void *libcups_handle;
|
|
||||||
|
|
||||||
#define CUPS_FUNCS \
|
|
||||||
DO_FUNC(cupsAddOption); \
|
|
||||||
DO_FUNC(cupsFreeDests); \
|
|
||||||
DO_FUNC(cupsFreeOptions); \
|
|
||||||
DO_FUNC(cupsGetOption); \
|
|
||||||
DO_FUNC(cupsParseOptions); \
|
|
||||||
DO_FUNC(cupsPrintFile)
|
|
||||||
#define CUPS_OPT_FUNCS \
|
|
||||||
DO_FUNC(cupsGetNamedDest); \
|
|
||||||
DO_FUNC(cupsGetPPD); \
|
|
||||||
DO_FUNC(cupsGetPPD3); \
|
|
||||||
DO_FUNC(cupsLastErrorString)
|
|
||||||
|
|
||||||
#define DO_FUNC(f) extern typeof(f) *p##f
|
|
||||||
CUPS_FUNCS;
|
|
||||||
#undef DO_FUNC
|
|
||||||
extern cups_dest_t * (*pcupsGetNamedDest)(http_t *, const char *, const char *);
|
|
||||||
extern const char * (*pcupsLastErrorString)(void);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
static BOOL init_unix_printers( void )
|
static BOOL init_unix_printers( void )
|
||||||
{
|
{
|
||||||
WCHAR *port, *ppd_dir = NULL, *default_printer = NULL;
|
WCHAR *port, *ppd_dir = NULL, *default_printer = NULL;
|
||||||
|
@ -7806,214 +7767,6 @@ BOOL WINAPI GetJobW(HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pJob,
|
||||||
return get_job_info(hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded, TRUE);
|
return get_job_info(hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded, TRUE);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*****************************************************************************
|
|
||||||
* schedule_pipe
|
|
||||||
*/
|
|
||||||
static BOOL schedule_pipe(LPCWSTR cmd, LPCWSTR filename)
|
|
||||||
{
|
|
||||||
#ifdef HAVE_FORK
|
|
||||||
char *unixname, *cmdA;
|
|
||||||
DWORD len;
|
|
||||||
int fds[2] = {-1, -1}, file_fd = -1, no_read;
|
|
||||||
BOOL ret = FALSE;
|
|
||||||
char buf[1024];
|
|
||||||
pid_t pid, wret;
|
|
||||||
int status;
|
|
||||||
|
|
||||||
if(!(unixname = wine_get_unix_file_name(filename)))
|
|
||||||
return FALSE;
|
|
||||||
|
|
||||||
len = WideCharToMultiByte(CP_UNIXCP, 0, cmd, -1, NULL, 0, NULL, NULL);
|
|
||||||
cmdA = HeapAlloc(GetProcessHeap(), 0, len);
|
|
||||||
WideCharToMultiByte(CP_UNIXCP, 0, cmd, -1, cmdA, len, NULL, NULL);
|
|
||||||
|
|
||||||
TRACE("printing with: %s\n", cmdA);
|
|
||||||
|
|
||||||
if((file_fd = open(unixname, O_RDONLY)) == -1)
|
|
||||||
goto end;
|
|
||||||
|
|
||||||
if (pipe(fds))
|
|
||||||
{
|
|
||||||
ERR("pipe() failed!\n");
|
|
||||||
goto end;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((pid = fork()) == 0)
|
|
||||||
{
|
|
||||||
close(0);
|
|
||||||
dup2(fds[0], 0);
|
|
||||||
close(fds[1]);
|
|
||||||
|
|
||||||
/* reset signals that we previously set to SIG_IGN */
|
|
||||||
signal(SIGPIPE, SIG_DFL);
|
|
||||||
|
|
||||||
execl("/bin/sh", "/bin/sh", "-c", cmdA, NULL);
|
|
||||||
_exit(1);
|
|
||||||
}
|
|
||||||
else if (pid == -1)
|
|
||||||
{
|
|
||||||
ERR("fork() failed!\n");
|
|
||||||
goto end;
|
|
||||||
}
|
|
||||||
|
|
||||||
close(fds[0]);
|
|
||||||
fds[0] = -1;
|
|
||||||
while((no_read = read(file_fd, buf, sizeof(buf))) > 0)
|
|
||||||
write(fds[1], buf, no_read);
|
|
||||||
|
|
||||||
close(fds[1]);
|
|
||||||
fds[1] = -1;
|
|
||||||
|
|
||||||
/* reap child */
|
|
||||||
do {
|
|
||||||
wret = waitpid(pid, &status, 0);
|
|
||||||
} while (wret < 0 && errno == EINTR);
|
|
||||||
if (wret < 0)
|
|
||||||
{
|
|
||||||
ERR("waitpid() failed!\n");
|
|
||||||
goto end;
|
|
||||||
}
|
|
||||||
if (!WIFEXITED(status) || WEXITSTATUS(status))
|
|
||||||
{
|
|
||||||
ERR("child process failed! %d\n", status);
|
|
||||||
goto end;
|
|
||||||
}
|
|
||||||
|
|
||||||
ret = TRUE;
|
|
||||||
|
|
||||||
end:
|
|
||||||
if(file_fd != -1) close(file_fd);
|
|
||||||
if(fds[0] != -1) close(fds[0]);
|
|
||||||
if(fds[1] != -1) close(fds[1]);
|
|
||||||
|
|
||||||
HeapFree(GetProcessHeap(), 0, cmdA);
|
|
||||||
HeapFree(GetProcessHeap(), 0, unixname);
|
|
||||||
return ret;
|
|
||||||
#else
|
|
||||||
return FALSE;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
/*****************************************************************************
|
|
||||||
* schedule_lpr
|
|
||||||
*/
|
|
||||||
static BOOL schedule_lpr(LPCWSTR printer_name, LPCWSTR filename)
|
|
||||||
{
|
|
||||||
static const WCHAR fmtW[] = {'l','p','r',' ','-','P','\'','%','s','\'',0};
|
|
||||||
WCHAR *cmd;
|
|
||||||
BOOL r;
|
|
||||||
|
|
||||||
cmd = HeapAlloc(GetProcessHeap(), 0, strlenW(printer_name) * sizeof(WCHAR) + sizeof(fmtW));
|
|
||||||
sprintfW(cmd, fmtW, printer_name);
|
|
||||||
|
|
||||||
r = schedule_pipe(cmd, filename);
|
|
||||||
|
|
||||||
HeapFree(GetProcessHeap(), 0, cmd);
|
|
||||||
return r;
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef SONAME_LIBCUPS
|
|
||||||
/*****************************************************************************
|
|
||||||
* get_cups_jobs_ticket_options
|
|
||||||
*
|
|
||||||
* Explicitly set CUPS options based on any %cupsJobTicket lines.
|
|
||||||
* The CUPS scheduler only looks for these in Print-File requests, and since
|
|
||||||
* cupsPrintFile uses Create-Job / Send-Document, the ticket lines don't get
|
|
||||||
* parsed.
|
|
||||||
*/
|
|
||||||
static int get_cups_job_ticket_options( const char *file, int num_options, cups_option_t **options )
|
|
||||||
{
|
|
||||||
FILE *fp = fopen( file, "r" );
|
|
||||||
char buf[257]; /* DSC max of 256 + '\0' */
|
|
||||||
const char *ps_adobe = "%!PS-Adobe-";
|
|
||||||
const char *cups_job = "%cupsJobTicket:";
|
|
||||||
|
|
||||||
if (!fp) return num_options;
|
|
||||||
if (!fgets( buf, sizeof(buf), fp )) goto end;
|
|
||||||
if (strncmp( buf, ps_adobe, strlen( ps_adobe ) )) goto end;
|
|
||||||
while (fgets( buf, sizeof(buf), fp ))
|
|
||||||
{
|
|
||||||
if (strncmp( buf, cups_job, strlen( cups_job ) )) break;
|
|
||||||
num_options = pcupsParseOptions( buf + strlen( cups_job ), num_options, options );
|
|
||||||
}
|
|
||||||
|
|
||||||
end:
|
|
||||||
fclose( fp );
|
|
||||||
return num_options;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int get_cups_default_options( const char *printer, int num_options, cups_option_t **options )
|
|
||||||
{
|
|
||||||
cups_dest_t *dest;
|
|
||||||
int i;
|
|
||||||
|
|
||||||
if (!pcupsGetNamedDest) return num_options;
|
|
||||||
|
|
||||||
dest = pcupsGetNamedDest( NULL, printer, NULL );
|
|
||||||
if (!dest) return num_options;
|
|
||||||
|
|
||||||
for (i = 0; i < dest->num_options; i++)
|
|
||||||
{
|
|
||||||
if (!pcupsGetOption( dest->options[i].name, num_options, *options ))
|
|
||||||
num_options = pcupsAddOption( dest->options[i].name, dest->options[i].value,
|
|
||||||
num_options, options );
|
|
||||||
}
|
|
||||||
|
|
||||||
pcupsFreeDests( 1, dest );
|
|
||||||
return num_options;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/*****************************************************************************
|
|
||||||
* schedule_cups
|
|
||||||
*/
|
|
||||||
static BOOL schedule_cups(LPCWSTR printer_name, LPCWSTR filename, LPCWSTR document_title)
|
|
||||||
{
|
|
||||||
#ifdef SONAME_LIBCUPS
|
|
||||||
if(pcupsPrintFile)
|
|
||||||
{
|
|
||||||
char *unixname, *queue, *unix_doc_title;
|
|
||||||
DWORD len;
|
|
||||||
BOOL ret;
|
|
||||||
int num_options = 0, i;
|
|
||||||
cups_option_t *options = NULL;
|
|
||||||
|
|
||||||
if(!(unixname = wine_get_unix_file_name(filename)))
|
|
||||||
return FALSE;
|
|
||||||
|
|
||||||
len = WideCharToMultiByte(CP_UNIXCP, 0, printer_name, -1, NULL, 0, NULL, NULL);
|
|
||||||
queue = HeapAlloc(GetProcessHeap(), 0, len);
|
|
||||||
WideCharToMultiByte(CP_UNIXCP, 0, printer_name, -1, queue, len, NULL, NULL);
|
|
||||||
|
|
||||||
len = WideCharToMultiByte(CP_UNIXCP, 0, document_title, -1, NULL, 0, NULL, NULL);
|
|
||||||
unix_doc_title = HeapAlloc(GetProcessHeap(), 0, len);
|
|
||||||
WideCharToMultiByte(CP_UNIXCP, 0, document_title, -1, unix_doc_title, len, NULL, NULL);
|
|
||||||
|
|
||||||
num_options = get_cups_job_ticket_options( unixname, num_options, &options );
|
|
||||||
num_options = get_cups_default_options( queue, num_options, &options );
|
|
||||||
|
|
||||||
TRACE( "printing via cups with options:\n" );
|
|
||||||
for (i = 0; i < num_options; i++)
|
|
||||||
TRACE( "\t%d: %s = %s\n", i, options[i].name, options[i].value );
|
|
||||||
|
|
||||||
ret = pcupsPrintFile( queue, unixname, unix_doc_title, num_options, options );
|
|
||||||
if (ret == 0 && pcupsLastErrorString)
|
|
||||||
WARN("cupsPrintFile failed with error %s\n", debugstr_a(pcupsLastErrorString()));
|
|
||||||
|
|
||||||
pcupsFreeOptions( num_options, options );
|
|
||||||
|
|
||||||
HeapFree(GetProcessHeap(), 0, unix_doc_title);
|
|
||||||
HeapFree(GetProcessHeap(), 0, queue);
|
|
||||||
HeapFree(GetProcessHeap(), 0, unixname);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
#endif
|
|
||||||
{
|
|
||||||
return schedule_lpr(printer_name, filename);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static INT_PTR CALLBACK file_dlg_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
|
static INT_PTR CALLBACK file_dlg_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
|
||||||
{
|
{
|
||||||
LPWSTR filename;
|
LPWSTR filename;
|
||||||
|
@ -8106,41 +7859,6 @@ static BOOL schedule_file(LPCWSTR filename)
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*****************************************************************************
|
|
||||||
* schedule_unixfile
|
|
||||||
*/
|
|
||||||
static BOOL schedule_unixfile(LPCWSTR output, LPCWSTR filename)
|
|
||||||
{
|
|
||||||
int in_fd, out_fd, no_read;
|
|
||||||
char buf[1024];
|
|
||||||
BOOL ret = FALSE;
|
|
||||||
char *unixname, *outputA;
|
|
||||||
DWORD len;
|
|
||||||
|
|
||||||
if(!(unixname = wine_get_unix_file_name(filename)))
|
|
||||||
return FALSE;
|
|
||||||
|
|
||||||
len = WideCharToMultiByte(CP_UNIXCP, 0, output, -1, NULL, 0, NULL, NULL);
|
|
||||||
outputA = HeapAlloc(GetProcessHeap(), 0, len);
|
|
||||||
WideCharToMultiByte(CP_UNIXCP, 0, output, -1, outputA, len, NULL, NULL);
|
|
||||||
|
|
||||||
out_fd = open(outputA, O_CREAT | O_TRUNC | O_WRONLY, 0666);
|
|
||||||
in_fd = open(unixname, O_RDONLY);
|
|
||||||
if(out_fd == -1 || in_fd == -1)
|
|
||||||
goto end;
|
|
||||||
|
|
||||||
while((no_read = read(in_fd, buf, sizeof(buf))) > 0)
|
|
||||||
write(out_fd, buf, no_read);
|
|
||||||
|
|
||||||
ret = TRUE;
|
|
||||||
end:
|
|
||||||
if(in_fd != -1) close(in_fd);
|
|
||||||
if(out_fd != -1) close(out_fd);
|
|
||||||
HeapFree(GetProcessHeap(), 0, outputA);
|
|
||||||
HeapFree(GetProcessHeap(), 0, unixname);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*****************************************************************************
|
/*****************************************************************************
|
||||||
* ScheduleJob [WINSPOOL.@]
|
* ScheduleJob [WINSPOOL.@]
|
||||||
*
|
*
|
||||||
|
@ -8169,6 +7887,7 @@ BOOL WINAPI ScheduleJob( HANDLE hPrinter, DWORD dwJobID )
|
||||||
{
|
{
|
||||||
PRINTER_INFO_5W *pi5 = NULL;
|
PRINTER_INFO_5W *pi5 = NULL;
|
||||||
LPWSTR portname = job->portname;
|
LPWSTR portname = job->portname;
|
||||||
|
UNICODE_STRING nt_name;
|
||||||
DWORD needed;
|
DWORD needed;
|
||||||
HKEY hkey;
|
HKEY hkey;
|
||||||
WCHAR output[1024];
|
WCHAR output[1024];
|
||||||
|
@ -8185,44 +7904,39 @@ BOOL WINAPI ScheduleJob( HANDLE hPrinter, DWORD dwJobID )
|
||||||
TRACE("need to schedule job %d filename %s to port %s\n", job->job_id, debugstr_w(job->filename),
|
TRACE("need to schedule job %d filename %s to port %s\n", job->job_id, debugstr_w(job->filename),
|
||||||
debugstr_w(portname));
|
debugstr_w(portname));
|
||||||
|
|
||||||
output[0] = 0;
|
if (!strncmpW( portname, FILE_Port, strlenW( FILE_Port ) ))
|
||||||
|
{
|
||||||
|
ret = schedule_file( job->filename );
|
||||||
|
}
|
||||||
|
else if (isalpha(portname[0]) && portname[1] == ':')
|
||||||
|
{
|
||||||
|
TRACE( "copying to %s\n", debugstr_w( portname ) );
|
||||||
|
ret = CopyFileW( job->filename, portname, FALSE );
|
||||||
|
}
|
||||||
|
else if (RtlDosPathNameToNtPathName_U( job->filename, &nt_name, NULL, NULL ))
|
||||||
|
{
|
||||||
|
struct schedule_job_params params =
|
||||||
|
{
|
||||||
|
.filename = nt_name.Buffer,
|
||||||
|
.port = portname,
|
||||||
|
.document_title = job->document_title,
|
||||||
|
.wine_port = output
|
||||||
|
};
|
||||||
|
|
||||||
|
output[0] = 0;
|
||||||
/* @@ Wine registry key: HKCU\Software\Wine\Printing\Spooler */
|
/* @@ Wine registry key: HKCU\Software\Wine\Printing\Spooler */
|
||||||
if(RegOpenKeyW(HKEY_CURRENT_USER, spooler_key, &hkey) == ERROR_SUCCESS)
|
if (RegOpenKeyW( HKEY_CURRENT_USER, spooler_key, &hkey ) == ERROR_SUCCESS)
|
||||||
{
|
{
|
||||||
DWORD type, count = sizeof(output);
|
DWORD type, count = sizeof(output);
|
||||||
RegQueryValueExW(hkey, portname, NULL, &type, (LPBYTE)output, &count);
|
RegQueryValueExW( hkey, portname, NULL, &type, (BYTE *)output, &count );
|
||||||
RegCloseKey(hkey);
|
RegCloseKey( hkey );
|
||||||
}
|
}
|
||||||
if(output[0] == '|')
|
ret = UNIX_CALL( schedule_job, ¶ms );
|
||||||
{
|
RtlFreeUnicodeString( &nt_name );
|
||||||
ret = schedule_pipe(output + 1, job->filename);
|
|
||||||
}
|
|
||||||
else if(output[0])
|
|
||||||
{
|
|
||||||
ret = schedule_unixfile(output, job->filename);
|
|
||||||
}
|
|
||||||
else if(!strncmpW(portname, LPR_Port, strlenW(LPR_Port)))
|
|
||||||
{
|
|
||||||
ret = schedule_lpr(portname + strlenW(LPR_Port), job->filename);
|
|
||||||
}
|
|
||||||
else if(!strncmpW(portname, CUPS_Port, strlenW(CUPS_Port)))
|
|
||||||
{
|
|
||||||
ret = schedule_cups(portname + strlenW(CUPS_Port), job->filename, job->document_title);
|
|
||||||
}
|
|
||||||
else if(!strncmpW(portname, FILE_Port, strlenW(FILE_Port)))
|
|
||||||
{
|
|
||||||
ret = schedule_file(job->filename);
|
|
||||||
}
|
|
||||||
else if(isalpha(portname[0]) && portname[1] == ':')
|
|
||||||
{
|
|
||||||
TRACE("copying to %s\n", debugstr_w(portname));
|
|
||||||
ret = CopyFileW(job->filename, portname, FALSE);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
FIXME("can't schedule to port %s\n", debugstr_w(portname));
|
|
||||||
}
|
}
|
||||||
|
else ret = FALSE;
|
||||||
|
|
||||||
|
if (!ret) FIXME( "can't schedule to port %s\n", debugstr_w( portname ) );
|
||||||
HeapFree(GetProcessHeap(), 0, pi5);
|
HeapFree(GetProcessHeap(), 0, pi5);
|
||||||
CloseHandle(hf);
|
CloseHandle(hf);
|
||||||
DeleteFileW(job->filename);
|
DeleteFileW(job->filename);
|
||||||
|
|
|
@ -64,9 +64,18 @@ struct get_ppd_params
|
||||||
const WCHAR *ppd;
|
const WCHAR *ppd;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct schedule_job_params
|
||||||
|
{
|
||||||
|
const WCHAR *filename;
|
||||||
|
const WCHAR *port;
|
||||||
|
const WCHAR *document_title;
|
||||||
|
const WCHAR *wine_port;
|
||||||
|
};
|
||||||
|
|
||||||
#define UNIX_CALL( func, params ) unix_ ## func( params )
|
#define UNIX_CALL( func, params ) unix_ ## func( params )
|
||||||
|
|
||||||
NTSTATUS unix_process_attach( void * ) DECLSPEC_HIDDEN;
|
NTSTATUS unix_process_attach( void * ) DECLSPEC_HIDDEN;
|
||||||
NTSTATUS unix_enum_printers( void * ) DECLSPEC_HIDDEN;
|
NTSTATUS unix_enum_printers( void * ) DECLSPEC_HIDDEN;
|
||||||
NTSTATUS unix_get_default_page_size( void * ) DECLSPEC_HIDDEN;
|
NTSTATUS unix_get_default_page_size( void * ) DECLSPEC_HIDDEN;
|
||||||
NTSTATUS unix_get_ppd( void * ) DECLSPEC_HIDDEN;
|
NTSTATUS unix_get_ppd( void * ) DECLSPEC_HIDDEN;
|
||||||
|
NTSTATUS unix_schedule_job( void * ) DECLSPEC_HIDDEN;
|
||||||
|
|
Loading…
Reference in New Issue