1 /*
2 * PROJECT: ReactOS Local Spooler
3 * LICENSE: GPL-2.0+ (https://spdx.org/licenses/GPL-2.0+)
4 * PURPOSE: Functions related to Ports of the Print Monitors
5 * COPYRIGHT: Copyright 2015-2017 Colin Finck (colin@reactos.org)
6 */
7
8 #include "precomp.h"
9
10 // Local Variables
11 static LIST_ENTRY _PortList;
12
13
14 PLOCAL_PORT
FindPort(PCWSTR pwszName)15 FindPort(PCWSTR pwszName)
16 {
17 PLIST_ENTRY pEntry;
18 PLOCAL_PORT pPort;
19
20 TRACE("FindPort(%S)\n", pwszName);
21
22 if (!pwszName)
23 return NULL;
24
25 for (pEntry = _PortList.Flink; pEntry != &_PortList; pEntry = pEntry->Flink)
26 {
27 pPort = CONTAINING_RECORD(pEntry, LOCAL_PORT, Entry);
28
29 if (_wcsicmp(pPort->pwszName, pwszName) == 0)
30 return pPort;
31 }
32
33 return NULL;
34 }
35
36 BOOL
CreatePortEntry(PCWSTR pwszName,PLOCAL_PRINT_MONITOR pPrintMonitor)37 CreatePortEntry( PCWSTR pwszName, PLOCAL_PRINT_MONITOR pPrintMonitor )
38 {
39 PLOCAL_PORT pPort;
40 DWORD cbPortName = (wcslen( pwszName ) + 1) * sizeof(WCHAR);
41
42 // Create a new LOCAL_PORT structure for it.
43 pPort = DllAllocSplMem(sizeof(LOCAL_PORT) + cbPortName);
44 if (!pPort)
45 {
46 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
47 return FALSE;
48 }
49
50 pPort->pPrintMonitor = pPrintMonitor;
51 pPort->pwszName = wcscpy( (PWSTR)(pPort+1), pwszName );
52
53 // Insert it into the list and advance to the next port.
54 InsertTailList(&_PortList, &pPort->Entry);
55
56 return TRUE;
57 }
58
59 BOOL
InitializePortList(void)60 InitializePortList(void)
61 {
62 BOOL bReturnValue;
63 DWORD cbNeeded;
64 DWORD cbPortName;
65 DWORD dwErrorCode;
66 DWORD dwReturned;
67 DWORD i;
68 PLOCAL_PORT pPort;
69 PLOCAL_PRINT_MONITOR pPrintMonitor;
70 PLIST_ENTRY pEntry;
71 PPORT_INFO_1W p;
72 PPORT_INFO_1W pPortInfo1 = NULL;
73
74 TRACE("InitializePortList()\n");
75
76 // Initialize an empty list for our Ports.
77 InitializeListHead(&_PortList);
78
79 // Loop through all Print Monitors.
80 for (pEntry = PrintMonitorList.Flink; pEntry != &PrintMonitorList; pEntry = pEntry->Flink)
81 {
82 // Cleanup from the previous run.
83 if (pPortInfo1)
84 {
85 DllFreeSplMem(pPortInfo1);
86 pPortInfo1 = NULL;
87 }
88
89 pPrintMonitor = CONTAINING_RECORD(pEntry, LOCAL_PRINT_MONITOR, Entry);
90
91 // Determine the required buffer size for EnumPorts.
92 if (pPrintMonitor->bIsLevel2)
93 bReturnValue = ((PMONITOR2)pPrintMonitor->pMonitor)->pfnEnumPorts(pPrintMonitor->hMonitor, NULL, 1, NULL, 0, &cbNeeded, &dwReturned);
94 else
95 bReturnValue = ((LPMONITOREX)pPrintMonitor->pMonitor)->Monitor.pfnEnumPorts(NULL, 1, NULL, 0, &cbNeeded, &dwReturned);
96
97 // Check the returned error code.
98 if (GetLastError() != ERROR_INSUFFICIENT_BUFFER)
99 {
100 ERR("Print Monitor \"%S\" failed with error %lu on EnumPorts!\n", pPrintMonitor->pwszName, GetLastError());
101 continue;
102 }
103
104 // Allocate a buffer large enough.
105 pPortInfo1 = DllAllocSplMem(cbNeeded);
106 if (!pPortInfo1)
107 {
108 dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
109 ERR("DllAllocSplMem failed!\n");
110 goto Cleanup;
111 }
112
113 // Get the ports handled by this monitor.
114 if (pPrintMonitor->bIsLevel2)
115 bReturnValue = ((PMONITOR2)pPrintMonitor->pMonitor)->pfnEnumPorts(pPrintMonitor->hMonitor, NULL, 1, (PBYTE)pPortInfo1, cbNeeded, &cbNeeded, &dwReturned);
116 else
117 bReturnValue = ((LPMONITOREX)pPrintMonitor->pMonitor)->Monitor.pfnEnumPorts(NULL, 1, (PBYTE)pPortInfo1, cbNeeded, &cbNeeded, &dwReturned);
118
119 // Check the return value.
120 if (!bReturnValue)
121 {
122 ERR("Print Monitor \"%S\" failed with error %lu on EnumPorts!\n", pPrintMonitor->pwszName, GetLastError());
123 continue;
124 }
125
126 // Loop through all returned ports.
127 p = pPortInfo1;
128
129 for (i = 0; i < dwReturned; i++)
130 {
131 cbPortName = (wcslen(p->pName) + 1) * sizeof(WCHAR);
132
133 // Create a new LOCAL_PORT structure for it.
134 pPort = DllAllocSplMem(sizeof(LOCAL_PORT) + cbPortName);
135 if (!pPort)
136 {
137 dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
138 ERR("DllAllocSplMem failed!\n");
139 goto Cleanup;
140 }
141
142 pPort->pPrintMonitor = pPrintMonitor;
143 pPort->pwszName = (PWSTR)((PBYTE)pPort + sizeof(LOCAL_PORT));
144 CopyMemory(pPort->pwszName, p->pName, cbPortName);
145
146 // Insert it into the list and advance to the next port.
147 InsertTailList(&_PortList, &pPort->Entry);
148 p++;
149 }
150 }
151
152 dwErrorCode = ERROR_SUCCESS;
153
154 Cleanup:
155 // Inside the loop
156 if (pPortInfo1)
157 DllFreeSplMem(pPortInfo1);
158
159 SetLastError(dwErrorCode);
160 return (dwErrorCode == ERROR_SUCCESS);
161 }
162
163 BOOL WINAPI
LocalEnumPorts(PWSTR pName,DWORD Level,PBYTE pPorts,DWORD cbBuf,PDWORD pcbNeeded,PDWORD pcReturned)164 LocalEnumPorts(PWSTR pName, DWORD Level, PBYTE pPorts, DWORD cbBuf, PDWORD pcbNeeded, PDWORD pcReturned)
165 {
166 BOOL bReturnValue = TRUE;
167 DWORD cbCallBuffer;
168 DWORD cbNeeded;
169 DWORD dwReturned;
170 PBYTE pCallBuffer;
171 PLOCAL_PRINT_MONITOR pPrintMonitor;
172 PLIST_ENTRY pEntry;
173
174 TRACE("LocalEnumPorts(%S, %lu, %p, %lu, %p, %p)\n", pName, Level, pPorts, cbBuf, pcbNeeded, pcReturned);
175
176 // Begin counting.
177 *pcbNeeded = 0;
178 *pcReturned = 0;
179
180 // At the beginning, we have the full buffer available.
181 cbCallBuffer = cbBuf;
182 pCallBuffer = pPorts;
183
184 // Loop through all Print Monitors.
185 for (pEntry = PrintMonitorList.Flink; pEntry != &PrintMonitorList; pEntry = pEntry->Flink)
186 {
187 pPrintMonitor = CONTAINING_RECORD(pEntry, LOCAL_PRINT_MONITOR, Entry);
188
189 // Call the EnumPorts function of this Print Monitor.
190 cbNeeded = 0;
191 dwReturned = 0;
192
193 if (pPrintMonitor->bIsLevel2)
194 bReturnValue = ((PMONITOR2)pPrintMonitor->pMonitor)->pfnEnumPorts(pPrintMonitor->hMonitor, pName, Level, pCallBuffer, cbCallBuffer, &cbNeeded, &dwReturned);
195 else
196 bReturnValue = ((LPMONITOREX)pPrintMonitor->pMonitor)->Monitor.pfnEnumPorts(pName, Level, pCallBuffer, cbCallBuffer, &cbNeeded, &dwReturned);
197
198 // Add the returned counts to the total values.
199 *pcbNeeded += cbNeeded;
200 *pcReturned += dwReturned;
201
202 // Reduce the available buffer size for the next call without risking an underflow.
203 if (cbNeeded < cbCallBuffer)
204 cbCallBuffer -= cbNeeded;
205 else
206 cbCallBuffer = 0;
207
208 // Advance the buffer if the caller provided it.
209 if (pCallBuffer)
210 pCallBuffer += cbNeeded;
211 }
212
213 return bReturnValue;
214 }
215
216 BOOL WINAPI
LocalAddPortEx(PWSTR pName,DWORD Level,PBYTE lpBuffer,PWSTR lpMonitorName)217 LocalAddPortEx(PWSTR pName, DWORD Level, PBYTE lpBuffer, PWSTR lpMonitorName)
218 {
219 DWORD lres;
220 BOOL res = FALSE;
221 PLOCAL_PORT pPort;
222 PLOCAL_PRINT_MONITOR pPrintMonitor;
223 PORT_INFO_1W * pi = (PORT_INFO_1W *) lpBuffer;
224
225 FIXME("LocalAddPortEx(%S, %lu, %p, %S)\n", pName, Level, lpBuffer, lpMonitorName);
226
227 lres = copy_servername_from_name(pName, NULL);
228 if ( lres )
229 {
230 FIXME("server %s not supported\n", debugstr_w(pName));
231 SetLastError(ERROR_INVALID_PARAMETER);
232 return FALSE;
233 }
234
235 if ( Level != 1 )
236 {
237 SetLastError(ERROR_INVALID_LEVEL);
238 return FALSE;
239 }
240
241 if ((!pi) || (!lpMonitorName) || (!lpMonitorName[0]))
242 {
243 SetLastError(ERROR_INVALID_PARAMETER);
244 return FALSE;
245 }
246
247 pPrintMonitor = FindPrintMonitor( lpMonitorName );
248 if (!pPrintMonitor )
249 {
250 SetLastError(ERROR_INVALID_PARAMETER);
251 return FALSE;
252 }
253
254 pPort = FindPort( pi->pName );
255 if ( pPort )
256 {
257 SetLastError(ERROR_INVALID_PARAMETER);
258 return FALSE;
259 }
260
261 if ( pPrintMonitor->bIsLevel2 && ((PMONITOR2)pPrintMonitor->pMonitor)->pfnAddPortEx )
262 {
263 res = ((PMONITOR2)pPrintMonitor->pMonitor)->pfnAddPortEx(pPrintMonitor->hMonitor, pName, Level, lpBuffer, lpMonitorName);
264 }
265 else if ( !pPrintMonitor->bIsLevel2 && ((LPMONITOREX)pPrintMonitor->pMonitor)->Monitor.pfnAddPortEx )
266 {
267 res = ((LPMONITOREX)pPrintMonitor->pMonitor)->Monitor.pfnAddPortEx(pName, Level, lpBuffer, lpMonitorName);
268 }
269 else
270 {
271 SetLastError(ERROR_INVALID_PARAMETER);
272 }
273
274 if ( res )
275 {
276 res = CreatePortEntry( pi->pName, pPrintMonitor );
277 }
278
279 return res;
280 }
281
282 //
283 // Local (AP, CP & DP) is still around, seems to be a backup if a failure was encountered.. New way, WinSpool->LocalUI->XcvDataW.
284 //
285 BOOL WINAPI
LocalAddPort(LPWSTR pName,HWND hWnd,LPWSTR pMonitorName)286 LocalAddPort(LPWSTR pName, HWND hWnd, LPWSTR pMonitorName)
287 {
288 DWORD lres;
289 BOOL res = FALSE;
290 PLOCAL_PRINT_MONITOR pPrintMonitor;
291
292 FIXME("LocalAddPort(%S, %p, %s)\n", pName, hWnd, debugstr_w(pMonitorName));
293
294 lres = copy_servername_from_name(pName, NULL);
295 if (lres)
296 {
297 FIXME("server %s not supported\n", debugstr_w(pName));
298 SetLastError(ERROR_INVALID_PARAMETER);
299 return FALSE;
300 }
301
302 /* an empty Monitorname is Invalid */
303 if (!pMonitorName[0])
304 {
305 SetLastError(ERROR_NOT_SUPPORTED);
306 return FALSE;
307 }
308
309 pPrintMonitor = FindPrintMonitor( pMonitorName );
310 if (!pPrintMonitor )
311 {
312 SetLastError(ERROR_INVALID_PARAMETER);
313 return FALSE;
314 }
315
316 if ( pPrintMonitor->bIsLevel2 && ((PMONITOR2)pPrintMonitor->pMonitor)->pfnAddPort )
317 {
318 res = ((PMONITOR2)pPrintMonitor->pMonitor)->pfnAddPort(pPrintMonitor->hMonitor, pName, hWnd, pMonitorName);
319 }
320 else if ( !pPrintMonitor->bIsLevel2 && ((LPMONITOREX)pPrintMonitor->pMonitor)->Monitor.pfnAddPort )
321 {
322 res = ((LPMONITOREX)pPrintMonitor->pMonitor)->Monitor.pfnAddPort(pName, hWnd, pMonitorName);
323 }
324 else
325 {
326 SetLastError(ERROR_INVALID_PARAMETER);
327 }
328
329 if ( res )
330 {
331 DWORD cbNeeded, cReturned, i;
332 PPORT_INFO_1 pPorts;
333
334 //
335 // Play it safe,,, we know its Monitor2.... This is ReactOS.
336 //
337 if ( LocalEnumPorts( pName, 1, NULL, 0, &cbNeeded, &cReturned ) )
338 {
339 pPorts = DllAllocSplMem( cbNeeded );
340 if (pPorts)
341 {
342 if ( LocalEnumPorts( pName, 1, (PBYTE)pPorts, cbNeeded, &cbNeeded, &cReturned ) )
343 {
344 for ( i = 0; i < cReturned; i++ )
345 {
346 if ( !FindPort( pPorts[i].pName ) )
347 {
348 CreatePortEntry( pPorts[i].pName, pPrintMonitor );
349 }
350 }
351 }
352 DllFreeSplMem( pPorts );
353 }
354 }
355 }
356
357 return res;
358 }
359
360 BOOL WINAPI
LocalConfigurePort(PWSTR pName,HWND hWnd,PWSTR pPortName)361 LocalConfigurePort(PWSTR pName, HWND hWnd, PWSTR pPortName)
362 {
363 LONG lres;
364 DWORD res;
365 PLOCAL_PORT pPrintPort;
366 PLOCAL_PRINT_MONITOR pPrintMonitor;
367
368 FIXME("LocalConfigurePort(%S, %p, %S)\n", pName, hWnd, pPortName);
369
370 lres = copy_servername_from_name(pName, NULL);
371 if (lres)
372 {
373 FIXME("server %s not supported\n", debugstr_w(pName));
374 SetLastError(ERROR_INVALID_NAME);
375 return FALSE;
376 }
377
378 /* an empty Portname is Invalid, but can popup a Dialog */
379 if (!pPortName[0])
380 {
381 SetLastError(ERROR_NOT_SUPPORTED);
382 return FALSE;
383 }
384
385 pPrintPort = FindPort(pPortName);
386 if (!pPrintPort )
387 {
388 SetLastError(ERROR_INVALID_PARAMETER);
389 return FALSE;
390 }
391
392 pPrintMonitor = pPrintPort->pPrintMonitor;
393
394 if ( pPrintMonitor->bIsLevel2 && ((PMONITOR2)pPrintMonitor->pMonitor)->pfnConfigurePort )
395 {
396 res = ((PMONITOR2)pPrintMonitor->pMonitor)->pfnConfigurePort(pPrintMonitor->hMonitor, pName, hWnd, pPortName);
397 }
398 else if ( !pPrintMonitor->bIsLevel2 && ((LPMONITOREX)pPrintMonitor->pMonitor)->Monitor.pfnConfigurePort )
399 {
400 res = ((LPMONITOREX)pPrintMonitor->pMonitor)->Monitor.pfnConfigurePort(pName, hWnd, pPortName);
401 }
402 else
403 {
404 SetLastError(ERROR_INVALID_PARAMETER);
405 }
406
407 return res;
408 }
409
410 BOOL WINAPI
LocalDeletePort(PWSTR pName,HWND hWnd,PWSTR pPortName)411 LocalDeletePort(PWSTR pName, HWND hWnd, PWSTR pPortName)
412 {
413 LONG lres;
414 DWORD res = FALSE;
415 PLOCAL_PORT pPrintPort;
416 PLOCAL_PRINT_MONITOR pPrintMonitor;
417
418 FIXME("LocalDeletePort(%S, %p, %S)\n", pName, hWnd, pPortName);
419
420 lres = copy_servername_from_name(pName, NULL);
421 if (lres)
422 {
423 FIXME("server %s not supported\n", debugstr_w(pName));
424 SetLastError(ERROR_INVALID_NAME);
425 return FALSE;
426 }
427
428 if (!pPortName[0])
429 {
430 SetLastError(ERROR_NOT_SUPPORTED);
431 return FALSE;
432 }
433
434 pPrintPort = FindPort(pPortName);
435 if (!pPrintPort )
436 {
437 SetLastError(ERROR_INVALID_PARAMETER);
438 return FALSE;
439 }
440
441 pPrintMonitor = pPrintPort->pPrintMonitor;
442
443 if ( pPrintMonitor->bIsLevel2 && ((PMONITOR2)pPrintMonitor->pMonitor)->pfnDeletePort )
444 {
445 res = ((PMONITOR2)pPrintMonitor->pMonitor)->pfnDeletePort(pPrintMonitor->hMonitor, pName, hWnd, pPortName);
446 }
447 else if ( !pPrintMonitor->bIsLevel2 && ((LPMONITOREX)pPrintMonitor->pMonitor)->Monitor.pfnDeletePort )
448 {
449 res = ((LPMONITOREX)pPrintMonitor->pMonitor)->Monitor.pfnDeletePort(pName, hWnd, pPortName);
450 }
451
452 RemoveEntryList(&pPrintPort->Entry);
453
454 DllFreeSplMem(pPrintPort);
455
456 return res;
457 }
458
459 BOOL WINAPI
LocalSetPort(PWSTR pName,PWSTR pPortName,DWORD dwLevel,PBYTE pPortInfo)460 LocalSetPort(PWSTR pName, PWSTR pPortName, DWORD dwLevel, PBYTE pPortInfo)
461 {
462 LONG lres;
463 DWORD res = 0;
464 PPORT_INFO_3W ppi3w = (PPORT_INFO_3W)pPortInfo;
465 PLOCAL_PORT pPrintPort;
466
467 TRACE("LocalSetPort(%S, %S, %lu, %p)\n", pName, pPortName, dwLevel, pPortInfo);
468
469 lres = copy_servername_from_name(pName, NULL);
470 if (lres)
471 {
472 FIXME("server %s not supported\n", debugstr_w(pName));
473 SetLastError(ERROR_INVALID_NAME);
474 return FALSE;
475 }
476
477 if ((dwLevel < 1) || (dwLevel > 2))
478 {
479 SetLastError(ERROR_INVALID_LEVEL);
480 return FALSE;
481 }
482
483 if ( !ppi3w )
484 {
485 SetLastError(ERROR_INVALID_PARAMETER);
486 return FALSE;
487 }
488
489 pPrintPort = FindPort(pPortName);
490 if ( !pPrintPort )
491 {
492 SetLastError(ERROR_UNKNOWN_PORT);
493 return FALSE;
494 }
495
496 FIXME("Add Status Support to Local Ports!\n");
497
498 return res;
499 }
500