Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
W
wine-cw
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Registry
Registry
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
wine
wine-cw
Commits
b09f8714
Commit
b09f8714
authored
Nov 29, 2022
by
Piotr Caban
Committed by
Alexandre Julliard
Dec 01, 2022
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
localspl: Add cups port extension.
parent
ee147d92
Hide whitespace changes
Inline
Side-by-side
Showing
5 changed files
with
312 additions
and
9 deletions
+312
-9
Makefile.in
dlls/localspl/Makefile.in
+2
-0
cups.c
dlls/localspl/cups.c
+289
-1
localmon.c
dlls/localspl/localmon.c
+17
-7
localspl_private.h
dlls/localspl/localspl_private.h
+2
-0
provider.c
dlls/localspl/provider.c
+2
-1
No files found.
dlls/localspl/Makefile.in
View file @
b09f8714
MODULE
=
localspl.dll
UNIXLIB
=
localspl.so
IMPORTS
=
spoolss user32 advapi32
UNIX_CFLAGS
=
$(CUPS_CFLAGS)
UNIX_LIBS
=
$(APPLICATIONSERVICES_LIBS)
EXTRADLLFLAGS
=
-Wb
,--prefer-native
...
...
dlls/localspl/cups.c
View file @
b09f8714
...
...
@@ -27,10 +27,14 @@
#include <stdarg.h>
#include <stdlib.h>
#include <unistd.h>
#include <dlfcn.h>
#include <fcntl.h>
#include <errno.h>
#include <signal.h>
#include <sys/wait.h>
#ifdef HAVE_CUPS_CUPS_H
#include <cups/cups.h>
#endif
#include "ntstatus.h"
#define WIN32_NO_STATUS
...
...
@@ -40,6 +44,32 @@
WINE_DEFAULT_DEBUG_CHANNEL
(
localspl
);
#ifdef SONAME_LIBCUPS
static
void
*
libcups_handle
;
#define CUPS_FUNCS \
DO_FUNC(cupsAddOption); \
DO_FUNC(cupsCreateJob); \
DO_FUNC(cupsFinishDocument); \
DO_FUNC(cupsFreeDests); \
DO_FUNC(cupsFreeOptions); \
DO_FUNC(cupsGetOption); \
DO_FUNC(cupsParseOptions); \
DO_FUNC(cupsStartDocument); \
DO_FUNC(cupsWriteRequestData)
#define CUPS_OPT_FUNCS \
DO_FUNC(cupsGetNamedDest); \
DO_FUNC(cupsLastErrorString)
#define DO_FUNC(f) static typeof(f) *p##f
CUPS_FUNCS
;
#undef DO_FUNC
static
cups_dest_t
*
(
*
pcupsGetNamedDest
)(
http_t
*
,
const
char
*
,
const
char
*
);
static
const
char
*
(
*
pcupsLastErrorString
)(
void
);
#endif
/* SONAME_LIBCUPS */
typedef
struct
_doc_t
{
BOOL
(
*
write_doc
)(
struct
_doc_t
*
,
const
BYTE
*
buf
,
unsigned
int
size
);
...
...
@@ -56,6 +86,25 @@ typedef struct _doc_t
{
int
fd
;
}
unixname
;
#ifdef SONAME_LIBCUPS
struct
{
char
*
queue
;
char
*
doc_title
;
enum
{
doc_parse_header
=
0
,
doc_parse_options
,
doc_create_job
,
doc_initialized
,
}
state
;
BOOL
restore_ps_header
;
int
num_options
;
cups_option_t
*
options
;
int
buf_len
;
char
buf
[
257
];
/* DSC max of 256 + '\0' */
}
cups
;
#endif
};
}
doc_t
;
...
...
@@ -178,10 +227,242 @@ static BOOL lpr_start_doc(doc_t *doc, const WCHAR *printer_name)
return
pipe_start_doc
(
doc
,
cmd
);
}
#ifdef SONAME_LIBCUPS
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
;
}
static
BOOL
cups_gets
(
doc_t
*
doc
,
const
BYTE
**
buf
,
unsigned
int
*
size
)
{
BYTE
b
;
while
(
doc
->
cups
.
buf_len
<
sizeof
(
doc
->
cups
.
buf
)
&&
*
size
)
{
b
=
(
*
buf
)[
0
];
doc
->
cups
.
buf
[
doc
->
cups
.
buf_len
++
]
=
b
;
(
*
buf
)
++
;
(
*
size
)
--
;
if
(
b
==
'\n'
)
return
TRUE
;
}
return
FALSE
;
}
static
BOOL
cups_write
(
const
char
*
buf
,
unsigned
int
size
)
{
if
(
!
size
)
return
TRUE
;
if
(
pcupsWriteRequestData
(
CUPS_HTTP_DEFAULT
,
buf
,
size
)
!=
HTTP_STATUS_CONTINUE
)
{
if
(
pcupsLastErrorString
)
WARN
(
"cupsWriteRequestData failed: %s
\n
"
,
debugstr_a
(
pcupsLastErrorString
()));
return
FALSE
;
}
return
TRUE
;
}
static
BOOL
cups_write_doc
(
doc_t
*
doc
,
const
BYTE
*
buf
,
unsigned
int
size
)
{
const
char
ps_adobe
[]
=
"%!PS-Adobe-3.0
\n
"
;
const
char
cups_job
[]
=
"%cupsJobTicket:"
;
if
(
doc
->
cups
.
state
==
doc_parse_header
)
{
if
(
!
cups_gets
(
doc
,
&
buf
,
&
size
))
{
if
(
doc
->
cups
.
buf_len
!=
sizeof
(
doc
->
cups
.
buf
))
return
TRUE
;
doc
->
cups
.
state
=
doc_create_job
;
}
else
if
(
!
strncmp
(
doc
->
cups
.
buf
,
ps_adobe
,
sizeof
(
ps_adobe
)
-
1
))
{
doc
->
cups
.
restore_ps_header
=
TRUE
;
doc
->
cups
.
state
=
doc_parse_options
;
doc
->
cups
.
buf_len
=
0
;
}
else
{
doc
->
cups
.
state
=
doc_create_job
;
}
}
/* Explicitly set CUPS options based on any %cupsJobTicket lines.
* The CUPS scheduler only looks for these in Print-File requests, and since
* we use Create-Job / Send-Document, the ticket lines don't get parsed.
*/
if
(
doc
->
cups
.
state
==
doc_parse_options
)
{
while
(
1
)
{
if
(
!
cups_gets
(
doc
,
&
buf
,
&
size
))
{
if
(
doc
->
cups
.
buf_len
!=
sizeof
(
doc
->
cups
.
buf
))
return
TRUE
;
doc
->
cups
.
state
=
doc_create_job
;
break
;
}
else
if
(
!
strncmp
(
doc
->
cups
.
buf
,
cups_job
,
sizeof
(
cups_job
)
-
1
))
{
doc
->
cups
.
buf
[
doc
->
cups
.
buf_len
-
1
]
=
0
;
doc
->
cups
.
num_options
=
pcupsParseOptions
(
doc
->
cups
.
buf
+
sizeof
(
cups_job
)
-
1
,
doc
->
cups
.
num_options
,
&
doc
->
cups
.
options
);
doc
->
cups
.
buf_len
=
0
;
}
else
{
doc
->
cups
.
state
=
doc_create_job
;
break
;
}
}
}
if
(
doc
->
cups
.
state
==
doc_create_job
)
{
const
char
*
format
;
int
i
,
job_id
;
doc
->
cups
.
num_options
=
get_cups_default_options
(
doc
->
cups
.
queue
,
doc
->
cups
.
num_options
,
&
doc
->
cups
.
options
);
TRACE
(
"printing via cups with options:
\n
"
);
for
(
i
=
0
;
i
<
doc
->
cups
.
num_options
;
i
++
)
TRACE
(
"
\t
%d: %s = %s
\n
"
,
i
,
doc
->
cups
.
options
[
i
].
name
,
doc
->
cups
.
options
[
i
].
value
);
if
(
pcupsGetOption
(
"raw"
,
doc
->
cups
.
num_options
,
doc
->
cups
.
options
))
format
=
CUPS_FORMAT_RAW
;
else
if
(
!
(
format
=
pcupsGetOption
(
"document-format"
,
doc
->
cups
.
num_options
,
doc
->
cups
.
options
)))
format
=
CUPS_FORMAT_AUTO
;
job_id
=
pcupsCreateJob
(
CUPS_HTTP_DEFAULT
,
doc
->
cups
.
queue
,
doc
->
cups
.
doc_title
,
doc
->
cups
.
num_options
,
doc
->
cups
.
options
);
if
(
!
job_id
)
{
if
(
pcupsLastErrorString
)
WARN
(
"cupsCreateJob failed: %s
\n
"
,
debugstr_a
(
pcupsLastErrorString
()));
return
FALSE
;
}
if
(
pcupsStartDocument
(
CUPS_HTTP_DEFAULT
,
doc
->
cups
.
queue
,
job_id
,
doc
->
cups
.
doc_title
,
format
,
TRUE
)
!=
HTTP_STATUS_CONTINUE
)
{
if
(
pcupsLastErrorString
)
WARN
(
"cupsStartDocument failed: %s
\n
"
,
debugstr_a
(
pcupsLastErrorString
()));
return
FALSE
;
}
doc
->
cups
.
state
=
doc_initialized
;
}
if
(
doc
->
cups
.
restore_ps_header
)
{
if
(
!
cups_write
(
ps_adobe
,
sizeof
(
ps_adobe
)
-
1
))
return
FALSE
;
doc
->
cups
.
restore_ps_header
=
FALSE
;
}
if
(
doc
->
cups
.
buf_len
)
{
if
(
!
cups_write
(
doc
->
cups
.
buf
,
doc
->
cups
.
buf_len
))
return
FALSE
;
doc
->
cups
.
buf_len
=
0
;
}
return
cups_write
((
const
char
*
)
buf
,
size
);
}
static
BOOL
cups_end_doc
(
doc_t
*
doc
)
{
if
(
doc
->
cups
.
buf_len
)
{
if
(
doc
->
cups
.
state
!=
doc_initialized
)
doc
->
cups
.
state
=
doc_create_job
;
cups_write_doc
(
doc
,
NULL
,
0
);
}
if
(
doc
->
cups
.
state
==
doc_initialized
)
pcupsFinishDocument
(
CUPS_HTTP_DEFAULT
,
doc
->
cups
.
queue
);
free
(
doc
->
cups
.
queue
);
free
(
doc
->
cups
.
doc_title
);
pcupsFreeOptions
(
doc
->
cups
.
num_options
,
doc
->
cups
.
options
);
return
TRUE
;
}
#endif
static
BOOL
cups_start_doc
(
doc_t
*
doc
,
const
WCHAR
*
printer_name
,
const
WCHAR
*
document_title
)
{
#ifdef SONAME_LIBCUPS
if
(
pcupsWriteRequestData
)
{
int
len
;
doc
->
write_doc
=
cups_write_doc
;
doc
->
end_doc
=
cups_end_doc
;
len
=
wcslen
(
printer_name
);
doc
->
cups
.
queue
=
malloc
(
len
*
3
+
1
);
ntdll_wcstoumbs
(
printer_name
,
len
+
1
,
doc
->
cups
.
queue
,
len
*
3
+
1
,
FALSE
);
len
=
wcslen
(
document_title
);
doc
->
cups
.
doc_title
=
malloc
(
len
*
3
+
1
);
ntdll_wcstoumbs
(
document_title
,
len
+
1
,
doc
->
cups
.
doc_title
,
len
+
3
+
1
,
FALSE
);
return
TRUE
;
}
#endif
return
lpr_start_doc
(
doc
,
printer_name
);
}
static
NTSTATUS
process_attach
(
void
*
args
)
{
#ifdef SONAME_LIBCUPS
libcups_handle
=
dlopen
(
SONAME_LIBCUPS
,
RTLD_NOW
);
TRACE
(
"%p: %s loaded
\n
"
,
libcups_handle
,
SONAME_LIBCUPS
);
if
(
!
libcups_handle
)
return
STATUS_DLL_NOT_FOUND
;
#define DO_FUNC(x) \
p##x = dlsym(libcups_handle, #x); \
if (!p##x) \
{ \
ERR("failed to load symbol %s\n", #x); \
libcups_handle = NULL; \
return STATUS_ENTRYPOINT_NOT_FOUND; \
}
CUPS_FUNCS
;
#undef DO_FUNC
#define DO_FUNC(x) p##x = dlsym(libcups_handle, #x)
CUPS_OPT_FUNCS
;
#undef DO_FUNC
return
STATUS_SUCCESS
;
#else
/* SONAME_LIBCUPS */
return
STATUS_NOT_SUPPORTED
;
#endif
/* SONAME_LIBCUPS */
}
static
NTSTATUS
start_doc
(
void
*
args
)
{
const
struct
start_doc_params
*
params
=
args
;
doc_t
*
doc
=
malloc
(
sizeof
(
*
doc
));
doc_t
*
doc
=
calloc
(
1
,
sizeof
(
*
doc
));
BOOL
ret
=
FALSE
;
if
(
!
doc
)
return
STATUS_NO_MEMORY
;
...
...
@@ -192,6 +473,9 @@ static NTSTATUS start_doc(void *args)
ret
=
unixname_start_doc
(
doc
,
params
->
port
);
else
if
(
params
->
type
==
PORT_IS_LPR
)
ret
=
lpr_start_doc
(
doc
,
params
->
port
+
4
/* strlen("lpr:") */
);
else
if
(
params
->
type
==
PORT_IS_CUPS
)
ret
=
cups_start_doc
(
doc
,
params
->
port
+
5
/*strlen("cups:") */
,
params
->
document_title
);
if
(
ret
)
*
params
->
doc
=
(
size_t
)
doc
;
...
...
@@ -221,6 +505,7 @@ static NTSTATUS end_doc(void *args)
const
unixlib_entry_t
__wine_unix_call_funcs
[]
=
{
process_attach
,
start_doc
,
write_doc
,
end_doc
,
...
...
@@ -236,6 +521,7 @@ static NTSTATUS wow64_start_doc(void *args)
{
unsigned
int
type
;
const
PTR32
port
;
const
PTR32
document_title
;
INT64
*
doc
;
}
const
*
params32
=
args
;
...
...
@@ -243,6 +529,7 @@ static NTSTATUS wow64_start_doc(void *args)
{
params32
->
type
,
ULongToPtr
(
params32
->
port
),
ULongToPtr
(
params32
->
document_title
),
params32
->
doc
,
};
...
...
@@ -270,6 +557,7 @@ static NTSTATUS wow64_write_doc(void *args)
const
unixlib_entry_t
__wine_unix_call_wow64_funcs
[]
=
{
process_attach
,
wow64_start_doc
,
wow64_write_doc
,
end_doc
,
...
...
dlls/localspl/localmon.c
View file @
b09f8714
...
...
@@ -96,7 +96,10 @@ BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
case
DLL_PROCESS_ATTACH
:
DisableThreadLibraryCalls
(
hinstDLL
);
localspl_instance
=
hinstDLL
;
return
!
__wine_init_unix_call
();
if
(
__wine_init_unix_call
())
return
FALSE
;
UNIX_CALL
(
process_attach
,
NULL
);
break
;
}
return
TRUE
;
}
...
...
@@ -506,8 +509,7 @@ static BOOL WINAPI localmon_StartDocPort(HANDLE hport, WCHAR *printer_name,
TRACE
(
"(%p %s %ld %ld %p)
\n
"
,
hport
,
debugstr_w
(
printer_name
),
job_id
,
level
,
doc_info
);
if
(
port
->
type
==
PORT_IS_PIPE
||
port
->
type
==
PORT_IS_UNIXNAME
||
port
->
type
==
PORT_IS_LPR
)
if
(
port
->
type
>=
PORT_IS_WINE
)
{
struct
start_doc_params
params
;
...
...
@@ -516,6 +518,7 @@ static BOOL WINAPI localmon_StartDocPort(HANDLE hport, WCHAR *printer_name,
params
.
type
=
port
->
type
;
params
.
port
=
port
->
nameW
;
params
.
document_title
=
doc_info
?
doc_info
->
pDocName
:
NULL
;
params
.
doc
=
&
port
->
doc_handle
;
return
UNIX_CALL
(
start_doc
,
&
params
);
}
...
...
@@ -547,12 +550,17 @@ static BOOL WINAPI localmon_WritePort(HANDLE hport, BYTE *buf, DWORD size,
TRACE
(
"(%p %p %lu %p)
\n
"
,
hport
,
buf
,
size
,
written
);
if
(
port
->
type
==
PORT_IS_PIPE
||
port
->
type
==
PORT_IS_UNIXNAME
||
port
->
type
==
PORT_IS_LPR
)
if
(
port
->
type
>=
PORT_IS_WINE
)
{
struct
write_doc_params
params
;
BOOL
ret
;
if
(
!
port
->
doc_handle
)
{
SetLastError
(
ERROR_INVALID_HANDLE
);
return
FALSE
;
}
params
.
doc
=
port
->
doc_handle
;
params
.
buf
=
buf
;
params
.
size
=
size
;
...
...
@@ -570,11 +578,13 @@ static BOOL WINAPI localmon_EndDocPort(HANDLE hport)
TRACE
(
"(%p)
\n
"
,
hport
);
if
(
port
->
type
==
PORT_IS_PIPE
||
port
->
type
==
PORT_IS_UNIXNAME
||
port
->
type
==
PORT_IS_LPR
)
if
(
port
->
type
>=
PORT_IS_WINE
)
{
struct
end_doc_params
params
;
if
(
!
port
->
doc_handle
)
return
TRUE
;
params
.
doc
=
port
->
doc_handle
;
port
->
doc_handle
=
0
;
return
UNIX_CALL
(
end_doc
,
&
params
);
...
...
dlls/localspl/localspl_private.h
View file @
b09f8714
...
...
@@ -171,6 +171,7 @@ struct start_doc_params
{
unsigned
int
type
;
const
WCHAR
*
port
;
const
WCHAR
*
document_title
;
INT64
*
doc
;
};
...
...
@@ -190,6 +191,7 @@ struct end_doc_params
enum
cups_funcs
{
unix_process_attach
,
unix_start_doc
,
unix_write_doc
,
unix_end_doc
,
...
...
dlls/localspl/provider.c
View file @
b09f8714
...
...
@@ -988,7 +988,8 @@ static monitor_t * monitor_load_by_port(LPCWSTR portname)
TRACE
(
"(%s)
\n
"
,
debugstr_w
(
portname
));
/* wine specific ports */
if
(
portname
[
0
]
==
'|'
||
portname
[
0
]
==
'/'
)
if
(
portname
[
0
]
==
'|'
||
portname
[
0
]
==
'/'
||
!
wcsncmp
(
portname
,
L"LPR:"
,
4
)
||
!
wcsncmp
(
portname
,
L"CUPS:"
,
5
))
return
monitor_load
(
L"Local Port"
,
NULL
);
/* Try the Local Monitor first */
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment