6#include "ConnectFreeRDP.h"
8#undef PEN_FLAG_INVERTED
9#include "freerdp/client.h"
10#include "freerdp/client/channels.h"
11#include "freerdp/channels/rdpei.h"
12#include "freerdp/channels/rdpdr.h"
13#include "freerdp/channels/disp.h"
14#include "freerdp/channels/tsmf.h"
15#include "freerdp/channels/rdpsnd.h"
16#include "freerdp/client/encomsp.h"
17#include "freerdp/gdi/gfx.h"
18#include "freerdp/settings.h"
19#include "freerdp/locale/keyboard.h"
20#include "freerdp/channels/rdpgfx.h"
21#include "freerdp/channels/cliprdr.h"
22#include "freerdp/client/cmdline.h"
23#include <freerdp/gdi/video.h>
25#include "RabbitCommonTools.h"
26#include "ConvertKeyCode.h"
30#include <QApplication>
32#include <QSslCertificate>
33#include <QInputDialog>
34#include <QMutexLocker>
36#include <QPrinterInfo>
38#include <QSerialPortInfo>
39#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
40 #include <QSoundEffect>
45static Q_LOGGING_CATEGORY(log,
"FreeRDP.Connect")
46static Q_LOGGING_CATEGORY(logKey, "FreeRDP.Connect.Key")
47static Q_LOGGING_CATEGORY(logMouse, "FreeRDP.Connect.Mouse")
52 m_pParameter(
nullptr),
60 qDebug(log) << Q_FUNC_INFO;
61 m_pParameter = qobject_cast<CParameterFreeRDP*>(pConnecter->GetParameter());
62 Q_ASSERT(m_pParameter);
65CConnectFreeRDP::~CConnectFreeRDP()
67 qDebug(log) << Q_FUNC_INFO;
78 qDebug(log) << Q_FUNC_INFO;
81 m_writeEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
83 qCritical(log) <<
"CreateEvent failed";
85 ZeroMemory(&m_ClientEntryPoints,
sizeof(RDP_CLIENT_ENTRY_POINTS));
86 m_ClientEntryPoints.Version = RDP_CLIENT_INTERFACE_VERSION;
87 m_ClientEntryPoints.Size =
sizeof(RDP_CLIENT_ENTRY_POINTS);
89 m_ClientEntryPoints.GlobalInit = cbGlobalInit;
90 m_ClientEntryPoints.GlobalUninit = cbGlobalUninit;
91 m_ClientEntryPoints.ClientNew = cbClientNew;
92 m_ClientEntryPoints.ClientFree = cbClientFree;
93 m_ClientEntryPoints.ClientStart = cbClientStart;
94 m_ClientEntryPoints.ClientStop = cbClientStop;
97 auto pRdpContext = freerdp_client_context_new(&m_ClientEntryPoints);
101 m_pContext->pThis =
this;
103 qCritical(log) <<
"freerdp_client_context_new fail";
104 return OnInitReturnValue::Fail;
107 rdpSettings* settings = pRdpContext->settings;
109 qCritical(log) <<
"settings is null";
110 return OnInitReturnValue::Fail;
123 char* argv[]= {(
char*)QApplication::applicationFilePath().toStdString().c_str()};
124 int argc =
sizeof(argv) /
sizeof(
char*);
125 nRet = freerdp_client_settings_parse_command_line(settings, argc, argv, TRUE);
128 nRet = freerdp_client_settings_command_line_status_print(settings, nRet, argc, argv);
129 return OnInitReturnValue::Fail;
132#if FreeRDP_VERSION_MAJOR >= 3
133 if (!stream_dump_register_handlers(pRdpContext,
134 CONNECTION_STATE_MCS_CREATE_REQUEST,
136 return OnInitReturnValue::Fail;
139 auto &user = m_pParameter->m_Net.
m_User;
140 if(!user.GetUser().isEmpty())
141 freerdp_settings_set_string(
142 settings, FreeRDP_Username,
143 user.GetUser().toStdString().c_str());
144 if(!user.GetPassword().isEmpty())
145 freerdp_settings_set_string(
146 settings, FreeRDP_Password,
147 user.GetPassword().toStdString().c_str());
149 freerdp_settings_set_bool(
150 settings, FreeRDP_RedirectClipboard, m_pParameter->GetClipboard());
152#if FreeRDP_VERSION_MAJOR >= 3
153 bool bOnlyView = m_pParameter->GetOnlyView();
154 freerdp_settings_set_bool(
155 settings, FreeRDP_SuspendInput, bOnlyView);
158 freerdp_settings_set_uint32(settings, FreeRDP_DesktopWidth,
159 m_pParameter->GetDesktopWidth());
160 freerdp_settings_set_uint32(settings, FreeRDP_DesktopHeight,
161 m_pParameter->GetDesktopHeight());
162 freerdp_settings_set_uint32(settings, FreeRDP_ColorDepth,
163 m_pParameter->GetColorDepth());
165 freerdp_settings_set_bool(settings, FreeRDP_UseMultimon,
166 m_pParameter->GetUseMultimon());
168 if(m_pParameter->GetReconnectInterval()) {
169 freerdp_settings_set_bool(
170 settings, FreeRDP_AutoReconnectionEnabled,
true);
171 freerdp_settings_set_uint32(
173 FreeRDP_AutoReconnectMaxRetries,
174 m_pParameter->GetReconnectInterval());
177 freerdp_settings_set_bool(
178 settings, FreeRDP_AutoReconnectionEnabled,
false);
182 RedirectionMicrophone();
184 RedirectionPrinter();
189 switch(m_pParameter->m_Proxy.GetUsedType())
191 case CParameterProxy::TYPE::None:
193 if(!m_pParameter->GetDomain().isEmpty())
194 freerdp_settings_set_string(
195 settings, FreeRDP_Domain,
196 m_pParameter->GetDomain().toStdString().c_str());
197 if(m_pParameter->m_Net.GetHost().isEmpty())
200 szErr = tr(
"The server is empty, please input it");
201 qCritical(log) << szErr;
203 emit
sigError(-1, szErr.toStdString().c_str());
204 return OnInitReturnValue::Fail;
206 auto &net = m_pParameter->m_Net;
207 freerdp_settings_set_string(
208 settings, FreeRDP_ServerHostname,
209 net.GetHost().toStdString().c_str());
210 freerdp_settings_set_uint32(
211 settings, FreeRDP_ServerPort,
214 nRet = freerdp_client_start(pRdpContext);
217 qCritical(log) <<
"freerdp_client_start fail";
218 return OnInitReturnValue::Fail;
223 case CParameterProxy::TYPE::SSHTunnel:
227 auto &ssh = m_pParameter->m_Proxy.m_SSH;
228 parameter->setServer(ssh.GetHost());
229 parameter->setPort(ssh.GetPort());
231 parameter->SetUser(user.GetUser());
232 parameter->SetUseSystemFile(user.GetUseSystemFile());
233 if(CParameterUser::TYPE::UserPassword == user.GetUsedType()) {
234 parameter->SetAuthenticationMethod(SSH_AUTH_METHOD_PASSWORD);
235 parameter->SetPassword(user.GetPassword());
237 if(CParameterUser::TYPE::PublicKey == user.GetUsedType()) {
238 parameter->SetAuthenticationMethod(SSH_AUTH_METHOD_PUBLICKEY);
239 parameter->SetPublicKeyFile(user.GetPublicKeyFile());
240 parameter->SetPrivateKeyFile(user.GetPrivateKeyFile());
241 parameter->SetPassphrase(user.GetPassphrase());
243 auto &net = m_pParameter->m_Net;
244 parameter->SetRemoteHost(net.GetHost());
245 parameter->SetRemotePort(net.GetPort());
251 return OnInitReturnValue::Fail;
252 bool check = connect(m_pThread, SIGNAL(sigServer(QString, quint16)),
253 this, SLOT(slotConnectProxyServer(QString, quint16)));
255 check = connect(m_pThread, SIGNAL(
sigError(
int,QString)),
256 this, SIGNAL(
sigError(
int,QString)));
269 return OnInitReturnValue::UseOnProcess;
274 qDebug(log) << Q_FUNC_INFO;
286 CloseHandle(m_writeEvent);
287 m_writeEvent =
nullptr;
291 rdpContext* pRdpContext = (rdpContext*)m_pContext;
292 if(!freerdp_disconnect(pRdpContext->instance))
293 qCritical(log) <<
"freerdp_disconnect fail";
295 if(freerdp_client_stop(pRdpContext))
296 qCritical(log) <<
"freerdp_client_stop fail";
298 freerdp_client_context_free(pRdpContext);
299 m_pContext =
nullptr;
322 rdpContext* pRdpContext = (rdpContext*)m_pContext;
324 if(
nullptr == freerdp_settings_get_string(pRdpContext->settings, FreeRDP_ServerHostname))
332 nCount = freerdp_get_event_handles(pRdpContext, &handles[nCount],
333 ARRAYSIZE(handles) - nCount);
336 qCritical(log) <<
"freerdp_get_event_handles failed";
341 handles[nCount] = m_writeEvent;
344 DWORD waitStatus = WaitForMultipleObjects(nCount, handles, FALSE, 500);
346 ResetEvent(m_writeEvent);
348 if (waitStatus == WAIT_FAILED)
350 qCritical(log) <<
"WaitForMultipleObjects: WAIT_FAILED";
355 if(waitStatus == WAIT_TIMEOUT)
362 if (!freerdp_check_event_handles(pRdpContext))
366 UINT32 err = freerdp_get_last_error(pRdpContext);
368 szErr =
"freerdp_check_event_handles fail.";
370 szErr += QString::number(err);
372 szErr += freerdp_get_last_error_category(err);
374 szErr += freerdp_get_last_error_name(err);
376 szErr += freerdp_get_last_error_string(err);
377 qCritical(log) << szErr;
401#if FreeRDP_VERSION_MAJOR >= 3
402 if(freerdp_shall_disconnect_context(pRdpContext))
404 if(freerdp_shall_disconnect(pRdpContext->instance))
407 qCritical(log) <<
"freerdp_shall_disconnect false";
415void CConnectFreeRDP::slotClipBoardChanged()
417 qDebug(log) << Q_FUNC_INFO;
418 if(m_pParameter && m_pParameter->GetOnlyView())
return;
419 if(m_pParameter->GetClipboard())
420 m_ClipBoard.slotClipBoardChanged();
423BOOL CConnectFreeRDP::cbGlobalInit()
425 qDebug(log) << Q_FUNC_INFO;
429void CConnectFreeRDP::cbGlobalUninit()
431 qDebug(log) << Q_FUNC_INFO;
434BOOL CConnectFreeRDP::cbClientNew(freerdp *instance, rdpContext *context)
436 qDebug(log) << Q_FUNC_INFO;
439 instance->PostDisconnect = cb_post_disconnect;
442#if FreeRDP_VERSION_MAJOR < 3
443 instance->Authenticate = cb_authenticate;
444 instance->GatewayAuthenticate = cb_GatewayAuthenticate;
446 instance->AuthenticateEx = cb_authenticate_ex;
447 instance->ChooseSmartcard = cb_choose_smartcard;
452 instance->PresentGatewayMessage = cb_present_gateway_message;
454 instance->LogonErrorInfo = cb_logon_error_info;
459void CConnectFreeRDP::cbClientFree(freerdp *instance, rdpContext *context)
461 qDebug(log) << Q_FUNC_INFO;
464int CConnectFreeRDP::cbClientStart(rdpContext *context)
466 qDebug(log) << Q_FUNC_INFO;
469 if (!context || !context->settings)
471 freerdp* instance = freerdp_client_get_instance(context);
475 auto settings = context->settings;
479 szHost = freerdp_settings_get_string(settings, FreeRDP_ServerHostname);
480 nPort = freerdp_settings_get_uint32(settings, FreeRDP_ServerPort);
482 auto &net = pThis->m_pParameter->m_Net;
483 szServer = net.GetHost() +
":" + QString::number(net.GetPort());
484 auto &proxy = pThis->m_pParameter->m_Proxy;
485 switch(proxy.GetUsedType()) {
486 case CParameterProxy::TYPE::SSHTunnel:
488 auto &sshNet = proxy.m_SSH;
489 szServer = szHost +
":" + QString::number(nPort)
490 +
" <-> " + sshNet.GetHost() +
":" + QString::number(sshNet.GetPort())
491 +
" <-> " + szServer;
498 BOOL status = freerdp_connect(instance);
500 QString szInfo = tr(
"Connect to ") + szServer;
501 qInfo(log) << szInfo;
505 UINT32 nErr = freerdp_get_last_error(context);
508 szErr = tr(
"Connect to ") + szServer + tr(
" fail.");
510 szErr += QString::number(nErr) +
" - ";
511 szErr += freerdp_get_last_error_name(nErr);
516 szErr += freerdp_get_last_error_string(nErr);
520 case FREERDP_ERROR_CONNECT_LOGON_FAILURE:
523 szErr = tr(
"Logon to ") + szServer;
524 szErr += tr(
" fail. Please check that the username and password are correct.") +
"\n";
527 case FREERDP_ERROR_CONNECT_WRONG_PASSWORD:
530 szErr = tr(
"Logon to ") + szServer;
531 szErr += tr(
" fail. Please check password are correct.") +
"\n";
534 case FREERDP_ERROR_AUTHENTICATION_FAILED:
537 szErr = tr(
"Logon to ") + szServer;
538 szErr += tr(
" authentication fail. please add a CA certificate to the store.") +
"\n";
541 case FREERDP_ERROR_CONNECT_TRANSPORT_FAILED:
544 szErr = tr(
"Logon to ") + szServer;
545 szErr += tr(
" connect transport layer fail.") +
"\n\n";
546 szErr += tr(
"Please:") +
"\n";
547 szErr += tr(
"1. Check for any network related issues") +
"\n";
548 szErr += tr(
"2. Check you have proper security settings ('NLA' enabled is required for most connections nowadays)") +
"\n";
549 szErr +=
" " + tr(
"If you do not know the server security settings, contact your server administrator.") +
"\n";
550 szErr += tr(
"3. Check the certificate is proper (and guacd properly checks that)") +
"\n";
553 case FREERDP_ERROR_SECURITY_NEGO_CONNECT_FAILED:
556 szErr += tr(
"Please check you have proper security settings.") +
"\n";
557 szErr += tr(
"If you do not know the server security settings, contact your server administrator.");
559 case FREERDP_ERROR_CONNECT_CANCELLED:
561 szErr = tr(
"The connect was canceled.") +
"\n\n" + szErr;
568 qCritical(log) << szErr;
569 emit pThis->
sigError(nRet, szErr.toStdString().c_str());
575int CConnectFreeRDP::cbClientStop(rdpContext *context)
578 qDebug(log) << Q_FUNC_INFO;
579#if FreeRDP_VERSION_MAJOR >= 3
580 nRet = freerdp_client_common_stop(context);
582 BOOL bRet = freerdp_abort_connect(context->instance);
584 { qCritical(log) <<
"freerdp_abort_connect fail";
611 qDebug(log) << Q_FUNC_INFO;
612 rdpChannels* channels =
nullptr;
613 rdpSettings* settings =
nullptr;
614 rdpContext* context = instance->context;
616 if (!instance || !instance->context || !instance->context->settings)
620 if(!pThis)
return FALSE;
621 settings = instance->context->settings;
622 channels = context->channels;
624 if(!channels || !pParameter)
628#if defined (Q_OS_WIN)
629 if (!freerdp_settings_set_uint32(
630 settings, FreeRDP_OsMajorType, OSMAJORTYPE_WINDOWS))
632 if (!freerdp_settings_set_uint32(
633 settings, FreeRDP_OsMinorType, OSMINORTYPE_WINDOWS_NT))
635#elif defined(Q_OS_ANDROID)
636 if (!freerdp_settings_set_uint32(
637 settings, FreeRDP_OsMajorType, OSMAJORTYPE_ANDROID))
639 if (!freerdp_settings_set_uint32(
640 settings, FreeRDP_OsMinorType, OSMINORTYPE_UNSPECIFIED))
642#elif defined(Q_OS_IOS)
643 if (!freerdp_settings_set_uint32(
644 settings, FreeRDP_OsMajorType, OSMAJORTYPE_IOS))
646 if (!freerdp_settings_set_uint32(
647 settings, FreeRDP_OsMinorType, OSMINORTYPE_UNSPECIFIED))
649#elif defined (Q_OS_UNIX)
650 if (!freerdp_settings_set_uint32(
651 settings, FreeRDP_OsMajorType, OSMAJORTYPE_UNIX))
653 if (!freerdp_settings_set_uint32(
654 settings, FreeRDP_OsMinorType, OSMINORTYPE_NATIVE_XSERVER))
657 if (!freerdp_settings_set_uint32(
658 settings, FreeRDP_OsMajorType, OSMAJORTYPE_UNSPECIFIED))
660 if (!freerdp_settings_set_uint32(
661 settings, FreeRDP_OsMinorType, OSMINORTYPE_UNSPECIFIED))
666 PubSub_SubscribeChannelConnected(instance->context->pubSub,
667 OnChannelConnectedEventHandler);
668 PubSub_SubscribeChannelDisconnected(instance->context->pubSub,
669 OnChannelDisconnectedEventHandler);
671#if FreeRDP_VERSION_MAJOR < 3
672 if (!freerdp_client_load_addins(channels, instance->context->settings))
675 #if defined(Q_OS_LINUX) || (defined(Q_OS_WIN) && defined(WITH_WINDOWS_CERT_STORE))
676 if (!freerdp_settings_set_bool(settings, FreeRDP_CertificateCallbackPreferPEM, TRUE))
681 if(!freerdp_settings_set_bool(
682 settings, FreeRDP_NegotiateSecurityLayer,
683 pParameter->GetNegotiateSecurityLayer()))
685 CParameterFreeRDP::Security security = pParameter->GetSecurity();
687 if(!freerdp_settings_set_bool(
688 settings, FreeRDP_RdpSecurity,
689 CParameterFreeRDP::Security::RDP & security))
691 if (!freerdp_settings_set_bool(
692 settings, FreeRDP_UseRdpSecurityLayer,
693 CParameterFreeRDP::Security::RDP & security))
696 if(!freerdp_settings_set_bool(
697 settings, FreeRDP_TlsSecurity,
698 CParameterFreeRDP::Security::TLS & security))
700 if(!freerdp_settings_set_bool(
701 settings, FreeRDP_NlaSecurity,
702 CParameterFreeRDP::Security::NLA & security))
704 if(!freerdp_settings_set_bool(
705 settings, FreeRDP_ExtSecurity,
706 CParameterFreeRDP::Security::NLA_Ext & security))
708#if FreeRDP_VERSION_MAJOR >= 3
709 if(!freerdp_settings_set_bool(
710 settings, FreeRDP_AadSecurity,
711 CParameterFreeRDP::Security::RDSAAD & security))
713 if(!freerdp_settings_set_bool(
714 settings, FreeRDP_RdstlsSecurity,
715 CParameterFreeRDP::Security::RDSTLS & security))
719 freerdp_settings_set_uint16(settings, FreeRDP_TLSMinVersion,
720 pParameter->GetTlsVersion());
723 if (freerdp_settings_get_bool(settings, FreeRDP_AuthenticationOnly))
726 auto &user = pParameter->m_Net.
m_User;
727 if(!freerdp_settings_get_string(settings, FreeRDP_Username)) {
728 if(user.GetUser().isEmpty()) {
729 if(user.GetUser().isEmpty()) {
731 qWarning(log) <<
"Auth-only, but no user name set. Will be call instance->Authenticate.";
734 freerdp_settings_set_string(
735 settings, FreeRDP_Username,
736 user.GetUser().toStdString().c_str());
738 if (!freerdp_settings_get_string(settings, FreeRDP_Password)) {
739 if (user.GetPassword().isEmpty()) {
741 qWarning(log) <<
"auth-only, but no password set. Will be call instance->Authenticate";
743 freerdp_settings_set_string(
744 settings, FreeRDP_Password,
745 user.GetPassword().toStdString().c_str());
747#if FreeRDP_VERSION_MAJOR >= 3
748 if (!freerdp_settings_set_bool(settings, FreeRDP_DeactivateClientDecoding, TRUE))
751 }
else if(freerdp_settings_get_bool(settings, FreeRDP_CredentialsFromStdin)){
753 }
else if(freerdp_settings_get_bool(settings, FreeRDP_SmartcardLogon)) {
764 UINT32 width = pParameter->GetDesktopWidth();
765 UINT32 height = pParameter->GetDesktopHeight();
766 if ((width < 64) || (height < 64) ||
767 (width > 4096) || (height > 4096))
769 QString szErr = tr(
"Invalid dimensions:")
770 + QString::number(width)
771 +
"*" + QString::number(height);
772 qCritical(log) << szErr;
776 qInfo(log) <<
"Init desktop size " << width <<
"*" << height;
780 <<
"width:" << freerdp_settings_get_uint32(settings, FreeRDP_DesktopWidth)
781 <<
"height:" << freerdp_settings_get_uint32(settings, FreeRDP_DesktopHeight)
782 <<
"ColorDepth:" << freerdp_settings_get_uint32(settings, FreeRDP_ColorDepth);
793 if(!freerdp_set_connection_type(settings, pParameter->GetConnectType()))
795 freerdp_settings_set_uint32(
796 settings, FreeRDP_PerformanceFlags, pParameter->GetPerformanceFlags());
797 freerdp_performance_flags_split(settings);
802const char* CConnectFreeRDP::GetTitle(freerdp* instance)
804 const char* windowTitle;
807 const char* name =
nullptr;
810 rdpSettings* settings = instance->context->settings;
815 windowTitle = freerdp_settings_get_string(settings, FreeRDP_WindowTitle);
819#if FreeRDP_VERSION_MAJOR >= 3
820 name = freerdp_settings_get_server_name(settings);
822 name = pThis->m_pParameter->m_Net.GetHost().toStdString().c_str();
824 port = freerdp_settings_get_uint32(settings, FreeRDP_ServerPort);
826 addPort = (port != 3389);
828 char buffer[MAX_PATH + 64] = { 0 };
831 sprintf_s(buffer,
sizeof(buffer),
"%s", name);
833 sprintf_s(buffer,
sizeof(buffer),
"%s:%" PRIu32, name, port);
835 freerdp_settings_set_string(settings, FreeRDP_WindowTitle, buffer);
836 return freerdp_settings_get_string(settings, FreeRDP_WindowTitle);
846 qDebug(log) << Q_FUNC_INFO;
848 rdpContext* context = instance->context;
849 rdpSettings* settings = instance->context->settings;
850 rdpUpdate* update = instance->context->update;
853 const char* pWindowTitle = GetTitle(instance);
856 WCHAR* windowTitle = NULL;
857#if FreeRDP_VERSION_MAJOR >= 3
858 windowTitle = ConvertUtf8ToWCharAlloc(pWindowTitle, NULL);
860 ConvertToUnicode(CP_UTF8, 0, pWindowTitle, -1, &windowTitle, 0);
864 QString title = QString::fromUtf16((
const char16_t*)windowTitle);
866 if(pThis->m_pParameter->GetServerName().isEmpty())
867 emit pThis->sigServerName(title);
871 int desktopWidth = freerdp_settings_get_uint32(settings, FreeRDP_DesktopWidth);
872 int desktopHeight = freerdp_settings_get_uint32(settings, FreeRDP_DesktopHeight);
873 emit pThis->sigSetDesktopSize(desktopWidth, desktopHeight);
875 if (!gdi_init(instance, PIXEL_FORMAT_BGRA32))
878 if(!pThis->CreateImage(instance->context))
881 Q_ASSERT(instance->context->cache);
884 if(pThis->m_Cursor.RegisterPointer(context->graphics))
887 update->BeginPaint = cb_begin_paint;
888 update->EndPaint = cb_end_paint;
889 update->DesktopResize = cb_desktop_resize;
891 update->PlaySound = cb_play_bell_sound;
893 update->SetKeyboardIndicators = cb_keyboard_set_indicators;
894 update->SetKeyboardImeStatus = cb_keyboard_set_ime_status;
900void CConnectFreeRDP::cb_post_disconnect(freerdp* instance)
902 qDebug(log) << Q_FUNC_INFO;
903 rdpContext* context =
nullptr;
905 if (!instance || !instance->context)
908 context = instance->context;
910 PubSub_UnsubscribeChannelConnected(instance->context->pubSub,
911 OnChannelConnectedEventHandler);
912 PubSub_UnsubscribeChannelDisconnected(instance->context->pubSub,
913 OnChannelDisconnectedEventHandler);
917int CConnectFreeRDP::cb_logon_error_info(freerdp* instance, UINT32 data, UINT32 type)
920 const char* str_data = freerdp_get_logon_error_info_data(data);
921 const char* str_type = freerdp_get_logon_error_info_type(type);
922 QString szErr = tr(
"FreeRDP logon info: [");
926 qDebug(log) << szErr;
932void CConnectFreeRDP::OnChannelConnectedEventHandler(
void *context,
933 #
if FreeRDP_VERSION_MAJOR >= 3
936 ChannelConnectedEventArgs *e)
938 rdpContext* pContext = (rdpContext*)context;
940 if (strcmp(e->name, CLIPRDR_SVC_CHANNEL_NAME) == 0) {
941 qDebug(log) <<
"channel" << e->name <<
"connected";
942 pThis->m_ClipBoard.Init((CliprdrClientContext*)e->pInterface,
943 pThis->m_pParameter->GetClipboard());
945#if FreeRDP_VERSION_MAJOR >= 3
947 freerdp_client_OnChannelConnectedEventHandler(pContext, e);
949 else if (strcmp(e->name, RDPGFX_DVC_CHANNEL_NAME) == 0)
951 if (freerdp_settings_get_bool(pContext->settings, FreeRDP_SoftwareGdi)) {
952 rdpGdi* gdi = pContext->gdi;
954 gdi_graphics_pipeline_init(gdi, (RdpgfxClientContext*) e->pInterface);
957 qDebug(log,
"Unimplemented: channel %s connected but libfreerdp is in HardwareGdi mode\n", e->name);
959 else if (strcmp(e->name, GEOMETRY_DVC_CHANNEL_NAME) == 0)
961 gdi_video_geometry_init(pContext->gdi, (GeometryClientContext*)e->pInterface);
963 else if (strcmp(e->name, VIDEO_DATA_DVC_CHANNEL_NAME) == 0)
965 gdi_video_data_init(pContext->gdi, (VideoClientContext*)e->pInterface);
967 qDebug(log) <<
"Unimplemented: channel" << e->name <<
"connected but we can’t use it";
971void CConnectFreeRDP::OnChannelDisconnectedEventHandler(
void *context,
972 #
if FreeRDP_VERSION_MAJOR >= 3
975 ChannelDisconnectedEventArgs *e)
977 rdpContext* pContext = (rdpContext*)context;
980 if (strcmp(e->name, CLIPRDR_SVC_CHANNEL_NAME) == 0) {
981 qDebug(log) <<
"channel" << e->name <<
"disconnected";
982 pThis->m_ClipBoard.UnInit((CliprdrClientContext*)e->pInterface,
983 pThis->m_pParameter->GetClipboard());
985#if FreeRDP_VERSION_MAJOR >= 3
987 freerdp_client_OnChannelDisconnectedEventHandler(pContext, e);
989 else if (strcmp(e->name, RDPGFX_DVC_CHANNEL_NAME) == 0)
991 if (freerdp_settings_get_bool(pContext->settings, FreeRDP_SoftwareGdi)) {
992 rdpGdi* gdi = pContext->gdi;
993 gdi_graphics_pipeline_uninit(gdi, (RdpgfxClientContext*) e->pInterface);
996 qDebug(log,
"Unimplemented: channel %s connected but libfreerdp is in HardwareGdi mode\n", e->name);
999 qDebug(log) <<
"Unimplemented: channel" << e->name <<
"disconnected but we can’t use it";
1004UINT32 CConnectFreeRDP::GetImageFormat(QImage::Format format)
1007#if (QT_VERSION >= QT_VERSION_CHECK(5,2,0))
1008 case QImage::Format_RGBA8888:
1009 return PIXEL_FORMAT_RGBA32;
1010 case QImage::Format_RGBX8888:
1011 return PIXEL_FORMAT_RGBX32;
1013 case QImage::Format_RGB16:
1014 return PIXEL_FORMAT_RGB16;
1015 case QImage::Format_ARGB32:
1016 return PIXEL_FORMAT_BGRA32;
1017 case QImage::Format_RGB32:
1018 return PIXEL_FORMAT_BGRA32;
1025UINT32 CConnectFreeRDP::GetImageFormat()
1027 return GetImageFormat(m_Image.format());
1030BOOL CConnectFreeRDP::CreateImage(rdpContext *context)
1033 ClientContext* pContext = (ClientContext*)context;
1035 rdpGdi* gdi = context->gdi;
1036 Q_ASSERT(pThis && gdi);
1037 pThis->m_Image = QImage(gdi->primary_buffer,
1038 static_cast<int>(gdi->width),
1039 static_cast<int>(gdi->height),
1040 QImage::Format_ARGB32);
1044#if FreeRDP_VERSION_MAJOR >= 3
1046static CREDUI_INFOW wfUiInfo = {
sizeof(CREDUI_INFOW), NULL, L
"Enter your credentials",
1047 L
"Remote Desktop Security", NULL };
1050BOOL CConnectFreeRDP::cb_authenticate_ex(freerdp* instance,
1051 char** username,
char** password,
1052 char** domain, rdp_auth_reason reason)
1054 qDebug(log) << Q_FUNC_INFO <<
"reason:" << reason;
1058 if(!username || !password || !domain)
return FALSE;
1060 rdpContext* pContext = (rdpContext*)instance->context;
1065 WCHAR UserNameW[CREDUI_MAX_USERNAME_LENGTH + 1] = { 0 };
1066 WCHAR UserW[CREDUI_MAX_USERNAME_LENGTH + 1] = { 0 };
1067 WCHAR DomainW[CREDUI_MAX_DOMAIN_TARGET_LENGTH + 1] = { 0 };
1068 WCHAR PasswordW[CREDUI_MAX_PASSWORD_LENGTH + 1] = { 0 };
1070 WINPR_ASSERT(instance);
1071 WINPR_ASSERT(instance->context);
1072 WINPR_ASSERT(instance->context->settings);
1074 WINPR_ASSERT(username);
1075 WINPR_ASSERT(domain);
1076 WINPR_ASSERT(password);
1078 const WCHAR auth[] = L
"Target credentials requested";
1079 const WCHAR authPin[] = L
"PIN requested";
1080 const WCHAR gwAuth[] = L
"Gateway credentials requested";
1081 const WCHAR* titleW = auth;
1084 dwFlags = CREDUI_FLAGS_DO_NOT_PERSIST | CREDUI_FLAGS_EXCLUDE_CERTIFICATES |
1085 CREDUI_FLAGS_USERNAME_TARGET_CREDENTIALS;
1092 if ((*username) && (*password))
1095 case AUTH_SMARTCARD_PIN:
1096 dwFlags &= ~CREDUI_FLAGS_USERNAME_TARGET_CREDENTIALS;
1097 dwFlags |= CREDUI_FLAGS_PASSWORD_ONLY_OK | CREDUI_FLAGS_KEEP_USERNAME;
1102 *username = _strdup(
"PIN");
1115 ConvertUtf8ToWChar(*username, UserNameW, ARRAYSIZE(UserNameW));
1116 ConvertUtf8ToWChar(*username, UserW, ARRAYSIZE(UserW));
1120 ConvertUtf8ToWChar(*password, PasswordW, ARRAYSIZE(PasswordW));
1123 ConvertUtf8ToWChar(*domain, DomainW, ARRAYSIZE(DomainW));
1125 if (_wcsnlen(PasswordW, ARRAYSIZE(PasswordW)) == 0)
1127 status = CredUIPromptForCredentialsW(&wfUiInfo, titleW, NULL, 0, UserNameW,
1128 ARRAYSIZE(UserNameW), PasswordW,
1129 ARRAYSIZE(PasswordW), &fSave, dwFlags);
1130 if (status != NO_ERROR)
1133 "CredUIPromptForCredentials unexpected status: 0x%08lX",
1138 if ((dwFlags & CREDUI_FLAGS_KEEP_USERNAME) == 0)
1140 status = CredUIParseUserNameW(UserNameW, UserW, ARRAYSIZE(UserW), DomainW,
1141 ARRAYSIZE(DomainW));
1142 if (status != NO_ERROR)
1144 CHAR User[CREDUI_MAX_USERNAME_LENGTH + 1] = { 0 };
1145 CHAR UserName[CREDUI_MAX_USERNAME_LENGTH + 1] = { 0 };
1146 CHAR Domain[CREDUI_MAX_DOMAIN_TARGET_LENGTH + 1] = { 0 };
1148 ConvertWCharNToUtf8(UserNameW, ARRAYSIZE(UserNameW), UserName, ARRAYSIZE(UserName));
1149 ConvertWCharNToUtf8(UserW, ARRAYSIZE(UserW), User, ARRAYSIZE(User));
1150 ConvertWCharNToUtf8(DomainW, ARRAYSIZE(DomainW), Domain, ARRAYSIZE(Domain));
1152 "Failed to parse UserName: %s into User: %s Domain: %s",
1153 UserName, User, Domain);
1159 *username = ConvertWCharNToUtf8Alloc(UserW, ARRAYSIZE(UserW), NULL);
1162 qCritical(log) <<
"ConvertWCharNToUtf8Alloc failed" << status;
1166 if (_wcsnlen(DomainW, ARRAYSIZE(DomainW)) > 0)
1167 *domain = ConvertWCharNToUtf8Alloc(DomainW, ARRAYSIZE(DomainW), NULL);
1169 *domain = _strdup(
"\0");
1174 qCritical(log) <<
"strdup failed" << status;
1178 *password = ConvertWCharNToUtf8Alloc(PasswordW, ARRAYSIZE(PasswordW), NULL);
1187 return cb_authenticate(instance, username, password, domain);
1192BOOL CConnectFreeRDP::cb_choose_smartcard(freerdp* instance,
1193 SmartcardCertInfo** cert_list,
1195 DWORD* choice, BOOL gateway)
1197 rdpContext* pContext = (rdpContext*)instance->context;
1199 QString msg(
"Multiple smartcards are available for use:\n");
1200 for (DWORD i = 0; i < count; i++)
1202 const SmartcardCertInfo* cert = cert_list[i];
1203 char* reader = ConvertWCharToUtf8Alloc(cert->reader, NULL);
1204 char* container_name = ConvertWCharToUtf8Alloc(cert->containerName, NULL);
1206 msg += QString::number(i) +
" ";
1207 msg += QString(container_name) +
"\n\t";
1208 msg +=
"Reader: " + QString(reader) +
"\n\t";
1209 msg +=
"User: " + QString(cert->userHint) + +
"@" + QString(cert->domainHint) +
"\n\t";
1210 msg +=
"Subject: " + QString(cert->subject) +
"\n\t";
1211 msg +=
"Issuer: " + QString(cert->issuer) +
"\n\t";
1212 msg +=
"UPN: " + QString(cert->upn) +
"\n";
1215 free(container_name);
1218 msg +=
"\nChoose a smartcard to use for ";
1220 msg +=
"gateway authentication";
1224 msg +=
"(0 - " + QString::number(count - 1) +
")";
1232 int n = num.toInt(&ok);
1242#ifdef WITH_WINDOWS_CERT_STORE
1250static void wf_report_error(
char* wszMessage, DWORD dwErrCode)
1252 LPSTR pwszMsgBuf = NULL;
1254 if (NULL != wszMessage && 0 != *wszMessage)
1256 WLog_ERR(TAG,
"%s", wszMessage);
1259 FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
1264 MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
1274 if (NULL != pwszMsgBuf)
1276 WLog_ERR(TAG,
"Error: 0x%08x (%d) %s", dwErrCode, dwErrCode, pwszMsgBuf);
1277 LocalFree(pwszMsgBuf);
1281 WLog_ERR(TAG,
"Error: 0x%08x (%d)", dwErrCode, dwErrCode);
1285static DWORD wf_is_x509_certificate_trusted(
const char* common_name,
const char* subject,
1286 const char* issuer,
const char* fingerprint)
1288 HRESULT hr = CRYPT_E_NOT_FOUND;
1290 DWORD dwChainFlags = CERT_CHAIN_REVOCATION_CHECK_CHAIN_EXCLUDE_ROOT;
1291 PCCERT_CONTEXT pCert = NULL;
1292 HCERTCHAINENGINE hChainEngine = NULL;
1293 PCCERT_CHAIN_CONTEXT pChainContext = NULL;
1295 CERT_ENHKEY_USAGE EnhkeyUsage = { 0 };
1296 CERT_USAGE_MATCH CertUsage = { 0 };
1297 CERT_CHAIN_PARA ChainPara = { 0 };
1298 CERT_CHAIN_POLICY_PARA ChainPolicy = { 0 };
1299 CERT_CHAIN_POLICY_STATUS PolicyStatus = { 0 };
1300 CERT_CHAIN_ENGINE_CONFIG EngineConfig = { 0 };
1302 DWORD derPubKeyLen = WINPR_ASSERTING_INT_CAST(uint32_t, strlen(fingerprint));
1303 char* derPubKey = calloc(derPubKeyLen,
sizeof(
char));
1304 if (NULL == derPubKey)
1306 WLog_ERR(TAG,
"Could not allocate derPubKey");
1313 if (!CryptStringToBinaryA(fingerprint, 0, CRYPT_STRING_BASE64HEADER, derPubKey, &derPubKeyLen,
1316 WLog_ERR(TAG,
"CryptStringToBinary failed. Err: %d", GetLastError());
1323 EnhkeyUsage.cUsageIdentifier = 0;
1324 EnhkeyUsage.rgpszUsageIdentifier = NULL;
1326 CertUsage.dwType = USAGE_MATCH_TYPE_AND;
1327 CertUsage.Usage = EnhkeyUsage;
1329 ChainPara.cbSize =
sizeof(ChainPara);
1330 ChainPara.RequestedUsage = CertUsage;
1332 ChainPolicy.cbSize =
sizeof(ChainPolicy);
1334 PolicyStatus.cbSize =
sizeof(PolicyStatus);
1336 EngineConfig.cbSize =
sizeof(EngineConfig);
1337 EngineConfig.dwUrlRetrievalTimeout = 0;
1339 pCert = CertCreateCertificateContext(X509_ASN_ENCODING, derPubKey, derPubKeyLen);
1342 WLog_ERR(TAG,
"FAILED: Certificate could not be parsed.");
1346 dwChainFlags |= CERT_CHAIN_ENABLE_PEER_TRUST;
1355 if (!CertCreateCertificateChainEngine(&EngineConfig, &hChainEngine))
1357 hr = HRESULT_FROM_WIN32(GetLastError());
1364 if (!CertGetCertificateChain(hChainEngine,
1375 hr = HRESULT_FROM_WIN32(GetLastError());
1382 if (!CertVerifyCertificateChainPolicy(CERT_CHAIN_POLICY_BASE,
1387 hr = HRESULT_FROM_WIN32(GetLastError());
1391 if (PolicyStatus.dwError != S_OK)
1393 wf_report_error(
"CertVerifyCertificateChainPolicy: Chain Status", PolicyStatus.dwError);
1394 hr = PolicyStatus.dwError;
1400 if (PolicyStatus.dwError == CRYPT_E_NO_REVOCATION_CHECK ||
1401 PolicyStatus.dwError == CRYPT_E_REVOCATION_OFFLINE)
1409 WLog_INFO(TAG,
"CertVerifyCertificateChainPolicy succeeded for %s (%s) issued by %s",
1410 common_name, subject, issuer);
1417 WLog_INFO(TAG,
"CertVerifyCertificateChainPolicy failed for %s (%s) issued by %s",
1418 common_name, subject, issuer);
1419 wf_report_error(NULL, hr);
1424 if (NULL != pChainContext)
1426 CertFreeCertificateChain(pChainContext);
1429 if (NULL != hChainEngine)
1431 CertFreeCertificateChainEngine(hChainEngine);
1436 CertFreeCertificateContext(pCert);
1445BOOL CConnectFreeRDP::cb_authenticate(freerdp* instance,
char** username,
1446 char** password,
char** domain)
1448 qDebug(log) << Q_FUNC_INFO;
1451 rdpContext* pContext = (rdpContext*)instance->context;
1453 if(!username || !password || !domain)
return FALSE;
1454 if(*username && *password )
return TRUE;
1456 int nRet = QDialog::Rejected;
1458 nRet, pThis->m_pParameter);
1459 if(QDialog::Accepted == nRet)
1461 QString szPassword = pThis->m_pParameter->m_Net.
m_User.GetPassword();
1462 QString szName = pThis->m_pParameter->m_Net.
m_User.GetUser();
1463 QString szDomain = pThis->m_pParameter->GetDomain();
1464 if(!szDomain.isEmpty() && domain)
1465 *domain = _strdup(szDomain.toStdString().c_str());
1466 if(!szName.isEmpty() && username)
1467 *username = _strdup(szName.toStdString().c_str());
1468 if(!szPassword.isEmpty() && password)
1469 *password = _strdup(szPassword.toStdString().c_str());
1476BOOL CConnectFreeRDP::cb_GatewayAuthenticate(freerdp *instance,
1477 char **username,
char **password,
char **domain)
1479 qDebug(log) << Q_FUNC_INFO;
1483 rdpContext* pContext = (rdpContext*)instance->context;
1485 if(!username || !password || !domain)
return FALSE;
1486 if(*username && *password )
return TRUE;
1488 int nRet = QDialog::Rejected;
1489 emit pThis->
sigBlockShowWidget(
"CDlgGetUserPasswordFreeRDP", nRet, pThis->m_pParameter);
1490 if(QDialog::Accepted == nRet)
1492 QString szPassword = pThis->m_pParameter->m_Net.
m_User.GetPassword();
1493 QString szName = pThis->m_pParameter->m_Net.
m_User.GetUser();
1494 QString szDomain = pThis->m_pParameter->GetDomain();
1495 if(!szDomain.isEmpty() && domain)
1496 *domain = _strdup(szDomain.toStdString().c_str());
1497 if(!szName.isEmpty() && username)
1498 *username = _strdup(szName.toStdString().c_str());
1499 if(!szPassword.isEmpty() && password)
1500 *password = _strdup(szPassword.toStdString().c_str());
1508 const BYTE* data,
size_t length,
1509 const char* hostname, UINT16 port, DWORD flags)
1511 qDebug(log) << Q_FUNC_INFO;
1512 rdpContext* pContext = (rdpContext*)instance->context;
1513 QSslCertificate cert(QByteArray((
const char*)data, length));
1514#if FreeRDP_VERSION_MAJOR >= 3
1518 if (flags & VERIFY_CERT_FLAG_FP_IS_PEM) {
1520 instance, hostname, port,
1521 cert.issuerDisplayName().toStdString().c_str(),
1522 cert.subjectDisplayName().toStdString().c_str(),
1523 cert.issuerDisplayName().toStdString().c_str(),
1529 instance, hostname, port,
1530 cert.issuerDisplayName().toStdString().c_str(),
1531 cert.subjectDisplayName().toStdString().c_str(),
1532 cert.issuerDisplayName().toStdString().c_str(),
1533 cert.serialNumber().toStdString().c_str(),
1537static QString pem_cert_fingerprint(
const char* pem, DWORD flags)
1539 QString szFingerPrint;
1540#if FreeRDP_VERSION_MAJOR >= 3
1544 if (flags & VERIFY_CERT_FLAG_FP_IS_PEM)
1546 rdpCertificate* cert = freerdp_certificate_new_from_pem(pem);
1550 char* fp = freerdp_certificate_get_fingerprint(cert);
1551 char* start = freerdp_certificate_get_validity(cert, TRUE);
1552 char* end = freerdp_certificate_get_validity(cert, FALSE);
1553 freerdp_certificate_free(cert);
1555 szFingerPrint = QObject::tr(
"Valid from: ") + QString(start) +
"\n";
1556 szFingerPrint += QObject::tr(
"Valid to: ") + QString(end) +
"\n";
1557 szFingerPrint += QObject::tr(
"Fingerprint: ") + QString(fp) +
"\n";
1564 szFingerPrint = QObject::tr(
"Fingerprint: ") + QString(pem) +
"\n";
1565 return szFingerPrint;
1584 const char *host, UINT16 port,
1585 const char *common_name,
const char *subject,
1586 const char *issuer,
const char *fingerprint, DWORD flags)
1588 qDebug(log) << Q_FUNC_INFO;
1590 rdpContext* pContext = (rdpContext*)instance->context;
1597 emit pThis->sigServerName(common_name);
1600 if(!pThis->m_pParameter->GetShowVerifyDiaglog()) {
1606#if FreeRDP_VERSION_MAJOR >= 3
1607#if defined(Q_OS_WIN) && defined(WITH_WINDOWS_CERT_STORE)
1608 if (flags & VERIFY_CERT_FLAG_FP_IS_PEM && !(flags & VERIFY_CERT_FLAG_MISMATCH))
1610 if (wf_is_x509_certificate_trusted(common_name, subject, issuer, fingerprint) == S_OK)
1618 QString szType = tr(
"RDP-Server");
1619 if (flags & VERIFY_CERT_FLAG_GATEWAY)
1620 szType = tr(
"RDP-Gateway");
1621 if (flags & VERIFY_CERT_FLAG_REDIRECT)
1622 szType = tr(
"RDP-Redirect");
1624 QString title(tr(
"Verify certificate"));
1627 message += szType + tr(
": %1:%2").arg(host, QString::number(port)) +
"\n";
1628 message += tr(
"Common name: ") + common_name +
"\n";
1629 message += tr(
"Subject: ") + subject +
"\n";
1630 message += tr(
"Issuer: ") + issuer +
"\n";
1631 message += pem_cert_fingerprint(fingerprint, flags);
1633 if(VERIFY_CERT_FLAG_CHANGED & flags) {
1634 message += tr(
"The above X.509 certificate is changed.\n"
1635 "It is possible that the server has changed its certificate, "
1636 "or Maybe it was attacked."
1637 "Please look at the OpenSSL documentation on "
1638 "how to add a private CA to the store.");
1640 message += tr(
"The above X.509 certificate could not be verified.\n"
1641 "Possibly because you do not have the CA certificate "
1642 "in your certificate store, or the certificate has expired.\n"
1643 "Please look at the OpenSSL documentation on "
1644 "how to add a private CA to the store.");
1648 message += tr(
"Yes - trusted") +
"\n";
1649 message += tr(
"Ignore - temporary trusted") +
"\n";
1650 message += tr(
"No - no trusted") +
"\n";
1652 QMessageBox::StandardButton nRet = QMessageBox::StandardButton::No;
1653 QMessageBox::StandardButtons buttons = QMessageBox::Yes | QMessageBox::Ignore | QMessageBox::No;
1654 bool bCheckBox =
false;
1656 tr(
"Don't show again"));
1657 pThis->m_pParameter->SetShowVerifyDiaglog(!bCheckBox);
1663 case QMessageBox::StandardButton::Yes:
1665 case QMessageBox::StandardButton::Ignore:
1693 const char *host, UINT16 port,
1694 const char *common_name,
const char *subject,
1695 const char *issuer,
const char *fingerprint,
1696 const char *old_subject,
const char *old_issuer,
1697 const char *old_fingerprint, DWORD flags)
1699 qDebug(log) << Q_FUNC_INFO;
1700 rdpContext* pContext = (rdpContext*)instance->context;
1703 emit pThis->sigServerName(common_name);
1705 if(!pThis->m_pParameter->GetShowVerifyDiaglog()) {
1711 QString szType = tr(
"RDP-Server");
1712 if (flags & VERIFY_CERT_FLAG_GATEWAY)
1713 szType = tr(
"RDP-Gateway");
1714 if (flags & VERIFY_CERT_FLAG_REDIRECT)
1715 szType = tr(
"RDP-Redirect");
1717 QString title(tr(
"Verify changed certificate"));
1719 message += szType + tr(
": %1:%2").arg(host, QString::number(port)) +
"\n";
1720 message += tr(
"New Certificate details:") +
"\n";
1721 message +=
" " + tr(
"name: ") + common_name +
"\n";
1722 message +=
" " + tr(
"subject: ") + subject +
"\n";
1723 message +=
" " + tr(
"issuer: ") + issuer +
"\n";
1724 message +=
" " + pem_cert_fingerprint(fingerprint, flags) +
"\n";
1725 message += tr(
"Old Certificate details:") +
"\n";
1726 message +=
" " + tr(
"subject: ") + old_subject +
"\n";
1727 message +=
" " + tr(
"issuer: ") + old_issuer +
"\n";
1728 message +=
" " + pem_cert_fingerprint(old_fingerprint, flags) +
"\n";
1730 message += tr(
"The above X.509 certificate could not be verified, "
1731 "possibly because you do not have the CA certificate "
1732 "in your certificate store, or the certificate has expired. "
1733 "Please look at the OpenSSL documentation on "
1734 "how to add a private CA to the store.");
1737 message += tr(
"Yes - trusted") +
"\n";
1738 message += tr(
"Ignore - temporary trusted") +
"\n";
1739 message += tr(
"No - no trusted") +
"\n";
1741 bool bCheckBox =
false;
1742 QMessageBox::StandardButton nRet = QMessageBox::StandardButton::No;
1743 QMessageBox::StandardButtons buttons = QMessageBox::Yes | QMessageBox::Ignore | QMessageBox::No;
1745 tr(
"Don't show again"));
1746 pThis->m_pParameter->SetShowVerifyDiaglog(!bCheckBox);
1753 case QMessageBox::StandardButton::Yes:
1755 case QMessageBox::StandardButton::Ignore:
1766BOOL CConnectFreeRDP::cb_present_gateway_message(
1767 freerdp* instance, UINT32 type, BOOL isDisplayMandatory,
1768 BOOL isConsentMandatory,
size_t length,
const WCHAR* message)
1770 qDebug(log) << Q_FUNC_INFO;
1772 if (!isDisplayMandatory && !isConsentMandatory)
1776 if (type == GATEWAY_MESSAGE_CONSENT && isConsentMandatory)
1778 QString msgType = (type == GATEWAY_MESSAGE_CONSENT)
1779 ? tr(
"Consent message") : tr(
"Service message");
1781#if FreeRDP_VERSION_MAJOR >= 3
1782 char* pMsg = ConvertWCharToUtf8Alloc(message, NULL);
1788 msgType += QString::fromStdWString((
wchar_t*)message);
1791 msgType += tr(
"I understand and agree to the terms of this policy (Y/N)");
1793 rdpContext* pContext = (rdpContext*)instance->context;
1795 QMessageBox::StandardButton nRet = QMessageBox::No;
1796 bool bCheckBox =
false;
1798 QMessageBox::Yes|QMessageBox::No,
1801 case QMessageBox::Yes:
1809 return client_cli_present_gateway_message(
1810 instance, type, isDisplayMandatory,
1811 isConsentMandatory, length, message);
1816BOOL CConnectFreeRDP::cb_begin_paint(rdpContext *context)
1820 if (!context || !context->gdi || !context->gdi->primary
1821 || !context->gdi->primary->hdc)
1824 hdc = context->gdi->primary->hdc;
1826 if (!hdc || !hdc->hwnd || !hdc->hwnd->invalid)
1829 hdc->hwnd->invalid->null = TRUE;
1830 hdc->hwnd->ninvalid = 0;
1834BOOL CConnectFreeRDP::UpdateBuffer(INT32 x, INT32 y, INT32 w, INT32 h)
1836 if(x > m_Image.width() || y > m_Image.height()) {
1837 qCritical(log) <<
"The width and height out of range."
1838 <<
"Image width:" << m_Image.width()
1839 <<
"Image height:" << m_Image.height()
1840 <<
"w:" << w <<
"h:" << h;
1844 QRect rect(x, y, w, h);
1845 QImage img = m_Image.copy(rect);
1851BOOL CConnectFreeRDP::cb_end_paint(rdpContext *context)
1854 ClientContext* pContext = (ClientContext*)context;
1858 REGION16 invalidRegion;
1859 RECTANGLE_16 invalidRect;
1860 const RECTANGLE_16* extents;
1864 if (!context || !context->gdi || !context->gdi->primary
1865 || !context->gdi->primary->hdc)
1868 hdc = context->gdi->primary->hdc;
1870 if (!hdc || !hdc->hwnd || !hdc->hwnd->invalid)
1873 rdpGdi* gdi = context->gdi;
1874 if (gdi->suppressOutput)
1877 HGDI_WND hwnd = context->gdi->primary->hdc->hwnd;
1878 ninvalid = hwnd->ninvalid;
1879 cinvalid = hwnd->cinvalid;
1883 region16_init(&invalidRegion);
1885 for (i = 0; i < ninvalid; i++)
1887 if(cinvalid[i].null)
1889 qWarning(log) <<
"is null region" << cinvalid[i].x << cinvalid[i].y
1890 << cinvalid[i].w << cinvalid[i].h;
1893 invalidRect.left = cinvalid[i].x;
1894 invalidRect.top = cinvalid[i].y;
1895 invalidRect.right = cinvalid[i].x + cinvalid[i].w;
1896 invalidRect.bottom = cinvalid[i].y + cinvalid[i].h;
1897 region16_union_rect(&invalidRegion, &invalidRegion, &invalidRect);
1900 if (!region16_is_empty(&invalidRegion))
1902 extents = region16_extents(&invalidRegion);
1904 pThis->UpdateBuffer(extents->left,
1906 extents->right - extents->left,
1907 extents->bottom - extents->top);
1910 region16_uninit(&invalidRegion);
1915BOOL CConnectFreeRDP::cb_desktop_resize(rdpContext* context)
1917 qDebug(log) << Q_FUNC_INFO;
1918 ClientContext* pContext = (ClientContext*)context;
1920 rdpSettings* settings;
1921 if (!context || !context->settings)
1923 settings = context->settings;
1924 int desktopWidth = freerdp_settings_get_uint32(settings, FreeRDP_DesktopWidth);
1925 int desktopHeight = freerdp_settings_get_uint32(settings, FreeRDP_DesktopHeight);
1927 if(!gdi_resize(context->gdi, desktopWidth, desktopHeight))
1929 if(!pThis->CreateImage(context))
1932 emit pThis->sigSetDesktopSize(desktopWidth, desktopHeight);
1933 pThis->UpdateBuffer(0, 0, desktopWidth, desktopHeight);
1937BOOL CConnectFreeRDP::cb_play_bell_sound(rdpContext *context,
const PLAY_SOUND_UPDATE *play_sound)
1939 qDebug(log) << Q_FUNC_INFO;
1940 ClientContext* pContext = (ClientContext*)context;
1942 WINPR_UNUSED(play_sound);
1943 QApplication::beep();
1947#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
1948 QSoundEffect effect;
1949 effect.setSource(QUrl::fromLocalFile(szFile));
1954 QSound::play(szFile);
1960BOOL CConnectFreeRDP::cb_keyboard_set_indicators(rdpContext *context, UINT16 led_flags)
1962 qDebug(log) << Q_FUNC_INFO;
1963 ClientContext* pContext = (ClientContext*)context;
1966 int state = CFrmViewer::LED_STATE::Unknown;
1968 if (led_flags & KBD_SYNC_NUM_LOCK)
1969 state |= CFrmViewer::LED_STATE::NumLock;
1970 if (led_flags & KBD_SYNC_CAPS_LOCK)
1971 state |= CFrmViewer::LED_STATE::CapsLock;
1972 if (led_flags & KBD_SYNC_SCROLL_LOCK)
1973 state |= CFrmViewer::LED_STATE::ScrollLock;
1975 emit pThis->sigUpdateLedState(state);
1981BOOL CConnectFreeRDP::cb_keyboard_set_ime_status(
1982 rdpContext* context, UINT16 imeId, UINT32 imeState, UINT32 imeConvMode)
1988 "KeyboardSetImeStatus(unitId=%04" PRIx16
", imeState=%08" PRIx32
1989 ", imeConvMode=%08" PRIx32
") ignored",
1990 imeId, imeState, imeConvMode);
1997 SetEvent(m_writeEvent);
2002bool CConnectFreeRDP::SendMouseEvent(UINT16 flags, QPoint pos,
bool isExtended)
2004 if(m_pParameter && m_pParameter->GetOnlyView())
return true;
2005 if(!m_pContext)
return false;
2007#if FreeRDP_VERSION_MAJOR >= 3
2009 freerdp_client_send_extended_button_event(
2010 &m_pContext->Context, FALSE, flags, pos.x(), pos.y());
2012 freerdp_client_send_button_event(
2013 &m_pContext->Context, FALSE, flags, pos.x(), pos.y());
2015 if(!m_pContext->Context.input)
return false;
2016 return freerdp_input_send_mouse_event(
2017 m_pContext->Context.input, flags, pos.x(), pos.y());
2022void CConnectFreeRDP::wheelEvent(QWheelEvent *event)
2024 qDebug(logMouse) << Q_FUNC_INFO << event;
2025 if(!m_pContext)
return;
2026 if(m_pParameter && m_pParameter->GetOnlyView())
return;
2030#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
2031 pos =
event->position();
2035 QPoint p =
event->angleDelta();
2038 flags |= PTR_FLAGS_WHEEL | p.y();
2042 flags |= PTR_FLAGS_WHEEL | PTR_FLAGS_WHEEL_NEGATIVE | -p.y();
2047 flags |= PTR_FLAGS_HWHEEL | PTR_FLAGS_WHEEL_NEGATIVE | -p.x();
2051 flags |= PTR_FLAGS_HWHEEL | p.x();
2053#if FreeRDP_VERSION_MAJOR >= 3
2054 freerdp_client_send_wheel_event(&m_pContext->Context, flags);
2059 freerdp_input_send_mouse_event(
2060 m_pContext->Context.input, flags, pos.x(), pos.y());
2065void CConnectFreeRDP::mouseMoveEvent(QMouseEvent *event)
2067 qDebug(logMouse) << Q_FUNC_INFO <<
event <<
event->buttons() <<
event->button();
2068 if(!m_pContext)
return;
2069 if(m_pParameter && m_pParameter->GetOnlyView())
return;
2070 UINT16 flags = PTR_FLAGS_MOVE;
2071 SendMouseEvent(flags, event->pos(),
false);
2074void CConnectFreeRDP::mousePressEvent(QMouseEvent *event)
2076 qDebug(logMouse) << Q_FUNC_INFO <<
event <<
event->buttons() <<
event->button();
2077 if(!m_pContext)
return;
2078 if(m_pParameter && m_pParameter->GetOnlyView())
return;
2081 bool isExtended =
false;
2082 Qt::MouseButton button =
event->button();
2083 if (button & Qt::MouseButton::LeftButton)
2085 flags = PTR_FLAGS_DOWN | PTR_FLAGS_BUTTON1;
2087 else if (button & Qt::MouseButton::RightButton)
2089 flags = PTR_FLAGS_DOWN | PTR_FLAGS_BUTTON2;
2091 else if (button & Qt::MouseButton::MiddleButton)
2093 flags = PTR_FLAGS_DOWN | PTR_FLAGS_BUTTON3;
2095 else if (button & Qt::MouseButton::ForwardButton)
2097 flags = PTR_XFLAGS_DOWN | PTR_XFLAGS_BUTTON2;
2100 else if (button & Qt::MouseButton::BackButton)
2102 flags = PTR_XFLAGS_DOWN | PTR_XFLAGS_BUTTON1;
2107 SendMouseEvent(flags, event->pos(), isExtended);
2111void CConnectFreeRDP::mouseReleaseEvent(QMouseEvent *event)
2113 qDebug(logMouse) << Q_FUNC_INFO <<
event <<
event->buttons() <<
event->button();
2114 if(!m_pContext)
return;
2115 if(m_pParameter && m_pParameter->GetOnlyView())
return;
2118 bool isExtended =
false;
2119 Qt::MouseButton button =
event->button();
2120 if (button & Qt::MouseButton::LeftButton)
2122 flags = PTR_FLAGS_BUTTON1;
2124 else if (button & Qt::MouseButton::MiddleButton)
2126 flags = PTR_FLAGS_BUTTON3;
2128 else if (button & Qt::MouseButton::RightButton)
2130 flags = PTR_FLAGS_BUTTON2;
2132 else if (button & Qt::MouseButton::ForwardButton)
2134 flags = PTR_XFLAGS_BUTTON2;
2137 else if (button & Qt::MouseButton::BackButton)
2139 flags = PTR_XFLAGS_BUTTON1;
2144 SendMouseEvent(flags, event->pos(), isExtended);
2148void CConnectFreeRDP::keyPressEvent(QKeyEvent *event)
2150 qDebug(logKey) << Q_FUNC_INFO << event;
2151 if(!m_pContext)
return;
2152 if(m_pParameter && m_pParameter->GetOnlyView())
return;
2155 if(RDP_SCANCODE_UNKNOWN != k)
2156#if FreeRDP_VERSION_MAJOR >= 3
2157 freerdp_input_send_keyboard_event_ex(
2158 m_pContext->Context.context.input,
true,
true, k);
2160 freerdp_input_send_keyboard_event_ex(
2161 m_pContext->Context.input,
true, k);
2165void CConnectFreeRDP::keyReleaseEvent(QKeyEvent *event)
2167 qDebug(logKey) << Q_FUNC_INFO << event;
2168 if(!m_pContext)
return;
2169 if(m_pParameter && m_pParameter->GetOnlyView())
return;
2171 if(RDP_SCANCODE_UNKNOWN != k)
2172#if FreeRDP_VERSION_MAJOR >= 3
2173 freerdp_input_send_keyboard_event_ex(
2174 m_pContext->Context.context.input,
false,
false, k);
2176 freerdp_input_send_keyboard_event_ex(
2177 m_pContext->Context.input,
false, k);
2181int CConnectFreeRDP::RedirectionSound()
2183 rdpContext* pRdpContext = (rdpContext*)m_pContext;
2184 freerdp* instance = freerdp_client_get_instance(pRdpContext);
2185 rdpSettings* settings = instance->context->settings;
2188 if(m_pParameter->GetRedirectionSound()
2189 == CParameterFreeRDP::RedirecionSoundType::Disable)
2192 freerdp_settings_set_bool(settings, FreeRDP_AudioPlayback, FALSE);
2193 freerdp_settings_set_bool(settings, FreeRDP_RemoteConsoleAudio, FALSE);
2195 }
else if(m_pParameter->GetRedirectionSound()
2196 == CParameterFreeRDP::RedirecionSoundType::Local)
2198 freerdp_settings_set_bool(settings, FreeRDP_AudioPlayback, TRUE);
2199 freerdp_settings_set_bool(settings, FreeRDP_AudioCapture, TRUE);
2200 }
else if(m_pParameter->GetRedirectionSound()
2201 == CParameterFreeRDP::RedirecionSoundType::Remote)
2203 freerdp_settings_set_bool(settings, FreeRDP_RemoteConsoleAudio, TRUE);
2218 ptr.p = CommandLineParseCommaSeparatedValuesEx(
"rdpsnd",
2219 m_pParameter->GetRedirectionSoundParameters().toStdString().c_str(),
2221 BOOL status = freerdp_client_add_static_channel(settings, count,
2222 #
if FreeRDP_VERSION_MAJOR < 3
2230 status = freerdp_client_add_dynamic_channel(settings, count,
2231 #
if FreeRDP_VERSION_MAJOR < 3
2241 qCritical(log) <<
"Load rdpsnd fail";
2248int CConnectFreeRDP::RedirectionMicrophone()
2250 if(m_pParameter->GetRedirectionSound()
2251 == CParameterFreeRDP::RedirecionSoundType::Remote)
2253 if(!m_pParameter->GetRedirectionMicrophone())
2256 rdpContext* pRdpContext = (rdpContext*)m_pContext;
2257 freerdp* instance = freerdp_client_get_instance(pRdpContext);
2259 rdpSettings* settings = instance->context->settings;
2262 freerdp_settings_set_bool(settings, FreeRDP_AudioCapture, TRUE);
2273 ptr.p = CommandLineParseCommaSeparatedValuesEx(
"audin",
2274 m_pParameter->GetRedirectionMicrophoneParameters().toStdString().c_str(),
2276 BOOL status = freerdp_client_add_dynamic_channel(settings, count,
2277 #
if FreeRDP_VERSION_MAJOR < 3
2286 qCritical(log) <<
"Load audin fail";
2293int CConnectFreeRDP::RedirectionDriver()
2295 QStringList lstDrives = m_pParameter->GetRedirectionDrives();
2296 if(lstDrives.isEmpty())
2299 rdpContext* pRdpContext = (rdpContext*)m_pContext;
2300 freerdp* instance = freerdp_client_get_instance(pRdpContext);
2301 rdpSettings* settings = instance->context->settings;
2304 foreach (
auto drive, lstDrives) {
2306 char* pDrive = _strdup(drive.toStdString().c_str());
2307 const char* argvDrive[] = {
"drive", pDrive};
2308 int count =
sizeof(argvDrive) /
sizeof(
const char*);
2309 BOOL status = freerdp_client_add_device_channel(settings, count,
2310 #
if FreeRDP_VERSION_MAJOR < 3
2314 if(pDrive) free(pDrive);
2317 qCritical(log) <<
"Load drive fail";
2325int CConnectFreeRDP::RedirectionPrinter()
2327 if(!m_pParameter->GetRedirectionPrinter())
2330 rdpContext* pRdpContext = (rdpContext*)m_pContext;
2331 freerdp* instance = freerdp_client_get_instance(pRdpContext);
2332 rdpSettings* settings = instance->context->settings;
2335 QStringList printerList = QPrinterInfo::availablePrinterNames();
2336 if(printerList.isEmpty())
2338 qCritical(log) <<
"The printer is empty";
2341 qDebug(log) << printerList;
2344 const char* argvPrinter[] = {
"printer",
nullptr,
nullptr};
2345 int count =
sizeof(argvPrinter) /
sizeof(
const char*);
2346 BOOL status = freerdp_client_add_device_channel(settings, count,
2347 #
if FreeRDP_VERSION_MAJOR < 3
2352 qCritical(log) <<
"Load printer fail";
2359int CConnectFreeRDP::RedirectionSerial()
2363 rdpContext* pRdpContext = (rdpContext*)m_pContext;
2364 freerdp* instance = freerdp_client_get_instance(pRdpContext);
2365 rdpSettings* settings = instance->context->settings;
2368 QList<QSerialPortInfo> lstSerial = QSerialPortInfo::availablePorts();
2371 foreach (
auto serial, lstSerial) {
2374 qDebug(log) <<
"systemLocation:" << serial.systemLocation()
2375 <<
"portName:" << serial.portName()
2376 <<
"serialNumber:" << serial.serialNumber();
2377 char* pSerial = _strdup(serial.systemLocation().toStdString().c_str());
2378 char* pName = _strdup(serial.portName().toStdString().c_str());
2379 const char* argvSerial[] = {
"serial", pName, pSerial};
2380 int count =
sizeof(argvSerial) /
sizeof(
const char*);
2381 BOOL status = freerdp_client_add_device_channel(settings, count,
2382 #
if FreeRDP_VERSION_MAJOR < 3
2386 if(pSerial) free(pSerial);
2387 if(pName) free(pName);
2391 qCritical(log) <<
"Load drive fail";
2399void CConnectFreeRDP::slotConnectProxyServer(QString szHost, quint16 nPort)
2401 qDebug(log) <<
"CConnectFreeRDP::slotConnectProxyServer" << nPort;
2402 rdpContext* pContext = (rdpContext*)m_pContext;
2403 rdpSettings* settings = pContext->settings;
2405 qCritical(log) <<
"settings is null";
2408 freerdp_settings_set_string(
2409 settings, FreeRDP_ServerHostname,
2410 szHost.toStdString().c_str());
2411 freerdp_settings_set_uint32(
2412 settings, FreeRDP_ServerPort,
2415 int nRet = freerdp_client_start(pContext);
2418 qCritical(log) <<
"freerdp_client_start fail";
2420 qDebug(log) <<
"CConnectFreeRDP::slotConnectProxyServer end";
Remote desktop connect interface.
void sigUpdateRect(const QRect &r, const QImage &image)
Notify the CFrmView update image.
virtual OnInitReturnValue OnInit() override
Specific plug-in realizes connection initialization.
virtual int OnClean() override
Clean.
static int cb_verify_x509_certificate(freerdp *instance, const BYTE *data, size_t length, const char *hostname, UINT16 port, DWORD flags)
Callback used if user interaction is required to accept a certificate.
static DWORD cb_verify_changed_certificate_ex(freerdp *instance, const char *host, UINT16 port, const char *common_name, const char *subject, const char *issuer, const char *fingerprint, const char *old_subject, const char *old_issuer, const char *old_fingerprint, DWORD flags)
Callback set in the rdp_freerdp structure, and used to make a certificate validation when a stored ce...
virtual int WakeUp() override
Wake up Connect thread(background thread)
static DWORD cb_verify_certificate_ex(freerdp *instance, const char *host, UINT16 port, const char *common_name, const char *subject, const char *issuer, const char *fingerprint, DWORD flags)
Callback set in the rdp_freerdp structure, and used to make a certificate validation when the connect...
virtual int OnProcess() override
Specific operation processing of plug-in connection.
static BOOL cb_post_connect(freerdp *instance)
Callback given to freerdp_connect() to perform post-connection operations.
static BOOL cb_pre_connect(freerdp *instance)
Callback given to freerdp_connect() to process the pre-connect operations.
void sigError(const int nError, const QString &szError=QString())
Triggered when an error is generated.
void sigInformation(const QString &szInfo)
Triggering from a background thread displays information in the main thread without blocking the back...
void sigBlockShowMessageBox(const QString &szTitle, const QString &szMessage, QMessageBox::StandardButtons buttons, QMessageBox::StandardButton &nRet, bool &checkBox, QString checkBoxContext=QString())
Block background threads and display message dialogs in foreground threads (QMessageBox)
void sigShowMessageBox(const QString &szTitle, const QString &szMessage, const QMessageBox::Icon &icon=QMessageBox::Information)
Trigger the display of a message dialog (QMessageBox) in the main thread from a background thread wit...
void sigBlockInputDialog(const QString &szTitle, const QString &szLable, const QString &szMessage, QString &szText)
Block background threads and display input dialogs in foreground threads (QInputDialog)
void sigConnected()
Emitted when the plugin is successfully connected.
void sigDisconnect()
Notify the user to call disconnect.
void sigBlockShowWidget(const QString &className, int &nRet, void *pContext)
Blocks the background thread and displays the window in the foreground thread.
static UINT32 QtToScanCode(int key, Qt::KeyboardModifiers modifiers)
CConvertKeyCode::QtToScanCode.
[Declare CParameterFreeRDP]
CParameterUser m_User
[Instance user]
void sigChanged()
emit when the parameter changes Usually if required, the corresponding parameter corresponds to a cha...
Data is forwarded over a local socket and SSH tunnel.