2 * FreeRDP: A Remote Desktop Protocol client.
3 * Print Virtual Channel - CUPS driver
5 * Copyright 2010-2011 Vic Lee
7 * Licensed under the Apache License, Version 2.0 (the "License");
8 * you may not use this file except in compliance with the License.
9 * You may obtain a copy of the License at
11 * http://www.apache.org/licenses/LICENSE-2.0
13 * Unless required by applicable law or agreed to in writing, software
14 * distributed under the License is distributed on an "AS IS" BASIS,
15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 * See the License for the specific language governing permissions and
17 * limitations under the License.
25 #include <cups/cups.h>
26 #include <freerdp/utils/memory.h>
27 #include <freerdp/utils/svc_plugin.h>
29 #include "rdpdr_constants.h"
30 #include "rdpdr_types.h"
31 #include "printer_main.h"
33 #include "printer_cups.h"
35 typedef struct rdp_cups_printer_driver rdpCupsPrinterDriver;
36 typedef struct rdp_cups_printer rdpCupsPrinter;
37 typedef struct rdp_cups_print_job rdpCupsPrintJob;
39 struct rdp_cups_printer_driver
41 rdpPrinterDriver driver;
46 struct rdp_cups_printer
50 rdpCupsPrintJob* printjob;
53 struct rdp_cups_print_job
57 void* printjob_object;
61 static void printer_cups_get_printjob_name(char* buf, int size)
68 snprintf(buf, size - 1, "FreeRDP Print Job %d%02d%02d%02d%02d%02d",
69 t->tm_year + 1900, t->tm_mon + 1, t->tm_mday,
70 t->tm_hour, t->tm_min, t->tm_sec);
73 static void printer_cups_write_printjob(rdpPrintJob* printjob, uint8* data, int size)
75 rdpCupsPrintJob* cups_printjob = (rdpCupsPrintJob*)printjob;
82 fp = fopen((const char*)cups_printjob->printjob_object, "a+b");
85 DEBUG_WARN("failed to open file %s", (char*)cups_printjob->printjob_object);
88 if (fwrite(data, 1, size, fp) < size)
90 DEBUG_WARN("failed to write file %s", (char*)cups_printjob->printjob_object);
97 cupsWriteRequestData((http_t*)cups_printjob->printjob_object, (const char*)data, size);
102 static void printer_cups_close_printjob(rdpPrintJob* printjob)
104 rdpCupsPrintJob* cups_printjob = (rdpCupsPrintJob*)printjob;
106 #ifndef _CUPS_API_1_4
111 printer_cups_get_printjob_name(buf, sizeof(buf));
112 if (cupsPrintFile(printjob->printer->name, (const char *)cups_printjob->printjob_object, buf, 0, NULL) == 0)
114 DEBUG_WARN("cupsPrintFile: %s", cupsLastErrorString());
116 unlink(cups_printjob->printjob_object);
117 xfree(cups_printjob->printjob_object);
122 cupsFinishDocument((http_t*)cups_printjob->printjob_object, printjob->printer->name);
123 cups_printjob->printjob_id = 0;
124 httpClose((http_t*)cups_printjob->printjob_object);
128 xfree(cups_printjob);
130 ((rdpCupsPrinter*)printjob->printer)->printjob = NULL;
133 static rdpPrintJob* printer_cups_create_printjob(rdpPrinter* printer, uint32 id)
135 rdpCupsPrinter* cups_printer = (rdpCupsPrinter*)printer;
136 rdpCupsPrintJob* cups_printjob;
138 if (cups_printer->printjob != NULL)
141 cups_printjob = xnew(rdpCupsPrintJob);
143 cups_printjob->printjob.id = id;
144 cups_printjob->printjob.printer = printer;
146 cups_printjob->printjob.Write = printer_cups_write_printjob;
147 cups_printjob->printjob.Close = printer_cups_close_printjob;
149 #ifndef _CUPS_API_1_4
151 cups_printjob->printjob_object = xstrdup(tmpnam(NULL));
157 cups_printjob->printjob_object = httpConnectEncrypt(cupsServer(), ippPort(), HTTP_ENCRYPT_IF_REQUESTED);
158 if (cups_printjob->printjob_object == NULL)
160 DEBUG_WARN("httpConnectEncrypt: %s", cupsLastErrorString());
161 xfree(cups_printjob);
165 printer_cups_get_printjob_name(buf, sizeof(buf));
166 cups_printjob->printjob_id = cupsCreateJob((http_t*)cups_printjob->printjob_object,
167 printer->name, buf, 0, NULL);
169 if (cups_printjob->printjob_id == 0)
171 DEBUG_WARN("cupsCreateJob: %s", cupsLastErrorString());
172 httpClose((http_t*)cups_printjob->printjob_object);
173 xfree(cups_printjob);
176 cupsStartDocument((http_t*)cups_printjob->printjob_object,
177 printer->name, cups_printjob->printjob_id, buf,
178 CUPS_FORMAT_AUTO, 1);
183 cups_printer->printjob = cups_printjob;
185 return (rdpPrintJob*)cups_printjob;
188 static rdpPrintJob* printer_cups_find_printjob(rdpPrinter* printer, uint32 id)
190 rdpCupsPrinter* cups_printer = (rdpCupsPrinter*)printer;
192 if (cups_printer->printjob == NULL)
194 if (cups_printer->printjob->printjob.id != id)
197 return (rdpPrintJob*)cups_printer->printjob;
200 static void printer_cups_free_printer(rdpPrinter* printer)
202 rdpCupsPrinter* cups_printer = (rdpCupsPrinter*)printer;
204 if (cups_printer->printjob)
205 cups_printer->printjob->printjob.Close((rdpPrintJob*)cups_printer->printjob);
206 xfree(printer->name);
210 static rdpPrinter* printer_cups_new_printer(rdpCupsPrinterDriver* cups_driver, const char* name, boolean is_default)
212 rdpCupsPrinter* cups_printer;
214 cups_printer = xnew(rdpCupsPrinter);
216 cups_printer->printer.id = cups_driver->id_sequence++;
217 cups_printer->printer.name = xstrdup(name);
218 /* This is a generic PostScript printer driver developed by MS, so it should be good in most cases */
219 cups_printer->printer.driver = "MS Publisher Imagesetter";
220 cups_printer->printer.is_default = is_default;
222 cups_printer->printer.CreatePrintJob = printer_cups_create_printjob;
223 cups_printer->printer.FindPrintJob = printer_cups_find_printjob;
224 cups_printer->printer.Free = printer_cups_free_printer;
226 return (rdpPrinter*)cups_printer;
229 static rdpPrinter** printer_cups_enum_printers(rdpPrinterDriver* driver)
231 rdpPrinter** printers;
238 num_dests = cupsGetDests(&dests);
239 printers = (rdpPrinter**)xzalloc(sizeof(rdpPrinter*) * (num_dests + 1));
241 for (i = 0, dest = dests; i < num_dests; i++, dest++)
243 if (dest->instance == NULL)
245 printers[num_printers++] = printer_cups_new_printer((rdpCupsPrinterDriver*)driver,
246 dest->name, dest->is_default);
249 cupsFreeDests(num_dests, dests);
254 static rdpPrinter* printer_cups_get_printer(rdpPrinterDriver* driver, const char* name)
256 rdpCupsPrinterDriver* cups_driver = (rdpCupsPrinterDriver*)driver;
258 return printer_cups_new_printer(cups_driver, name, cups_driver->id_sequence == 1 ? true : false);
261 static rdpCupsPrinterDriver* cups_driver = NULL;
263 rdpPrinterDriver* printer_cups_get_driver(void)
265 if (cups_driver == NULL)
267 cups_driver = xnew(rdpCupsPrinterDriver);
269 cups_driver->driver.EnumPrinters = printer_cups_enum_printers;
270 cups_driver->driver.GetPrinter = printer_cups_get_printer;
272 cups_driver->id_sequence = 1;
275 DEBUG_SVC("using CUPS API 1.4");
277 DEBUG_SVC("using CUPS API 1.2");
281 return (rdpPrinterDriver*)cups_driver;