1 /*
2  * PROJECT:     ReactOS Spooler Router
3  * LICENSE:     GPL-2.0+ (https://spdx.org/licenses/GPL-2.0+)
4  * PURPOSE:     Functions related to Printers and printing
5  * COPYRIGHT:   Copyright 2015-2017 Colin Finck (colin@reactos.org)
6  */
7 
8 #include "precomp.h"
9 
10 BOOL WINAPI
11 AbortPrinter(HANDLE hPrinter)
12 {
13     PSPOOLSS_PRINTER_HANDLE pHandle = (PSPOOLSS_PRINTER_HANDLE)hPrinter;
14 
15     // Sanity checks.
16     if (!pHandle)
17     {
18         SetLastError(ERROR_INVALID_PARAMETER);
19         return FALSE;
20     }
21 
22     return pHandle->pPrintProvider->PrintProvider.fpAbortPrinter(pHandle->hPrinter);
23 }
24 
25 //
26 // See [MS-RPRN] 2.2.1.11 SPLCLIENT_INFO, SPLCLIENT_INFO Level.
27 //
28 HANDLE WINAPI
29 AddPrinterExW( PWSTR pName, DWORD Level, PBYTE pPrinter, PBYTE pClientInfo, DWORD ClientInfoLevel)
30 {
31     BOOL bReturnValue;
32     DWORD dwErrorCode = ERROR_INVALID_PRINTER_NAME;
33     HANDLE hPrinter = NULL;
34     PWSTR pPrinterName = NULL;
35     PLIST_ENTRY pEntry;
36     PSPOOLSS_PRINTER_HANDLE pHandle;
37     PSPOOLSS_PRINT_PROVIDER pPrintProvider;
38 
39     if ( Level != 2 )
40     {
41         FIXME( "Unsupported level %d\n", Level );
42         SetLastError( ERROR_INVALID_LEVEL );
43         return hPrinter;
44     }
45     else
46     {
47         PPRINTER_INFO_2W pi2w = (PPRINTER_INFO_2W)pPrinter;
48         pPrinterName = pi2w->pPrinterName;
49     }
50 
51     // Loop through all Print Providers to find one able to open this Printer.
52     for (pEntry = PrintProviderList.Flink; pEntry != &PrintProviderList; pEntry = pEntry->Flink)
53     {
54         pPrintProvider = CONTAINING_RECORD(pEntry, SPOOLSS_PRINT_PROVIDER, Entry);
55 
56         hPrinter = pPrintProvider->PrintProvider.fpAddPrinterEx(pName, Level, pPrinter, pClientInfo, ClientInfoLevel);
57 
58         bReturnValue = GetLastError();
59 
60         // Fallback.... ?
61 
62         if ( hPrinter == NULL && bReturnValue == ERROR_NOT_SUPPORTED )
63         {
64             hPrinter = pPrintProvider->PrintProvider.fpAddPrinter(pName, Level, pPrinter);
65         }
66 
67         bReturnValue = GetLastError();
68 
69         if ( bReturnValue == ROUTER_SUCCESS && hPrinter )
70         {
71             // This Print Provider has opened this Printer.
72             // Store this information and return a handle.
73             pHandle = DllAllocSplMem(sizeof(SPOOLSS_PRINTER_HANDLE));
74             if (!pHandle)
75             {
76                 dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
77                 ERR("DllAllocSplMem failed!\n");
78                 goto Cleanup;
79             }
80 
81             pHandle->pPrintProvider = pPrintProvider;
82             pHandle->hPrinter = hPrinter;
83 
84             dwErrorCode = ERROR_SUCCESS;
85             goto Cleanup;
86         }
87         else if (bReturnValue == ROUTER_STOP_ROUTING)
88         {
89             ERR("A Print Provider returned ROUTER_STOP_ROUTING for Printer \"%S\"!\n", pPrinterName);
90             dwErrorCode = GetLastError();
91             goto Cleanup;
92         }
93     }
94 
95 Cleanup:
96     // ERROR_INVALID_NAME by the Print Provider is translated to ERROR_INVALID_PRINTER_NAME here, but not in other APIs as far as I know.
97     if (dwErrorCode == ERROR_INVALID_NAME)
98         dwErrorCode = ERROR_INVALID_PRINTER_NAME;
99 
100     SetLastError(dwErrorCode);
101     return hPrinter;
102 }
103 
104 HANDLE WINAPI
105 AddPrinterW(PWSTR pName, DWORD Level, PBYTE pPrinter)
106 {
107     BOOL bReturnValue;
108     DWORD dwErrorCode = ERROR_INVALID_PRINTER_NAME;
109     HANDLE hPrinter = NULL;
110     PWSTR pPrinterName = NULL;
111     PLIST_ENTRY pEntry;
112     PSPOOLSS_PRINTER_HANDLE pHandle;
113     PSPOOLSS_PRINT_PROVIDER pPrintProvider;
114 
115     FIXME("AddPrinterW(%S, %lu, %p)\n", pName, Level, pPrinter);
116 
117     if ( Level != 2 )
118     {
119         FIXME( "Unsupported level %d\n", Level );
120         SetLastError( ERROR_INVALID_LEVEL );
121         return hPrinter;
122     }
123     else
124     {
125         PPRINTER_INFO_2W pi2w = (PPRINTER_INFO_2W)pPrinter;
126         pPrinterName = pi2w->pPrinterName;
127     }
128 
129     // Xp return AddPrinterExW( pName, Level, pPrinter, NULL, 0); but,,,, W7u just Forward Direct.
130 
131     // Loop through all Print Providers to find one able to open this Printer.
132     for (pEntry = PrintProviderList.Flink; pEntry != &PrintProviderList; pEntry = pEntry->Flink)
133     {
134         pPrintProvider = CONTAINING_RECORD(pEntry, SPOOLSS_PRINT_PROVIDER, Entry);
135 
136         hPrinter = pPrintProvider->PrintProvider.fpAddPrinter(pName, Level, pPrinter);
137 
138         bReturnValue = GetLastError();
139 
140         if ( bReturnValue == ROUTER_SUCCESS && hPrinter )
141         {
142             // This Print Provider has opened this Printer.
143             // Store this information and return a handle.
144             pHandle = DllAllocSplMem(sizeof(SPOOLSS_PRINTER_HANDLE));
145             if (!pHandle)
146             {
147                 dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
148                 ERR("DllAllocSplMem failed!\n");
149                 goto Cleanup;
150             }
151 
152             pHandle->pPrintProvider = pPrintProvider;
153             pHandle->hPrinter = hPrinter;
154 
155             dwErrorCode = ERROR_SUCCESS;
156             goto Cleanup;
157         }
158         else if (bReturnValue == ROUTER_STOP_ROUTING)
159         {
160             ERR("A Print Provider returned ROUTER_STOP_ROUTING for Printer \"%S\"!\n", pPrinterName);
161             dwErrorCode = GetLastError();
162             goto Cleanup;
163         }
164     }
165 
166 Cleanup:
167     // ERROR_INVALID_NAME by the Print Provider is translated to ERROR_INVALID_PRINTER_NAME here, but not in other APIs as far as I know.
168     if (dwErrorCode == ERROR_INVALID_NAME)
169         dwErrorCode = ERROR_INVALID_PRINTER_NAME;
170 
171     SetLastError(dwErrorCode);
172     return hPrinter;
173 }
174 
175 BOOL WINAPI
176 ClosePrinter(HANDLE hPrinter)
177 {
178     BOOL bReturnValue;
179     PSPOOLSS_PRINTER_HANDLE pHandle = (PSPOOLSS_PRINTER_HANDLE)hPrinter;
180 
181     FIXME("ClosePrinter %p\n",hPrinter);
182 
183     // Sanity checks.
184     if (!pHandle)
185     {
186         SetLastError(ERROR_INVALID_PARAMETER);
187         return FALSE;
188     }
189 
190     // FIXME: Call FindClosePrinterChangeNotification for all created change notifications (according to MSDN).
191 
192     // Call CloseHandle of the Print Provider.
193     bReturnValue = pHandle->pPrintProvider->PrintProvider.fpClosePrinter(pHandle->hPrinter);
194     FIXME("ClosePrinter 2\n");
195     // Free our handle information.
196     DllFreeSplMem(pHandle);
197     FIXME("ClosePrinter 3\n");
198     return bReturnValue;
199 }
200 
201 BOOL WINAPI
202 DeletePrinter(HANDLE hPrinter)
203 {
204     PSPOOLSS_PRINTER_HANDLE pHandle = (PSPOOLSS_PRINTER_HANDLE)hPrinter;
205 
206     // Sanity checks.
207     if (!pHandle)
208     {
209         SetLastError(ERROR_INVALID_PARAMETER);
210         return FALSE;
211     }
212 
213     return pHandle->pPrintProvider->PrintProvider.fpDeletePrinter(pHandle->hPrinter);
214 }
215 
216 BOOL WINAPI
217 EndDocPrinter(HANDLE hPrinter)
218 {
219     PSPOOLSS_PRINTER_HANDLE pHandle = (PSPOOLSS_PRINTER_HANDLE)hPrinter;
220 
221     // Sanity checks.
222     if (!pHandle)
223     {
224         SetLastError(ERROR_INVALID_PARAMETER);
225         return FALSE;
226     }
227 
228     return pHandle->pPrintProvider->PrintProvider.fpEndDocPrinter(pHandle->hPrinter);
229 }
230 
231 BOOL WINAPI
232 EndPagePrinter(HANDLE hPrinter)
233 {
234     PSPOOLSS_PRINTER_HANDLE pHandle = (PSPOOLSS_PRINTER_HANDLE)hPrinter;
235 
236     // Sanity checks.
237     if (!pHandle)
238     {
239         SetLastError(ERROR_INVALID_PARAMETER);
240         return FALSE;
241     }
242 
243     return pHandle->pPrintProvider->PrintProvider.fpEndPagePrinter(pHandle->hPrinter);
244 }
245 
246 BOOL WINAPI
247 EnumPrintersW(DWORD Flags, PWSTR Name, DWORD Level, PBYTE pPrinterEnum, DWORD cbBuf, PDWORD pcbNeeded, PDWORD pcReturned)
248 {
249     DWORD cbCallBuffer;
250     DWORD cbNeeded;
251     DWORD dwErrorCode = MAXDWORD;
252     DWORD dwReturned;
253     PBYTE pCallBuffer;
254     BOOL Ret = FALSE;
255     PSPOOLSS_PRINT_PROVIDER pPrintProvider;
256     PLIST_ENTRY pEntry;
257 
258     // Begin counting.
259     *pcbNeeded = 0;
260     *pcReturned = 0;
261 
262     if (cbBuf && !pPrinterEnum)
263     {
264         dwErrorCode = ERROR_INVALID_USER_BUFFER;
265         goto Cleanup;
266     }
267 
268     // At the beginning, we have the full buffer available.
269     cbCallBuffer = cbBuf;
270     pCallBuffer = pPrinterEnum;
271 
272     // Loop through all Print Providers.
273     for (pEntry = PrintProviderList.Flink; pEntry != &PrintProviderList; pEntry = pEntry->Flink)
274     {
275         pPrintProvider = CONTAINING_RECORD(pEntry, SPOOLSS_PRINT_PROVIDER, Entry);
276 
277         // Call the EnumPrinters function of this Print Provider.
278         cbNeeded = 0;
279         dwReturned = 0;
280         Ret = pPrintProvider->PrintProvider.fpEnumPrinters(Flags, Name, Level, pCallBuffer, cbCallBuffer, &cbNeeded, &dwReturned);
281 
282         if ( !Ret )
283         {
284             dwErrorCode = GetLastError();
285         }
286 
287         // Add the returned counts to the total values.
288         *pcbNeeded += cbNeeded;
289         *pcReturned += dwReturned;
290 
291         // Reduce the available buffer size for the next call without risking an underflow.
292         if (cbNeeded < cbCallBuffer)
293             cbCallBuffer -= cbNeeded;
294         else
295             cbCallBuffer = 0;
296 
297         // Advance the buffer if the caller provided it.
298         if (pCallBuffer)
299             pCallBuffer += cbNeeded;
300 
301         // dwErrorCode shall not be overwritten if a previous EnumPrinters call already succeeded.
302         if (dwErrorCode != ERROR_SUCCESS)
303             dwErrorCode = GetLastError();
304     }
305 
306 Cleanup:
307     SetLastError(dwErrorCode);
308     return (dwErrorCode == ERROR_SUCCESS);
309 }
310 
311 BOOL WINAPI
312 GetPrinterW(HANDLE hPrinter, DWORD Level, PBYTE pPrinter, DWORD cbBuf, PDWORD pcbNeeded)
313 {
314     PSPOOLSS_PRINTER_HANDLE pHandle = (PSPOOLSS_PRINTER_HANDLE)hPrinter;
315 
316     // Sanity checks.
317     if (!pHandle)
318     {
319         SetLastError(ERROR_INVALID_PARAMETER);
320         return FALSE;
321     }
322 
323     return pHandle->pPrintProvider->PrintProvider.fpGetPrinter(pHandle->hPrinter, Level, pPrinter, cbBuf, pcbNeeded);
324 }
325 
326 //
327 // Forward Dead API to Local/Remote....
328 //
329 DWORD WINAPI
330 PrinterMessageBoxW(HANDLE hPrinter, DWORD Error, HWND hWnd, LPWSTR pText, LPWSTR pCaption, DWORD dwType)
331 {
332     PSPOOLSS_PRINTER_HANDLE pHandle = (PSPOOLSS_PRINTER_HANDLE)hPrinter;
333 
334     // Sanity checks.
335     if (!pHandle)
336     {
337         SetLastError(ERROR_INVALID_PARAMETER);
338         return FALSE;
339     }
340 
341     return pHandle->pPrintProvider->PrintProvider.fpPrinterMessageBox(pHandle->hPrinter, Error, hWnd, pText, pCaption, dwType);
342 }
343 
344 BOOL WINAPI
345 OpenPrinterW(PWSTR pPrinterName, PHANDLE phPrinter, PPRINTER_DEFAULTSW pDefault)
346 {
347     BOOL bReturnValue;
348     DWORD dwErrorCode = ERROR_INVALID_PRINTER_NAME;
349     HANDLE hPrinter;
350     PLIST_ENTRY pEntry;
351     PSPOOLSS_PRINTER_HANDLE pHandle;
352     PSPOOLSS_PRINT_PROVIDER pPrintProvider;
353 
354     // Loop through all Print Providers to find one able to open this Printer.
355     for (pEntry = PrintProviderList.Flink; pEntry != &PrintProviderList; pEntry = pEntry->Flink)
356     {
357         pPrintProvider = CONTAINING_RECORD(pEntry, SPOOLSS_PRINT_PROVIDER, Entry);
358 
359         bReturnValue = pPrintProvider->PrintProvider.fpOpenPrinter(pPrinterName, &hPrinter, pDefault);
360         if (bReturnValue == ROUTER_SUCCESS)
361         {
362             // This Print Provider has opened this Printer.
363             // Store this information and return a handle.
364             pHandle = DllAllocSplMem(sizeof(SPOOLSS_PRINTER_HANDLE));
365             if (!pHandle)
366             {
367                 dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
368                 ERR("DllAllocSplMem failed!\n");
369                 goto Cleanup;
370             }
371 
372             pHandle->pPrintProvider = pPrintProvider;
373             pHandle->hPrinter = hPrinter;
374             *phPrinter = (HANDLE)pHandle;
375 
376             dwErrorCode = ERROR_SUCCESS;
377             goto Cleanup;
378         }
379         else if (bReturnValue == ROUTER_STOP_ROUTING)
380         {
381             ERR("A Print Provider returned ROUTER_STOP_ROUTING for Printer \"%S\"!\n", pPrinterName);
382             dwErrorCode = GetLastError();
383             goto Cleanup;
384         }
385     }
386 
387 Cleanup:
388     // ERROR_INVALID_NAME by the Print Provider is translated to ERROR_INVALID_PRINTER_NAME here, but not in other APIs as far as I know.
389     if (dwErrorCode == ERROR_INVALID_NAME)
390         dwErrorCode = ERROR_INVALID_PRINTER_NAME;
391 
392     SetLastError(dwErrorCode);
393     return (dwErrorCode == ERROR_SUCCESS);
394 }
395 
396 BOOL WINAPI
397 ReadPrinter(HANDLE hPrinter, PVOID pBuf, DWORD cbBuf, PDWORD pNoBytesRead)
398 {
399     PSPOOLSS_PRINTER_HANDLE pHandle = (PSPOOLSS_PRINTER_HANDLE)hPrinter;
400 
401     // Sanity checks.
402     if (!pHandle)
403     {
404         SetLastError(ERROR_INVALID_PARAMETER);
405         return FALSE;
406     }
407 
408     return pHandle->pPrintProvider->PrintProvider.fpReadPrinter(pHandle->hPrinter, pBuf, cbBuf, pNoBytesRead);
409 }
410 
411 BOOL WINAPI
412 SeekPrinter( HANDLE hPrinter, LARGE_INTEGER liDistanceToMove, PLARGE_INTEGER pliNewPointer, DWORD dwMoveMethod, BOOL bWrite )
413 {
414     PSPOOLSS_PRINTER_HANDLE pHandle = (PSPOOLSS_PRINTER_HANDLE)hPrinter;
415 
416     // Sanity checks.
417     if (!pHandle)
418     {
419         SetLastError(ERROR_INVALID_PARAMETER);
420         return FALSE;
421     }
422 
423     return pHandle->pPrintProvider->PrintProvider.fpSeekPrinter( pHandle->hPrinter, liDistanceToMove, pliNewPointer, dwMoveMethod, bWrite );
424 }
425 
426 BOOL WINAPI
427 SetPrinterW(HANDLE hPrinter, DWORD Level, PBYTE pPrinter, DWORD Command)
428 {
429     PSPOOLSS_PRINTER_HANDLE pHandle = (PSPOOLSS_PRINTER_HANDLE)hPrinter;
430 
431     // Sanity checks.
432     if (!pHandle)
433     {
434         SetLastError(ERROR_INVALID_PARAMETER);
435         return FALSE;
436     }
437 
438     return pHandle->pPrintProvider->PrintProvider.fpSetPrinter( pHandle->hPrinter, Level, pPrinter, Command );
439 }
440 
441 DWORD WINAPI
442 StartDocPrinterW(HANDLE hPrinter, DWORD Level, PBYTE pDocInfo)
443 {
444     PSPOOLSS_PRINTER_HANDLE pHandle = (PSPOOLSS_PRINTER_HANDLE)hPrinter;
445 
446     // Sanity checks.
447     if (!pHandle)
448     {
449         SetLastError(ERROR_INVALID_PARAMETER);
450         return FALSE;
451     }
452 
453     return pHandle->pPrintProvider->PrintProvider.fpStartDocPrinter(pHandle->hPrinter, Level, pDocInfo);
454 }
455 
456 BOOL WINAPI
457 StartPagePrinter(HANDLE hPrinter)
458 {
459     PSPOOLSS_PRINTER_HANDLE pHandle = (PSPOOLSS_PRINTER_HANDLE)hPrinter;
460 
461     // Sanity checks.
462     if (!pHandle)
463     {
464         SetLastError(ERROR_INVALID_PARAMETER);
465         return FALSE;
466     }
467 
468     return pHandle->pPrintProvider->PrintProvider.fpStartPagePrinter(pHandle->hPrinter);
469 }
470 
471 BOOL WINAPI
472 WritePrinter(HANDLE hPrinter, PVOID pBuf, DWORD cbBuf, PDWORD pcWritten)
473 {
474     PSPOOLSS_PRINTER_HANDLE pHandle = (PSPOOLSS_PRINTER_HANDLE)hPrinter;
475 
476     // Sanity checks.
477     if (!pHandle)
478     {
479         SetLastError(ERROR_INVALID_PARAMETER);
480         return FALSE;
481     }
482 
483     return pHandle->pPrintProvider->PrintProvider.fpWritePrinter(pHandle->hPrinter, pBuf, cbBuf, pcWritten);
484 }
485 
486 BOOL WINAPI
487 XcvDataW(HANDLE hXcv, PCWSTR pszDataName, PBYTE pInputData, DWORD cbInputData, PBYTE pOutputData, DWORD cbOutputData, PDWORD pcbOutputNeeded, PDWORD pdwStatus)
488 {
489     PSPOOLSS_PRINTER_HANDLE pHandle = (PSPOOLSS_PRINTER_HANDLE)hXcv;
490 
491     FIXME("XcvDataW( %p, %S,,,)\n",hXcv, pszDataName);
492 
493     // Sanity checks.
494     if (!pHandle)
495     {
496         SetLastError(ERROR_INVALID_PARAMETER);
497         return FALSE;
498     }
499 
500     return pHandle->pPrintProvider->PrintProvider.fpXcvData(pHandle->hPrinter, pszDataName, pInputData, cbInputData, pOutputData, cbOutputData, pcbOutputNeeded, pdwStatus);
501 }
502