1 /*
2  * PROJECT:     ReactOS Spooler Router
3  * LICENSE:     GPL-2.0+ (https://spdx.org/licenses/GPL-2.0+)
4  * PURPOSE:     Functions related to Print Monitors
5  * COPYRIGHT:   Copyright 2015-2017 Colin Finck (colin@reactos.org)
6  */
7 
8 #include "precomp.h"
9 
10 BOOL WINAPI
11 AddMonitorW(PWSTR pName, DWORD Level, PBYTE pMonitors)
12 {
13     BOOL bReturnValue = TRUE;
14     DWORD dwErrorCode = MAXDWORD;
15     PSPOOLSS_PRINT_PROVIDER pPrintProvider;
16     PLIST_ENTRY pEntry;
17 
18     // Loop through all Print Provider.
19     for (pEntry = PrintProviderList.Flink; pEntry != &PrintProviderList; pEntry = pEntry->Flink)
20     {
21         pPrintProvider = CONTAINING_RECORD(pEntry, SPOOLSS_PRINT_PROVIDER, Entry);
22 
23         // Check if this Print Provider provides the function.
24         if (!pPrintProvider->PrintProvider.fpAddMonitor)
25             continue;
26 
27         bReturnValue = pPrintProvider->PrintProvider.fpAddMonitor(pName, Level, pMonitors);
28 
29         if ( !bReturnValue )
30         {
31             dwErrorCode = GetLastError();
32         }
33 
34         // dwErrorCode shall not be overwritten if a previous call already succeeded.
35         if (dwErrorCode != ERROR_SUCCESS)
36             dwErrorCode = GetLastError();
37     }
38 
39     SetLastError(dwErrorCode);
40     return (dwErrorCode == ERROR_SUCCESS);
41 }
42 
43 BOOL WINAPI
44 DeleteMonitorW(PWSTR pName, PWSTR pEnvironment, PWSTR pMonitorName)
45 {
46     BOOL bReturnValue = TRUE;
47     DWORD dwErrorCode = MAXDWORD;
48     PSPOOLSS_PRINT_PROVIDER pPrintProvider;
49     PLIST_ENTRY pEntry;
50 
51     // Loop through all Print Provider.
52     for (pEntry = PrintProviderList.Flink; pEntry != &PrintProviderList; pEntry = pEntry->Flink)
53     {
54         pPrintProvider = CONTAINING_RECORD(pEntry, SPOOLSS_PRINT_PROVIDER, Entry);
55 
56         // Check if this Print Provider provides the function.
57         if (!pPrintProvider->PrintProvider.fpDeleteMonitor)
58             continue;
59 
60         bReturnValue = pPrintProvider->PrintProvider.fpDeleteMonitor(pName, pEnvironment, pMonitorName);
61 
62         if ( !bReturnValue )
63         {
64             dwErrorCode = GetLastError();
65         }
66 
67         // dwErrorCode shall not be overwritten if a previous call already succeeded.
68         if (dwErrorCode != ERROR_SUCCESS)
69             dwErrorCode = GetLastError();
70     }
71 
72     SetLastError(dwErrorCode);
73     return (dwErrorCode == ERROR_SUCCESS);
74 }
75 
76 BOOL WINAPI
77 EnumMonitorsW(PWSTR pName, DWORD Level, PBYTE pMonitors, DWORD cbBuf, PDWORD pcbNeeded, PDWORD pcReturned)
78 {
79     BOOL bReturnValue = TRUE;
80     DWORD cbCallBuffer;
81     DWORD cbNeeded;
82     DWORD dwReturned;
83     DWORD dwErrorCode = MAXDWORD;
84     PBYTE pCallBuffer;
85     PSPOOLSS_PRINT_PROVIDER pPrintProvider;
86     PLIST_ENTRY pEntry;
87 
88     // Sanity checks.
89     if (cbBuf && !pMonitors)
90     {
91         SetLastError(ERROR_INVALID_USER_BUFFER);
92         return FALSE;
93     }
94 
95     // Begin counting.
96     *pcbNeeded = 0;
97     *pcReturned = 0;
98 
99     // At the beginning, we have the full buffer available.
100     cbCallBuffer = cbBuf;
101     pCallBuffer = pMonitors;
102 
103     // Loop through all Print Provider.
104     for (pEntry = PrintProviderList.Flink; pEntry != &PrintProviderList; pEntry = pEntry->Flink)
105     {
106         pPrintProvider = CONTAINING_RECORD(pEntry, SPOOLSS_PRINT_PROVIDER, Entry);
107 
108         // Check if this Print Provider provides an EnumMonitors function.
109         if (!pPrintProvider->PrintProvider.fpEnumMonitors)
110             continue;
111 
112         // Call the EnumMonitors function of this Print Provider.
113         cbNeeded = 0;
114         dwReturned = 0;
115         bReturnValue = pPrintProvider->PrintProvider.fpEnumMonitors(pName, Level, pCallBuffer, cbCallBuffer, &cbNeeded, &dwReturned);
116 
117         if ( !bReturnValue )
118         {
119             dwErrorCode = GetLastError();
120         }
121 
122         // Add the returned counts to the total values.
123         *pcbNeeded += cbNeeded;
124         *pcReturned += dwReturned;
125 
126         // Reduce the available buffer size for the next call without risking an underflow.
127         if (cbNeeded < cbCallBuffer)
128             cbCallBuffer -= cbNeeded;
129         else
130             cbCallBuffer = 0;
131 
132         // Advance the buffer if the caller provided it.
133         if (pCallBuffer)
134             pCallBuffer += cbNeeded;
135 
136         // dwErrorCode shall not be overwritten if a previous EnumPrinters call already succeeded.
137         if (dwErrorCode != ERROR_SUCCESS)
138             dwErrorCode = GetLastError();
139     }
140 
141     SetLastError(dwErrorCode);
142     return (dwErrorCode == ERROR_SUCCESS);
143 }
144