diff --git a/CMakeLists.txt b/CMakeLists.txt index deedd2ab9..e52db4d8a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -81,6 +81,7 @@ if(NOT WIN32) find_package(ZLIB REQUIRED) find_package(ALSA) find_package(PulseAudio) + find_package(Cups) endif() # Endian diff --git a/channels/rdpdr/CMakeLists.txt b/channels/rdpdr/CMakeLists.txt index 059f4a442..be54ca647 100644 --- a/channels/rdpdr/CMakeLists.txt +++ b/channels/rdpdr/CMakeLists.txt @@ -38,3 +38,5 @@ target_link_libraries(rdpdr freerdp-utils) install(TARGETS rdpdr DESTINATION ${FREERDP_PLUGIN_PATH}) add_subdirectory(disk) +add_subdirectory(printer) + diff --git a/channels/rdpdr/printer/CMakeLists.txt b/channels/rdpdr/printer/CMakeLists.txt new file mode 100644 index 000000000..fc7784f1e --- /dev/null +++ b/channels/rdpdr/printer/CMakeLists.txt @@ -0,0 +1,45 @@ +# FreeRDP: A Remote Desktop Protocol Client +# FreeRDP cmake build script +# +# Copyright 2011 O.S. Systems Software Ltda. +# Copyright 2011 Otavio Salvador +# Copyright 2011 Marc-Andre Moreau +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +set(PRINTER_SRCS + printer_main.c + printer_main.h +) + +if(CUPS_FOUND) + set(PRINTER_SRCS + ${PRINTER_SRCS} + printer_cups.c + printer_cups.h + ) + include_directories(${CUPS_INCLUDE_DIR}) +endif() + +include_directories(..) + +add_library(printer SHARED ${PRINTER_SRCS}) +set_target_properties(printer PROPERTIES PREFIX "") + +target_link_libraries(printer freerdp-utils) + +if(CUPS_FOUND) + target_link_libraries(printer ${CUPS_LIBRARIES}) +endif() + +install(TARGETS printer DESTINATION ${FREERDP_PLUGIN_PATH}) diff --git a/channels/rdpdr/printer/printer_cups.c b/channels/rdpdr/printer/printer_cups.c new file mode 100644 index 000000000..dc8861d71 --- /dev/null +++ b/channels/rdpdr/printer/printer_cups.c @@ -0,0 +1,284 @@ +/** + * FreeRDP: A Remote Desktop Protocol client. + * Print Virtual Channel - CUPS driver + * + * Copyright 2010-2011 Vic Lee + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "rdpdr_constants.h" +#include "rdpdr_types.h" +#include "printer_main.h" + +#include "printer_cups.h" + +typedef struct rdp_cups_printer_driver rdpCupsPrinterDriver; +typedef struct rdp_cups_printer rdpCupsPrinter; +typedef struct rdp_cups_print_job rdpCupsPrintJob; + +struct rdp_cups_printer_driver +{ + rdpPrinterDriver driver; + + int id_sequence; +}; + +struct rdp_cups_printer +{ + rdpPrinter printer; + + rdpCupsPrintJob* printjob; +}; + +struct rdp_cups_print_job +{ + rdpPrintJob printjob; + + void* printjob_object; + int printjob_id; +}; + +static void printer_cups_get_printjob_name(char* buf, int size) +{ + time_t tt; + struct tm* t; + + tt = time(NULL); + t = localtime(&tt); + snprintf(buf, size - 1, "FreeRDP Print Job %d%02d%02d%02d%02d%02d", + t->tm_year + 1900, t->tm_mon + 1, t->tm_mday, + t->tm_hour, t->tm_min, t->tm_sec); +} + +static void printer_cups_write_printjob(rdpPrintJob* printjob, uint8* data, int size) +{ + rdpCupsPrintJob* cups_printjob = (rdpCupsPrintJob*)printjob; + +#ifndef _CUPS_API_1_4 + + { + FILE* fp; + + fp = fopen((const char*)cups_printjob->printjob_object, "a+b"); + if (fp == NULL) + { + DEBUG_WARN("failed to open file %s", (char*)cups_printjob->printjob_object); + return; + } + if (fwrite(data, 1, size, fp) < size) + { + DEBUG_WARN("failed to write file %s", (char*)cups_printjob->printjob_object); + } + fclose(fp); + } + +#else + + cupsWriteRequestData((http_t*)cups_printjob->printjob_object, (const char*)data, size); + +#endif +} + +static void printer_cups_close_printjob(rdpPrintJob* printjob) +{ + rdpCupsPrintJob* cups_printjob = (rdpCupsPrintJob*)printjob; + +#ifndef _CUPS_API_1_4 + + { + char buf[100]; + + printer_cups_get_printjob_name(buf, sizeof(buf)); + if (cupsPrintFile(printjob->printer->name, (const char *)cups_printjob->printjob_object, buf, 0, NULL) == 0) + { + DEBUG_WARN("cupsPrintFile: %s", cupsLastErrorString()); + } + unlink(cups_printjob->printjob_object); + xfree(cups_printjob->printjob_object); + } + +#else + + cupsFinishDocument((http_t*)cups_printjob->printjob_object, printjob->printer->name); + cups_printjob->printjob_id = 0; + httpClose((http_t*)cups_printjob->printjob_object); + +#endif + + xfree(cups_printjob); + + ((rdpCupsPrinter*)printjob->printer)->printjob = NULL; +} + +static rdpPrintJob* printer_cups_create_printjob(rdpPrinter* printer, uint32 id) +{ + rdpCupsPrinter* cups_printer = (rdpCupsPrinter*)printer; + rdpCupsPrintJob* cups_printjob; + + if (cups_printer->printjob != NULL) + return NULL; + + cups_printjob = xnew(rdpCupsPrintJob); + + cups_printjob->printjob.id = id; + cups_printjob->printjob.printer = printer; + + cups_printjob->printjob.Write = printer_cups_write_printjob; + cups_printjob->printjob.Close = printer_cups_close_printjob; + +#ifndef _CUPS_API_1_4 + + cups_printjob->printjob_object = xstrdup(tmpnam(NULL)); + +#else + { + char buf[100]; + + cups_printjob->printjob_object = httpConnectEncrypt(cupsServer(), ippPort(), HTTP_ENCRYPT_IF_REQUESTED); + if (cups_printjob->printjob_object == NULL) + { + DEBUG_WARN("httpConnectEncrypt: %s", cupsLastErrorString()); + xfree(cups_printjob); + return NULL; + } + + printer_cups_get_printjob_name(buf, sizeof(buf)); + cups_printjob->printjob_id = cupsCreateJob((http_t*)cups_printjob->printjob_object, + printer->name, buf, 0, NULL); + + if (cups_printjob->printjob_id == 0) + { + DEBUG_WARN("cupsCreateJob: %s", cupsLastErrorString()); + httpClose((http_t*)cups_printjob->printjob_object); + xfree(cups_printjob); + return NULL; + } + cupsStartDocument((http_t*)cups_printjob->printjob_object, + printer->name, cups_printjob->printjob_id, buf, + CUPS_FORMAT_POSTSCRIPT, 1); + } + +#endif + + cups_printer->printjob = cups_printjob; + + return (rdpPrintJob*)cups_printjob; +} + +static rdpPrintJob* printer_cups_find_printjob(rdpPrinter* printer, uint32 id) +{ + rdpCupsPrinter* cups_printer = (rdpCupsPrinter*)printer; + + if (cups_printer->printjob == NULL) + return NULL; + if (cups_printer->printjob->printjob.id != id) + return NULL; + + return (rdpPrintJob*)cups_printer->printjob; +} + +static void printer_cups_free_printer(rdpPrinter* printer) +{ + rdpCupsPrinter* cups_printer = (rdpCupsPrinter*)printer; + + if (cups_printer->printjob) + cups_printer->printjob->printjob.Close((rdpPrintJob*)cups_printer->printjob); + xfree(printer->name); + xfree(printer); +} + +static rdpPrinter* printer_cups_new_printer(rdpCupsPrinterDriver* cups_driver, const char* name, boolean is_default) +{ + rdpCupsPrinter* cups_printer; + + cups_printer = xnew(rdpCupsPrinter); +printf("*** created printer %s %X of size %d\n", name, cups_printer, sizeof(rdpCupsPrinter)); + + cups_printer->printer.id = cups_driver->id_sequence++; + cups_printer->printer.name = xstrdup(name); + /* This is a generic PostScript printer driver developed by MS, so it should be good in most cases */ + cups_printer->printer.driver = "MS Publisher Imagesetter"; + cups_printer->printer.is_default = is_default; + + cups_printer->printer.CreatePrintJob = printer_cups_create_printjob; + cups_printer->printer.FindPrintJob = printer_cups_find_printjob; + cups_printer->printer.Free = printer_cups_free_printer; + + return (rdpPrinter*)cups_printer; +} + +static rdpPrinter** printer_cups_enum_printers(rdpPrinterDriver* driver) +{ + rdpPrinter** printers; + int num_printers; + cups_dest_t *dests; + cups_dest_t *dest; + int num_dests; + int i; + + num_dests = cupsGetDests(&dests); + printers = (rdpPrinter**)xzalloc(sizeof(rdpPrinter*) * (num_dests + 1)); + num_printers = 0; + for (i = 0, dest = dests; i < num_dests; i++, dest++) + { + if (dest->instance == NULL) + { + printers[num_printers++] = printer_cups_new_printer((rdpCupsPrinterDriver*)driver, + dest->name, dest->is_default); + } + } + cupsFreeDests(num_dests, dests); + + return printers; +} + +static rdpPrinter* printer_cups_get_printer(rdpPrinterDriver* driver, const char* name) +{ + rdpCupsPrinterDriver* cups_driver = (rdpCupsPrinterDriver*)driver; + + return printer_cups_new_printer(cups_driver, name, cups_driver->id_sequence == 1 ? True : False); +} + +static rdpCupsPrinterDriver* cups_driver = NULL; + +rdpPrinterDriver* printer_cups_get_driver(void) +{ + if (cups_driver == NULL) + { + cups_driver = xnew(rdpCupsPrinterDriver); + + cups_driver->driver.EnumPrinters = printer_cups_enum_printers; + cups_driver->driver.GetPrinter = printer_cups_get_printer; + + cups_driver->id_sequence = 1; + +#ifdef _CUPS_API_1_4 + DEBUG_SVC("using CUPS API 1.4"); +#else + DEBUG_SVC("using CUPS API 1.2"); +#endif + } + + return (rdpPrinterDriver*)cups_driver; +} + diff --git a/channels/rdpdr/printer/printer_cups.h b/channels/rdpdr/printer/printer_cups.h new file mode 100644 index 000000000..c6e1ff51a --- /dev/null +++ b/channels/rdpdr/printer/printer_cups.h @@ -0,0 +1,28 @@ +/** + * FreeRDP: A Remote Desktop Protocol client. + * Print Virtual Channel - CUPS driver + * + * Copyright 2010-2011 Vic Lee + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __PRINTER_CUPS_H +#define __PRINTER_CUPS_H + +#include "printer_main.h" + +rdpPrinterDriver* printer_cups_get_driver(void); + +#endif + diff --git a/channels/rdpdr/printer/printer_main.c b/channels/rdpdr/printer/printer_main.c new file mode 100644 index 000000000..b35e8c6fb --- /dev/null +++ b/channels/rdpdr/printer/printer_main.c @@ -0,0 +1,339 @@ +/** + * FreeRDP: A Remote Desktop Protocol client. + * Print Virtual Channel + * + * Copyright 2010-2011 Vic Lee + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "config.h" +#include +#include +#include +#include +#include +#include +#include +#include + +#include "rdpdr_constants.h" +#include "rdpdr_types.h" + +#ifdef CUPS_FOUND +#include "printer_cups.h" +#endif + +#include "printer_main.h" + +typedef struct _PRINTER_DEVICE PRINTER_DEVICE; +struct _PRINTER_DEVICE +{ + DEVICE device; + + rdpPrinter* printer; + + LIST* irp_list; + freerdp_thread* thread; +}; + +static void printer_process_irp_create(PRINTER_DEVICE* printer_dev, IRP* irp) +{ + rdpPrintJob* printjob = NULL; + + if (printer_dev->printer != NULL) + printjob = printer_dev->printer->CreatePrintJob(printer_dev->printer, irp->devman->id_sequence++); + + if (printjob != NULL) + { + stream_write_uint32(irp->output, printjob->id); /* FileId */ + + DEBUG_SVC("printjob id: %d", printjob->id); + } + else + { + stream_write_uint32(irp->output, 0); /* FileId */ + irp->IoStatus = STATUS_PRINT_QUEUE_FULL; + + DEBUG_WARN("error creating print job."); + } + + irp->Complete(irp); +} + +static void printer_process_irp_close(PRINTER_DEVICE* printer_dev, IRP* irp) +{ + rdpPrintJob* printjob = NULL; + + if (printer_dev->printer != NULL) + printjob = printer_dev->printer->FindPrintJob(printer_dev->printer, irp->FileId); + + if (printjob == NULL) + { + irp->IoStatus = STATUS_UNSUCCESSFUL; + + DEBUG_WARN("printjob id %d not found.", irp->FileId); + } + else + { + printjob->Close(printjob); + + DEBUG_SVC("printjob id %d closed.", irp->FileId); + } + + stream_write_zero(irp->output, 4); /* Padding(4) */ + + irp->Complete(irp); +} + +static void printer_process_irp_write(PRINTER_DEVICE* printer_dev, IRP* irp) +{ + rdpPrintJob* printjob = NULL; + uint32 Length; + uint64 Offset; + + stream_read_uint32(irp->input, Length); + stream_read_uint64(irp->input, Offset); + stream_seek(irp->input, 20); /* Padding */ + + if (printer_dev->printer != NULL) + printjob = printer_dev->printer->FindPrintJob(printer_dev->printer, irp->FileId); + + if (printjob == NULL) + { + irp->IoStatus = STATUS_UNSUCCESSFUL; + Length = 0; + + DEBUG_WARN("printjob id %d not found.", irp->FileId); + } + else + { + printjob->Write(printjob, stream_get_tail(irp->input), Length); + + DEBUG_SVC("printjob id %d written %d bytes.", irp->FileId, Length); + } + + stream_write_uint32(irp->output, Length); + stream_write_uint8(irp->output, 0); /* Padding */ + + irp->Complete(irp); +} + +static void printer_process_irp(PRINTER_DEVICE* printer_dev, IRP* irp) +{ + switch (irp->MajorFunction) + { + case IRP_MJ_CREATE: + printer_process_irp_create(printer_dev, irp); + break; + + case IRP_MJ_CLOSE: + printer_process_irp_close(printer_dev, irp); + break; + + case IRP_MJ_WRITE: + printer_process_irp_write(printer_dev, irp); + break; + + default: + DEBUG_WARN("MajorFunction 0x%X not supported", irp->MajorFunction); + irp->IoStatus = STATUS_NOT_SUPPORTED; + irp->Complete(irp); + break; + } +} + +static void printer_process_irp_list(PRINTER_DEVICE* printer_dev) +{ + IRP* irp; + + while (1) + { + if (freerdp_thread_is_stopped(printer_dev->thread)) + break; + + freerdp_thread_lock(printer_dev->thread); + irp = (IRP*)list_dequeue(printer_dev->irp_list); + freerdp_thread_unlock(printer_dev->thread); + + if (irp == NULL) + break; + + printer_process_irp(printer_dev, irp); + } +} + +static void* printer_thread_func(void* arg) +{ + PRINTER_DEVICE* printer_dev = (PRINTER_DEVICE*)arg; + + while (1) + { + freerdp_thread_wait(printer_dev->thread); + + if (freerdp_thread_is_stopped(printer_dev->thread)) + break; + + freerdp_thread_reset(printer_dev->thread); + printer_process_irp_list(printer_dev); + } + + freerdp_thread_quit(printer_dev->thread); + + return NULL; +} + +static void printer_irp_request(DEVICE* device, IRP* irp) +{ + PRINTER_DEVICE* printer_dev = (PRINTER_DEVICE*)device; + + freerdp_thread_lock(printer_dev->thread); + list_enqueue(printer_dev->irp_list, irp); + freerdp_thread_unlock(printer_dev->thread); + + freerdp_thread_signal(printer_dev->thread); +} + +static void printer_free(DEVICE* device) +{ + PRINTER_DEVICE* printer_dev = (PRINTER_DEVICE*)device; + IRP* irp; + + freerdp_thread_stop(printer_dev->thread); + + while ((irp = (IRP*)list_dequeue(printer_dev->irp_list)) != NULL) + irp->Discard(irp); + list_free(printer_dev->irp_list); + + if (printer_dev->printer) + printer_dev->printer->Free(printer_dev->printer); + + xfree(printer_dev->device.name); + + xfree(printer_dev); +} + +void printer_register(PDEVICE_SERVICE_ENTRY_POINTS pEntryPoints, rdpPrinter* printer) +{ + PRINTER_DEVICE* printer_dev; + char* port; + UNICONV* uniconv; + uint32 Flags; + size_t DriverNameLen; + char* DriverName; + size_t PrintNameLen; + char* PrintName; + uint32 CachedFieldsLen; + uint8* CachedPrinterConfigData; + + port = xmalloc(10); + snprintf(port, 10, "PRN%d", printer->id); + + printer_dev = xnew(PRINTER_DEVICE); + + printer_dev->device.type = RDPDR_DTYP_PRINT; + printer_dev->device.name = port; + printer_dev->device.IRPRequest = printer_irp_request; + printer_dev->device.Free = printer_free; + + printer_dev->printer = printer; + + CachedFieldsLen = 0; + CachedPrinterConfigData = NULL; + +printf("**** printer %s %X register\n", printer->name, printer); + + Flags = 0; + if (printer->is_default) + Flags |= RDPDR_PRINTER_ANNOUNCE_FLAG_DEFAULTPRINTER; + + uniconv = freerdp_uniconv_new(); + DriverName = freerdp_uniconv_out(uniconv, printer->driver, &DriverNameLen); + PrintName = freerdp_uniconv_out(uniconv, printer->name, &PrintNameLen); + freerdp_uniconv_free(uniconv); + + printer_dev->device.data = stream_new(28 + DriverNameLen + PrintNameLen + CachedFieldsLen); + + stream_write_uint32(printer_dev->device.data, Flags); + stream_write_uint32(printer_dev->device.data, 0); /* CodePage, reserved */ + stream_write_uint32(printer_dev->device.data, 0); /* PnPNameLen */ + stream_write_uint32(printer_dev->device.data, DriverNameLen + 2); + stream_write_uint32(printer_dev->device.data, PrintNameLen + 2); + stream_write_uint32(printer_dev->device.data, CachedFieldsLen); + stream_write(printer_dev->device.data, DriverName, DriverNameLen); + stream_write_uint16(printer_dev->device.data, 0); + stream_write(printer_dev->device.data, PrintName, PrintNameLen); + stream_write_uint16(printer_dev->device.data, 0); + if (CachedFieldsLen > 0) + { + stream_write(printer_dev->device.data, CachedPrinterConfigData, CachedFieldsLen); + } + + xfree(DriverName); + xfree(PrintName); + + printer_dev->irp_list = list_new(); + printer_dev->thread = freerdp_thread_new(); + + pEntryPoints->RegisterDevice(pEntryPoints->devman, (DEVICE*)printer_dev); + + freerdp_thread_start(printer_dev->thread, printer_thread_func, printer_dev); +} + +int DeviceServiceEntry(PDEVICE_SERVICE_ENTRY_POINTS pEntryPoints) +{ + rdpPrinterDriver* driver = NULL; + rdpPrinter** printers; + rdpPrinter* printer; + int i; + char* name; + char* driver_name; + +#ifdef CUPS_FOUND + driver = printer_cups_get_driver(); +#endif + if (driver == NULL) + { + DEBUG_WARN("no driver."); + return 1; + } + + name = (char*)pEntryPoints->plugin_data->data[1]; + driver_name = (char*)pEntryPoints->plugin_data->data[2]; + + if (name && name[0]) + { + printer = driver->GetPrinter(driver, name); + if (printer == NULL) + { + DEBUG_WARN("printer %s not found.", name); + return 1; + } + if (driver_name && driver_name[0]) + printer->driver = driver_name; + + printer_register(pEntryPoints, printer); + } + else + { + printers = driver->EnumPrinters(driver); + for (i = 0; printers[i]; i++) + { + printer = printers[i]; + printer_register(pEntryPoints, printer); + } + xfree(printers); + } + + return 0; +} diff --git a/channels/rdpdr/printer/printer_main.h b/channels/rdpdr/printer/printer_main.h new file mode 100644 index 000000000..256c4a77d --- /dev/null +++ b/channels/rdpdr/printer/printer_main.h @@ -0,0 +1,79 @@ +/** + * FreeRDP: A Remote Desktop Protocol client. + * Print Virtual Channel + * + * Copyright 2010-2011 Vic Lee + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __PRINTER_MAIN_H +#define __PRINTER_MAIN_H + +#include "rdpdr_types.h" + +/* SERVER_PRINTER_CACHE_EVENT.cachedata */ +#define RDPDR_ADD_PRINTER_EVENT 0x00000001 +#define RDPDR_UPDATE_PRINTER_EVENT 0x00000002 +#define RDPDR_DELETE_PRINTER_EVENT 0x00000003 +#define RDPDR_RENAME_PRINTER_EVENT 0x00000004 + +/* DR_PRN_DEVICE_ANNOUNCE.Flags */ +#define RDPDR_PRINTER_ANNOUNCE_FLAG_ASCII 0x00000001 +#define RDPDR_PRINTER_ANNOUNCE_FLAG_DEFAULTPRINTER 0x00000002 +#define RDPDR_PRINTER_ANNOUNCE_FLAG_NETWORKPRINTER 0x00000004 +#define RDPDR_PRINTER_ANNOUNCE_FLAG_TSPRINTER 0x00000008 +#define RDPDR_PRINTER_ANNOUNCE_FLAG_XPSFORMAT 0x00000010 + +typedef struct rdp_printer_driver rdpPrinterDriver; +typedef struct rdp_printer rdpPrinter; +typedef struct rdp_print_job rdpPrintJob; + +typedef rdpPrinter** (*pcEnumPrinters) (rdpPrinterDriver* driver); +typedef rdpPrinter* (*pcGetPrinter) (rdpPrinterDriver* driver, const char* name); + +struct rdp_printer_driver +{ + pcEnumPrinters EnumPrinters; + pcGetPrinter GetPrinter; +}; + +typedef rdpPrintJob* (*pcCreatePrintJob) (rdpPrinter* printer, uint32 id); +typedef rdpPrintJob* (*pcFindPrintJob) (rdpPrinter* printer, uint32 id); +typedef void (*pcFreePrinter) (rdpPrinter* printer); + +struct rdp_printer +{ + int id; + char* name; + char* driver; + boolean is_default; + + pcCreatePrintJob CreatePrintJob; + pcFindPrintJob FindPrintJob; + pcFreePrinter Free; +}; + +typedef void (*pcWritePrintJob) (rdpPrintJob* printjob, uint8* data, int size); +typedef void (*pcClosePrintJob) (rdpPrintJob* printjob); + +struct rdp_print_job +{ + uint32 id; + rdpPrinter* printer; + + pcWritePrintJob Write; + pcClosePrintJob Close; +}; + +#endif diff --git a/config.h.in b/config.h.in index 5cc505739..360067bd7 100644 --- a/config.h.in +++ b/config.h.in @@ -10,6 +10,9 @@ #cmakedefine HAVE_FCNTL_H #cmakedefine HAVE_UNISTD_H +/* Found packages */ +#cmakedefine CUPS_FOUND + /* Endian */ #cmakedefine BIG_ENDIAN diff --git a/libfreerdp-utils/args.c b/libfreerdp-utils/args.c index b9fae60c4..2479ffa92 100644 --- a/libfreerdp-utils/args.c +++ b/libfreerdp-utils/args.c @@ -287,6 +287,10 @@ int freerdp_parse_args(rdpSettings* settings, int argc, char** argv, { plugin_data = (FRDP_PLUGIN_DATA*)xrealloc(plugin_data, sizeof(FRDP_PLUGIN_DATA) * (i + 2)); plugin_data[i].size = sizeof(FRDP_PLUGIN_DATA); + plugin_data[i].data[0] = NULL; + plugin_data[i].data[1] = NULL; + plugin_data[i].data[2] = NULL; + plugin_data[i].data[3] = NULL; plugin_data[i + 1].size = 0; for (j = 0, p = argv[index]; j < 4 && p != NULL; j++) {