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";
void sigUpdateRect(const QRect &r, const QImage &image)
通知视图,图像更新
virtual OnInitReturnValue OnInit() override
具体的插件实现连接初始化
virtual int OnClean() override
清理
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
唤醒连接线程(后台线程)
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
插件连接的具体操作处理。因为此插件是非Qt事件,所以在此函数中等待。
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())
当有错误产生时触发
void sigInformation(const QString &szInfo)
从后台线程中触发在主线程中显示信息,不阻塞后台线程
void sigBlockShowMessageBox(const QString &szTitle, const QString &szMessage, QMessageBox::StandardButtons buttons, QMessageBox::StandardButton &nRet, bool &checkBox, QString checkBoxContext=QString())
阻塞后台线程,并在前台线程中显示消息对话框(QMessageBox)
void sigShowMessageBox(const QString &szTitle, const QString &szMessage, const QMessageBox::Icon &icon=QMessageBox::Information)
从后台线程中触发在主线程中显示消息对话框(QMessageBox),不阻塞后台线程
void sigBlockInputDialog(const QString &szTitle, const QString &szLable, const QString &szMessage, QString &szText)
阻塞后台线程,并在前台线程中显示输入对话框 (QInputDialog)
void sigConnected()
当插件连接成功后触发。仅由插件触发
void sigDisconnect()
通知用户断开连接。仅由插件触发。 当从插件中需要要断开连接时触发。例如:对端断开连接、重置连接或者连接出错。
void sigBlockShowWidget(const QString &className, int &nRet, void *pContext)
阻塞后台线程,并在前台线程中显示窗口。
static UINT32 QtToScanCode(int key, Qt::KeyboardModifiers modifiers)
CConvertKeyCode::QtToScanCode
[Declare CParameterFreeRDP]
CParameterUser m_User
[Instance user]
void sigChanged()
当参数改变时,触发 通常如果需要,则相应的参数会对应一个改变事件。
实现通过本地 SOCKET 与 SSH 隧道转发数据。适用于库没有实现传输层接口,只有 socket 的情况。