1 /*
2  * PROJECT:     ReactOS Spooler Router
3  * LICENSE:     GPL-2.0+ (https://spdx.org/licenses/GPL-2.0+)
4  * PURPOSE:     Functions related to Printer Configuration Data
5  * COPYRIGHT:   Copyright 2020 ReactOS
6  */
7 
8 #include "precomp.h"
9 
10 BOOL WINAPI
11 AddPrinterDriverExW(PWSTR pName, DWORD Level, PBYTE pDriverInfo, DWORD dwFileCopyFlags)
12 {
13     BOOL bReturnValue;
14     DWORD dwErrorCode = ERROR_INVALID_PRINTER_NAME;
15     PLIST_ENTRY pEntry;
16     PSPOOLSS_PRINT_PROVIDER pPrintProvider;
17 
18     // Loop through all Print Providers.
19     for (pEntry = PrintProviderList.Flink; pEntry != &PrintProviderList; pEntry = pEntry->Flink)
20     {
21         pPrintProvider = CONTAINING_RECORD(pEntry, SPOOLSS_PRINT_PROVIDER, Entry);
22 
23         bReturnValue = pPrintProvider->PrintProvider.fpAddPrinterDriverEx(pName, Level, pDriverInfo, dwFileCopyFlags);
24 
25         if (bReturnValue == ROUTER_SUCCESS)
26         {
27             dwErrorCode = ERROR_SUCCESS;
28             goto Cleanup;
29         }
30         else if (bReturnValue == ROUTER_STOP_ROUTING)
31         {
32             ERR("A Print Provider returned ROUTER_STOP_ROUTING for Printer \"%S\"!\n", pName);
33             dwErrorCode = GetLastError();
34             goto Cleanup;
35         }
36     }
37 
38 Cleanup:
39     // 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.
40     if (dwErrorCode == ERROR_INVALID_NAME)
41         dwErrorCode = ERROR_INVALID_PRINTER_NAME;
42 
43     SetLastError(dwErrorCode);
44     return (dwErrorCode == ERROR_SUCCESS);
45 }
46 
47 BOOL WINAPI
48 AddPrinterDriverW(PWSTR pName, DWORD Level, PBYTE pDriverInfo)
49 {
50     TRACE("AddPrinterDriverW(%S, %lu, %p)\n", pName, Level, pDriverInfo);
51     return AddPrinterDriverExW(pName, Level, pDriverInfo, APD_COPY_NEW_FILES);
52 }
53 
54 BOOL WINAPI
55 DeletePrinterDriverExW(PWSTR pName, PWSTR pEnvironment, PWSTR pDriverName, DWORD dwDeleteFlag, DWORD dwVersionFlag)
56 {
57     BOOL bReturnValue;
58     DWORD dwErrorCode = ERROR_INVALID_PRINTER_NAME;
59     PLIST_ENTRY pEntry;
60     PSPOOLSS_PRINT_PROVIDER pPrintProvider;
61 
62     // Loop through all Print Providers.
63     for (pEntry = PrintProviderList.Flink; pEntry != &PrintProviderList; pEntry = pEntry->Flink)
64     {
65         pPrintProvider = CONTAINING_RECORD(pEntry, SPOOLSS_PRINT_PROVIDER, Entry);
66 
67         bReturnValue = pPrintProvider->PrintProvider.fpDeletePrinterDriverEx(pName, pEnvironment, pDriverName, dwDeleteFlag, dwVersionFlag);
68 
69         if (bReturnValue == ROUTER_SUCCESS)
70         {
71             dwErrorCode = ERROR_SUCCESS;
72             goto Cleanup;
73         }
74         else if (bReturnValue == ROUTER_STOP_ROUTING)
75         {
76             ERR("A Print Provider returned ROUTER_STOP_ROUTING for Printer \"%S\"!\n", pName);
77             dwErrorCode = GetLastError();
78             goto Cleanup;
79         }
80     }
81 
82 Cleanup:
83     // 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.
84     if (dwErrorCode == ERROR_INVALID_NAME)
85         dwErrorCode = ERROR_INVALID_PRINTER_NAME;
86 
87     SetLastError(dwErrorCode);
88     return (dwErrorCode == ERROR_SUCCESS);
89 }
90 
91 BOOL WINAPI
92 DeletePrinterDriverW(PWSTR pName, PWSTR pEnvironment, PWSTR pDriverName)
93 {
94     TRACE("DeletePrinterDriverW(%S, %S, %S)\n", pName, pEnvironment, pDriverName);
95     return DeletePrinterDriverExW(pName, pEnvironment, pDriverName, 0, 0);
96 }
97 
98 BOOL WINAPI
99 EnumPrinterDriversW(PWSTR pName, PWSTR pEnvironment, DWORD Level, PBYTE pDriverInfo, DWORD cbBuf, PDWORD pcbNeeded, PDWORD pcReturned)
100 {
101     DWORD cbCallBuffer;
102     DWORD cbNeeded;
103     DWORD dwErrorCode = MAXDWORD;
104     DWORD dwReturned;
105     PBYTE pCallBuffer;
106     BOOL Ret = FALSE;
107     PSPOOLSS_PRINT_PROVIDER pPrintProvider;
108     PLIST_ENTRY pEntry;
109 
110     // Begin counting.
111     *pcbNeeded = 0;
112     *pcReturned = 0;
113 
114     if ( cbBuf && !pDriverInfo )
115     {
116         dwErrorCode = ERROR_INVALID_USER_BUFFER;
117         goto Cleanup;
118     }
119 
120     // At the beginning, we have the full buffer available.
121     cbCallBuffer = cbBuf;
122     pCallBuffer = pDriverInfo;
123 
124     // Loop through all Print Providers.
125     for (pEntry = PrintProviderList.Flink; pEntry != &PrintProviderList; pEntry = pEntry->Flink)
126     {
127         pPrintProvider = CONTAINING_RECORD(pEntry, SPOOLSS_PRINT_PROVIDER, Entry);
128 
129         // Call the EnumPrinters function of this Print Provider.
130         cbNeeded = 0;
131         dwReturned = 0;
132 
133         Ret = pPrintProvider->PrintProvider.fpEnumPrinterDrivers( pName, pEnvironment, Level, pCallBuffer, cbCallBuffer, &cbNeeded, &dwReturned);
134 
135         if ( !Ret )
136         {
137             dwErrorCode = GetLastError();
138         }
139 
140         // Add the returned counts to the total values.
141         *pcbNeeded += cbNeeded;
142         *pcReturned += dwReturned;
143 
144         // Reduce the available buffer size for the next call without risking an underflow.
145         if (cbNeeded < cbCallBuffer)
146             cbCallBuffer -= cbNeeded;
147         else
148             cbCallBuffer = 0;
149 
150         // Advance the buffer if the caller provided it.
151         if (pCallBuffer)
152             pCallBuffer += cbNeeded;
153 
154         // dwErrorCode shall not be overwritten if a previous EnumPrinters call already succeeded.
155         if (dwErrorCode != ERROR_SUCCESS)
156             dwErrorCode = GetLastError();
157     }
158 
159 Cleanup:
160     SetLastError(dwErrorCode);
161     return (dwErrorCode == ERROR_SUCCESS);
162 }
163 
164 BOOL WINAPI
165 GetPrinterDriverW(HANDLE hPrinter, PWSTR pEnvironment, DWORD Level, PBYTE pDriverInfo, DWORD cbBuf, PDWORD pcbNeeded)
166 {
167     PSPOOLSS_PRINTER_HANDLE pHandle = (PSPOOLSS_PRINTER_HANDLE)hPrinter;
168 
169     // Sanity checks.
170     if (!pHandle)
171     {
172         SetLastError(ERROR_INVALID_PARAMETER);
173         return FALSE;
174     }
175 
176     return pHandle->pPrintProvider->PrintProvider.fpGetPrinterDriver(pHandle->hPrinter, pEnvironment, Level, pDriverInfo, cbBuf, pcbNeeded);
177 }
178 
179 
180 BOOL WINAPI
181 GetPrinterDriverExW(
182     HANDLE hPrinter,
183     LPWSTR pEnvironment,
184     DWORD Level,
185     LPBYTE pDriverInfo,
186     DWORD cbBuf,
187     LPDWORD pcbNeeded,
188     DWORD dwClientMajorVersion,
189     DWORD dwClientMinorVersion,
190     PDWORD pdwServerMajorVersion,
191     PDWORD pdwServerMinorVersion )
192 {
193     PSPOOLSS_PRINTER_HANDLE pHandle = (PSPOOLSS_PRINTER_HANDLE)hPrinter;
194 
195     FIXME("GetPrinterDriverExW(%p, %lu, %lu, %p, %lu, %p, %lu, %lu, %p, %p)\n", hPrinter, pEnvironment, Level, pDriverInfo, cbBuf, pcbNeeded, dwClientMajorVersion, dwClientMinorVersion, pdwServerMajorVersion, pdwServerMinorVersion);
196 
197     // Sanity checks.
198     if (!pHandle)
199     {
200         SetLastError(ERROR_INVALID_PARAMETER);
201         return FALSE;
202     }
203 
204     if ( cbBuf && !pDriverInfo )
205     {
206         SetLastError(ERROR_INVALID_USER_BUFFER);
207         return FALSE;
208     }
209 
210     return pHandle->pPrintProvider->PrintProvider.fpGetPrinterDriverEx(pHandle->hPrinter, pEnvironment, Level, pDriverInfo, cbBuf, pcbNeeded, dwClientMajorVersion, dwClientMinorVersion, pdwServerMajorVersion, pdwServerMinorVersion);
211 }
212 
213 BOOL WINAPI
214 GetPrinterDriverDirectoryW(PWSTR pName, PWSTR pEnvironment, DWORD Level, PBYTE pDriverDirectory, DWORD cbBuf, PDWORD pcbNeeded)
215 {
216     BOOL bReturnValue;
217     DWORD dwErrorCode = ERROR_INVALID_PRINTER_NAME;
218     PLIST_ENTRY pEntry;
219     PSPOOLSS_PRINT_PROVIDER pPrintProvider;
220 
221     if ( cbBuf && !pDriverDirectory )
222     {
223         SetLastError(ERROR_INVALID_USER_BUFFER);
224         return FALSE;
225     }
226 
227     // Loop through all Print Providers.
228     for (pEntry = PrintProviderList.Flink; pEntry != &PrintProviderList; pEntry = pEntry->Flink)
229     {
230         pPrintProvider = CONTAINING_RECORD(pEntry, SPOOLSS_PRINT_PROVIDER, Entry);
231 
232         bReturnValue = pPrintProvider->PrintProvider.fpGetPrinterDriverDirectory(pName, pEnvironment, Level, pDriverDirectory, cbBuf, pcbNeeded);
233 
234         if (bReturnValue == ROUTER_SUCCESS)
235         {
236             dwErrorCode = ERROR_SUCCESS;
237             goto Cleanup;
238         }
239         else if (bReturnValue == ROUTER_STOP_ROUTING)
240         {
241             ERR("A Print Provider returned ROUTER_STOP_ROUTING for Printer \"%S\"!\n", pName);
242             dwErrorCode = GetLastError();
243             goto Cleanup;
244         }
245     }
246 
247 Cleanup:
248     // 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.
249     if (dwErrorCode == ERROR_INVALID_NAME)
250         dwErrorCode = ERROR_INVALID_PRINTER_NAME;
251 
252     SetLastError(dwErrorCode);
253     return (dwErrorCode == ERROR_SUCCESS);
254 }
255