summaryrefslogtreecommitdiffstats
path: root/channels/printer/client/win
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-04 01:24:41 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-04 01:24:41 +0000
commita9bcc81f821d7c66f623779fa5147e728eb3c388 (patch)
tree98676963bcdd537ae5908a067a8eb110b93486a6 /channels/printer/client/win
parentInitial commit. (diff)
downloadfreerdp3-a9bcc81f821d7c66f623779fa5147e728eb3c388.tar.xz
freerdp3-a9bcc81f821d7c66f623779fa5147e728eb3c388.zip
Adding upstream version 3.3.0+dfsg1.upstream/3.3.0+dfsg1
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'channels/printer/client/win')
-rw-r--r--channels/printer/client/win/CMakeLists.txt30
-rw-r--r--channels/printer/client/win/printer_win.c463
2 files changed, 493 insertions, 0 deletions
diff --git a/channels/printer/client/win/CMakeLists.txt b/channels/printer/client/win/CMakeLists.txt
new file mode 100644
index 0000000..7f0960a
--- /dev/null
+++ b/channels/printer/client/win/CMakeLists.txt
@@ -0,0 +1,30 @@
+# FreeRDP: A Remote Desktop Protocol Implementation
+# FreeRDP cmake build script
+#
+# Copyright 2019 Armin Novak <armin.novak@thincast.com>
+# Copyright 2019 Thincast Technologies GmbH
+#
+# 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.
+define_channel_client_subsystem("printer" "win" "")
+
+set(${MODULE_PREFIX}_SRCS
+ printer_win.c)
+
+set(${MODULE_PREFIX}_LIBS
+ winpr
+ freerdp
+)
+
+include_directories(..)
+
+add_channel_client_subsystem_library(${MODULE_PREFIX} ${MODULE_NAME} ${CHANNEL_NAME} "" TRUE "")
diff --git a/channels/printer/client/win/printer_win.c b/channels/printer/client/win/printer_win.c
new file mode 100644
index 0000000..9bd7589
--- /dev/null
+++ b/channels/printer/client/win/printer_win.c
@@ -0,0 +1,463 @@
+/**
+ * FreeRDP: A Remote Desktop Protocol Implementation
+ * Print Virtual Channel - WIN driver
+ *
+ * Copyright 2012 Gerald Richter
+ * Copyright 2015 Thincast Technologies GmbH
+ * Copyright 2015 DI (FH) Martin Haimberger <martin.haimberger@thincast.com>
+ * Copyright 2016 Armin Novak <armin.novak@gmail.com>
+ *
+ * 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 <freerdp/config.h>
+
+#include <winpr/crt.h>
+#include <winpr/string.h>
+#include <winpr/windows.h>
+
+#include <time.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <winspool.h>
+
+#include <freerdp/client/printer.h>
+
+#define WIDEN_INT(x) L##x
+#define WIDEN(x) WIDEN_INT(x)
+#define PRINTER_TAG CHANNELS_TAG("printer.client")
+#ifdef WITH_DEBUG_WINPR
+#define DEBUG_WINPR(...) WLog_DBG(PRINTER_TAG, __VA_ARGS__)
+#else
+#define DEBUG_WINPR(...) \
+ do \
+ { \
+ } while (0)
+#endif
+
+typedef struct
+{
+ rdpPrinterDriver driver;
+
+ size_t id_sequence;
+ size_t references;
+} rdpWinPrinterDriver;
+
+typedef struct
+{
+ rdpPrintJob printjob;
+ DOC_INFO_1 di;
+ DWORD handle;
+
+ void* printjob_object;
+ int printjob_id;
+} rdpWinPrintJob;
+
+typedef struct
+{
+ rdpPrinter printer;
+ HANDLE hPrinter;
+ rdpWinPrintJob* printjob;
+} rdpWinPrinter;
+
+static WCHAR* printer_win_get_printjob_name(size_t id)
+{
+ time_t tt;
+ struct tm tres;
+ errno_t err;
+ WCHAR* str;
+ size_t len = 1024;
+ int rc;
+
+ tt = time(NULL);
+ err = localtime_s(&tres, &tt);
+
+ str = calloc(len, sizeof(WCHAR));
+ if (!str)
+ return NULL;
+
+ rc = swprintf_s(str, len,
+ WIDEN("FreeRDP Print %04d-%02d-%02d% 02d-%02d-%02d - Job %") WIDEN(PRIuz)
+ WIDEN("\0"),
+ tres.tm_year + 1900, tres.tm_mon + 1, tres.tm_mday, tres.tm_hour, tres.tm_min,
+ tres.tm_sec, id);
+
+ return str;
+}
+
+/**
+ * Function description
+ *
+ * @return 0 on success, otherwise a Win32 error code
+ */
+static UINT printer_win_write_printjob(rdpPrintJob* printjob, const BYTE* data, size_t size)
+{
+ rdpWinPrinter* printer;
+ LPCVOID pBuf = data;
+ DWORD cbBuf = size;
+ DWORD pcWritten;
+
+ if (!printjob || !data)
+ return ERROR_BAD_ARGUMENTS;
+
+ printer = (rdpWinPrinter*)printjob->printer;
+ if (!printer)
+ return ERROR_BAD_ARGUMENTS;
+
+ if (!WritePrinter(printer->hPrinter, pBuf, cbBuf, &pcWritten))
+ return ERROR_INTERNAL_ERROR;
+ return CHANNEL_RC_OK;
+}
+
+static void printer_win_close_printjob(rdpPrintJob* printjob)
+{
+ rdpWinPrintJob* win_printjob = (rdpWinPrintJob*)printjob;
+ rdpWinPrinter* win_printer;
+
+ if (!printjob)
+ return;
+
+ win_printer = (rdpWinPrinter*)printjob->printer;
+ if (!win_printer)
+ return;
+
+ if (!EndPagePrinter(win_printer->hPrinter))
+ {
+ }
+
+ if (!ClosePrinter(win_printer->hPrinter))
+ {
+ }
+
+ win_printer->printjob = NULL;
+
+ free(win_printjob->di.pDocName);
+ free(win_printjob);
+}
+
+static rdpPrintJob* printer_win_create_printjob(rdpPrinter* printer, UINT32 id)
+{
+ rdpWinPrinter* win_printer = (rdpWinPrinter*)printer;
+ rdpWinPrintJob* win_printjob;
+
+ if (win_printer->printjob != NULL)
+ return NULL;
+
+ win_printjob = (rdpWinPrintJob*)calloc(1, sizeof(rdpWinPrintJob));
+ if (!win_printjob)
+ return NULL;
+
+ win_printjob->printjob.id = id;
+ win_printjob->printjob.printer = printer;
+ win_printjob->di.pDocName = printer_win_get_printjob_name(id);
+ win_printjob->di.pDatatype = NULL;
+ win_printjob->di.pOutputFile = NULL;
+
+ win_printjob->handle = StartDocPrinter(win_printer->hPrinter, 1, (LPBYTE) & (win_printjob->di));
+
+ if (!win_printjob->handle)
+ {
+ free(win_printjob->di.pDocName);
+ free(win_printjob);
+ return NULL;
+ }
+
+ if (!StartPagePrinter(win_printer->hPrinter))
+ {
+ free(win_printjob->di.pDocName);
+ free(win_printjob);
+ return NULL;
+ }
+
+ win_printjob->printjob.Write = printer_win_write_printjob;
+ win_printjob->printjob.Close = printer_win_close_printjob;
+
+ win_printer->printjob = win_printjob;
+
+ return &win_printjob->printjob;
+}
+
+static rdpPrintJob* printer_win_find_printjob(rdpPrinter* printer, UINT32 id)
+{
+ rdpWinPrinter* win_printer = (rdpWinPrinter*)printer;
+
+ if (!win_printer->printjob)
+ return NULL;
+
+ if (win_printer->printjob->printjob.id != id)
+ return NULL;
+
+ return (rdpPrintJob*)win_printer->printjob;
+}
+
+static void printer_win_free_printer(rdpPrinter* printer)
+{
+ rdpWinPrinter* win_printer = (rdpWinPrinter*)printer;
+
+ if (win_printer->printjob)
+ win_printer->printjob->printjob.Close((rdpPrintJob*)win_printer->printjob);
+
+ if (printer->backend)
+ printer->backend->ReleaseRef(printer->backend);
+
+ free(printer->name);
+ free(printer->driver);
+ free(printer);
+}
+
+static void printer_win_add_ref_printer(rdpPrinter* printer)
+{
+ if (printer)
+ printer->references++;
+}
+
+static void printer_win_release_ref_printer(rdpPrinter* printer)
+{
+ if (!printer)
+ return;
+ if (printer->references <= 1)
+ printer_win_free_printer(printer);
+ else
+ printer->references--;
+}
+
+static rdpPrinter* printer_win_new_printer(rdpWinPrinterDriver* win_driver, const WCHAR* name,
+ const WCHAR* drivername, BOOL is_default)
+{
+ rdpWinPrinter* win_printer;
+ DWORD needed = 0;
+ PRINTER_INFO_2* prninfo = NULL;
+
+ if (!name)
+ return NULL;
+
+ win_printer = (rdpWinPrinter*)calloc(1, sizeof(rdpWinPrinter));
+ if (!win_printer)
+ return NULL;
+
+ win_printer->printer.backend = &win_driver->driver;
+ win_printer->printer.id = win_driver->id_sequence++;
+ win_printer->printer.name = ConvertWCharToUtf8Alloc(name, NULL);
+ if (!win_printer->printer.name)
+ goto fail;
+
+ if (!win_printer->printer.name)
+ goto fail;
+ win_printer->printer.is_default = is_default;
+
+ win_printer->printer.CreatePrintJob = printer_win_create_printjob;
+ win_printer->printer.FindPrintJob = printer_win_find_printjob;
+ win_printer->printer.AddRef = printer_win_add_ref_printer;
+ win_printer->printer.ReleaseRef = printer_win_release_ref_printer;
+
+ if (!OpenPrinter(name, &(win_printer->hPrinter), NULL))
+ goto fail;
+
+ /* How many memory should be allocated for printer data */
+ GetPrinter(win_printer->hPrinter, 2, (LPBYTE)prninfo, 0, &needed);
+ if (needed == 0)
+ goto fail;
+
+ prninfo = (PRINTER_INFO_2*)GlobalAlloc(GPTR, needed);
+ if (!prninfo)
+ goto fail;
+
+ if (!GetPrinter(win_printer->hPrinter, 2, (LPBYTE)prninfo, needed, &needed))
+ {
+ GlobalFree(prninfo);
+ goto fail;
+ }
+
+ if (drivername)
+ win_printer->printer.driver = ConvertWCharToUtf8Alloc(drivername, NULL);
+ else
+ win_printer->printer.driver = ConvertWCharToUtf8Alloc(prninfo->pDriverName, NULL);
+ GlobalFree(prninfo);
+ if (!win_printer->printer.driver)
+ goto fail;
+
+ win_printer->printer.AddRef(&win_printer->printer);
+ win_printer->printer.backend->AddRef(win_printer->printer.backend);
+ return &win_printer->printer;
+
+fail:
+ printer_win_free_printer(&win_printer->printer);
+ return NULL;
+}
+
+static void printer_win_release_enum_printers(rdpPrinter** printers)
+{
+ rdpPrinter** cur = printers;
+
+ while ((cur != NULL) && ((*cur) != NULL))
+ {
+ if ((*cur)->ReleaseRef)
+ (*cur)->ReleaseRef(*cur);
+ cur++;
+ }
+ free(printers);
+}
+
+static rdpPrinter** printer_win_enum_printers(rdpPrinterDriver* driver)
+{
+ rdpPrinter** printers;
+ int num_printers;
+ PRINTER_INFO_2* prninfo = NULL;
+ DWORD needed, returned;
+ BOOL haveDefault = FALSE;
+ LPWSTR defaultPrinter = NULL;
+
+ GetDefaultPrinter(NULL, &needed);
+ if (needed)
+ {
+ defaultPrinter = (LPWSTR)calloc(needed, sizeof(WCHAR));
+
+ if (!defaultPrinter)
+ return NULL;
+
+ if (!GetDefaultPrinter(defaultPrinter, &needed))
+ defaultPrinter[0] = '\0';
+ }
+
+ /* find required size for the buffer */
+ EnumPrinters(PRINTER_ENUM_LOCAL | PRINTER_ENUM_CONNECTIONS, NULL, 2, NULL, 0, &needed,
+ &returned);
+
+ /* allocate array of PRINTER_INFO structures */
+ prninfo = (PRINTER_INFO_2*)GlobalAlloc(GPTR, needed);
+ if (!prninfo)
+ {
+ free(defaultPrinter);
+ return NULL;
+ }
+
+ /* call again */
+ if (!EnumPrinters(PRINTER_ENUM_LOCAL | PRINTER_ENUM_CONNECTIONS, NULL, 2, (LPBYTE)prninfo,
+ needed, &needed, &returned))
+ {
+ }
+
+ printers = (rdpPrinter**)calloc((returned + 1), sizeof(rdpPrinter*));
+ if (!printers)
+ {
+ GlobalFree(prninfo);
+ free(defaultPrinter);
+ return NULL;
+ }
+
+ num_printers = 0;
+
+ for (int i = 0; i < (int)returned; i++)
+ {
+ rdpPrinter* current = printers[num_printers];
+ current = printer_win_new_printer((rdpWinPrinterDriver*)driver, prninfo[i].pPrinterName,
+ prninfo[i].pDriverName,
+ _wcscmp(prninfo[i].pPrinterName, defaultPrinter) == 0);
+ if (!current)
+ {
+ printer_win_release_enum_printers(printers);
+ printers = NULL;
+ break;
+ }
+ if (current->is_default)
+ haveDefault = TRUE;
+ printers[num_printers++] = current;
+ }
+
+ if (!haveDefault && (returned > 0))
+ printers[0]->is_default = TRUE;
+
+ GlobalFree(prninfo);
+ free(defaultPrinter);
+ return printers;
+}
+
+static rdpPrinter* printer_win_get_printer(rdpPrinterDriver* driver, const char* name,
+ const char* driverName, BOOL isDefault)
+{
+ WCHAR* driverNameW = NULL;
+ WCHAR* nameW = NULL;
+ rdpWinPrinterDriver* win_driver = (rdpWinPrinterDriver*)driver;
+ rdpPrinter* myPrinter = NULL;
+
+ if (name)
+ {
+ nameW = ConvertUtf8ToWCharAlloc(name, NULL);
+ if (!nameW)
+ return NULL;
+ }
+ if (driverName)
+ {
+ driverNameW = ConvertUtf8ToWCharAlloc(driverName, NULL);
+ if (!driverNameW)
+ return NULL;
+ }
+
+ myPrinter = printer_win_new_printer(win_driver, nameW, driverNameW, isDefault);
+ free(driverNameW);
+ free(nameW);
+
+ return myPrinter;
+}
+
+static void printer_win_add_ref_driver(rdpPrinterDriver* driver)
+{
+ rdpWinPrinterDriver* win = (rdpWinPrinterDriver*)driver;
+ if (win)
+ win->references++;
+}
+
+/* Singleton */
+static rdpWinPrinterDriver* win_driver = NULL;
+
+static void printer_win_release_ref_driver(rdpPrinterDriver* driver)
+{
+ rdpWinPrinterDriver* win = (rdpWinPrinterDriver*)driver;
+ if (win->references <= 1)
+ {
+ free(win);
+ win_driver = NULL;
+ }
+ else
+ win->references--;
+}
+
+FREERDP_ENTRY_POINT(UINT win_freerdp_printer_client_subsystem_entry(void* arg))
+{
+ rdpPrinterDriver** ppPrinter = (rdpPrinterDriver**)arg;
+ if (!ppPrinter)
+ return ERROR_INVALID_PARAMETER;
+
+ if (!win_driver)
+ {
+ win_driver = (rdpWinPrinterDriver*)calloc(1, sizeof(rdpWinPrinterDriver));
+
+ if (!win_driver)
+ return ERROR_OUTOFMEMORY;
+
+ win_driver->driver.EnumPrinters = printer_win_enum_printers;
+ win_driver->driver.ReleaseEnumPrinters = printer_win_release_enum_printers;
+ win_driver->driver.GetPrinter = printer_win_get_printer;
+
+ win_driver->driver.AddRef = printer_win_add_ref_driver;
+ win_driver->driver.ReleaseRef = printer_win_release_ref_driver;
+
+ win_driver->id_sequence = 1;
+ }
+
+ win_driver->driver.AddRef(&win_driver->driver);
+
+ *ppPrinter = &win_driver->driver;
+ return CHANNEL_RC_OK;
+}