Blame channels/printer/client/printer_win.c

Packit 1fb8d4
/**
Packit 1fb8d4
 * FreeRDP: A Remote Desktop Protocol Implementation
Packit 1fb8d4
 * Print Virtual Channel - WIN driver
Packit 1fb8d4
 *
Packit 1fb8d4
 * Copyright 2012 Gerald Richter
Packit 1fb8d4
 * Copyright 2015 Thincast Technologies GmbH
Packit 1fb8d4
 * Copyright 2015 DI (FH) Martin Haimberger <martin.haimberger@thincast.com>
Packit 1fb8d4
 * Copyright 2016 Armin Novak <armin.novak@gmail.com>
Packit 1fb8d4
 *
Packit 1fb8d4
 * Licensed under the Apache License, Version 2.0 (the "License");
Packit 1fb8d4
 * you may not use this file except in compliance with the License.
Packit 1fb8d4
 * You may obtain a copy of the License at
Packit 1fb8d4
 *
Packit 1fb8d4
 *     http://www.apache.org/licenses/LICENSE-2.0
Packit 1fb8d4
 *
Packit 1fb8d4
 * Unless required by applicable law or agreed to in writing, software
Packit 1fb8d4
 * distributed under the License is distributed on an "AS IS" BASIS,
Packit 1fb8d4
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
Packit 1fb8d4
 * See the License for the specific language governing permissions and
Packit 1fb8d4
 * limitations under the License.
Packit 1fb8d4
 */
Packit 1fb8d4
Packit 1fb8d4
#ifdef HAVE_CONFIG_H
Packit 1fb8d4
#include "config.h"
Packit 1fb8d4
#endif
Packit 1fb8d4
Packit 1fb8d4
#include <winpr/crt.h>
Packit 1fb8d4
#include <winpr/string.h>
Packit 1fb8d4
#include <winpr/windows.h>
Packit 1fb8d4
Packit 1fb8d4
#include <time.h>
Packit 1fb8d4
#include <stdio.h>
Packit 1fb8d4
#include <stdlib.h>
Packit 1fb8d4
#include <string.h>
Packit 1fb8d4
#include <winspool.h>
Packit 1fb8d4
Packit 1fb8d4
#include "printer_main.h"
Packit 1fb8d4
Packit 1fb8d4
#include "printer_win.h"
Packit 1fb8d4
Packit 1fb8d4
typedef struct rdp_win_printer_driver rdpWinPrinterDriver;
Packit 1fb8d4
typedef struct rdp_win_printer rdpWinPrinter;
Packit 1fb8d4
typedef struct rdp_win_print_job rdpWinPrintJob;
Packit 1fb8d4
Packit 1fb8d4
struct rdp_win_printer_driver
Packit 1fb8d4
{
Packit 1fb8d4
	rdpPrinterDriver driver;
Packit 1fb8d4
Packit 1fb8d4
	int id_sequence;
Packit 1fb8d4
};
Packit 1fb8d4
Packit 1fb8d4
struct rdp_win_printer
Packit 1fb8d4
{
Packit 1fb8d4
	rdpPrinter printer;
Packit 1fb8d4
	HANDLE hPrinter;
Packit 1fb8d4
	rdpWinPrintJob* printjob;
Packit 1fb8d4
};
Packit 1fb8d4
Packit 1fb8d4
struct rdp_win_print_job
Packit 1fb8d4
{
Packit 1fb8d4
	rdpPrintJob printjob;
Packit 1fb8d4
	DOC_INFO_1 di;
Packit 1fb8d4
	DWORD handle;
Packit 1fb8d4
Packit 1fb8d4
	void* printjob_object;
Packit 1fb8d4
	int printjob_id;
Packit 1fb8d4
};
Packit 1fb8d4
Packit 1fb8d4
static void printer_win_get_printjob_name(char* buf, int size)
Packit 1fb8d4
{
Packit 1fb8d4
	time_t tt;
Packit 1fb8d4
	struct tm* t;
Packit 1fb8d4
Packit 1fb8d4
	tt = time(NULL);
Packit 1fb8d4
	t = localtime(&tt;;
Packit 1fb8d4
	sprintf_s(buf, size - 1, "FreeRDP Print Job %d%02d%02d%02d%02d%02d",
Packit 1fb8d4
		t->tm_year + 1900, t->tm_mon + 1, t->tm_mday,
Packit 1fb8d4
		t->tm_hour, t->tm_min, t->tm_sec);
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
/**
Packit 1fb8d4
 * Function description
Packit 1fb8d4
 *
Packit 1fb8d4
 * @return 0 on success, otherwise a Win32 error code
Packit 1fb8d4
 */
Packit 1fb8d4
static UINT printer_win_write_printjob(rdpPrintJob* printjob, BYTE* data, int size)
Packit 1fb8d4
{
Packit 1fb8d4
	rdpWinPrintJob* win_printjob = (rdpWinPrintJob*) printjob;
Packit 1fb8d4
Packit 1fb8d4
	LPVOID pBuf = data;
Packit 1fb8d4
	DWORD cbBuf = size;
Packit 1fb8d4
	DWORD pcWritten;
Packit 1fb8d4
Packit 1fb8d4
	if(!WritePrinter(((rdpWinPrinter*)printjob->printer)->hPrinter, pBuf, cbBuf, &pcWritten))
Packit 1fb8d4
		return ERROR_INTERNAL_ERROR;
Packit 1fb8d4
	return CHANNEL_RC_OK;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
static void printer_win_close_printjob(rdpPrintJob* printjob)
Packit 1fb8d4
{
Packit 1fb8d4
	rdpWinPrintJob* win_printjob = (rdpWinPrintJob*) printjob;
Packit 1fb8d4
Packit 1fb8d4
	if (!EndPagePrinter(((rdpWinPrinter*) printjob->printer)->hPrinter))
Packit 1fb8d4
	{
Packit 1fb8d4
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	if (!ClosePrinter(((rdpWinPrinter*) printjob->printer)->hPrinter))
Packit 1fb8d4
	{
Packit 1fb8d4
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	((rdpWinPrinter*) printjob->printer)->printjob = NULL;
Packit 1fb8d4
Packit 1fb8d4
	free(win_printjob);
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
static rdpPrintJob* printer_win_create_printjob(rdpPrinter* printer, UINT32 id)
Packit 1fb8d4
{
Packit 1fb8d4
	rdpWinPrinter* win_printer = (rdpWinPrinter*)printer;
Packit 1fb8d4
	rdpWinPrintJob* win_printjob;
Packit 1fb8d4
Packit 1fb8d4
	if (win_printer->printjob != NULL)
Packit 1fb8d4
		return NULL;
Packit 1fb8d4
Packit 1fb8d4
	win_printjob = (rdpWinPrintJob*) calloc(1, sizeof(rdpWinPrintJob));
Packit 1fb8d4
	if (!win_printjob)
Packit 1fb8d4
		return NULL;
Packit 1fb8d4
Packit 1fb8d4
	win_printjob->printjob.id = id;
Packit 1fb8d4
	win_printjob->printjob.printer = printer;
Packit 1fb8d4
	win_printjob->di.pDocName = L"FREERDPjob";
Packit 1fb8d4
	win_printjob->di.pDatatype= NULL;
Packit 1fb8d4
	win_printjob->di.pOutputFile = NULL;
Packit 1fb8d4
Packit 1fb8d4
	win_printjob->handle = StartDocPrinter(win_printer->hPrinter, 1, (LPBYTE) &(win_printjob->di));
Packit 1fb8d4
Packit 1fb8d4
	if (!win_printjob->handle)
Packit 1fb8d4
	{
Packit 1fb8d4
		free(win_printjob);
Packit 1fb8d4
		return NULL;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	if (!StartPagePrinter(win_printer->hPrinter))
Packit 1fb8d4
	{
Packit 1fb8d4
		free(win_printjob);
Packit 1fb8d4
		return NULL;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	win_printjob->printjob.Write = printer_win_write_printjob;
Packit 1fb8d4
	win_printjob->printjob.Close = printer_win_close_printjob;
Packit 1fb8d4
Packit 1fb8d4
	win_printer->printjob = win_printjob;
Packit 1fb8d4
	
Packit 1fb8d4
	return (rdpPrintJob*) win_printjob;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
static rdpPrintJob* printer_win_find_printjob(rdpPrinter* printer, UINT32 id)
Packit 1fb8d4
{
Packit 1fb8d4
	rdpWinPrinter* win_printer = (rdpWinPrinter*) printer;
Packit 1fb8d4
Packit 1fb8d4
	if (!win_printer->printjob)
Packit 1fb8d4
		return NULL;
Packit 1fb8d4
Packit 1fb8d4
	if (win_printer->printjob->printjob.id != id)
Packit 1fb8d4
		return NULL;
Packit 1fb8d4
Packit 1fb8d4
	return (rdpPrintJob*) win_printer->printjob;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
static void printer_win_free_printer(rdpPrinter* printer)
Packit 1fb8d4
{
Packit 1fb8d4
	rdpWinPrinter* win_printer = (rdpWinPrinter*) printer;
Packit 1fb8d4
Packit 1fb8d4
	if (win_printer->printjob)
Packit 1fb8d4
		win_printer->printjob->printjob.Close((rdpPrintJob*) win_printer->printjob);
Packit 1fb8d4
Packit 1fb8d4
	free(printer->name);
Packit 1fb8d4
	free(printer->driver);
Packit 1fb8d4
	free(printer);
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
static rdpPrinter* printer_win_new_printer(rdpWinPrinterDriver* win_driver,
Packit 1fb8d4
	const WCHAR* name, const WCHAR* drivername, BOOL is_default)
Packit 1fb8d4
{
Packit 1fb8d4
	rdpWinPrinter* win_printer;
Packit 1fb8d4
	DWORD needed = 0;
Packit 1fb8d4
	int status;
Packit 1fb8d4
	PRINTER_INFO_2 *prninfo=NULL;
Packit 1fb8d4
Packit 1fb8d4
	win_printer = (rdpWinPrinter*) calloc(1, sizeof(rdpWinPrinter));
Packit 1fb8d4
	if (!win_printer)
Packit 1fb8d4
		return NULL;
Packit 1fb8d4
Packit 1fb8d4
	win_printer->printer.id = win_driver->id_sequence++;
Packit 1fb8d4
	if (ConvertFromUnicode(CP_UTF8, 0, name, -1, &win_printer->printer.name, 0, NULL, NULL) < 1)
Packit 1fb8d4
	{
Packit 1fb8d4
		free(win_printer);
Packit 1fb8d4
		return NULL;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	if (!win_printer->printer.name)
Packit 1fb8d4
	{
Packit 1fb8d4
		free(win_printer);
Packit 1fb8d4
		return NULL;
Packit 1fb8d4
	}
Packit 1fb8d4
	win_printer->printer.is_default = is_default;
Packit 1fb8d4
Packit 1fb8d4
	win_printer->printer.CreatePrintJob = printer_win_create_printjob;
Packit 1fb8d4
	win_printer->printer.FindPrintJob = printer_win_find_printjob;
Packit 1fb8d4
	win_printer->printer.Free = printer_win_free_printer;
Packit 1fb8d4
Packit 1fb8d4
	if (!OpenPrinter(name, &(win_printer->hPrinter), NULL))
Packit 1fb8d4
	{
Packit 1fb8d4
		free(win_printer->printer.name);
Packit 1fb8d4
		free(win_printer);
Packit 1fb8d4
		return NULL;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	/* How many memory should be allocated for printer data */
Packit 1fb8d4
	GetPrinter(win_printer->hPrinter, 2, (LPBYTE) prninfo, 0, &needed);
Packit 1fb8d4
	if (needed == 0)
Packit 1fb8d4
	{
Packit 1fb8d4
		free(win_printer->printer.name);
Packit 1fb8d4
		free(win_printer);
Packit 1fb8d4
		return NULL;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	prninfo = (PRINTER_INFO_2*) GlobalAlloc(GPTR,needed);
Packit 1fb8d4
	if (!prninfo)
Packit 1fb8d4
	{
Packit 1fb8d4
		free(win_printer->printer.name);
Packit 1fb8d4
		free(win_printer);
Packit 1fb8d4
		return NULL;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	if (!GetPrinter(win_printer->hPrinter, 2, (LPBYTE) prninfo, needed, &needed))
Packit 1fb8d4
	{
Packit 1fb8d4
		GlobalFree(prninfo);
Packit 1fb8d4
		free(win_printer->printer.name);
Packit 1fb8d4
		free(win_printer);
Packit 1fb8d4
		return NULL;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	if (drivername)
Packit 1fb8d4
		status = ConvertFromUnicode(CP_UTF8, 0, drivername, -1, &win_printer->printer.driver, 0, NULL, NULL);
Packit 1fb8d4
	else
Packit 1fb8d4
		status = ConvertFromUnicode(CP_UTF8, 0, prninfo->pDriverName, -1, &win_printer->printer.driver, 0, NULL, NULL);
Packit 1fb8d4
	if (!win_printer->printer.driver || (status <= 0))
Packit 1fb8d4
	{
Packit 1fb8d4
		GlobalFree(prninfo);
Packit 1fb8d4
		free(win_printer->printer.name);
Packit 1fb8d4
		free(win_printer);
Packit 1fb8d4
		return NULL;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	return (rdpPrinter*)win_printer;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
static rdpPrinter** printer_win_enum_printers(rdpPrinterDriver* driver)
Packit 1fb8d4
{
Packit 1fb8d4
	rdpPrinter** printers;
Packit 1fb8d4
	int num_printers;
Packit 1fb8d4
	int i;
Packit 1fb8d4
	PRINTER_INFO_2* prninfo = NULL;
Packit 1fb8d4
	DWORD needed, returned;
Packit 1fb8d4
Packit 1fb8d4
	/* find required size for the buffer */
Packit 1fb8d4
	EnumPrinters(PRINTER_ENUM_LOCAL|PRINTER_ENUM_CONNECTIONS, NULL, 2, NULL, 0, &needed, &returned);
Packit 1fb8d4
Packit 1fb8d4
Packit 1fb8d4
	/* allocate array of PRINTER_INFO structures */
Packit 1fb8d4
	prninfo = (PRINTER_INFO_2*) GlobalAlloc(GPTR,needed);
Packit 1fb8d4
	if (!prninfo)
Packit 1fb8d4
		return NULL;
Packit 1fb8d4
 
Packit 1fb8d4
	/* call again */
Packit 1fb8d4
	if (!EnumPrinters(PRINTER_ENUM_LOCAL|PRINTER_ENUM_CONNECTIONS, NULL, 2, (LPBYTE) prninfo, needed, &needed, &returned))
Packit 1fb8d4
	{
Packit 1fb8d4
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	printers = (rdpPrinter**) calloc((returned + 1), sizeof(rdpPrinter*));
Packit 1fb8d4
	if (!printers)
Packit 1fb8d4
	{
Packit 1fb8d4
		GlobalFree(prninfo);
Packit 1fb8d4
		return NULL;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	num_printers = 0;
Packit 1fb8d4
Packit 1fb8d4
	for (i = 0; i < (int) returned; i++)
Packit 1fb8d4
	{
Packit 1fb8d4
		printers[num_printers++] = printer_win_new_printer((rdpWinPrinterDriver*)driver,
Packit 1fb8d4
			prninfo[i].pPrinterName, prninfo[i].pDriverName, 0);
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	GlobalFree(prninfo);
Packit 1fb8d4
	return printers;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
static rdpPrinter* printer_win_get_printer(rdpPrinterDriver* driver,
Packit 1fb8d4
	const char* name, const char* driverName)
Packit 1fb8d4
{
Packit 1fb8d4
	WCHAR* driverNameW = NULL;
Packit 1fb8d4
	rdpWinPrinterDriver* win_driver = (rdpWinPrinterDriver*)driver;
Packit 1fb8d4
	rdpPrinter *myPrinter = NULL;
Packit 1fb8d4
	
Packit 1fb8d4
	if (driverName)
Packit 1fb8d4
	{
Packit 1fb8d4
		ConvertToUnicode(CP_UTF8, 0, driverName, -1, &driverNameW, 0);
Packit 1fb8d4
		if (!driverNameW)
Packit 1fb8d4
			return NULL;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	myPrinter = printer_win_new_printer(win_driver, name, driverNameW,
Packit 1fb8d4
	win_driver->id_sequence == 1 ? TRUE : FALSE);
Packit 1fb8d4
	free(driverNameW);
Packit 1fb8d4
Packit 1fb8d4
	return myPrinter;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
static rdpWinPrinterDriver* win_driver = NULL;
Packit 1fb8d4
Packit 1fb8d4
rdpPrinterDriver* printer_win_get_driver(void)
Packit 1fb8d4
{
Packit 1fb8d4
	if (!win_driver)
Packit 1fb8d4
	{
Packit 1fb8d4
		win_driver = (rdpWinPrinterDriver*) calloc(1, sizeof(rdpWinPrinterDriver));
Packit 1fb8d4
		if (!win_driver)
Packit 1fb8d4
			return NULL;
Packit 1fb8d4
Packit 1fb8d4
		win_driver->driver.EnumPrinters = printer_win_enum_printers;
Packit 1fb8d4
		win_driver->driver.GetPrinter = printer_win_get_printer;
Packit 1fb8d4
Packit 1fb8d4
		win_driver->id_sequence = 1;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	return (rdpPrinterDriver*) win_driver;
Packit 1fb8d4
}
Packit 1fb8d4