server: proxy: cliprdr support
authorkubistika <kmizrachi18@gmail.com>
Sun, 4 Aug 2019 14:41:43 +0000 (17:41 +0300)
committerakallabeth <akallabeth@users.noreply.github.com>
Mon, 19 Aug 2019 07:30:40 +0000 (09:30 +0200)
server/proxy/CMakeLists.txt
server/proxy/config.ini
server/proxy/pf_channels.c
server/proxy/pf_cliprdr.c [new file with mode: 0644]
server/proxy/pf_cliprdr.h [new file with mode: 0644]
server/proxy/pf_config.c
server/proxy/pf_config.h
server/proxy/pf_context.h
server/proxy/pf_server.c

index 727d469..557cdef 100644 (file)
@@ -45,7 +45,9 @@ set(${MODULE_PREFIX}_SRCS
   pf_graphics.h
   pf_filters.c
   pf_filters.h
-  pf_log.h)
+  pf_log.h
+  pf_cliprdr.c
+  pf_cliprdr.h)
 
 # On windows create dll version information.
 # Vendor, product and year are already set in top level CMakeLists.txt
index 91c1b23..4ac80a7 100644 (file)
@@ -26,6 +26,11 @@ RdpSecurity = 1
 [Channels]
 GFX = 1
 DisplayControl = 1
+Clipboard = 1
+
+[Clipboard]
+TextOnly = 1
+MaxTextLength = 10 # 0 for no limit.
 
 [Filters]
 ; FilterName = FilterPath
index ff73137..d03ddb0 100644 (file)
@@ -36,8 +36,9 @@
 #include "pf_client.h"
 #include "pf_context.h"
 #include "pf_rdpgfx.h"
-#include "pf_log.h"
+#include "pf_cliprdr.h"
 #include "pf_disp.h"
+#include "pf_log.h"
 
 #define TAG PROXY_TAG("channels")
 
@@ -75,6 +76,17 @@ void pf_OnChannelConnectedEventHandler(void* data,
                pc->disp = (DispClientContext*) e->pInterface;
                pf_disp_register_callbacks(pc->disp, ps->disp, pc->pdata);
        }
+       else if (strcmp(e->name, CLIPRDR_SVC_CHANNEL_NAME) == 0)
+       {
+               if (ps->cliprdr->Start(ps->cliprdr) != CHANNEL_RC_OK)
+               {
+                       WLog_ERR(TAG, "failed to open cliprdr channel");
+                       return;
+               }
+
+               pc->cliprdr = (CliprdrClientContext*) e->pInterface;
+               pf_cliprdr_register_callbacks(pc->cliprdr, ps->cliprdr, pc->pdata);
+       }
 }
 
 void pf_OnChannelDisconnectedEventHandler(void* data,
@@ -104,6 +116,13 @@ void pf_OnChannelDisconnectedEventHandler(void* data,
 
                pc->disp = NULL;
        }
+       else if (strcmp(e->name, CLIPRDR_SVC_CHANNEL_NAME) == 0)
+       {
+               if (ps->cliprdr->Stop(ps->cliprdr) != CHANNEL_RC_OK)
+                       WLog_ERR(TAG, "failed to stop cliprdr server");
+
+               pc->cliprdr = NULL;
+       }
 }
 
 BOOL pf_server_channels_init(pServerContext* ps)
@@ -123,6 +142,12 @@ BOOL pf_server_channels_init(pServerContext* ps)
                        return FALSE;
        }
 
+       if (config->Clipboard && WTSVirtualChannelManagerIsChannelJoined(ps->vcm, CLIPRDR_SVC_CHANNEL_NAME))
+       {
+               if (!pf_server_cliprdr_init(ps))
+                       return FALSE;
+       }
+
        return TRUE;
 }
 
@@ -139,4 +164,10 @@ void pf_server_channels_free(pServerContext* ps)
                disp_server_context_free(ps->disp);
                ps->disp = NULL;
        }
+
+       if (ps->cliprdr)
+       {
+               cliprdr_server_context_free(ps->cliprdr);
+               ps->cliprdr = NULL;
+       }
 }
diff --git a/server/proxy/pf_cliprdr.c b/server/proxy/pf_cliprdr.c
new file mode 100644 (file)
index 0000000..92337b5
--- /dev/null
@@ -0,0 +1,428 @@
+/**
+ * FreeRDP: A Remote Desktop Protocol Implementation
+ * FreeRDP Proxy Server
+ *
+ * Copyright 2019 Kobi Mizrachi <kmizrachi18@gmail.com>
+ * Copyright 2019 Idan Freiberg <speidy@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 "pf_cliprdr.h"
+#include "pf_log.h"
+
+#define TAG PROXY_TAG("cliprdr")
+#define TEXT_FORMATS_COUNT 2
+
+/* used for createing a fake format list response, containing only text formats */
+static CLIPRDR_FORMAT g_text_formats[] = { { CF_TEXT, '\0' }, { CF_UNICODETEXT, '\0' } };
+
+BOOL pf_server_cliprdr_init(pServerContext* ps)
+{
+       CliprdrServerContext* cliprdr;
+       cliprdr = ps->cliprdr = cliprdr_server_context_new(ps->vcm);
+
+       if (!cliprdr)
+       {
+               WLog_ERR(TAG, "cliprdr_server_context_new failed.");
+               return FALSE;
+       }
+
+       cliprdr->rdpcontext = (rdpContext*)ps;
+
+       /* enable all capabilities */
+       cliprdr->useLongFormatNames = TRUE;
+       cliprdr->streamFileClipEnabled = TRUE;
+       cliprdr->fileClipNoFilePaths = TRUE;
+       cliprdr->canLockClipData = TRUE;
+
+       /* disable initialization sequence, for caps sync */
+       cliprdr->autoInitializationSequence = FALSE;
+       return TRUE;
+}
+
+static INLINE BOOL pf_cliprdr_is_text_format(UINT32 format)
+{
+       switch (format)
+       {
+               case CF_TEXT:
+               case CF_UNICODETEXT:
+                       return TRUE;
+       }
+
+       return FALSE;
+}
+
+static INLINE void pf_cliprdr_create_text_only_format_list(CLIPRDR_FORMAT_LIST* list)
+{
+       list->msgFlags = CB_RESPONSE_OK;
+       list->msgType = CB_FORMAT_LIST;
+       list->dataLen = (4 + 1) * TEXT_FORMATS_COUNT;
+       list->numFormats = TEXT_FORMATS_COUNT;
+       list->formats = g_text_formats;
+}
+
+/* format data response PDU returns the copied text as a unicode buffer.
+ * pf_cliprdr_is_copy_paste_valid returns TRUE if the length of the copied
+ * text is valid according to the configuration value of `MaxTextLength`.
+ */
+static BOOL pf_cliprdr_is_copy_paste_valid(proxyConfig* config,
+        const CLIPRDR_FORMAT_DATA_RESPONSE* pdu, UINT32 format)
+{
+       size_t copy_len;
+       if (config->MaxTextLength == 0)
+       {
+               /* no size limit */
+               return TRUE;
+       }
+
+       if (pdu->dataLen == 0)
+       {
+               /* no data */
+               return FALSE;
+       }
+
+       WLog_DBG(TAG, "pf_cliprdr_is_copy_paste_valid(): checking format %"PRIu32"", format);
+
+       switch (format)
+       {
+               case CF_UNICODETEXT:
+                       copy_len = (pdu->dataLen / 2) - 1;
+                       break;
+               case CF_TEXT:
+                       copy_len = pdu->dataLen;
+                       break;
+               default:
+                       WLog_WARN(TAG, "received unknown format: %"PRIu32", format");
+                       return FALSE;
+       }
+
+       if (copy_len > config->MaxTextLength)
+       {
+               WLog_WARN(TAG, "text size is too large: %"PRIu32" (max %"PRIu32")", copy_len,
+                         config->MaxTextLength);
+               return FALSE;
+       }
+
+       return TRUE;
+}
+
+/*
+ * if the requested text size is too long, we need a way to return a message to the other side of
+ * the connection, indicating that the copy/paste operation failed, instead of just not forwarding
+ * the response (because that destroys the state of the RDPECLIP channel). This is done by sending a
+ * `format_data_response` PDU with msgFlags = CB_RESPONSE_FAIL.
+ */
+static INLINE void pf_cliprdr_create_failed_format_data_response(CLIPRDR_FORMAT_DATA_RESPONSE* dst)
+{
+       dst->requestedFormatData = NULL;
+       dst->dataLen = 0;
+       dst->msgType = CB_FORMAT_DATA_RESPONSE;
+       dst->msgFlags = CB_RESPONSE_FAIL;
+}
+
+/* server callbacks */
+static UINT pf_cliprdr_ClientCapabilities(CliprdrServerContext* context,
+        const CLIPRDR_CAPABILITIES* capabilities)
+{
+       proxyData* pdata = (proxyData*) context->custom;
+       CliprdrClientContext* client = pdata->pc->cliprdr;
+       WLog_VRB(TAG, __FUNCTION__);
+       return client->ClientCapabilities(client, capabilities);
+}
+
+static UINT pf_cliprdr_TempDirectory(CliprdrServerContext* context,
+                                     const CLIPRDR_TEMP_DIRECTORY* tempDirectory)
+{
+       proxyData* pdata = (proxyData*) context->custom;
+       CliprdrClientContext* client = pdata->pc->cliprdr;
+       WLog_VRB(TAG, __FUNCTION__);
+       return client->TempDirectory(client, tempDirectory);
+}
+
+static UINT pf_cliprdr_ClientFormatList(CliprdrServerContext* context,
+                                        const CLIPRDR_FORMAT_LIST* formatList)
+{
+       proxyData* pdata = (proxyData*) context->custom;
+       CliprdrClientContext* client = pdata->pc->cliprdr;
+       WLog_VRB(TAG, __FUNCTION__);
+
+       if (pdata->config->TextOnly)
+       {
+               CLIPRDR_FORMAT_LIST list;
+               pf_cliprdr_create_text_only_format_list(&list);
+               return client->ClientFormatList(client, &list);
+       }
+
+       /* send a format list that allows only text */
+       return client->ClientFormatList(client, formatList);
+}
+
+static UINT pf_cliprdr_ClientFormatListResponse(CliprdrServerContext* context,
+        const CLIPRDR_FORMAT_LIST_RESPONSE* formatListResponse)
+{
+       proxyData* pdata = (proxyData*) context->custom;
+       CliprdrClientContext* client = pdata->pc->cliprdr;
+       WLog_VRB(TAG, __FUNCTION__);
+       return client->ClientFormatListResponse(client, formatListResponse);
+}
+
+static UINT pf_cliprdr_ClientLockClipboardData(CliprdrServerContext* context,
+        const CLIPRDR_LOCK_CLIPBOARD_DATA* lockClipboardData)
+{
+       proxyData* pdata = (proxyData*) context->custom;
+       CliprdrClientContext* client = pdata->pc->cliprdr;
+       WLog_VRB(TAG, __FUNCTION__);
+       return client->ClientLockClipboardData(client, lockClipboardData);
+}
+
+static UINT pf_cliprdr_ClientUnlockClipboardData(CliprdrServerContext* context,
+        const CLIPRDR_UNLOCK_CLIPBOARD_DATA* unlockClipboardData)
+{
+       proxyData* pdata = (proxyData*) context->custom;
+       CliprdrClientContext* client = pdata->pc->cliprdr;
+       WLog_VRB(TAG, __FUNCTION__);
+       return client->ClientUnlockClipboardData(client, unlockClipboardData);
+}
+
+static UINT pf_cliprdr_ClientFormatDataRequest(CliprdrServerContext* context,
+        const CLIPRDR_FORMAT_DATA_REQUEST* formatDataRequest)
+{
+       proxyData* pdata = (proxyData*) context->custom;
+       CliprdrClientContext* client = pdata->pc->cliprdr;
+       CliprdrServerContext* server = pdata->ps->cliprdr;
+       WLog_VRB(TAG, __FUNCTION__);
+
+       if (pdata->config->TextOnly &&
+           !pf_cliprdr_is_text_format(formatDataRequest->requestedFormatId))
+       {
+               CLIPRDR_FORMAT_DATA_RESPONSE resp;
+               pf_cliprdr_create_failed_format_data_response(&resp);
+               return server->ServerFormatDataResponse(server, &resp);
+       }
+
+       return client->ClientFormatDataRequest(client, formatDataRequest);
+}
+
+static UINT pf_cliprdr_ClientFormatDataResponse(CliprdrServerContext* context,
+        const CLIPRDR_FORMAT_DATA_RESPONSE* formatDataResponse)
+{
+       proxyData* pdata = (proxyData*) context->custom;
+       CliprdrClientContext* client = pdata->pc->cliprdr;
+       WLog_VRB(TAG, __FUNCTION__);
+
+       if (pf_cliprdr_is_text_format(client->lastRequestedFormatId))
+       {
+               if (!pf_cliprdr_is_copy_paste_valid(pdata->config, formatDataResponse, client->lastRequestedFormatId))
+               {
+                       CLIPRDR_FORMAT_DATA_RESPONSE resp;
+                       pf_cliprdr_create_failed_format_data_response(&resp);
+                       return client->ClientFormatDataResponse(client, &resp);
+               }
+       }
+
+       return client->ClientFormatDataResponse(client, formatDataResponse);
+}
+
+static UINT pf_cliprdr_ClientFileContentsRequest(CliprdrServerContext* context,
+        const CLIPRDR_FILE_CONTENTS_REQUEST* fileContentsRequest)
+{
+       proxyData* pdata = (proxyData*) context->custom;
+       CliprdrClientContext* client = pdata->pc->cliprdr;
+       WLog_VRB(TAG, __FUNCTION__);
+
+       if (pdata->config->TextOnly)
+               return CHANNEL_RC_OK;
+
+       return client->ClientFileContentsRequest(client, fileContentsRequest);
+}
+
+static UINT pf_cliprdr_ClientFileContentsResponse(CliprdrServerContext* context,
+        const CLIPRDR_FILE_CONTENTS_RESPONSE* fileContentsResponse)
+{
+       proxyData* pdata = (proxyData*) context->custom;
+       CliprdrClientContext* client = pdata->pc->cliprdr;
+       WLog_VRB(TAG, __FUNCTION__);
+
+       if (pdata->config->TextOnly)
+               return CHANNEL_RC_OK;
+
+       return client->ClientFileContentsResponse(client, fileContentsResponse);
+}
+
+/* client callbacks */
+
+static UINT pf_cliprdr_ServerCapabilities(CliprdrClientContext* context,
+        const CLIPRDR_CAPABILITIES* capabilities)
+{
+       proxyData* pdata = (proxyData*) context->custom;
+       CliprdrServerContext* server = pdata->ps->cliprdr;
+       WLog_VRB(TAG, __FUNCTION__);
+       return server->ServerCapabilities(server, capabilities);
+}
+
+static UINT pf_cliprdr_MonitorReady(CliprdrClientContext* context,
+                                    const CLIPRDR_MONITOR_READY* monitorReady)
+{
+       proxyData* pdata = (proxyData*) context->custom;
+       CliprdrServerContext* server = pdata->ps->cliprdr;
+       WLog_VRB(TAG, __FUNCTION__);
+       return server->MonitorReady(server, monitorReady);
+}
+
+static UINT pf_cliprdr_ServerFormatList(CliprdrClientContext* context,
+                                        const CLIPRDR_FORMAT_LIST* formatList)
+{
+       proxyData* pdata = (proxyData*) context->custom;
+       CliprdrServerContext* server = pdata->ps->cliprdr;
+       WLog_VRB(TAG, __FUNCTION__);
+
+       if (pdata->config->TextOnly)
+       {
+               CLIPRDR_FORMAT_LIST list;
+               pf_cliprdr_create_text_only_format_list(&list);
+               return server->ServerFormatList(server, &list);
+       }
+
+       return server->ServerFormatList(server, formatList);
+}
+
+
+static UINT pf_cliprdr_ServerFormatListResponse(CliprdrClientContext* context,
+        const CLIPRDR_FORMAT_LIST_RESPONSE* formatListResponse)
+{
+       proxyData* pdata = (proxyData*) context->custom;
+       CliprdrServerContext* server = pdata->ps->cliprdr;
+       WLog_VRB(TAG, __FUNCTION__);
+       return server->ServerFormatListResponse(server, formatListResponse);
+}
+
+
+static UINT pf_cliprdr_ServerLockClipboardData(CliprdrClientContext* context,
+        const CLIPRDR_LOCK_CLIPBOARD_DATA* lockClipboardData)
+{
+       proxyData* pdata = (proxyData*) context->custom;
+       CliprdrServerContext* server = pdata->ps->cliprdr;
+       WLog_VRB(TAG, __FUNCTION__);
+       return server->ServerLockClipboardData(server, lockClipboardData);
+}
+
+
+static UINT pf_cliprdr_ServerUnlockClipboardData(CliprdrClientContext* context,
+        const CLIPRDR_UNLOCK_CLIPBOARD_DATA* unlockClipboardData)
+{
+       proxyData* pdata = (proxyData*) context->custom;
+       CliprdrServerContext* server = pdata->ps->cliprdr;
+       WLog_VRB(TAG, __FUNCTION__);
+       return server->ServerUnlockClipboardData(server, unlockClipboardData);
+}
+
+
+static UINT pf_cliprdr_ServerFormatDataRequest(CliprdrClientContext* context,
+        const CLIPRDR_FORMAT_DATA_REQUEST* formatDataRequest)
+{
+       proxyData* pdata = (proxyData*) context->custom;
+       CliprdrServerContext* server = pdata->ps->cliprdr;
+       CliprdrClientContext* client = pdata->pc->cliprdr;
+       WLog_VRB(TAG, __FUNCTION__);
+
+       if (pdata->config->TextOnly &&
+           !pf_cliprdr_is_text_format(formatDataRequest->requestedFormatId))
+       {
+               /* proxy's client needs to return a failed response directly to the client */
+               CLIPRDR_FORMAT_DATA_RESPONSE resp;
+               pf_cliprdr_create_failed_format_data_response(&resp);
+               return client->ClientFormatDataResponse(client, &resp);
+       }
+
+       return server->ServerFormatDataRequest(server, formatDataRequest);
+}
+
+static UINT pf_cliprdr_ServerFormatDataResponse(CliprdrClientContext* context,
+        const CLIPRDR_FORMAT_DATA_RESPONSE* formatDataResponse)
+{
+       proxyData* pdata = (proxyData*) context->custom;
+       CliprdrServerContext* server = pdata->ps->cliprdr;
+       WLog_VRB(TAG, __FUNCTION__);
+
+       if (pf_cliprdr_is_text_format(server->lastRequestedFormatId))
+       {
+               if (!pf_cliprdr_is_copy_paste_valid(pdata->config, formatDataResponse, server->lastRequestedFormatId))
+               {
+                       CLIPRDR_FORMAT_DATA_RESPONSE resp;
+                       pf_cliprdr_create_failed_format_data_response(&resp);
+                       return server->ServerFormatDataResponse(server, &resp);
+               }
+       }
+
+       return server->ServerFormatDataResponse(server, formatDataResponse);
+}
+
+
+static UINT pf_cliprdr_ServerFileContentsRequest(CliprdrClientContext* context,
+        const CLIPRDR_FILE_CONTENTS_REQUEST* fileContentsRequest)
+{
+       proxyData* pdata = (proxyData*) context->custom;
+       CliprdrServerContext* server = pdata->ps->cliprdr;
+       WLog_VRB(TAG, __FUNCTION__);
+
+       if (pdata->config->TextOnly)
+               return CHANNEL_RC_OK;
+
+       return server->ServerFileContentsRequest(server, fileContentsRequest);
+}
+
+
+static UINT pf_cliprdr_ServerFileContentsResponse(CliprdrClientContext* context,
+        const CLIPRDR_FILE_CONTENTS_RESPONSE* fileContentsResponse)
+{
+       proxyData* pdata = (proxyData*) context->custom;
+       CliprdrServerContext* server = pdata->ps->cliprdr;
+       WLog_VRB(TAG, __FUNCTION__);
+
+       if (pdata->config->TextOnly)
+               return CHANNEL_RC_OK;
+
+       return server->ServerFileContentsResponse(server, fileContentsResponse);
+}
+
+void pf_cliprdr_register_callbacks(CliprdrClientContext* cliprdr_client,
+                                 CliprdrServerContext* cliprdr_server,
+                                 proxyData* pdata)
+{
+       /* Set server and client side references to proxy data */
+       cliprdr_server->custom = (void*) pdata;
+       cliprdr_client->custom = (void*) pdata;
+       /* Set server callbacks */
+       cliprdr_server->ClientCapabilities = pf_cliprdr_ClientCapabilities;
+       cliprdr_server->TempDirectory = pf_cliprdr_TempDirectory;
+       cliprdr_server->ClientFormatList = pf_cliprdr_ClientFormatList;
+       cliprdr_server->ClientFormatListResponse = pf_cliprdr_ClientFormatListResponse;
+       cliprdr_server->ClientLockClipboardData = pf_cliprdr_ClientLockClipboardData;
+       cliprdr_server->ClientUnlockClipboardData = pf_cliprdr_ClientUnlockClipboardData;
+       cliprdr_server->ClientFormatDataRequest = pf_cliprdr_ClientFormatDataRequest;
+       cliprdr_server->ClientFormatDataResponse = pf_cliprdr_ClientFormatDataResponse;
+       cliprdr_server->ClientFileContentsRequest = pf_cliprdr_ClientFileContentsRequest;
+       cliprdr_server->ClientFileContentsResponse = pf_cliprdr_ClientFileContentsResponse;
+       /* Set client callbacks */
+       cliprdr_client->ServerCapabilities = pf_cliprdr_ServerCapabilities;
+       cliprdr_client->MonitorReady = pf_cliprdr_MonitorReady;
+       cliprdr_client->ServerFormatList = pf_cliprdr_ServerFormatList;
+       cliprdr_client->ServerFormatListResponse = pf_cliprdr_ServerFormatListResponse;
+       cliprdr_client->ServerLockClipboardData = pf_cliprdr_ServerLockClipboardData;
+       cliprdr_client->ServerUnlockClipboardData = pf_cliprdr_ServerUnlockClipboardData;
+       cliprdr_client->ServerFormatDataRequest = pf_cliprdr_ServerFormatDataRequest;
+       cliprdr_client->ServerFormatDataResponse = pf_cliprdr_ServerFormatDataResponse;
+       cliprdr_client->ServerFileContentsRequest = pf_cliprdr_ServerFileContentsRequest;
+       cliprdr_client->ServerFileContentsResponse = pf_cliprdr_ServerFileContentsResponse;
+}
\ No newline at end of file
diff --git a/server/proxy/pf_cliprdr.h b/server/proxy/pf_cliprdr.h
new file mode 100644 (file)
index 0000000..5c79571
--- /dev/null
@@ -0,0 +1,34 @@
+/**
+ * FreeRDP: A Remote Desktop Protocol Implementation
+ * FreeRDP Proxy Server
+ *
+ * Copyright 2019 Kobi Mizrachi <kmizrachi18@gmail.com>
+ * Copyright 2019 Idan Freiberg <speidy@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.
+ */
+
+#ifndef FREERDP_SERVER_PROXY_PFCLIPRDR_H
+#define FREERDP_SERVER_PROXY_PFCLIPRDR_H
+
+#include <freerdp/client/cliprdr.h>
+#include <freerdp/server/cliprdr.h>
+
+#include "pf_context.h"
+
+BOOL pf_server_cliprdr_init(pServerContext* ps);
+void pf_cliprdr_register_callbacks(CliprdrClientContext* cliprdr_client,
+                                 CliprdrServerContext* cliprdr_server,
+                                 proxyData* pdata);
+
+#endif /* FREERDP_SERVER_PROXY_PFCLIPRDR_H */
index d7784c1..04921ad 100644 (file)
@@ -34,6 +34,7 @@
 #define CONFIG_PRINT_STR(config, key) WLog_INFO(TAG, "\t\t%s: %s", #key, config->key)
 #define CONFIG_PRINT_BOOL(config, key) WLog_INFO(TAG, "\t\t%s: %s", #key, config->key ? "TRUE" : "FALSE")
 #define CONFIG_PRINT_UINT16(config, key) WLog_INFO(TAG, "\t\t%s: %"PRIu16"", #key, config->key);
+#define CONFIG_PRINT_UINT32(config, key) WLog_INFO(TAG, "\t\t%s: %"PRIu32"", #key, config->key);
 
 #define CONFIG_GET_STR(ini, section, key) IniFile_GetKeyValueString(ini, section, key)
 #define CONFIG_GET_BOOL(ini, section, key) IniFile_GetKeyValueInt(ini, section, key)
@@ -79,6 +80,7 @@ static BOOL pf_config_load_channels(wIniFile* ini, proxyConfig* config)
 {
        config->GFX = CONFIG_GET_BOOL(ini, "Channels", "GFX");
        config->DisplayControl = CONFIG_GET_BOOL(ini, "Channels", "DisplayControl");
+       config->Clipboard = CONFIG_GET_BOOL(ini, "Channels", "Clipboard");
        return TRUE;
 }
 
@@ -193,6 +195,12 @@ void pf_server_config_print(proxyConfig* config)
        CONFIG_PRINT_SECTION("Channels");
        CONFIG_PRINT_BOOL(config, GFX);
        CONFIG_PRINT_BOOL(config, DisplayControl);
+       CONFIG_PRINT_BOOL(config, Clipboard);
+
+       CONFIG_PRINT_SECTION("Clipboard");
+       CONFIG_PRINT_BOOL(config, TextOnly);
+       if (config->MaxTextLength > 0)
+               CONFIG_PRINT_UINT32(config, MaxTextLength);
 }
 
 void pf_server_config_free(proxyConfig* config)
index 6881224..e7026db 100644 (file)
@@ -50,9 +50,14 @@ struct proxy_config
        /* channels */
        BOOL GFX;
        BOOL DisplayControl;
+       BOOL Clipboard;
 
        /* filters */
        filters_list* Filters;
+
+       /* clipboard specific settings*/
+       BOOL TextOnly;
+       UINT32 MaxTextLength;
 };
 
 typedef struct proxy_config proxyConfig;
index c57544c..c6e1173 100644 (file)
@@ -29,6 +29,7 @@
 #include <freerdp/server/rdpgfx.h>
 #include <freerdp/client/disp.h>
 #include <freerdp/server/disp.h>
+#include <freerdp/server/cliprdr.h>
 
 #include "pf_config.h"
 #include "pf_server.h"
@@ -50,6 +51,7 @@ struct p_server_context
 
        RdpgfxServerContext* gfx;
        DispServerContext* disp;
+       CliprdrServerContext* cliprdr;
 };
 typedef struct p_server_context pServerContext;
 
@@ -65,6 +67,7 @@ struct p_client_context
        RdpeiClientContext* rdpei;
        RdpgfxClientContext* gfx;
        DispClientContext* disp;
+       CliprdrClientContext* cliprdr;
 
        /*
         * In a case when freerdp_connect fails,
index 961634a..b40b4f1 100644 (file)
@@ -47,6 +47,7 @@
 #include "pf_context.h"
 #include "pf_input.h"
 #include "pf_update.h"
+#include "pf_channels.h"
 #include "pf_rdpgfx.h"
 #include "pf_disp.h"
 #include "pf_channels.h"
@@ -232,6 +233,7 @@ static DWORD WINAPI pf_server_handle_client(LPVOID arg)
        pdata->config = client->ContextExtra;
        config = pdata->config;
        client->settings->UseMultimon = TRUE;
+       client->settings->RedirectClipboard = config->Clipboard;
        client->settings->SupportGraphicsPipeline = config->GFX;
        client->settings->SupportDynamicChannels = TRUE;
        client->settings->CertificateFile = _strdup("server.crt");