4 * Copyright 2021 Huw Davies
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
30 #include <sys/types.h>
37 #ifdef HAVE_CUPS_CUPS_H
38 #include <cups/cups.h>
40 #ifdef HAVE_CUPS_PPD_H
45 #define GetCurrentProcess GetCurrentProcess_Mac
46 #define GetCurrentThread GetCurrentThread_Mac
47 #define LoadResource LoadResource_Mac
48 #define AnimatePalette AnimatePalette_Mac
49 #define EqualRgn EqualRgn_Mac
50 #define FillRgn FillRgn_Mac
51 #define FrameRgn FrameRgn_Mac
52 #define GetPixel GetPixel_Mac
53 #define InvertRgn InvertRgn_Mac
54 #define LineTo LineTo_Mac
55 #define OffsetRgn OffsetRgn_Mac
56 #define PaintRgn PaintRgn_Mac
57 #define Polygon Polygon_Mac
58 #define ResizePalette ResizePalette_Mac
59 #define SetRectRgn SetRectRgn_Mac
60 #define EqualRect EqualRect_Mac
61 #define FillRect FillRect_Mac
62 #define FrameRect FrameRect_Mac
63 #define GetCursor GetCursor_Mac
64 #define InvertRect InvertRect_Mac
65 #define OffsetRect OffsetRect_Mac
66 #define PtInRect PtInRect_Mac
67 #define SetCursor SetCursor_Mac
68 #define SetRect SetRect_Mac
69 #define ShowCursor ShowCursor_Mac
70 #define UnionRect UnionRect_Mac
71 #include <ApplicationServices/ApplicationServices.h>
72 #undef GetCurrentProcess
73 #undef GetCurrentThread
100 #include "ntstatus.h"
101 #define WIN32_NO_STATUS
104 #include "winternl.h"
106 #include "winerror.h"
109 #include "winspool.h"
110 #include "ddk/winsplp.h"
111 #include "wine/debug.h"
112 #include "wine/unixlib.h"
116 WINE_DEFAULT_DEBUG_CHANNEL(winspool
);
118 #ifdef SONAME_LIBCUPS
120 static void *libcups_handle
;
123 DO_FUNC(cupsFreeDests); \
124 DO_FUNC(cupsGetDests); \
125 DO_FUNC(cupsGetOption);
126 #define CUPS_OPT_FUNCS \
127 DO_FUNC(cupsGetPPD); \
128 DO_FUNC(cupsGetPPD3);
130 #define DO_FUNC(f) static typeof(f) *p##f
133 static const char * (*pcupsGetPPD
)(const char *);
134 static http_status_t (*pcupsGetPPD3
)(http_t
*, const char *, time_t *, char *, size_t);
136 #endif /* SONAME_LIBCUPS */
138 static NTSTATUS
process_attach( void *args
)
140 #ifdef SONAME_LIBCUPS
141 libcups_handle
= dlopen( SONAME_LIBCUPS
, RTLD_NOW
);
142 TRACE( "%p: %s loaded\n", libcups_handle
, SONAME_LIBCUPS
);
143 if (!libcups_handle
) return STATUS_DLL_NOT_FOUND
;
146 p##x = dlsym( libcups_handle, #x ); \
149 ERR( "failed to load symbol %s\n", #x ); \
150 libcups_handle = NULL; \
151 return STATUS_ENTRYPOINT_NOT_FOUND; \
155 #define DO_FUNC(x) p##x = dlsym( libcups_handle, #x )
158 return STATUS_SUCCESS
;
159 #else /* SONAME_LIBCUPS */
160 return STATUS_NOT_SUPPORTED
;
161 #endif /* SONAME_LIBCUPS */
164 static char *get_unix_file_name( LPCWSTR path
)
166 UNICODE_STRING nt_name
;
167 OBJECT_ATTRIBUTES attr
;
172 nt_name
.Buffer
= (WCHAR
*)path
;
173 nt_name
.MaximumLength
= nt_name
.Length
= wcslen( path
) * sizeof(WCHAR
);
174 InitializeObjectAttributes( &attr
, &nt_name
, 0, 0, NULL
);
177 if (!(buffer
= malloc( size
))) return NULL
;
178 status
= wine_nt_to_unix_file_name( &attr
, buffer
, &size
, FILE_OPEN_IF
);
179 if (status
!= STATUS_BUFFER_TOO_SMALL
) break;
182 if (status
&& status
!= STATUS_NO_SUCH_FILE
)
191 #ifdef SONAME_LIBCUPS
192 static WCHAR
*cups_get_optionW( const char *opt_name
, int num_options
, cups_option_t
*options
)
198 value
= pcupsGetOption( opt_name
, num_options
, options
);
199 if (!value
) return NULL
;
201 len
= strlen( value
) + 1;
202 ret
= malloc( len
* sizeof(WCHAR
) );
203 if (ret
) ntdll_umbstowcs( value
, len
, ret
, len
);
208 static cups_ptype_t
cups_get_printer_type( const cups_dest_t
*dest
)
214 value
= pcupsGetOption( "printer-type", dest
->num_options
, dest
->options
);
215 if (!value
) return 0;
216 ret
= (cups_ptype_t
)strtoul( value
, &end
, 10 );
221 static BOOL
cups_is_scanner( cups_dest_t
*dest
)
223 return cups_get_printer_type( dest
) & 0x2000000 /* CUPS_PRINTER_SCANNER */;
226 static BOOL
copy_file( const char *src
, const char *dst
)
228 int fds
[2] = { -1, -1 }, num
;
232 fds
[0] = open( src
, O_RDONLY
);
233 fds
[1] = open( dst
, O_CREAT
| O_TRUNC
| O_WRONLY
, 0666 );
234 if (fds
[0] == -1 || fds
[1] == -1) goto fail
;
236 while ((num
= read( fds
[0], buf
, sizeof(buf
) )) != 0)
238 if (num
== -1) goto fail
;
239 if (write( fds
[1], buf
, num
) != num
) goto fail
;
244 if (fds
[1] != -1) close( fds
[1] );
245 if (fds
[0] != -1) close( fds
[0] );
249 static http_status_t
cupsGetPPD3_wrapper( http_t
*http
, const char *name
, time_t *modtime
,
250 char *buffer
, size_t bufsize
)
254 if (pcupsGetPPD3
) return pcupsGetPPD3( http
, name
, modtime
, buffer
, bufsize
);
255 if (!pcupsGetPPD
) return HTTP_NOT_FOUND
;
257 TRACE( "No cupsGetPPD3 implementation, so calling cupsGetPPD\n" );
260 ppd
= pcupsGetPPD( name
);
262 TRACE( "cupsGetPPD returns %s\n", debugstr_a(ppd
) );
264 if (!ppd
) return HTTP_NOT_FOUND
;
266 if (rename( ppd
, buffer
) == -1)
268 BOOL res
= copy_file( ppd
, buffer
);
270 if (!res
) return HTTP_NOT_FOUND
;
274 #endif /* SONAME_LIBCUPS */
276 static NTSTATUS
enum_printers( void *args
)
278 const struct enum_printers_params
*params
= args
;
279 #ifdef SONAME_LIBCUPS
280 unsigned int num
, i
, name_len
, comment_len
, location_len
, needed
;
281 WCHAR
*comment
, *location
, *ptr
;
282 struct printer_info
*info
;
286 if (!pcupsGetDests
) return STATUS_NOT_SUPPORTED
;
288 num
= pcupsGetDests( &dests
);
290 for (i
= 0; i
< num
; i
++)
292 if (cups_is_scanner( dests
+ i
))
294 TRACE( "Printer %d: %s - skipping scanner\n", i
, debugstr_a( dests
[i
].name
) );
297 TRACE( "Printer %d: %s\n", i
, debugstr_a( dests
[i
].name
) );
301 needed
= sizeof( *info
) * *params
->num
;
302 info
= params
->printers
;
303 ptr
= (WCHAR
*)(info
+ *params
->num
);
305 for (i
= 0; i
< num
; i
++)
307 if (cups_is_scanner( dests
+ i
)) continue;
309 comment
= cups_get_optionW( "printer-info", dests
[i
].num_options
, dests
[i
].options
);
310 location
= cups_get_optionW( "printer-location", dests
[i
].num_options
, dests
[i
].options
);
312 name_len
= strlen( dests
[i
].name
) + 1;
313 comment_len
= comment
? wcslen( comment
) + 1 : 0;
314 location_len
= location
? wcslen( location
) + 1 : 0;
315 needed
+= (name_len
+ comment_len
+ location_len
) * sizeof(WCHAR
);
317 if (needed
<= *params
->size
)
320 ntdll_umbstowcs( dests
[i
].name
, name_len
, info
->name
, name_len
);
321 info
->comment
= comment
? ptr
+ name_len
: NULL
;
322 memcpy( info
->comment
, comment
, comment_len
* sizeof(WCHAR
) );
323 info
->location
= location
? ptr
+ name_len
+ comment_len
: NULL
;
324 memcpy( info
->location
, location
, location_len
* sizeof(WCHAR
) );
325 info
->is_default
= dests
[i
].is_default
;
327 ptr
+= name_len
+ comment_len
+ location_len
;
332 pcupsFreeDests( num
, dests
);
334 if (needed
> *params
->size
)
336 *params
->size
= needed
;
337 return STATUS_BUFFER_OVERFLOW
;
339 return STATUS_SUCCESS
;
342 return STATUS_NOT_SUPPORTED
;
343 #endif /* SONAME_LIBCUPS */
346 static NTSTATUS
get_ppd( void *args
)
348 const struct get_ppd_params
*params
= args
;
349 char *unix_ppd
= get_unix_file_name( params
->ppd
);
350 NTSTATUS status
= STATUS_SUCCESS
;
352 TRACE( "(%s, %s)\n", debugstr_w( params
->printer
), debugstr_w( params
->ppd
) );
354 if (!unix_ppd
) return STATUS_NO_SUCH_FILE
;
356 if (!params
->printer
) /* unlink */
362 #ifdef SONAME_LIBCUPS
363 http_status_t http_status
;
368 len
= wcslen( params
->printer
);
369 printer_name
= malloc( len
* 3 + 1 );
370 ntdll_wcstoumbs( params
->printer
, len
+ 1, printer_name
, len
* 3 + 1, FALSE
);
372 http_status
= cupsGetPPD3_wrapper( 0, printer_name
, &modtime
, unix_ppd
, strlen( unix_ppd
) + 1 );
373 if (http_status
!= HTTP_OK
)
376 status
= STATUS_DEVICE_UNREACHABLE
;
378 free( printer_name
);
380 status
= STATUS_NOT_SUPPORTED
;
387 static NTSTATUS
get_default_page_size( void *args
)
390 const struct get_default_page_size_params
*params
= args
;
391 NTSTATUS status
= STATUS_UNSUCCESSFUL
;
392 PMPrintSession session
= NULL
;
393 PMPageFormat format
= NULL
;
394 CFStringRef paper_name
;
399 if (PMCreateSession( &session
)) goto end
;
400 if (PMCreatePageFormat( &format
)) goto end
;
401 if (PMSessionDefaultPageFormat( session
, format
)) goto end
;
402 if (PMGetPageFormatPaper( format
, &paper
)) goto end
;
403 if (PMPaperGetPPDPaperName( paper
, &paper_name
)) goto end
;
406 range
.length
= CFStringGetLength( paper_name
);
407 size
= (range
.length
+ 1) * sizeof(WCHAR
);
409 if (*params
->name_size
>= size
)
411 CFStringGetCharacters( paper_name
, range
, (UniChar
*)params
->name
);
412 params
->name
[range
.length
] = 0;
413 status
= STATUS_SUCCESS
;
416 status
= STATUS_BUFFER_OVERFLOW
;
417 *params
->name_size
= size
;
420 if (format
) PMRelease( format
);
421 if (session
) PMRelease( session
);
424 return STATUS_NOT_IMPLEMENTED
;
428 const unixlib_entry_t __wine_unix_call_funcs
[] =
432 get_default_page_size
,
436 C_ASSERT( ARRAYSIZE(__wine_unix_call_funcs
) == unix_funcs_count
);
442 struct printer_info32
450 static NTSTATUS
wow64_enum_printers( void *args
)
457 } const *params32
= args
;
461 struct enum_printers_params params
=
463 ULongToPtr( params32
->printers
),
464 ULongToPtr( params32
->size
),
465 ULongToPtr( params32
->num
)
468 if (!(status
= enum_printers( ¶ms
)))
470 /* convert structures in place */
471 struct printer_info
*info
= ULongToPtr( params32
->printers
);
472 struct printer_info32
*info32
= (struct printer_info32
*)info
;
473 unsigned int num
= *(unsigned int *)ULongToPtr( params32
->num
);
475 for (i
= 0; i
< num
; i
++)
477 info32
[i
].name
= PtrToUlong(info
[i
].name
);
478 info32
[i
].comment
= PtrToUlong(info
[i
].comment
);
479 info32
[i
].location
= PtrToUlong(info
[i
].location
);
480 info32
[i
].is_default
= info
[i
].is_default
;
486 static NTSTATUS
wow64_get_default_page_size( void *args
)
492 } const *params32
= args
;
494 struct get_default_page_size_params params
=
496 ULongToPtr( params32
->name
),
497 ULongToPtr( params32
->name_size
)
500 return get_default_page_size( ¶ms
);
503 static NTSTATUS
wow64_get_ppd( void *args
)
509 } const *params32
= args
;
511 struct get_ppd_params params
=
513 ULongToPtr( params32
->printer
),
514 ULongToPtr( params32
->ppd
)
517 return get_ppd( ¶ms
);
520 const unixlib_entry_t __wine_unix_call_wow64_funcs
[] =
524 wow64_get_default_page_size
,
528 C_ASSERT( ARRAYSIZE(__wine_unix_call_wow64_funcs
) == unix_funcs_count
);