mirror of
https://github.com/morgan9e/FreeRDP
synced 2026-04-14 00:14:11 +09:00
Merge pull request #5140 from akallabeth/print_custom_component
Added callback to handle printer custom components in printer backend.
This commit is contained in:
@@ -938,6 +938,7 @@ endif()
|
||||
if(OPENSSL_FOUND)
|
||||
add_definitions("-DWITH_OPENSSL")
|
||||
message(STATUS "Using OpenSSL Version: ${OPENSSL_VERSION}")
|
||||
include_directories(${OPENSSL_INCLUDE_DIR})
|
||||
endif()
|
||||
|
||||
if(MBEDTLS_FOUND)
|
||||
|
||||
@@ -84,7 +84,7 @@ static void printer_cups_get_printjob_name(char* buf, int size)
|
||||
*
|
||||
* @return 0 on success, otherwise a Win32 error code
|
||||
*/
|
||||
static UINT printer_cups_write_printjob(rdpPrintJob* printjob, BYTE* data, int size)
|
||||
static UINT printer_cups_write_printjob(rdpPrintJob* printjob, const BYTE* data, size_t size)
|
||||
{
|
||||
rdpCupsPrintJob* cups_printjob = (rdpCupsPrintJob*) printjob;
|
||||
|
||||
|
||||
@@ -35,8 +35,10 @@
|
||||
#include <winpr/thread.h>
|
||||
#include <winpr/stream.h>
|
||||
#include <winpr/interlocked.h>
|
||||
#include <winpr/path.h>
|
||||
|
||||
#include <freerdp/channels/rdpdr.h>
|
||||
#include <freerdp/crypto/crypto.h>
|
||||
|
||||
#include "../printer.h"
|
||||
|
||||
@@ -71,6 +73,364 @@ struct _PRINTER_DEVICE
|
||||
char port[64];
|
||||
};
|
||||
|
||||
typedef enum
|
||||
{
|
||||
PRN_CONF_PORT = 0,
|
||||
PRN_CONF_PNP = 1,
|
||||
PRN_CONF_DRIVER = 2,
|
||||
PRN_CONF_DATA = 3
|
||||
}
|
||||
prn_conf_t;
|
||||
|
||||
static const char* filemap[] =
|
||||
{
|
||||
"PortDosName",
|
||||
"PnPName",
|
||||
"DriverName",
|
||||
"CachedPrinterConfigData"
|
||||
};
|
||||
|
||||
static char* get_printer_config_path(const rdpSettings* settings, const WCHAR* name, size_t length)
|
||||
{
|
||||
char* dir = GetCombinedPath(settings->ConfigPath, "printers");
|
||||
char* bname = crypto_base64_encode((const BYTE*) name, (int)length);
|
||||
char* config = GetCombinedPath(dir, bname);
|
||||
|
||||
if (config && !PathFileExistsA(config))
|
||||
{
|
||||
if (!PathMakePathA(config, NULL))
|
||||
{
|
||||
free(config);
|
||||
config = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
free(dir);
|
||||
free(bname);
|
||||
return config;
|
||||
}
|
||||
|
||||
static BOOL printer_write_setting(const char* path, prn_conf_t type, const void* data,
|
||||
size_t length)
|
||||
{
|
||||
DWORD written = 0;
|
||||
BOOL rc = FALSE;
|
||||
HANDLE file;
|
||||
size_t b64len;
|
||||
char* base64 = NULL;
|
||||
const char* name = filemap[type];
|
||||
char* abs = GetCombinedPath(path, name);
|
||||
|
||||
if (!abs)
|
||||
return FALSE;
|
||||
|
||||
file = CreateFileA(abs, GENERIC_WRITE, 0,
|
||||
NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
|
||||
free(abs);
|
||||
|
||||
if (file == INVALID_HANDLE_VALUE)
|
||||
return FALSE;
|
||||
|
||||
if (length > 0)
|
||||
{
|
||||
base64 = crypto_base64_encode(data, length);
|
||||
|
||||
if (!base64)
|
||||
goto fail;
|
||||
|
||||
b64len = strlen(base64);
|
||||
rc = WriteFile(file, base64, b64len, &written, NULL);
|
||||
|
||||
if (b64len != written)
|
||||
rc = FALSE;
|
||||
}
|
||||
else
|
||||
rc = TRUE;
|
||||
|
||||
fail:
|
||||
CloseHandle(file);
|
||||
free(base64);
|
||||
return rc;
|
||||
}
|
||||
|
||||
static BOOL printer_config_valid(const char* path)
|
||||
{
|
||||
if (!path)
|
||||
return FALSE;
|
||||
|
||||
if (!PathFileExistsA(path))
|
||||
return FALSE;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static BOOL printer_read_setting(const char* path, prn_conf_t type, void** data, size_t* length)
|
||||
{
|
||||
DWORD lowSize, highSize;
|
||||
DWORD read = 0;
|
||||
BOOL rc = FALSE;
|
||||
HANDLE file;
|
||||
BYTE* fdata = NULL;
|
||||
const char* name = filemap[type];
|
||||
char* abs = GetCombinedPath(path, name);
|
||||
|
||||
if (!abs)
|
||||
return FALSE;
|
||||
|
||||
file = CreateFileA(abs, GENERIC_READ, 0,
|
||||
NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
|
||||
free(abs);
|
||||
|
||||
if (file == INVALID_HANDLE_VALUE)
|
||||
return FALSE;
|
||||
|
||||
lowSize = GetFileSize(file, &highSize);
|
||||
|
||||
if ((lowSize == INVALID_FILE_SIZE) || (highSize != 0))
|
||||
goto fail;
|
||||
|
||||
if (lowSize != 0)
|
||||
{
|
||||
fdata = malloc(lowSize);
|
||||
|
||||
if (!fdata)
|
||||
goto fail;
|
||||
|
||||
rc = ReadFile(file, fdata, lowSize, &read, NULL);
|
||||
|
||||
if (lowSize != read)
|
||||
rc = FALSE;
|
||||
}
|
||||
|
||||
fail:
|
||||
CloseHandle(file);
|
||||
|
||||
if (rc)
|
||||
{
|
||||
int blen = 0;
|
||||
crypto_base64_decode(fdata, lowSize, data, &blen);
|
||||
|
||||
if (*data)
|
||||
*length = blen;
|
||||
else
|
||||
{
|
||||
rc = FALSE;
|
||||
*length = 0;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
*length = 0;
|
||||
*data = NULL;
|
||||
}
|
||||
|
||||
free(fdata);
|
||||
return rc;
|
||||
}
|
||||
|
||||
static BOOL printer_save_to_config(const rdpSettings* settings,
|
||||
const char* PortDosName, size_t PortDosNameLen,
|
||||
const WCHAR* PnPName, size_t PnPNameLen,
|
||||
const WCHAR* DriverName, size_t DriverNameLen,
|
||||
const WCHAR* PrinterName, size_t PrintNameLen,
|
||||
const BYTE* CachedPrinterConfigData, size_t CacheFieldsLen)
|
||||
{
|
||||
BOOL rc = FALSE;
|
||||
char* path = get_printer_config_path(settings, PrinterName, PrintNameLen);
|
||||
|
||||
if (!path)
|
||||
goto fail;
|
||||
|
||||
if (!printer_write_setting(path, PRN_CONF_PORT, PortDosName, PortDosNameLen))
|
||||
goto fail;
|
||||
|
||||
if (!printer_write_setting(path, PRN_CONF_PNP, PnPName, PnPNameLen))
|
||||
goto fail;
|
||||
|
||||
if (!printer_write_setting(path, PRN_CONF_DRIVER, DriverName, DriverNameLen))
|
||||
goto fail;
|
||||
|
||||
if (!printer_write_setting(path, PRN_CONF_DATA, CachedPrinterConfigData, CacheFieldsLen))
|
||||
goto fail;
|
||||
|
||||
fail:
|
||||
free(path);
|
||||
return rc;
|
||||
}
|
||||
|
||||
static BOOL printer_update_to_config(const rdpSettings* settings, const WCHAR* name, size_t length,
|
||||
const BYTE* data, size_t datalen)
|
||||
{
|
||||
BOOL rc = FALSE;
|
||||
char* path = get_printer_config_path(settings, name, length);
|
||||
rc = printer_write_setting(path, PRN_CONF_DATA, data, datalen);
|
||||
free(path);
|
||||
return rc;
|
||||
}
|
||||
|
||||
static BOOL printer_remove_config(const rdpSettings* settings, const WCHAR* name, size_t length)
|
||||
{
|
||||
BOOL rc = FALSE;
|
||||
char* path = get_printer_config_path(settings, name, length);
|
||||
|
||||
if (!printer_config_valid(path))
|
||||
goto fail;
|
||||
|
||||
rc = RemoveDirectoryA(path);
|
||||
fail:
|
||||
free(path);
|
||||
return rc;
|
||||
}
|
||||
|
||||
static BOOL printer_move_config(const rdpSettings* settings, const WCHAR* oldName, size_t oldLength,
|
||||
const WCHAR* newName, size_t newLength)
|
||||
{
|
||||
BOOL rc = FALSE;
|
||||
char* oldPath = get_printer_config_path(settings, oldName, oldLength);
|
||||
char* newPath = get_printer_config_path(settings, newName, newLength);
|
||||
|
||||
if (printer_config_valid(oldPath))
|
||||
rc = MoveFileA(oldPath, newPath);
|
||||
|
||||
free(oldPath);
|
||||
free(newPath);
|
||||
return rc;
|
||||
}
|
||||
|
||||
static BOOL printer_load_from_config(const rdpSettings* settings, rdpPrinter* printer,
|
||||
PRINTER_DEVICE* printer_dev)
|
||||
{
|
||||
BOOL res = FALSE;
|
||||
WCHAR* wname = NULL;
|
||||
size_t wlen;
|
||||
char* path = NULL;
|
||||
int rc;
|
||||
UINT32 flags = 0;
|
||||
WCHAR* DriverName = NULL;
|
||||
size_t DriverNameLen = 0;
|
||||
WCHAR* PnPName = NULL;
|
||||
size_t PnPNameLen = 0;
|
||||
BYTE* CachedPrinterConfigData = NULL;
|
||||
size_t CachedFieldsLen = 0;
|
||||
size_t PrinterNameLen = 0;
|
||||
|
||||
if (!settings || !printer)
|
||||
return FALSE;
|
||||
|
||||
rc = ConvertToUnicode(CP_UTF8, 0, printer->name, -1, &wname, 0);
|
||||
|
||||
if (rc <= 0)
|
||||
goto fail;
|
||||
|
||||
wlen = _wcslen(wname) + 1;
|
||||
path = get_printer_config_path(settings, wname, wlen * sizeof(WCHAR));
|
||||
PrinterNameLen = (wlen + 1) * sizeof(WCHAR);
|
||||
|
||||
if (!path)
|
||||
goto fail;
|
||||
|
||||
if (printer->is_default)
|
||||
flags |= RDPDR_PRINTER_ANNOUNCE_FLAG_DEFAULTPRINTER;
|
||||
|
||||
if (!printer_read_setting(path, PRN_CONF_PNP, &PnPName, &PnPNameLen))
|
||||
{
|
||||
}
|
||||
|
||||
if (!printer_read_setting(path, PRN_CONF_DRIVER, &DriverName, &DriverNameLen))
|
||||
{
|
||||
DriverNameLen = ConvertToUnicode(CP_UTF8, 0, printer->driver, -1, &DriverName,
|
||||
0) * 2 + 1;
|
||||
}
|
||||
|
||||
if (!printer_read_setting(path, PRN_CONF_DATA, &CachedPrinterConfigData, &CachedFieldsLen))
|
||||
{
|
||||
}
|
||||
|
||||
Stream_SetPosition(printer_dev->device.data, 0);
|
||||
|
||||
if (!Stream_EnsureRemainingCapacity(printer_dev->device.data, 24))
|
||||
goto fail;
|
||||
|
||||
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, PnPNameLen); /* PnPNameLen */
|
||||
Stream_Write_UINT32(printer_dev->device.data, DriverNameLen);
|
||||
Stream_Write_UINT32(printer_dev->device.data, PrinterNameLen);
|
||||
Stream_Write_UINT32(printer_dev->device.data, CachedFieldsLen);
|
||||
|
||||
if (!Stream_EnsureRemainingCapacity(printer_dev->device.data, PnPNameLen))
|
||||
goto fail;
|
||||
|
||||
if (PnPNameLen > 0)
|
||||
Stream_Write(printer_dev->device.data, PnPName, PnPNameLen);
|
||||
|
||||
if (!Stream_EnsureRemainingCapacity(printer_dev->device.data, DriverNameLen))
|
||||
goto fail;
|
||||
|
||||
Stream_Write(printer_dev->device.data, DriverName, DriverNameLen);
|
||||
|
||||
if (!Stream_EnsureRemainingCapacity(printer_dev->device.data, PrinterNameLen))
|
||||
goto fail;
|
||||
|
||||
Stream_Write(printer_dev->device.data, wname, PrinterNameLen);
|
||||
|
||||
if (!Stream_EnsureRemainingCapacity(printer_dev->device.data, CachedFieldsLen))
|
||||
goto fail;
|
||||
|
||||
Stream_Write(printer_dev->device.data, CachedPrinterConfigData, CachedFieldsLen);
|
||||
res = TRUE;
|
||||
fail:
|
||||
free(path);
|
||||
free(wname);
|
||||
free(PnPName);
|
||||
free(DriverName);
|
||||
free(CachedPrinterConfigData);
|
||||
return res;
|
||||
}
|
||||
|
||||
static BOOL printer_save_default_config(const rdpSettings* settings, rdpPrinter* printer)
|
||||
{
|
||||
BOOL res = FALSE;
|
||||
WCHAR* wname = NULL;
|
||||
WCHAR* driver = NULL;
|
||||
size_t wlen, dlen;
|
||||
char* path = NULL;
|
||||
int rc;
|
||||
|
||||
if (!settings || !printer)
|
||||
return FALSE;
|
||||
|
||||
rc = ConvertToUnicode(CP_UTF8, 0, printer->name, -1, &wname, 0);
|
||||
|
||||
if (rc <= 0)
|
||||
goto fail;
|
||||
|
||||
rc = ConvertToUnicode(CP_UTF8, 0, printer->driver, -1, &driver, 0);
|
||||
|
||||
if (rc <= 0)
|
||||
goto fail;
|
||||
|
||||
wlen = _wcslen(wname) + 1;
|
||||
dlen = _wcslen(driver) + 1;
|
||||
path = get_printer_config_path(settings, wname, wlen * sizeof(WCHAR));
|
||||
|
||||
if (!path)
|
||||
goto fail;
|
||||
|
||||
if (dlen > 1)
|
||||
{
|
||||
if (!printer_write_setting(path, PRN_CONF_DRIVER, driver, dlen * sizeof(WCHAR)))
|
||||
goto fail;
|
||||
}
|
||||
|
||||
res = TRUE;
|
||||
fail:
|
||||
free(path);
|
||||
free(wname);
|
||||
free(driver);
|
||||
return res;
|
||||
}
|
||||
|
||||
/**
|
||||
* Function description
|
||||
*
|
||||
@@ -293,6 +653,182 @@ static UINT printer_irp_request(DEVICE* device, IRP* irp)
|
||||
return CHANNEL_RC_OK;
|
||||
}
|
||||
|
||||
static UINT printer_custom_component(DEVICE* device, UINT16 component, UINT16 packetId, wStream* s)
|
||||
{
|
||||
UINT32 eventID;
|
||||
PRINTER_DEVICE* printer_dev = (PRINTER_DEVICE*) device;
|
||||
const rdpSettings* settings = printer_dev->rdpcontext->settings;
|
||||
|
||||
if (component != RDPDR_CTYP_PRN)
|
||||
return ERROR_INVALID_DATA;
|
||||
|
||||
if (Stream_GetRemainingLength(s) < 4)
|
||||
return ERROR_INVALID_DATA;
|
||||
|
||||
Stream_Read_UINT32(s, eventID);
|
||||
|
||||
switch (packetId)
|
||||
{
|
||||
case PAKID_PRN_CACHE_DATA:
|
||||
switch (eventID)
|
||||
{
|
||||
case RDPDR_ADD_PRINTER_EVENT:
|
||||
{
|
||||
char PortDosName[8];
|
||||
UINT32 PnPNameLen, DriverNameLen, PrintNameLen, CacheFieldsLen;
|
||||
const WCHAR* PnPName, *DriverName, *PrinterName;
|
||||
const BYTE* CachedPrinterConfigData;
|
||||
|
||||
if (Stream_GetRemainingLength(s) < 24)
|
||||
return ERROR_INVALID_DATA;
|
||||
|
||||
Stream_Read(s, PortDosName, sizeof(PortDosName));
|
||||
Stream_Read_UINT32(s, PnPNameLen);
|
||||
Stream_Read_UINT32(s, DriverNameLen);
|
||||
Stream_Read_UINT32(s, PrintNameLen);
|
||||
Stream_Read_UINT32(s, CacheFieldsLen);
|
||||
|
||||
if (Stream_GetRemainingLength(s) < PnPNameLen)
|
||||
return ERROR_INVALID_DATA;
|
||||
|
||||
PnPName = (const WCHAR*)Stream_Pointer(s);
|
||||
Stream_Seek(s, PnPNameLen);
|
||||
|
||||
if (Stream_GetRemainingLength(s) < DriverNameLen)
|
||||
return ERROR_INVALID_DATA;
|
||||
|
||||
DriverName = (const WCHAR*)Stream_Pointer(s);
|
||||
Stream_Seek(s, DriverNameLen);
|
||||
|
||||
if (Stream_GetRemainingLength(s) < PrintNameLen)
|
||||
return ERROR_INVALID_DATA;
|
||||
|
||||
PrinterName = (const WCHAR*)Stream_Pointer(s);
|
||||
Stream_Seek(s, PrintNameLen);
|
||||
|
||||
if (Stream_GetRemainingLength(s) < CacheFieldsLen)
|
||||
return ERROR_INVALID_DATA;
|
||||
|
||||
CachedPrinterConfigData = Stream_Pointer(s);
|
||||
Stream_Seek(s, CacheFieldsLen);
|
||||
|
||||
if (!printer_save_to_config(settings,
|
||||
PortDosName, sizeof(PortDosName),
|
||||
PnPName, PnPNameLen,
|
||||
DriverName, DriverNameLen,
|
||||
PrinterName, PrintNameLen,
|
||||
CachedPrinterConfigData, CacheFieldsLen))
|
||||
return ERROR_INTERNAL_ERROR;
|
||||
}
|
||||
break;
|
||||
|
||||
case RDPDR_UPDATE_PRINTER_EVENT:
|
||||
{
|
||||
UINT32 PrinterNameLen, ConfigDataLen;
|
||||
const WCHAR* PrinterName;
|
||||
const BYTE* ConfigData;
|
||||
|
||||
if (Stream_GetRemainingLength(s) < 8)
|
||||
return ERROR_INVALID_DATA;
|
||||
|
||||
Stream_Read_UINT32(s, PrinterNameLen);
|
||||
Stream_Read_UINT32(s, ConfigDataLen);
|
||||
|
||||
if (Stream_GetRemainingLength(s) < PrinterNameLen)
|
||||
return ERROR_INVALID_DATA;
|
||||
|
||||
PrinterName = (const WCHAR*)Stream_Pointer(s);
|
||||
Stream_Seek(s, PrinterNameLen);
|
||||
|
||||
if (Stream_GetRemainingLength(s) < ConfigDataLen)
|
||||
return ERROR_INVALID_DATA;
|
||||
|
||||
ConfigData = Stream_Pointer(s);
|
||||
Stream_Seek(s, ConfigDataLen);
|
||||
|
||||
if (!printer_update_to_config(settings, PrinterName, PrinterNameLen, ConfigData, ConfigDataLen))
|
||||
return ERROR_INTERNAL_ERROR;
|
||||
}
|
||||
break;
|
||||
|
||||
case RDPDR_DELETE_PRINTER_EVENT:
|
||||
{
|
||||
UINT32 PrinterNameLen;
|
||||
const WCHAR* PrinterName;
|
||||
|
||||
if (Stream_GetRemainingLength(s) < 4)
|
||||
return ERROR_INVALID_DATA;
|
||||
|
||||
Stream_Read_UINT32(s, PrinterNameLen);
|
||||
|
||||
if (Stream_GetRemainingLength(s) < PrinterNameLen)
|
||||
return ERROR_INVALID_DATA;
|
||||
|
||||
PrinterName = (const WCHAR*)Stream_Pointer(s);
|
||||
Stream_Seek(s, PrinterNameLen);
|
||||
printer_remove_config(settings, PrinterName, PrinterNameLen);
|
||||
}
|
||||
break;
|
||||
|
||||
case RDPDR_RENAME_PRINTER_EVENT:
|
||||
{
|
||||
UINT32 OldPrinterNameLen, NewPrinterNameLen;
|
||||
const WCHAR* OldPrinterName;
|
||||
const WCHAR* NewPrinterName;
|
||||
|
||||
if (Stream_GetRemainingLength(s) < 8)
|
||||
return ERROR_INVALID_DATA;
|
||||
|
||||
Stream_Read_UINT32(s, OldPrinterNameLen);
|
||||
Stream_Read_UINT32(s, NewPrinterNameLen);
|
||||
|
||||
if (Stream_GetRemainingLength(s) < OldPrinterNameLen)
|
||||
return ERROR_INVALID_DATA;
|
||||
|
||||
OldPrinterName = (const WCHAR*)Stream_Pointer(s);
|
||||
Stream_Seek(s, OldPrinterNameLen);
|
||||
|
||||
if (Stream_GetRemainingLength(s) < NewPrinterNameLen)
|
||||
return ERROR_INVALID_DATA;
|
||||
|
||||
NewPrinterName = (const WCHAR*)Stream_Pointer(s);
|
||||
Stream_Seek(s, NewPrinterNameLen);
|
||||
|
||||
if (!printer_move_config(settings, OldPrinterName, OldPrinterNameLen, NewPrinterName,
|
||||
NewPrinterNameLen))
|
||||
return ERROR_INTERNAL_ERROR;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
WLog_ERR(TAG, "Unknown cache data eventID: 0x%08"PRIX32"", eventID);
|
||||
return ERROR_INVALID_DATA;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case PAKID_PRN_USING_XPS:
|
||||
{
|
||||
UINT32 flags;
|
||||
|
||||
if (Stream_GetRemainingLength(s) < 4)
|
||||
return ERROR_INVALID_DATA;
|
||||
|
||||
Stream_Read_UINT32(s, flags);
|
||||
WLog_ERR(TAG,
|
||||
"Ignoring unhandled message PAKID_PRN_USING_XPS [printerID=%08"PRIx32", flags=%08"PRIx32"]",
|
||||
eventID, flags);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
WLog_ERR(TAG, "Unknown printing component packetID: 0x%04"PRIX16"", packetId);
|
||||
return ERROR_INVALID_DATA;
|
||||
}
|
||||
|
||||
return CHANNEL_RC_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* Function description
|
||||
*
|
||||
@@ -336,13 +872,6 @@ static UINT printer_free(DEVICE* device)
|
||||
UINT printer_register(PDEVICE_SERVICE_ENTRY_POINTS pEntryPoints,
|
||||
rdpPrinter* printer)
|
||||
{
|
||||
UINT32 Flags;
|
||||
int DriverNameLen;
|
||||
WCHAR* DriverName = NULL;
|
||||
int PrintNameLen;
|
||||
WCHAR* PrintName = NULL;
|
||||
UINT32 CachedFieldsLen;
|
||||
BYTE* CachedPrinterConfigData;
|
||||
PRINTER_DEVICE* printer_dev;
|
||||
UINT error;
|
||||
printer_dev = (PRINTER_DEVICE*) calloc(1, sizeof(PRINTER_DEVICE));
|
||||
@@ -353,55 +882,19 @@ UINT printer_register(PDEVICE_SERVICE_ENTRY_POINTS pEntryPoints,
|
||||
return CHANNEL_RC_NO_MEMORY;
|
||||
}
|
||||
|
||||
printer_dev->device.data = Stream_New(NULL, 1024);
|
||||
|
||||
if (!printer_dev->device.data)
|
||||
goto error_out;
|
||||
|
||||
sprintf_s(printer_dev->port, sizeof(printer_dev->port), "PRN%d", printer->id);
|
||||
printer_dev->device.type = RDPDR_DTYP_PRINT;
|
||||
printer_dev->device.name = printer_dev->port;
|
||||
printer_dev->device.IRPRequest = printer_irp_request;
|
||||
printer_dev->device.CustomComponentRequest = printer_custom_component;
|
||||
printer_dev->device.Free = printer_free;
|
||||
printer_dev->rdpcontext = pEntryPoints->rdpcontext;
|
||||
printer_dev->printer = printer;
|
||||
CachedFieldsLen = 0;
|
||||
CachedPrinterConfigData = NULL;
|
||||
Flags = 0;
|
||||
|
||||
if (printer->is_default)
|
||||
Flags |= RDPDR_PRINTER_ANNOUNCE_FLAG_DEFAULTPRINTER;
|
||||
|
||||
DriverNameLen = ConvertToUnicode(CP_UTF8, 0, printer->driver, -1, &DriverName,
|
||||
0) * 2;
|
||||
PrintNameLen = ConvertToUnicode(CP_UTF8, 0, printer->name, -1, &PrintName,
|
||||
0) * 2;
|
||||
printer_dev->device.data = Stream_New(NULL,
|
||||
28 + DriverNameLen + PrintNameLen + CachedFieldsLen);
|
||||
|
||||
if (!printer_dev->device.data)
|
||||
{
|
||||
WLog_ERR(TAG, "calloc failed!");
|
||||
error = CHANNEL_RC_NO_MEMORY;
|
||||
free(DriverName);
|
||||
free(PrintName);
|
||||
goto error_out;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
free(DriverName);
|
||||
free(PrintName);
|
||||
printer_dev->pIrpList = (WINPR_PSLIST_HEADER) _aligned_malloc(sizeof(
|
||||
WINPR_SLIST_HEADER), MEMORY_ALLOCATION_ALIGNMENT);
|
||||
|
||||
@@ -412,6 +905,9 @@ UINT printer_register(PDEVICE_SERVICE_ENTRY_POINTS pEntryPoints,
|
||||
goto error_out;
|
||||
}
|
||||
|
||||
if (!printer_load_from_config(pEntryPoints->rdpcontext->settings, printer, printer_dev))
|
||||
goto error_out;
|
||||
|
||||
InitializeSListHead(printer_dev->pIrpList);
|
||||
|
||||
if (!(printer_dev->event = CreateEvent(NULL, TRUE, FALSE, NULL)))
|
||||
@@ -497,6 +993,9 @@ UINT DeviceServiceEntry(PDEVICE_SERVICE_ENTRY_POINTS pEntryPoints)
|
||||
return CHANNEL_RC_INITIALIZATION_ERROR;
|
||||
}
|
||||
|
||||
if (!printer_save_default_config(pEntryPoints->rdpcontext->settings, printer))
|
||||
return CHANNEL_RC_INITIALIZATION_ERROR;
|
||||
|
||||
if ((error = printer_register(pEntryPoints, printer)))
|
||||
{
|
||||
WLog_ERR(TAG, "printer_register failed with error %"PRIu32"!", error);
|
||||
|
||||
@@ -54,7 +54,7 @@ struct rdp_printer
|
||||
pcFreePrinter Free;
|
||||
};
|
||||
|
||||
typedef UINT (*pcWritePrintJob) (rdpPrintJob* printjob, BYTE* data, int size);
|
||||
typedef UINT (*pcWritePrintJob) (rdpPrintJob* printjob, const BYTE* data, size_t size);
|
||||
typedef void (*pcClosePrintJob) (rdpPrintJob* printjob);
|
||||
|
||||
struct rdp_print_job
|
||||
|
||||
@@ -68,8 +68,8 @@ DEVMAN* devman_new(rdpdrPlugin* rdpdr)
|
||||
|
||||
devman->plugin = (void*) rdpdr;
|
||||
devman->id_sequence = 1;
|
||||
|
||||
devman->devices = ListDictionary_New(TRUE);
|
||||
|
||||
if (!devman->devices)
|
||||
{
|
||||
WLog_INFO(TAG, "ListDictionary_New failed!");
|
||||
@@ -78,7 +78,6 @@ DEVMAN* devman_new(rdpdrPlugin* rdpdr)
|
||||
}
|
||||
|
||||
ListDictionary_ValueObject(devman->devices)->fnObjectFree = devman_device_free;
|
||||
|
||||
return devman;
|
||||
}
|
||||
|
||||
@@ -114,26 +113,57 @@ static UINT devman_register_device(DEVMAN* devman, DEVICE* device)
|
||||
return ERROR_INVALID_PARAMETER;
|
||||
|
||||
device->id = devman->id_sequence++;
|
||||
key = (void*) (size_t) device->id;
|
||||
key = (void*)(size_t) device->id;
|
||||
|
||||
if (!ListDictionary_Add(devman->devices, key, device))
|
||||
{
|
||||
WLog_INFO(TAG, "ListDictionary_Add failed!");
|
||||
return ERROR_INTERNAL_ERROR;
|
||||
}
|
||||
|
||||
return CHANNEL_RC_OK;
|
||||
}
|
||||
|
||||
DEVICE* devman_get_device_by_id(DEVMAN* devman, UINT32 id)
|
||||
{
|
||||
DEVICE* device = NULL;
|
||||
void* key = (void*) (size_t) id;
|
||||
void* key = (void*)(size_t) id;
|
||||
|
||||
if (!devman)
|
||||
return NULL;
|
||||
|
||||
device = (DEVICE*) ListDictionary_GetItemValue(devman->devices, key);
|
||||
return device;
|
||||
}
|
||||
|
||||
DEVICE* devman_get_device_by_type(DEVMAN* devman, UINT32 type)
|
||||
{
|
||||
DEVICE* device = NULL;
|
||||
ULONG_PTR* keys;
|
||||
int count, x;
|
||||
|
||||
if (!devman)
|
||||
return NULL;
|
||||
|
||||
ListDictionary_Lock(devman->devices);
|
||||
count = ListDictionary_GetKeys(devman->devices, &keys);
|
||||
|
||||
for (x = 0; x < count; x++)
|
||||
{
|
||||
DEVICE* cur = (DEVICE*) ListDictionary_GetItemValue(devman->devices, keys[x]);
|
||||
|
||||
if (!cur)
|
||||
continue;
|
||||
|
||||
if (cur->type != type)
|
||||
continue;
|
||||
|
||||
device = cur;
|
||||
break;
|
||||
}
|
||||
|
||||
free(keys);
|
||||
ListDictionary_Unlock(devman->devices);
|
||||
return device;
|
||||
}
|
||||
|
||||
@@ -178,7 +208,9 @@ UINT devman_load_device_service(DEVMAN* devman, RDPDR_DEVICE* device, rdpContext
|
||||
WLog_INFO(TAG, "Loading device service %s [%s] (static)", ServiceName, device->Name);
|
||||
else
|
||||
WLog_INFO(TAG, "Loading device service %s (static)", ServiceName);
|
||||
entry = (PDEVICE_SERVICE_ENTRY) freerdp_load_channel_addin_entry(ServiceName, NULL, "DeviceServiceEntry", 0);
|
||||
|
||||
entry = (PDEVICE_SERVICE_ENTRY) freerdp_load_channel_addin_entry(ServiceName, NULL,
|
||||
"DeviceServiceEntry", 0);
|
||||
|
||||
if (!entry)
|
||||
{
|
||||
@@ -190,6 +222,5 @@ UINT devman_load_device_service(DEVMAN* devman, RDPDR_DEVICE* device, rdpContext
|
||||
ep.RegisterDevice = devman_register_device;
|
||||
ep.device = device;
|
||||
ep.rdpcontext = rdpcontext;
|
||||
|
||||
return entry(&ep);
|
||||
}
|
||||
|
||||
@@ -28,6 +28,7 @@
|
||||
void devman_unregister_device(DEVMAN* devman, void* key);
|
||||
UINT devman_load_device_service(DEVMAN* devman, RDPDR_DEVICE* device, rdpContext* rdpcontext);
|
||||
DEVICE* devman_get_device_by_id(DEVMAN* devman, UINT32 id);
|
||||
DEVICE* devman_get_device_by_type(DEVMAN* devman, UINT32 type);
|
||||
|
||||
DEVMAN* devman_new(rdpdrPlugin* rdpdr);
|
||||
void devman_free(DEVMAN* devman);
|
||||
|
||||
@@ -135,7 +135,8 @@ BOOL check_path(char* path)
|
||||
{
|
||||
UINT type = GetDriveTypeA(path);
|
||||
|
||||
if (!(type == DRIVE_FIXED ||type == DRIVE_REMOVABLE || type == DRIVE_CDROM || type == DRIVE_REMOTE))
|
||||
if (!(type == DRIVE_FIXED || type == DRIVE_REMOVABLE || type == DRIVE_CDROM ||
|
||||
type == DRIVE_REMOTE))
|
||||
return FALSE;
|
||||
|
||||
return GetVolumeInformationA(path, NULL, 0, NULL, NULL, NULL, NULL, 0);
|
||||
@@ -1324,6 +1325,31 @@ static UINT rdpdr_process_irp(rdpdrPlugin* rdpdr, wStream* s)
|
||||
return error;
|
||||
}
|
||||
|
||||
static UINT rdpdr_process_component(rdpdrPlugin* rdpdr, UINT16 component, UINT16 packetId,
|
||||
wStream* s)
|
||||
{
|
||||
UINT32 type;
|
||||
DEVICE* device;
|
||||
|
||||
switch (component)
|
||||
{
|
||||
case RDPDR_CTYP_PRN:
|
||||
type = RDPDR_DTYP_PRINT;
|
||||
break;
|
||||
|
||||
default:
|
||||
return ERROR_INVALID_DATA;
|
||||
}
|
||||
|
||||
device = devman_get_device_by_type(rdpdr->devman, type);
|
||||
|
||||
if (!device)
|
||||
return ERROR_INVALID_PARAMETER;
|
||||
|
||||
return IFCALLRESULT(ERROR_INVALID_PARAMETER, device->CustomComponentRequest, device, component,
|
||||
packetId, s);
|
||||
}
|
||||
|
||||
/**
|
||||
* Function description
|
||||
*
|
||||
@@ -1368,141 +1394,114 @@ static UINT rdpdr_process_receive(rdpdrPlugin* rdpdr, wStream* s)
|
||||
UINT16 packetId;
|
||||
UINT32 deviceId;
|
||||
UINT32 status;
|
||||
UINT error;
|
||||
UINT error = ERROR_INVALID_DATA;
|
||||
|
||||
if (!rdpdr || !s)
|
||||
return CHANNEL_RC_NULL_DATA;
|
||||
|
||||
if (Stream_GetRemainingLength(s) < 4)
|
||||
return ERROR_INVALID_DATA;
|
||||
|
||||
Stream_Read_UINT16(s, component); /* Component (2 bytes) */
|
||||
Stream_Read_UINT16(s, packetId); /* PacketId (2 bytes) */
|
||||
|
||||
if (component == RDPDR_CTYP_CORE)
|
||||
if (Stream_GetRemainingLength(s) >= 4)
|
||||
{
|
||||
switch (packetId)
|
||||
Stream_Read_UINT16(s, component); /* Component (2 bytes) */
|
||||
Stream_Read_UINT16(s, packetId); /* PacketId (2 bytes) */
|
||||
|
||||
if (component == RDPDR_CTYP_CORE)
|
||||
{
|
||||
case PAKID_CORE_SERVER_ANNOUNCE:
|
||||
if ((error = rdpdr_process_server_announce_request(rdpdr, s)))
|
||||
return error;
|
||||
switch (packetId)
|
||||
{
|
||||
case PAKID_CORE_SERVER_ANNOUNCE:
|
||||
if ((error = rdpdr_process_server_announce_request(rdpdr, s)))
|
||||
{
|
||||
}
|
||||
else if ((error = rdpdr_send_client_announce_reply(rdpdr)))
|
||||
{
|
||||
WLog_ERR(TAG, "rdpdr_send_client_announce_reply failed with error %"PRIu32"", error);
|
||||
}
|
||||
else if ((error = rdpdr_send_client_name_request(rdpdr)))
|
||||
{
|
||||
WLog_ERR(TAG, "rdpdr_send_client_name_request failed with error %"PRIu32"", error);
|
||||
}
|
||||
else if ((error = rdpdr_process_init(rdpdr)))
|
||||
{
|
||||
WLog_ERR(TAG, "rdpdr_process_init failed with error %"PRIu32"", error);
|
||||
}
|
||||
|
||||
if ((error = rdpdr_send_client_announce_reply(rdpdr)))
|
||||
{
|
||||
WLog_ERR(TAG, "rdpdr_send_client_announce_reply failed with error %"PRIu32"", error);
|
||||
return error;
|
||||
}
|
||||
break;
|
||||
|
||||
if ((error = rdpdr_send_client_name_request(rdpdr)))
|
||||
{
|
||||
WLog_ERR(TAG, "rdpdr_send_client_name_request failed with error %"PRIu32"", error);
|
||||
return error;
|
||||
}
|
||||
case PAKID_CORE_SERVER_CAPABILITY:
|
||||
if ((error = rdpdr_process_capability_request(rdpdr, s)))
|
||||
{
|
||||
}
|
||||
else if ((error = rdpdr_send_capability_response(rdpdr)))
|
||||
{
|
||||
WLog_ERR(TAG, "rdpdr_send_capability_response failed with error %"PRIu32"", error);
|
||||
}
|
||||
|
||||
if ((error = rdpdr_process_init(rdpdr)))
|
||||
{
|
||||
WLog_ERR(TAG, "rdpdr_process_init failed with error %"PRIu32"", error);
|
||||
return error;
|
||||
}
|
||||
break;
|
||||
|
||||
break;
|
||||
case PAKID_CORE_CLIENTID_CONFIRM:
|
||||
if ((error = rdpdr_process_server_clientid_confirm(rdpdr, s)))
|
||||
{
|
||||
}
|
||||
else if ((error = rdpdr_send_device_list_announce_request(rdpdr, FALSE)))
|
||||
{
|
||||
WLog_ERR(TAG, "rdpdr_send_device_list_announce_request failed with error %"PRIu32"",
|
||||
error);
|
||||
}
|
||||
|
||||
case PAKID_CORE_SERVER_CAPABILITY:
|
||||
if ((error = rdpdr_process_capability_request(rdpdr, s)))
|
||||
return error;
|
||||
break;
|
||||
|
||||
if ((error = rdpdr_send_capability_response(rdpdr)))
|
||||
{
|
||||
WLog_ERR(TAG, "rdpdr_send_capability_response failed with error %"PRIu32"", error);
|
||||
return error;
|
||||
}
|
||||
case PAKID_CORE_USER_LOGGEDON:
|
||||
if ((error = rdpdr_send_device_list_announce_request(rdpdr, TRUE)))
|
||||
{
|
||||
WLog_ERR(TAG, "rdpdr_send_device_list_announce_request failed with error %"PRIu32"",
|
||||
error);
|
||||
}
|
||||
|
||||
break;
|
||||
break;
|
||||
|
||||
case PAKID_CORE_CLIENTID_CONFIRM:
|
||||
if ((error = rdpdr_process_server_clientid_confirm(rdpdr, s)))
|
||||
return error;
|
||||
case PAKID_CORE_DEVICE_REPLY:
|
||||
|
||||
if ((error = rdpdr_send_device_list_announce_request(rdpdr, FALSE)))
|
||||
{
|
||||
WLog_ERR(TAG, "rdpdr_send_device_list_announce_request failed with error %"PRIu32"",
|
||||
error);
|
||||
return error;
|
||||
}
|
||||
/* connect to a specific resource */
|
||||
if (Stream_GetRemainingLength(s) >= 8)
|
||||
{
|
||||
Stream_Read_UINT32(s, deviceId);
|
||||
Stream_Read_UINT32(s, status);
|
||||
error = CHANNEL_RC_OK;
|
||||
}
|
||||
|
||||
break;
|
||||
break;
|
||||
|
||||
case PAKID_CORE_USER_LOGGEDON:
|
||||
if ((error = rdpdr_send_device_list_announce_request(rdpdr, TRUE)))
|
||||
{
|
||||
WLog_ERR(TAG, "rdpdr_send_device_list_announce_request failed with error %"PRIu32"",
|
||||
error);
|
||||
return error;
|
||||
}
|
||||
case PAKID_CORE_DEVICE_IOREQUEST:
|
||||
if ((error = rdpdr_process_irp(rdpdr, s)))
|
||||
{
|
||||
WLog_ERR(TAG, "rdpdr_process_irp failed with error %"PRIu32"", error);
|
||||
return error;
|
||||
}
|
||||
else
|
||||
s = NULL;
|
||||
|
||||
break;
|
||||
break;
|
||||
|
||||
case PAKID_CORE_DEVICE_REPLY:
|
||||
|
||||
/* connect to a specific resource */
|
||||
if (Stream_GetRemainingLength(s) < 8)
|
||||
return ERROR_INVALID_DATA;
|
||||
|
||||
Stream_Read_UINT32(s, deviceId);
|
||||
Stream_Read_UINT32(s, status);
|
||||
break;
|
||||
|
||||
case PAKID_CORE_DEVICE_IOREQUEST:
|
||||
if ((error = rdpdr_process_irp(rdpdr, s)))
|
||||
{
|
||||
WLog_ERR(TAG, "rdpdr_process_irp failed with error %"PRIu32"", error);
|
||||
return error;
|
||||
}
|
||||
|
||||
s = NULL;
|
||||
break;
|
||||
|
||||
default:
|
||||
WLog_ERR(TAG, "RDPDR_CTYP_CORE unknown PacketId: 0x%04"PRIX16"", packetId);
|
||||
return ERROR_INVALID_DATA;
|
||||
break;
|
||||
default:
|
||||
WLog_ERR(TAG, "RDPDR_CTYP_CORE unknown PacketId: 0x%04"PRIX16"", packetId);
|
||||
error = ERROR_INVALID_DATA;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (component == RDPDR_CTYP_PRN)
|
||||
{
|
||||
switch (packetId)
|
||||
else
|
||||
{
|
||||
case PAKID_PRN_CACHE_DATA:
|
||||
{
|
||||
UINT32 eventID;
|
||||
error = rdpdr_process_component(rdpdr, component, packetId, s);
|
||||
|
||||
if (Stream_GetRemainingLength(s) < 4)
|
||||
return ERROR_INVALID_DATA;
|
||||
|
||||
Stream_Read_UINT32(s, eventID);
|
||||
WLog_ERR(TAG,
|
||||
"Ignoring unhandled message PAKID_PRN_CACHE_DATA (EventID: 0x%08"PRIX32")", eventID);
|
||||
}
|
||||
break;
|
||||
|
||||
case PAKID_PRN_USING_XPS:
|
||||
WLog_ERR(TAG, "Ignoring unhandled message PAKID_PRN_USING_XPS");
|
||||
break;
|
||||
|
||||
default:
|
||||
WLog_ERR(TAG, "Unknown printing component packetID: 0x%04"PRIX16"", packetId);
|
||||
return ERROR_INVALID_DATA;
|
||||
if (error != CHANNEL_RC_OK)
|
||||
{
|
||||
WLog_ERR(TAG, "Unknown message: Component: 0x%04"PRIX16" PacketId: 0x%04"PRIX16"", component,
|
||||
packetId);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
WLog_ERR(TAG, "Unknown message: Component: 0x%04"PRIX16" PacketId: 0x%04"PRIX16"", component,
|
||||
packetId);
|
||||
return ERROR_INVALID_DATA;
|
||||
}
|
||||
|
||||
Stream_Free(s, TRUE);
|
||||
return CHANNEL_RC_OK;
|
||||
return error;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -316,6 +316,8 @@ typedef struct _DEVICE DEVICE;
|
||||
typedef struct _IRP IRP;
|
||||
typedef struct _DEVMAN DEVMAN;
|
||||
|
||||
typedef UINT(*pcCustomComponentRequest)(DEVICE* device, UINT16 component, UINT16 packetId,
|
||||
wStream* s);
|
||||
typedef UINT(*pcIRPRequest)(DEVICE* device, IRP* irp);
|
||||
typedef UINT(*pcInitDevice)(DEVICE* device);
|
||||
typedef UINT(*pcFreeDevice)(DEVICE* device);
|
||||
@@ -328,6 +330,7 @@ struct _DEVICE
|
||||
const char* name;
|
||||
wStream* data;
|
||||
|
||||
pcCustomComponentRequest CustomComponentRequest;
|
||||
pcIRPRequest IRPRequest;
|
||||
pcInitDevice Init;
|
||||
pcFreeDevice Free;
|
||||
|
||||
Reference in New Issue
Block a user