FreeRDP
Loading...
Searching...
No Matches
printer_android.c
1
20#include <stdio.h>
21#include <stdlib.h>
22#include <string.h>
23#include <time.h>
24
25#include <winpr/crt.h>
26#include <winpr/assert.h>
27#include <freerdp/client/printer.h>
28#include <freerdp/channels/log.h>
29
30#define TAG CHANNELS_TAG("printer.client.android")
31
32#define PRINT_OUTPUT_DIR "/sdcard/Download/"
33#define PRINT_OUTPUT_PREFIX "rdp_print_"
34#define ANDROID_PRINTER_NAME "aFreeRDP Print"
35#define ANDROID_PRINTER_DRIVER "Microsoft Print to PDF"
36
37typedef struct
38{
39 rdpPrinterDriver driver;
40 size_t id_sequence;
41 size_t references;
42} rdpAndroidPrinterDriver;
43
44typedef struct
45{
46 rdpPrintJob printjob;
47 FILE* file;
48 char path[256];
49} rdpAndroidPrintJob;
50
51typedef struct
52{
53 rdpPrinter printer;
54 rdpAndroidPrintJob* printjob;
55} rdpAndroidPrinter;
56
57static UINT printer_android_write_printjob(rdpPrintJob* printjob, const BYTE* data, size_t size)
58{
59 rdpAndroidPrintJob* aj = (rdpAndroidPrintJob*)printjob;
60 if (aj->file)
61 {
62 if (fwrite(data, 1, size, aj->file) != size)
63 WLog_WARN(TAG, "Short write on print job file");
64 }
65 return CHANNEL_RC_OK;
66}
67
68static void printer_android_close_printjob(rdpPrintJob* printjob)
69{
70 rdpAndroidPrintJob* aj = (rdpAndroidPrintJob*)printjob;
71 rdpAndroidPrinter* ap = (rdpAndroidPrinter*)printjob->printer;
72
73 if (aj->file)
74 {
75 fclose(aj->file);
76 aj->file = nullptr;
77 WLog_INFO(TAG, "Print job complete, saved to %s", aj->path);
78 }
79
80 ap->printjob = nullptr;
81 free(aj);
82}
83
84static rdpPrintJob* printer_android_create_printjob(rdpPrinter* printer, UINT32 id)
85{
86 rdpAndroidPrinter* ap = (rdpAndroidPrinter*)printer;
87
88 WINPR_ASSERT(ap);
89
90 if (ap->printjob != nullptr)
91 {
92 WLog_WARN(TAG, "printjob [printer '%s'] already existing, abort!", printer->name);
93 return nullptr;
94 }
95
96 rdpAndroidPrintJob* aj = calloc(1, sizeof(*aj));
97 if (!aj)
98 return nullptr;
99
100 aj->printjob.id = id;
101 aj->printjob.printer = printer;
102 aj->printjob.Write = printer_android_write_printjob;
103 aj->printjob.Close = printer_android_close_printjob;
104
105 time_t t = time(NULL);
106 snprintf(aj->path, sizeof(aj->path), PRINT_OUTPUT_DIR PRINT_OUTPUT_PREFIX "%lld.pdf",
107 (long long)t);
108
109 aj->file = fopen(aj->path, "wb");
110 if (!aj->file)
111 {
112 WLog_ERR(TAG, "Failed to open dump file %s", aj->path);
113 free(aj);
114 return NULL;
115 }
116
117 ap->printjob = aj;
118 return &aj->printjob;
119}
120
121static rdpPrintJob* printer_android_find_printjob(rdpPrinter* printer, UINT32 id)
122{
123 rdpAndroidPrinter* ap = (rdpAndroidPrinter*)printer;
124
125 WINPR_ASSERT(ap);
126
127 if (ap->printjob == NULL)
128 return NULL;
129 if (ap->printjob->printjob.id != id)
130 return NULL;
131
132 return &ap->printjob->printjob;
133}
134
135static void printer_android_free_printer(rdpPrinter* printer)
136{
137 rdpAndroidPrinter* ap = (rdpAndroidPrinter*)printer;
138
139 WINPR_ASSERT(ap);
140
141 if (ap->printjob)
142 {
143 WINPR_ASSERT(ap->printjob->printjob.Close);
144 ap->printjob->printjob.Close(&ap->printjob->printjob);
145 }
146
147 if (printer->backend)
148 {
149 WINPR_ASSERT(printer->backend->ReleaseRef);
150 printer->backend->ReleaseRef(printer->backend);
151 }
152
153 free(printer->name);
154 free(printer->driver);
155 free(printer);
156}
157
158static void printer_android_add_ref_printer(rdpPrinter* printer)
159{
160 if (printer)
161 printer->references++;
162}
163
164static void printer_android_release_ref_printer(rdpPrinter* printer)
165{
166 if (!printer)
167 return;
168 if (printer->references <= 1)
169 printer_android_free_printer(printer);
170 else
171 printer->references--;
172}
173
174static rdpPrinter* printer_android_new_printer(rdpAndroidPrinterDriver* drv, const char* name,
175 const char* driverName, BOOL isDefault)
176{
177 rdpAndroidPrinter* ap = calloc(1, sizeof(*ap));
178 if (!ap)
179 return NULL;
180
181 ap->printer.backend = &drv->driver;
182 ap->printer.id = drv->id_sequence++;
183 ap->printer.name = _strdup(name ? name : ANDROID_PRINTER_NAME);
184 if (!ap->printer.name)
185 goto fail;
186
187 ap->printer.driver = _strdup(driverName ? driverName : ANDROID_PRINTER_DRIVER);
188 if (!ap->printer.driver)
189 goto fail;
190
191 ap->printer.is_default = isDefault;
192 ap->printer.CreatePrintJob = printer_android_create_printjob;
193 ap->printer.FindPrintJob = printer_android_find_printjob;
194 ap->printer.AddRef = printer_android_add_ref_printer;
195 ap->printer.ReleaseRef = printer_android_release_ref_printer;
196
197 WINPR_ASSERT(ap->printer.AddRef);
198 ap->printer.AddRef(&ap->printer);
199
200 WINPR_ASSERT(ap->printer.backend->AddRef);
201 ap->printer.backend->AddRef(ap->printer.backend);
202
203 return &ap->printer;
204
205fail:
206 printer_android_free_printer(&ap->printer);
207 return NULL;
208}
209
210static rdpPrinter** printer_android_enum_printers(rdpPrinterDriver* driver)
211{
212 rdpAndroidPrinterDriver* ad = (rdpAndroidPrinterDriver*)driver;
213 rdpPrinter** list = calloc(2, sizeof(rdpPrinter*));
214 if (!list)
215 return NULL;
216
217 list[0] = printer_android_new_printer(ad, ANDROID_PRINTER_NAME, ANDROID_PRINTER_DRIVER, TRUE);
218 list[1] = NULL;
219 return list;
220}
221
222static void printer_android_release_enum_printers(rdpPrinter** printers)
223{
224 if (!printers)
225 return;
226 for (rdpPrinter** p = printers; *p; p++)
227 {
228 if ((*p)->ReleaseRef)
229 (*p)->ReleaseRef(*p);
230 }
231 free(printers);
232}
233
234static rdpPrinter* printer_android_get_printer(rdpPrinterDriver* driver, const char* name,
235 const char* driverName, BOOL isDefault)
236{
237 return printer_android_new_printer((rdpAndroidPrinterDriver*)driver, name, driverName,
238 isDefault);
239}
240
241static void printer_android_add_ref_driver(rdpPrinterDriver* driver)
242{
243 rdpAndroidPrinterDriver* ad = (rdpAndroidPrinterDriver*)driver;
244 if (ad)
245 ad->references++;
246}
247
248static void printer_android_release_ref_driver(rdpPrinterDriver* driver)
249{
250 rdpAndroidPrinterDriver* ad = (rdpAndroidPrinterDriver*)driver;
251
252 WINPR_ASSERT(ad);
253 if (ad->references <= 1)
254 free(ad);
255 else
256 ad->references--;
257}
258
259FREERDP_ENTRY_POINT(UINT VCAPITYPE android_freerdp_printer_client_subsystem_entry(void* arg))
260{
261 rdpPrinterDriver** ppDriver = (rdpPrinterDriver**)arg;
262
263 if (!ppDriver)
264 return ERROR_INVALID_PARAMETER;
265
266 rdpAndroidPrinterDriver* drv = calloc(1, sizeof(*drv));
267 if (!drv)
268 return ERROR_OUTOFMEMORY;
269
270 drv->driver.EnumPrinters = printer_android_enum_printers;
271 drv->driver.ReleaseEnumPrinters = printer_android_release_enum_printers;
272 drv->driver.GetPrinter = printer_android_get_printer;
273 drv->driver.AddRef = printer_android_add_ref_driver;
274 drv->driver.ReleaseRef = printer_android_release_ref_driver;
275 drv->id_sequence = 1;
276
277 WINPR_ASSERT(drv->driver.AddRef);
278 drv->driver.AddRef(&drv->driver);
279
280 *ppDriver = &drv->driver;
281 return CHANNEL_RC_OK;
282}