玉兔远程控制 0.0.34
载入中...
搜索中...
未找到
ConnectFreeRDP.cpp
1// Author: Kang Lin <kl222@126.com>
2// https://learn.microsoft.com/zh-cn/windows-server/remote/remote-desktop-services/welcome-to-rds
3// X.509 Public Key Certificates: https://learn.microsoft.com/zh-cn/windows/win32/seccertenroll/about-x-509-public-key-certificates
4// Cryptography: https://learn.microsoft.com/zh-cn/windows/win32/seccrypto/cryptography-portal
5
6#include "ConnectFreeRDP.h"
7
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>
24
25#include "RabbitCommonTools.h"
26#include "ConvertKeyCode.h"
27
28#include <memory.h>
29#include <QDebug>
30#include <QApplication>
31#include <QScreen>
32#include <QSslCertificate>
33#include <QInputDialog>
34#include <QMutexLocker>
35#include <QPainter>
36#include <QPrinterInfo>
37#include <QSerialPort>
38#include <QSerialPortInfo>
39#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
40 #include <QSoundEffect>
41#else
42 #include <QSound>
43#endif
44
45static Q_LOGGING_CATEGORY(log, "FreeRDP.Connect")
46static Q_LOGGING_CATEGORY(logKey, "FreeRDP.Connect.Key")
47static Q_LOGGING_CATEGORY(logMouse, "FreeRDP.Connect.Mouse")
48
50 : CConnectDesktop(pConnecter),
51 m_pContext(nullptr),
52 m_pParameter(nullptr),
53 m_ClipBoard(this),
54 m_Cursor(this),
55 m_writeEvent(nullptr)
56#ifdef HAVE_LIBSSH
57 ,m_pThread(nullptr)
58#endif
59{
60 qDebug(log) << Q_FUNC_INFO;
61 m_pParameter = qobject_cast<CParameterFreeRDP*>(pConnecter->GetParameter());
62 Q_ASSERT(m_pParameter);
63}
64
65CConnectFreeRDP::~CConnectFreeRDP()
66{
67 qDebug(log) << Q_FUNC_INFO;
68}
69
70/*
71 * \return
72 * \li OnInitReturnValue::Fail: error
73 * \li OnInitReturnValue::UseOnProcess: Use OnProcess (non-Qt event loop)
74 * \li OnInitReturnValue::NotUseOnProcess: Don't use OnProcess (qt event loop)
75 */
76CConnect::OnInitReturnValue CConnectFreeRDP::OnInit()
77{
78 qDebug(log) << Q_FUNC_INFO;
79 int nRet = 0;
80
81 m_writeEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
82 if(!m_writeEvent)
83 qCritical(log) << "CreateEvent failed";
84
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);
88 //m_ClientEntryPoints.settings = m_pParameter->m_pSettings;
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;
95 m_ClientEntryPoints.ContextSize = sizeof(ClientContext);
96
97 auto pRdpContext = freerdp_client_context_new(&m_ClientEntryPoints);
98 if(pRdpContext)
99 {
100 m_pContext = (ClientContext*)pRdpContext;
101 m_pContext->pThis = this;
102 } else {
103 qCritical(log) << "freerdp_client_context_new fail";
104 return OnInitReturnValue::Fail;
105 }
106
107 rdpSettings* settings = pRdpContext->settings;
108 if(!settings) {
109 qCritical(log) << "settings is null";
110 return OnInitReturnValue::Fail;
111 }
112
113 char* argv[]= {(char*)QApplication::applicationFilePath().toStdString().c_str()};
114 int argc = sizeof(argv) / sizeof(char*);
115 nRet = freerdp_client_settings_parse_command_line(settings, argc, argv, TRUE);
116 if (nRet)
117 {
118 nRet = freerdp_client_settings_command_line_status_print(settings, nRet, argc, argv);
119 return OnInitReturnValue::Fail;
120 }
121
122#if FreeRDP_VERSION_MAJOR >= 3
123 if (!stream_dump_register_handlers(pRdpContext,
124 CONNECTION_STATE_MCS_CREATE_REQUEST,
125 FALSE))
126 return OnInitReturnValue::Fail;
127#endif
128
129 auto &user = m_pParameter->m_Net.m_User;
130 if(!user.GetUser().isEmpty())
131 freerdp_settings_set_string(
132 settings, FreeRDP_Username,
133 user.GetUser().toStdString().c_str());
134 if(!user.GetPassword().isEmpty())
135 freerdp_settings_set_string(
136 settings, FreeRDP_Password,
137 user.GetPassword().toStdString().c_str());
138
139 freerdp_settings_set_bool(
140 settings, FreeRDP_RedirectClipboard, m_pParameter->GetClipboard());
141
142#if FreeRDP_VERSION_MAJOR >= 3
143 bool bOnlyView = m_pParameter->GetOnlyView();
144 freerdp_settings_set_bool(
145 settings, FreeRDP_SuspendInput, bOnlyView);
146#endif
147
148 freerdp_settings_set_uint32(settings, FreeRDP_DesktopWidth,
149 m_pParameter->GetDesktopWidth());
150 freerdp_settings_set_uint32(settings, FreeRDP_DesktopHeight,
151 m_pParameter->GetDesktopHeight());
152 freerdp_settings_set_uint32(settings, FreeRDP_ColorDepth,
153 m_pParameter->GetColorDepth());
154
155 freerdp_settings_set_bool(settings, FreeRDP_UseMultimon,
156 m_pParameter->GetUseMultimon());
157
158 if(m_pParameter->GetReconnectInterval()) {
159 freerdp_settings_set_bool(
160 settings, FreeRDP_AutoReconnectionEnabled, true);
161 freerdp_settings_set_uint32(
162 settings,
163 FreeRDP_AutoReconnectMaxRetries,
164 m_pParameter->GetReconnectInterval());
165 }
166 else
167 freerdp_settings_set_bool(
168 settings, FreeRDP_AutoReconnectionEnabled, false);
169
170 //*Load channel
171 RedirectionSound();
172 RedirectionMicrophone();
173 RedirectionDriver();
174 RedirectionPrinter();
175 RedirectionSerial();
176 //*/
177
178 // Set proxy
179 switch(m_pParameter->m_Proxy.GetUsedType())
180 {
181 case CParameterProxy::TYPE::None:
182 {
183 if(!m_pParameter->GetDomain().isEmpty())
184 freerdp_settings_set_string(
185 settings, FreeRDP_Domain,
186 m_pParameter->GetDomain().toStdString().c_str());
187 if(m_pParameter->m_Net.GetHost().isEmpty())
188 {
189 QString szErr;
190 szErr = tr("The server is empty, please input it");
191 qCritical(log) << szErr;
192 emit sigShowMessageBox(tr("Error"), szErr, QMessageBox::Critical);
193 emit sigError(-1, szErr.toStdString().c_str());
194 return OnInitReturnValue::Fail;
195 }
196 auto &net = m_pParameter->m_Net;
197 freerdp_settings_set_string(
198 settings, FreeRDP_ServerHostname,
199 net.GetHost().toStdString().c_str());
200 freerdp_settings_set_uint32(
201 settings, FreeRDP_ServerPort,
202 net.GetPort());
203
204 nRet = freerdp_client_start(pRdpContext);
205 if(nRet)
206 {
207 qCritical(log) << "freerdp_client_start fail";
208 return OnInitReturnValue::Fail;
209 }
210 break;
211 }
212#ifdef HAVE_LIBSSH
213 case CParameterProxy::TYPE::SSHTunnel:
214 {
215 // Set SSH parameters
216 QSharedPointer<CParameterChannelSSH> parameter(new CParameterChannelSSH());
217 auto &ssh = m_pParameter->m_Proxy.m_SSH;
218 parameter->setServer(ssh.GetHost());
219 parameter->setPort(ssh.GetPort());
220 auto &user = ssh.m_User;
221 parameter->SetUser(user.GetUser());
222 parameter->SetUseSystemFile(user.GetUseSystemFile());
223 if(CParameterUser::TYPE::UserPassword == user.GetUsedType()) {
224 parameter->SetAuthenticationMethod(SSH_AUTH_METHOD_PASSWORD);
225 parameter->SetPassword(user.GetPassword());
226 }
227 if(CParameterUser::TYPE::PublicKey == user.GetUsedType()) {
228 parameter->SetAuthenticationMethod(SSH_AUTH_METHOD_PUBLICKEY);
229 parameter->SetPublicKeyFile(user.GetPublicKeyFile());
230 parameter->SetPrivateKeyFile(user.GetPrivateKeyFile());
231 parameter->SetPassphrase(user.GetPassphrase());
232 }
233 auto &net = m_pParameter->m_Net;
234 parameter->SetRemoteHost(net.GetHost());
235 parameter->SetRemotePort(net.GetPort());
236
237 // Start ssh thread
238 if(!m_pThread)
239 m_pThread = new CSSHTunnelThread(parameter);
240 if(!m_pThread)
241 return OnInitReturnValue::Fail;
242 bool check = connect(m_pThread, SIGNAL(sigServer(QString, quint16)),
243 this, SLOT(slotConnectProxyServer(QString, quint16)));
244 Q_ASSERT(check);
245 check = connect(m_pThread, SIGNAL(sigError(int,QString)),
246 this, SIGNAL(sigError(int,QString)));
247 Q_ASSERT(check);
248 check = connect(m_pThread, SIGNAL(sigDisconnect()),
249 this, SIGNAL(sigDisconnect()));
250 Q_ASSERT(check);
251 m_pThread->start();
252 break;
253 }
254#endif
255 default:
256 break;
257 };
258
259 return OnInitReturnValue::UseOnProcess;
260}
261
263{
264 qDebug(log) << Q_FUNC_INFO;
265 int nRet = 0;
266
267#ifdef HAVE_LIBSSH
268 if(m_pThread)
269 {
270 m_pThread->Exit();
271 m_pThread = nullptr;
272 }
273#endif
274 if(m_writeEvent)
275 {
276 CloseHandle(m_writeEvent);
277 m_writeEvent = nullptr;
278 }
279 if(m_pContext)
280 {
281 rdpContext* pRdpContext = (rdpContext*)m_pContext;
282 if(!freerdp_disconnect(pRdpContext->instance))
283 qCritical(log) << "freerdp_disconnect fail";
284
285 if(freerdp_client_stop(pRdpContext))
286 qCritical(log) << "freerdp_client_stop fail";
287
288 freerdp_client_context_free(pRdpContext);
289 m_pContext = nullptr;
290 }
291 return nRet;
292}
293
308{
309 //qDebug(log) << Q_FUNC_INFO;
310 int nRet = 0;
311 HANDLE handles[64];
312 rdpContext* pRdpContext = (rdpContext*)m_pContext;
313
314 if(nullptr == freerdp_settings_get_string(pRdpContext->settings, FreeRDP_ServerHostname))
315 {
316 return 50;
317 }
318
319 do {
320
321 DWORD nCount = 0;
322 nCount = freerdp_get_event_handles(pRdpContext, &handles[nCount],
323 ARRAYSIZE(handles) - nCount);
324 if (nCount == 0)
325 {
326 qCritical(log) << "freerdp_get_event_handles failed";
327 nRet = -2;
328 break;
329 }
330
331 handles[nCount] = m_writeEvent;
332 nCount++;
333
334 DWORD waitStatus = WaitForMultipleObjects(nCount, handles, FALSE, 500);
335
336 ResetEvent(m_writeEvent);
337
338 if (waitStatus == WAIT_FAILED)
339 {
340 qCritical(log) << "WaitForMultipleObjects: WAIT_FAILED";
341 nRet = -3;
342 break;
343 }
344
345 if(waitStatus == WAIT_TIMEOUT)
346 {
347 //qDebug(log) << "WaitForMultipleObjects timeout";
348 nRet = 0;
349 break;
350 }
351
352 if (!freerdp_check_event_handles(pRdpContext))
353 {
354 nRet = -5;
355
356 UINT32 err = freerdp_get_last_error(pRdpContext);
357 QString szErr;
358 szErr = "freerdp_check_event_handles fail.";
359 szErr += " [";
360 szErr += QString::number(err);
361 szErr += " - ";
362 szErr += freerdp_get_last_error_category(err);
363 szErr += " - ";
364 szErr += freerdp_get_last_error_name(err);
365 szErr += "] ";
366 szErr += freerdp_get_last_error_string(err);
367 qCritical(log) << szErr;
368 emit sigError(err, szErr);
369
370 /*/ Reconnect
371 freerdp *instance = pRdpContext->instance;
372 if (client_auto_reconnect(instance))
373 {
374 nRet = 0;
375 break;
376 }
377
378 err = freerdp_get_last_error(pRdpContext);
379 szErr = "client_auto_reconnect[";
380 szErr += QString::number(err);
381 szErr += "]";
382 szErr += freerdp_get_last_error_category(err);
383 szErr += "-";
384 szErr += freerdp_get_last_error_name(err);
385 szErr += ":";
386 szErr += freerdp_get_last_error_string(err);
387 qCritical(log) << szErr;
388 emit sigError(err, szErr);//*/
389 }
390
391#if FreeRDP_VERSION_MAJOR >= 3
392 if(freerdp_shall_disconnect_context(pRdpContext))
393#else
394 if(freerdp_shall_disconnect(pRdpContext->instance))
395#endif
396 {
397 qCritical(log) << "freerdp_shall_disconnect false";
398 nRet = -7;
399 }
400 } while(false);
401
402 return nRet;
403}
404
405void CConnectFreeRDP::slotClipBoardChanged()
406{
407 qDebug(log) << Q_FUNC_INFO;
408 if(m_pParameter && m_pParameter->GetOnlyView()) return;
409 if(m_pParameter->GetClipboard())
410 m_ClipBoard.slotClipBoardChanged();
411}
412
413BOOL CConnectFreeRDP::cbGlobalInit()
414{
415 qDebug(log) << Q_FUNC_INFO;
416 return TRUE;
417}
418
419void CConnectFreeRDP::cbGlobalUninit()
420{
421 qDebug(log) << Q_FUNC_INFO;
422}
423
424BOOL CConnectFreeRDP::cbClientNew(freerdp *instance, rdpContext *context)
425{
426 qDebug(log) << Q_FUNC_INFO;
427 instance->PreConnect = cb_pre_connect;
428 instance->PostConnect = cb_post_connect;
429 instance->PostDisconnect = cb_post_disconnect;
430
431 // Because it is already set in the parameters
432#if FreeRDP_VERSION_MAJOR < 3
433 instance->Authenticate = cb_authenticate;
434 instance->GatewayAuthenticate = cb_GatewayAuthenticate;
435#else
436 instance->AuthenticateEx = cb_authenticate_ex;
437 instance->ChooseSmartcard = cb_choose_smartcard;
438#endif
439 instance->VerifyX509Certificate = cb_verify_x509_certificate;
440 /*instance->VerifyCertificateEx = cb_verify_certificate_ex;
441 instance->VerifyChangedCertificateEx = cb_verify_changed_certificate_ex;//*/
442 instance->PresentGatewayMessage = cb_present_gateway_message;
443
444 instance->LogonErrorInfo = cb_logon_error_info;
445
446 return TRUE;
447}
448
449void CConnectFreeRDP::cbClientFree(freerdp *instance, rdpContext *context)
450{
451 qDebug(log) << Q_FUNC_INFO;
452}
453
454int CConnectFreeRDP::cbClientStart(rdpContext *context)
455{
456 qDebug(log) << Q_FUNC_INFO;
457 int nRet = 0;
458
459 if (!context || !context->settings)
460 return -1;
461 freerdp* instance = freerdp_client_get_instance(context);
462 if(!instance)
463 return -2;
464 CConnectFreeRDP* pThis = ((ClientContext*)context)->pThis;
465 auto settings = context->settings;
466
467 QString szHost;
468 quint16 nPort;
469 szHost = freerdp_settings_get_string(settings, FreeRDP_ServerHostname);
470 nPort = freerdp_settings_get_uint32(settings, FreeRDP_ServerPort);
471 QString szServer;
472 auto &net = pThis->m_pParameter->m_Net;
473 szServer = net.GetHost() + ":" + QString::number(net.GetPort());
474 auto &proxy = pThis->m_pParameter->m_Proxy;
475 switch(proxy.GetUsedType()) {
476 case CParameterProxy::TYPE::SSHTunnel:
477 {
478 auto &sshNet = proxy.m_SSH;
479 szServer = szHost + ":" + QString::number(nPort)
480 + " <-> " + sshNet.GetHost() + ":" + QString::number(sshNet.GetPort())
481 + " <-> " + szServer;
482 break;
483 }
484 default:
485 break;
486 }
487
488 BOOL status = freerdp_connect(instance);
489 if (status) {
490 QString szInfo = tr("Connect to ") + szServer;
491 qInfo(log) << szInfo;
492 emit pThis->sigInformation(szInfo);
493 } else {
494 //DWORD dwErrCode = freerdp_error_info(instance);
495 UINT32 nErr = freerdp_get_last_error(context);
496
497 QString szErr;
498 szErr = tr("Connect to ") + szServer + tr(" fail.");
499 szErr += "\n[";
500 szErr += QString::number(nErr) + " - ";
501 szErr += freerdp_get_last_error_name(nErr);
502 szErr += "] ";
503 /*szErr += "[";
504 szErr += freerdp_get_last_error_category(nErr);
505 szErr += "] ";*/
506 szErr += freerdp_get_last_error_string(nErr);
507 //szErr += "]";
508
509 switch(nErr) {
510 case FREERDP_ERROR_CONNECT_LOGON_FAILURE:
511 {
512 nRet = -3;
513 QString szErr = tr("Logon to ") + szServer;
514 szErr += tr(" fail. Please check that the username and password are correct.") + "\n";
515 emit pThis->sigShowMessageBox(tr("Error"), szErr, QMessageBox::Critical);
516 break;
517 }
518 case FREERDP_ERROR_CONNECT_WRONG_PASSWORD:
519 {
520 nRet = -4;
521 QString szErr = tr("Logon to ") + szServer;
522 szErr += tr(" fail. Please check password are correct.") + "\n";
523 emit pThis->sigShowMessageBox(tr("Error"), szErr, QMessageBox::Critical);
524 break;
525 }
526 case FREERDP_ERROR_AUTHENTICATION_FAILED:
527 {
528 nRet = -5;
529 QString szErr = tr("Logon to ") + szServer;
530 szErr += tr(" authentication fail. please add a CA certificate to the store.") + "\n";
531 emit pThis->sigShowMessageBox(tr("Error"), szErr, QMessageBox::Critical);
532 break;
533 }
534 case FREERDP_ERROR_CONNECT_TRANSPORT_FAILED:
535 {
536 nRet = -6;
537 QString szErr = tr("Logon to ") + szServer;
538 szErr += tr(" connect transport layer fail.") + "\n\n";
539 szErr += tr("Please:") + "\n";
540 szErr += tr("1. Check for any network related issues") + "\n";
541 szErr += tr("2. Check you have proper security settings ('NLA' enabled is required for most connections nowadays)") + "\n";
542 szErr += tr("3. Check the certificate is proper (and guacd properly checks that)") + "\n";
543 emit pThis->sigShowMessageBox(tr("Error"), szErr, QMessageBox::Critical);
544 break;
545 }
546 case FREERDP_ERROR_SECURITY_NEGO_CONNECT_FAILED:
547 default:
548 nRet = -7;
549 emit pThis->sigShowMessageBox(tr("Error"), szErr, QMessageBox::Critical);
550 }
551
552 qCritical(log) << szErr;
553 emit pThis->sigError(nRet, szErr.toStdString().c_str());
554 }
555 return nRet;
556}
557
558int CConnectFreeRDP::cbClientStop(rdpContext *context)
559{
560 int nRet = 0;
561 qDebug(log) << Q_FUNC_INFO;
562#if FreeRDP_VERSION_MAJOR >= 3
563 nRet = freerdp_client_common_stop(context);
564#else
565 BOOL bRet = freerdp_abort_connect(context->instance);
566 if(!bRet)
567 { qCritical(log) << "freerdp_abort_connect fail";
568 nRet = -1;
569 }
570#endif
571 return nRet;
572}
573
592BOOL CConnectFreeRDP::cb_pre_connect(freerdp* instance)
593{
594 qDebug(log) << Q_FUNC_INFO;
595 rdpChannels* channels = nullptr;
596 rdpSettings* settings = nullptr;
597 rdpContext* context = instance->context;
598
599 if (!instance || !instance->context || !instance->context->settings)
600 {
601 return FALSE;
602 }
603
604 CConnectFreeRDP* pThis = ((ClientContext*)context)->pThis;
605 if(!pThis) return FALSE;
606 settings = instance->context->settings;
607 channels = context->channels;
608
609 /* Optional OS identifier sent to server */
610#if defined (Q_OS_WIN)
611 if (!freerdp_settings_set_uint32(settings, FreeRDP_OsMajorType, OSMAJORTYPE_WINDOWS))
612 return FALSE;
613 if (!freerdp_settings_set_uint32(settings, FreeRDP_OsMinorType, OSMINORTYPE_WINDOWS_NT))
614 return FALSE;
615#elif defined(Q_OS_ANDROID)
616 if (!freerdp_settings_set_uint32(settings, FreeRDP_OsMajorType, OSMAJORTYPE_ANDROID))
617 return FALSE;
618 if (!freerdp_settings_set_uint32(settings, FreeRDP_OsMinorType, OSMINORTYPE_UNSPECIFIED))
619 return FALSE;
620#elif defined(Q_OS_IOS)
621 if (!freerdp_settings_set_uint32(settings, FreeRDP_OsMajorType, OSMAJORTYPE_IOS))
622 return FALSE;
623 if (!freerdp_settings_set_uint32(settings, FreeRDP_OsMinorType, OSMINORTYPE_UNSPECIFIED))
624 return FALSE;
625#elif defined (Q_OS_UNIX)
626 if (!freerdp_settings_set_uint32(settings, FreeRDP_OsMajorType, OSMAJORTYPE_UNIX))
627 return FALSE;
628 if (!freerdp_settings_set_uint32(settings, FreeRDP_OsMinorType, OSMINORTYPE_NATIVE_XSERVER))
629 return FALSE;
630#else
631 if (!freerdp_settings_set_uint32(settings, FreeRDP_OsMajorType, OSMAJORTYPE_UNSPECIFIED))
632 return FALSE;
633 if (!freerdp_settings_set_uint32(settings, FreeRDP_OsMinorType, OSMINORTYPE_UNSPECIFIED))
634 return FALSE;
635#endif
636
637 // Subscribe channel event
638 PubSub_SubscribeChannelConnected(instance->context->pubSub,
639 OnChannelConnectedEventHandler);
640 PubSub_SubscribeChannelDisconnected(instance->context->pubSub,
641 OnChannelDisconnectedEventHandler);
642
643#if FreeRDP_VERSION_MAJOR < 3
644 if (!freerdp_client_load_addins(channels, instance->context->settings))
645 return FALSE;
646#endif
647
648 // Check authentication parameters
649 if (freerdp_settings_get_bool(settings, FreeRDP_AuthenticationOnly))
650 {
651 /* Check +auth-only has a username and password. */
652 auto &user = pThis->m_pParameter->m_Net.m_User;
653 if(!freerdp_settings_get_string(settings, FreeRDP_Username)) {
654 if(user.GetUser().isEmpty()) {
655 if(user.GetUser().isEmpty()) {
656 // Will be call instance->Authenticate = cb_authenticate
657 qWarning(log) << "Auth-only, but no user name set. Will be call instance->Authenticate.";
658 }
659 } else
660 freerdp_settings_set_string(
661 settings, FreeRDP_Username,
662 user.GetUser().toStdString().c_str());
663 }
664 if (!freerdp_settings_get_string(settings, FreeRDP_Password)) {
665 if (user.GetPassword().isEmpty()) {
666 // Will be call instance->Authenticate = cb_authenticate
667 qWarning(log) << "auth-only, but no password set. Will be call instance->Authenticate";
668 } else
669 freerdp_settings_set_string(
670 settings, FreeRDP_Password,
671 user.GetPassword().toStdString().c_str());
672 }
673#if FreeRDP_VERSION_MAJOR >= 3
674 if (!freerdp_settings_set_bool(settings, FreeRDP_DeactivateClientDecoding, TRUE))
675 return FALSE;
676#endif
677 qInfo(log) << "Authentication only. Don't connect to X.";
678 } else if(freerdp_settings_get_bool(settings, FreeRDP_CredentialsFromStdin)){
679 // Because the pragram is GUI. so don't process it.
680 } else if(freerdp_settings_get_bool(settings, FreeRDP_SmartcardLogon)) {
681 // TODO: add FreeRDP_SmartcardLogon !
682 }
683
684 /* TODO: Check Keyboard layout
685 UINT32 rc = freerdp_keyboard_init(
686 freerdp_settings_get_uint32(settings, FreeRDP_KeyboardLayout));
687 freerdp_settings_set_uint32(settings, FreeRDP_KeyboardLayout, rc);
688 //*/
689
690 // Check desktop size, it is set in parameter
691 UINT32 width = pThis->m_pParameter->GetDesktopWidth();
692 UINT32 height = pThis->m_pParameter->GetDesktopHeight();
693 if ((width < 64) || (height < 64) ||
694 (width > 4096) || (height > 4096))
695 {
696 QString szErr = tr("Invalid dimensions:")
697 + QString::number(width)
698 + "*" + QString::number(height);
699 qCritical(log) << szErr;
700 //emit pThis->sigShowMessageBox(tr("Error"), szErr);
701 return FALSE;
702 } else {
703 qInfo(log) << "Init desktop size " << width << "*" << height;
704 }
705
706 qDebug(log)
707 << "width:" << freerdp_settings_get_uint32(settings, FreeRDP_DesktopWidth)
708 << "height:" << freerdp_settings_get_uint32(settings, FreeRDP_DesktopHeight)
709 << "ColorDepth:" << freerdp_settings_get_uint32(settings, FreeRDP_ColorDepth);
710
711 return TRUE;
712}
713
714const char* CConnectFreeRDP::GetTitle(freerdp* instance)
715{
716 const char* windowTitle;
717 UINT32 port;
718 BOOL addPort;
719 const char* name = nullptr;
720
721 CConnectFreeRDP* pThis = ((ClientContext*)instance->context)->pThis;
722 rdpSettings* settings = instance->context->settings;
723
724 if (!settings)
725 return nullptr;
726
727 windowTitle = freerdp_settings_get_string(settings, FreeRDP_WindowTitle);
728 if (windowTitle)
729 return windowTitle;
730
731#if FreeRDP_VERSION_MAJOR >= 3
732 name = freerdp_settings_get_server_name(settings);
733#else
734 name = pThis->m_pParameter->m_Net.GetHost().toStdString().c_str();
735#endif
736 port = freerdp_settings_get_uint32(settings, FreeRDP_ServerPort);
737
738 addPort = (port != 3389);
739
740 char buffer[MAX_PATH + 64] = { 0 };
741
742 if (!addPort)
743 sprintf_s(buffer, sizeof(buffer), "%s", name);
744 else
745 sprintf_s(buffer, sizeof(buffer), "%s:%" PRIu32, name, port);
746
747 freerdp_settings_set_string(settings, FreeRDP_WindowTitle, buffer);
748 return freerdp_settings_get_string(settings, FreeRDP_WindowTitle);
749}
750
756BOOL CConnectFreeRDP::cb_post_connect(freerdp* instance)
757{
758 qDebug(log) << Q_FUNC_INFO;
759
760 rdpContext* context = instance->context;
761 rdpSettings* settings = instance->context->settings;
762 rdpUpdate* update = instance->context->update;
763 CConnectFreeRDP* pThis = ((ClientContext*)instance->context)->pThis;
764
765 const char* pWindowTitle = GetTitle(instance);
766 if(pWindowTitle)
767 {
768 WCHAR* windowTitle = NULL;
769#if FreeRDP_VERSION_MAJOR >= 3
770 windowTitle = ConvertUtf8ToWCharAlloc(pWindowTitle, NULL);
771#else
772 ConvertToUnicode(CP_UTF8, 0, pWindowTitle, -1, &windowTitle, 0);
773#endif
774 if(windowTitle)
775 {
776 QString title = QString::fromUtf16((const char16_t*)windowTitle);
777 delete windowTitle;
778 if(pThis->m_pParameter->GetServerName().isEmpty())
779 emit pThis->sigServerName(title);
780 }
781 }
782
783 int desktopWidth = freerdp_settings_get_uint32(settings, FreeRDP_DesktopWidth);
784 int desktopHeight = freerdp_settings_get_uint32(settings, FreeRDP_DesktopHeight);
785 emit pThis->sigSetDesktopSize(desktopWidth, desktopHeight);
786
787 if (!gdi_init(instance, PIXEL_FORMAT_BGRA32))
788 return FALSE;
789
790 if(!pThis->CreateImage(instance->context))
791 return FALSE;
792
793 Q_ASSERT(instance->context->cache);
794
795 // Register cursor pointer
796 if(pThis->m_Cursor.RegisterPointer(context->graphics))
797 return FALSE;
798
799 update->BeginPaint = cb_begin_paint;
800 update->EndPaint = cb_end_paint;
801 update->DesktopResize = cb_desktop_resize;
802
803 update->PlaySound = cb_play_bell_sound;
804
805 update->SetKeyboardIndicators = cb_keyboard_set_indicators;
806 update->SetKeyboardImeStatus = cb_keyboard_set_ime_status;
807
808 emit pThis->sigConnected();
809 return TRUE;
810}
811
812void CConnectFreeRDP::cb_post_disconnect(freerdp* instance)
813{
814 qDebug(log) << Q_FUNC_INFO;
815 rdpContext* context = nullptr;
816
817 if (!instance || !instance->context)
818 return;
819
820 context = instance->context;
821
822 PubSub_UnsubscribeChannelConnected(instance->context->pubSub,
823 OnChannelConnectedEventHandler);
824 PubSub_UnsubscribeChannelDisconnected(instance->context->pubSub,
825 OnChannelDisconnectedEventHandler);
826 gdi_free(instance);
827}
828
829int CConnectFreeRDP::cb_logon_error_info(freerdp* instance, UINT32 data, UINT32 type)
830{
831 CConnectFreeRDP* pThis = ((ClientContext*)instance->context)->pThis;
832 const char* str_data = freerdp_get_logon_error_info_data(data);
833 const char* str_type = freerdp_get_logon_error_info_type(type);
834 QString szErr = tr("FreeRDP logon info: [");
835 szErr += str_type;
836 szErr += "] ";
837 szErr += str_data;
838 qDebug(log) << szErr;
839 emit pThis->sigInformation(szErr);
840 emit pThis->sigError(type, szErr);
841 return 1;
842}
843
844void CConnectFreeRDP::OnChannelConnectedEventHandler(void *context,
845 #if FreeRDP_VERSION_MAJOR >= 3
846 const
847 #endif
848 ChannelConnectedEventArgs *e)
849{
850 rdpContext* pContext = (rdpContext*)context;
851 CConnectFreeRDP* pThis = ((ClientContext*)context)->pThis;
852 if (strcmp(e->name, CLIPRDR_SVC_CHANNEL_NAME) == 0) {
853 qDebug(log) << "channel" << e->name << "connected";
854 pThis->m_ClipBoard.Init((CliprdrClientContext*)e->pInterface,
855 pThis->m_pParameter->GetClipboard());
856 }
857#if FreeRDP_VERSION_MAJOR >= 3
858 else
859 freerdp_client_OnChannelConnectedEventHandler(pContext, e);
860#else
861 else if (strcmp(e->name, RDPGFX_DVC_CHANNEL_NAME) == 0)
862 {
863 if (freerdp_settings_get_bool(pContext->settings, FreeRDP_SoftwareGdi)) {
864 rdpGdi* gdi = pContext->gdi;
865 // See: https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-rdpegfx/da5c75f9-cd99-450c-98c4-014a496942b0
866 gdi_graphics_pipeline_init(gdi, (RdpgfxClientContext*) e->pInterface);
867 }
868 else
869 qDebug(log, "Unimplemented: channel %s connected but libfreerdp is in HardwareGdi mode\n", e->name);
870 }
871 else if (strcmp(e->name, GEOMETRY_DVC_CHANNEL_NAME) == 0)
872 {
873 gdi_video_geometry_init(pContext->gdi, (GeometryClientContext*)e->pInterface);
874 }
875 else if (strcmp(e->name, VIDEO_DATA_DVC_CHANNEL_NAME) == 0)
876 {
877 gdi_video_data_init(pContext->gdi, (VideoClientContext*)e->pInterface);
878 } else
879 qDebug(log) << "Unimplemented: channel" << e->name << "connected but we can’t use it";
880#endif
881}
882
883void CConnectFreeRDP::OnChannelDisconnectedEventHandler(void *context,
884 #if FreeRDP_VERSION_MAJOR >= 3
885 const
886 #endif
887 ChannelDisconnectedEventArgs *e)
888{
889 rdpContext* pContext = (rdpContext*)context;
890 CConnectFreeRDP* pThis = ((ClientContext*)context)->pThis;
891
892 if (strcmp(e->name, CLIPRDR_SVC_CHANNEL_NAME) == 0) {
893 qDebug(log) << "channel" << e->name << "disconnected";
894 pThis->m_ClipBoard.UnInit((CliprdrClientContext*)e->pInterface,
895 pThis->m_pParameter->GetClipboard());
896 }
897#if FreeRDP_VERSION_MAJOR >= 3
898 else
899 freerdp_client_OnChannelDisconnectedEventHandler(pContext, e);
900#else
901 else if (strcmp(e->name, RDPGFX_DVC_CHANNEL_NAME) == 0)
902 {
903 if (freerdp_settings_get_bool(pContext->settings, FreeRDP_SoftwareGdi)) {
904 rdpGdi* gdi = pContext->gdi;
905 gdi_graphics_pipeline_uninit(gdi, (RdpgfxClientContext*) e->pInterface);
906 }
907 else
908 qDebug(log, "Unimplemented: channel %s connected but libfreerdp is in HardwareGdi mode\n", e->name);
909 }
910 else
911 qDebug(log) << "Unimplemented: channel" << e->name << "disconnected but we can’t use it";
912#endif
913
914}
915
916UINT32 CConnectFreeRDP::GetImageFormat(QImage::Format format)
917{
918 switch (format) {
919#if (QT_VERSION >= QT_VERSION_CHECK(5,2,0))
920 case QImage::Format_RGBA8888:
921 return PIXEL_FORMAT_RGBA32;
922 case QImage::Format_RGBX8888:
923 return PIXEL_FORMAT_RGBX32;
924#endif
925 case QImage::Format_RGB16:
926 return PIXEL_FORMAT_RGB16;
927 case QImage::Format_ARGB32:
928 return PIXEL_FORMAT_BGRA32;
929 case QImage::Format_RGB32:
930 return PIXEL_FORMAT_BGRA32;
931 default:
932 break;
933 }
934 return 0;
935}
936
937UINT32 CConnectFreeRDP::GetImageFormat()
938{
939 return GetImageFormat(m_Image.format());
940}
941
942BOOL CConnectFreeRDP::CreateImage(rdpContext *context)
943{
944 Q_ASSERT(context);
945 ClientContext* pContext = (ClientContext*)context;
946 CConnectFreeRDP* pThis = pContext->pThis;
947 rdpGdi* gdi = context->gdi;
948 Q_ASSERT(pThis && gdi);
949 pThis->m_Image = QImage(gdi->primary_buffer,
950 static_cast<int>(gdi->width),
951 static_cast<int>(gdi->height),
952 QImage::Format_ARGB32);
953 return TRUE;
954}
955
956#if FreeRDP_VERSION_MAJOR >= 3
957#ifdef Q_OS_WINDOWS
958static CREDUI_INFOW wfUiInfo = { sizeof(CREDUI_INFOW), NULL, L"Enter your credentials",
959 L"Remote Desktop Security", NULL };
960#endif
961BOOL CConnectFreeRDP::cb_authenticate_ex(freerdp* instance,
962 char** username, char** password,
963 char** domain, rdp_auth_reason reason)
964{
965 qDebug(log) << Q_FUNC_INFO << "reason:" << reason;
966 if(!instance)
967 return FALSE;
968
969 if(!username || !password || !domain) return FALSE;
970
971 rdpContext* pContext = (rdpContext*)instance->context;
972#ifdef Q_OS_WINDOWS
973 BOOL fSave;
974 DWORD status;
975 DWORD dwFlags;
976 WCHAR UserNameW[CREDUI_MAX_USERNAME_LENGTH + 1] = { 0 };
977 WCHAR UserW[CREDUI_MAX_USERNAME_LENGTH + 1] = { 0 };
978 WCHAR DomainW[CREDUI_MAX_DOMAIN_TARGET_LENGTH + 1] = { 0 };
979 WCHAR PasswordW[CREDUI_MAX_PASSWORD_LENGTH + 1] = { 0 };
980
981 WINPR_ASSERT(instance);
982 WINPR_ASSERT(instance->context);
983 WINPR_ASSERT(instance->context->settings);
984
985 WINPR_ASSERT(username);
986 WINPR_ASSERT(domain);
987 WINPR_ASSERT(password);
988
989 const WCHAR auth[] = L"Target credentials requested";
990 const WCHAR authPin[] = L"PIN requested";
991 const WCHAR gwAuth[] = L"Gateway credentials requested";
992 const WCHAR* titleW = auth;
993
994 fSave = FALSE;
995 dwFlags = CREDUI_FLAGS_DO_NOT_PERSIST | CREDUI_FLAGS_EXCLUDE_CERTIFICATES |
996 CREDUI_FLAGS_USERNAME_TARGET_CREDENTIALS;
997 switch (reason)
998 {
999 case AUTH_NLA:
1000 break;
1001 case AUTH_TLS:
1002 case AUTH_RDP:
1003 if ((*username) && (*password))
1004 return TRUE;
1005 break;
1006 case AUTH_SMARTCARD_PIN:
1007 dwFlags &= ~CREDUI_FLAGS_USERNAME_TARGET_CREDENTIALS;
1008 dwFlags |= CREDUI_FLAGS_PASSWORD_ONLY_OK | CREDUI_FLAGS_KEEP_USERNAME;
1009 titleW = authPin;
1010 if (*password)
1011 return TRUE;
1012 if (!(*username))
1013 *username = _strdup("PIN");
1014 break;
1015 case GW_AUTH_HTTP:
1016 case GW_AUTH_RDG:
1017 case GW_AUTH_RPC:
1018 titleW = gwAuth;
1019 break;
1020 default:
1021 return FALSE;
1022 }
1023
1024 if (*username)
1025 {
1026 ConvertUtf8ToWChar(*username, UserNameW, ARRAYSIZE(UserNameW));
1027 ConvertUtf8ToWChar(*username, UserW, ARRAYSIZE(UserW));
1028 }
1029
1030 if (*password)
1031 ConvertUtf8ToWChar(*password, PasswordW, ARRAYSIZE(PasswordW));
1032
1033 if (*domain)
1034 ConvertUtf8ToWChar(*domain, DomainW, ARRAYSIZE(DomainW));
1035
1036 if (_wcsnlen(PasswordW, ARRAYSIZE(PasswordW)) == 0)
1037 {
1038 status = CredUIPromptForCredentialsW(&wfUiInfo, titleW, NULL, 0, UserNameW,
1039 ARRAYSIZE(UserNameW), PasswordW,
1040 ARRAYSIZE(PasswordW), &fSave, dwFlags);
1041 if (status != NO_ERROR)
1042 {
1043 qCritical(log,
1044 "CredUIPromptForCredentials unexpected status: 0x%08lX",
1045 status);
1046 return FALSE;
1047 }
1048
1049 if ((dwFlags & CREDUI_FLAGS_KEEP_USERNAME) == 0)
1050 {
1051 status = CredUIParseUserNameW(UserNameW, UserW, ARRAYSIZE(UserW), DomainW,
1052 ARRAYSIZE(DomainW));
1053 if (status != NO_ERROR)
1054 {
1055 CHAR User[CREDUI_MAX_USERNAME_LENGTH + 1] = { 0 };
1056 CHAR UserName[CREDUI_MAX_USERNAME_LENGTH + 1] = { 0 };
1057 CHAR Domain[CREDUI_MAX_DOMAIN_TARGET_LENGTH + 1] = { 0 };
1058
1059 ConvertWCharNToUtf8(UserNameW, ARRAYSIZE(UserNameW), UserName, ARRAYSIZE(UserName));
1060 ConvertWCharNToUtf8(UserW, ARRAYSIZE(UserW), User, ARRAYSIZE(User));
1061 ConvertWCharNToUtf8(DomainW, ARRAYSIZE(DomainW), Domain, ARRAYSIZE(Domain));
1062 qCritical(log,
1063 "Failed to parse UserName: %s into User: %s Domain: %s",
1064 UserName, User, Domain);
1065 return FALSE;
1066 }
1067 }
1068 }
1069
1070 *username = ConvertWCharNToUtf8Alloc(UserW, ARRAYSIZE(UserW), NULL);
1071 if (!(*username))
1072 {
1073 qCritical(log) << "ConvertWCharNToUtf8Alloc failed" << status;
1074 return FALSE;
1075 }
1076
1077 if (_wcsnlen(DomainW, ARRAYSIZE(DomainW)) > 0)
1078 *domain = ConvertWCharNToUtf8Alloc(DomainW, ARRAYSIZE(DomainW), NULL);
1079 else
1080 *domain = _strdup("\0");
1081
1082 if (!(*domain))
1083 {
1084 free(*username);
1085 qCritical(log) << "strdup failed" << status;
1086 return FALSE;
1087 }
1088
1089 *password = ConvertWCharNToUtf8Alloc(PasswordW, ARRAYSIZE(PasswordW), NULL);
1090 if (!(*password))
1091 {
1092 free(*username);
1093 free(*domain);
1094 return FALSE;
1095 }
1096 return TRUE;
1097#else
1098 return cb_authenticate(instance, username, password, domain);
1099#endif //#ifdef Q_OS_WINDOWS
1100}
1101
1102//TODO: to be continue!!!
1103BOOL CConnectFreeRDP::cb_choose_smartcard(freerdp* instance,
1104 SmartcardCertInfo** cert_list,
1105 DWORD count,
1106 DWORD* choice, BOOL gateway)
1107{
1108 rdpContext* pContext = (rdpContext*)instance->context;
1109 CConnectFreeRDP* pThis = ((ClientContext*)pContext)->pThis;
1110 QString msg("Multiple smartcards are available for use:\n");
1111 for (DWORD i = 0; i < count; i++)
1112 {
1113 const SmartcardCertInfo* cert = cert_list[i];
1114 char* reader = ConvertWCharToUtf8Alloc(cert->reader, NULL);
1115 char* container_name = ConvertWCharToUtf8Alloc(cert->containerName, NULL);
1116
1117 msg += QString::number(i) + " ";
1118 msg += QString(container_name) + "\n\t";
1119 msg += "Reader: " + QString(reader) + "\n\t";
1120 msg += "User: " + QString(cert->userHint) + + "@" + QString(cert->domainHint) + "\n\t";
1121 msg += "Subject: " + QString(cert->subject) + "\n\t";
1122 msg += "Issuer: " + QString(cert->issuer) + "\n\t";
1123 msg += "UPN: " + QString(cert->upn) + "\n";
1124
1125 free(reader);
1126 free(container_name);
1127 }
1128
1129 msg += "\nChoose a smartcard to use for ";
1130 if(gateway)
1131 msg += "gateway authentication";
1132 else
1133 msg += "logon";
1134
1135 msg += "(0 - " + QString::number(count - 1) + ")";
1136
1137 QString num;
1138 emit pThis->sigBlockInputDialog(tr("Choose"), tr("Please choose smartcard"),
1139 msg, num);
1140 if(!num.isEmpty())
1141 {
1142 bool ok = false;
1143 int n = num.toInt(&ok);
1144 if(ok)
1145 {
1146 *choice = n;
1147 return TRUE;
1148 }
1149 }
1150 return FALSE;
1151}
1152
1153#endif //#if FreeRDP_VERSION_MAJOR >= 3
1154
1155BOOL CConnectFreeRDP::cb_authenticate(freerdp* instance, char** username,
1156 char** password, char** domain)
1157{
1158 qDebug(log) << Q_FUNC_INFO;
1159 if(!instance)
1160 return FALSE;
1161 rdpContext* pContext = (rdpContext*)instance->context;
1162 CConnectFreeRDP* pThis = ((ClientContext*)pContext)->pThis;
1163 if(!username || !password || !domain) return FALSE;
1164 if(*username && *password ) return TRUE;
1165
1166 int nRet = QDialog::Rejected;
1167 emit pThis->sigBlockShowWidget("CDlgGetUserPasswordFreeRDP",
1168 nRet, pThis->m_pParameter);
1169 if(QDialog::Accepted == nRet)
1170 {
1171 QString szPassword = pThis->m_pParameter->m_Net.m_User.GetPassword();
1172 QString szName = pThis->m_pParameter->m_Net.m_User.GetUser();
1173 QString szDomain = pThis->m_pParameter->GetDomain();
1174 if(!szDomain.isEmpty() && domain)
1175 *domain = _strdup(szDomain.toStdString().c_str());
1176 if(!szName.isEmpty() && username)
1177 *username = _strdup(szName.toStdString().c_str());
1178 if(!szPassword.isEmpty() && password)
1179 *password = _strdup(szPassword.toStdString().c_str());
1180 } else
1181 return FALSE;
1182
1183 return TRUE;
1184}
1185
1186BOOL CConnectFreeRDP::cb_GatewayAuthenticate(freerdp *instance,
1187 char **username, char **password, char **domain)
1188{
1189 qDebug(log) << Q_FUNC_INFO;
1190 if(!instance)
1191 return FALSE;
1192
1193 rdpContext* pContext = (rdpContext*)instance->context;
1194 CConnectFreeRDP* pThis = ((ClientContext*)pContext)->pThis;
1195 if(!username || !password || !domain) return FALSE;
1196 if(*username && *password ) return TRUE;
1197
1198 int nRet = QDialog::Rejected;
1199 emit pThis->sigBlockShowWidget("CDlgGetUserPasswordFreeRDP", nRet, pThis->m_pParameter);
1200 if(QDialog::Accepted == nRet)
1201 {
1202 QString szPassword = pThis->m_pParameter->m_Net.m_User.GetPassword();
1203 QString szName = pThis->m_pParameter->m_Net.m_User.GetUser();
1204 QString szDomain = pThis->m_pParameter->GetDomain();
1205 if(!szDomain.isEmpty() && domain)
1206 *domain = _strdup(szDomain.toStdString().c_str());
1207 if(!szName.isEmpty() && username)
1208 *username = _strdup(szName.toStdString().c_str());
1209 if(!szPassword.isEmpty() && password)
1210 *password = _strdup(szPassword.toStdString().c_str());
1211 } else
1212 return FALSE;
1213
1214 return TRUE;
1215}
1216
1218 const BYTE* data, size_t length,
1219 const char* hostname, UINT16 port, DWORD flags)
1220{
1221 qDebug(log) << Q_FUNC_INFO;
1222 rdpContext* pContext = (rdpContext*)instance->context;
1223
1224 QSslCertificate cert(QByteArray((const char*)data, length));
1225
1227 instance, hostname, port,
1228 cert.issuerDisplayName().toStdString().c_str(),
1229 cert.subjectDisplayName().toStdString().c_str(),
1230 cert.issuerDisplayName().toStdString().c_str(),
1231 cert.serialNumber().toStdString().c_str(),
1232 flags);
1233
1234 return 0;
1235}
1236
1253 const char *host, UINT16 port,
1254 const char *common_name, const char *subject,
1255 const char *issuer, const char *fingerprint, DWORD flags)
1256{
1257 qDebug(log) << Q_FUNC_INFO;
1258
1259 rdpContext* pContext = (rdpContext*)instance->context;
1260 Q_ASSERT(pContext);
1261 CConnectFreeRDP* pThis = ((ClientContext*)pContext)->pThis;
1262 Q_ASSERT(pThis);
1263 if(common_name)
1264 {
1265 //pThis->m_pParameter->SetServerName(common_name);
1266 emit pThis->sigServerName(common_name);
1267 }
1268
1269 if(!pThis->m_pParameter->GetShowVerifyDiaglog()) {
1270 /* return 1 to accept and store a certificate, 2 to accept
1271 * a certificate only for this session, 0 otherwise */
1272 return 2;
1273 }
1274
1275 QString szType = tr("RDP-Server");
1276 if (flags & VERIFY_CERT_FLAG_GATEWAY)
1277 szType = tr("RDP-Gateway");
1278 if (flags & VERIFY_CERT_FLAG_REDIRECT)
1279 szType = tr("RDP-Redirect");
1280
1281 QString title(tr("Verify certificate"));
1282 QString message;
1283
1284 message += szType + tr(": %1:%2").arg(host, QString::number(port)) + "\n";
1285 message += tr("Common name: ") + common_name + "\n";
1286 message += tr("Subject: ") + subject + "\n";
1287 message += tr("Issuer: ") + issuer + "\n";
1288 message += tr("Fingerprint: ") + fingerprint + "\n";
1289 message += "\n";
1290 if(VERIFY_CERT_FLAG_CHANGED & flags) {
1291 message += tr("The above X.509 certificate is changed.\n"
1292 "It is possible that the server has changed its certificate, "
1293 "or Maybe it was attacked."
1294 "Please look at the OpenSSL documentation on "
1295 "how to add a private CA to the store.");
1296 } else {
1297 message += tr("The above X.509 certificate could not be verified.\n"
1298 "Possibly because you do not have the CA certificate "
1299 "in your certificate store, or the certificate has expired.\n"
1300 "Please look at the OpenSSL documentation on "
1301 "how to add a private CA to the store.");
1302 }
1303 message += "\n";
1304 message += "\n";
1305 message += tr("Yes - trusted") + "\n";
1306 message += tr("Ignore - temporary trusted") + "\n";
1307 message += tr("No - no trusted") + "\n";
1308
1309 QMessageBox::StandardButton nRet = QMessageBox::StandardButton::No;
1310 QMessageBox::StandardButtons buttons = QMessageBox::Yes | QMessageBox::Ignore | QMessageBox::No;
1311 bool bCheckBox = false;
1312 emit pThis->sigBlockShowMessageBox(title, message, buttons, nRet, bCheckBox,
1313 tr("Don't show again"));
1314 pThis->m_pParameter->SetShowVerifyDiaglog(!bCheckBox);
1315 emit pThis->m_pParameter->sigChanged();
1316 /* return 1 to accept and store a certificate, 2 to accept
1317 * a certificate only for this session, 0 otherwise */
1318 switch(nRet)
1319 {
1320 case QMessageBox::StandardButton::Yes:
1321 return 1;
1322 case QMessageBox::StandardButton::Ignore:
1323 return 2;
1324 default:
1325 return 0;
1326 }
1327 return 2;
1328}
1329
1350 const char *host, UINT16 port,
1351 const char *common_name, const char *subject,
1352 const char *issuer, const char *fingerprint,
1353 const char *old_subject, const char *old_issuer,
1354 const char *old_fingerprint, DWORD flags)
1355{
1356 qDebug(log) << Q_FUNC_INFO;
1357 rdpContext* pContext = (rdpContext*)instance->context;
1358 CConnectFreeRDP* pThis = ((ClientContext*)pContext)->pThis;
1359 if(common_name)
1360 emit pThis->sigServerName(common_name);
1361
1362 if(!pThis->m_pParameter->GetShowVerifyDiaglog()) {
1363 /* return 1 to accept and store a certificate, 2 to accept
1364 * a certificate only for this session, 0 otherwise */
1365 return 2;
1366 }
1367
1368 QString szType = tr("RDP-Server");
1369 if (flags & VERIFY_CERT_FLAG_GATEWAY)
1370 szType = tr("RDP-Gateway");
1371 if (flags & VERIFY_CERT_FLAG_REDIRECT)
1372 szType = tr("RDP-Redirect");
1373
1374 QString title(tr("Verify changed certificate"));
1375 QString message;
1376 message += szType + tr(": %1:%2").arg(host, QString::number(port)) + "\n";
1377 message += tr("Common name: ") + common_name + "\n";
1378 message += tr("New subject: ") + subject + "\n";
1379 message += tr("New issuer: ") + issuer + "\n";
1380 message += tr("New fingerprint: ") + fingerprint + "\n";
1381 message += tr("Old subject: ") + old_subject + "\n";
1382 message += tr("Old issuer: ") + old_issuer + "\n";
1383 message += tr("Old fingerprint: ") + old_fingerprint + "\n";
1384 message += "\n";
1385 message += tr("The above X.509 certificate could not be verified, "
1386 "possibly because you do not have the CA certificate "
1387 "in your certificate store, or the certificate has expired. "
1388 "Please look at the OpenSSL documentation on "
1389 "how to add a private CA to the store.");
1390 message += "\n";
1391 message += "\n";
1392 message += tr("Yes - trusted") + "\n";
1393 message += tr("Ignore - temporary trusted") + "\n";
1394 message += tr("No - no trusted") + "\n";
1395
1396 bool bCheckBox = false;
1397 QMessageBox::StandardButton nRet = QMessageBox::StandardButton::No;
1398 QMessageBox::StandardButtons buttons = QMessageBox::Yes | QMessageBox::Ignore | QMessageBox::No;
1399 emit pThis->sigBlockShowMessageBox(title, message, buttons, nRet, bCheckBox,
1400 tr("Don't show again"));
1401 pThis->m_pParameter->SetShowVerifyDiaglog(!bCheckBox);
1402 emit pThis->m_pParameter->sigChanged();
1403
1404 /* return 1 to accept and store a certificate, 2 to accept
1405 * a certificate only for this session, 0 otherwise */
1406 switch(nRet)
1407 {
1408 case QMessageBox::StandardButton::Yes:
1409 return 1;
1410 case QMessageBox::StandardButton::Ignore:
1411 return 2;
1412 default:
1413 return 0;
1414 }
1415
1416 /* return 1 to accept and store a certificate, 2 to accept
1417 * a certificate only for this session, 0 otherwise */
1418 return 2;
1419}
1420
1421BOOL CConnectFreeRDP::cb_present_gateway_message(
1422 freerdp* instance, UINT32 type, BOOL isDisplayMandatory,
1423 BOOL isConsentMandatory, size_t length, const WCHAR* message)
1424{
1425 qDebug(log) << Q_FUNC_INFO;
1426
1427 if (!isDisplayMandatory && !isConsentMandatory)
1428 return TRUE;
1429
1430 /* special handling for consent messages (show modal dialog) */
1431 if (type == GATEWAY_MESSAGE_CONSENT && isConsentMandatory)
1432 {
1433 QString msgType = (type == GATEWAY_MESSAGE_CONSENT)
1434 ? tr("Consent message") : tr("Service message");
1435 msgType += "\n";
1436#if FreeRDP_VERSION_MAJOR >= 3
1437 char* pMsg = ConvertWCharToUtf8Alloc(message, NULL);
1438 if(pMsg) {
1439 msgType += pMsg;
1440 free(pMsg);
1441 }
1442#else
1443 msgType += QString::fromStdWString((wchar_t*)message);
1444#endif
1445 msgType += "\n";
1446 msgType += tr("I understand and agree to the terms of this policy (Y/N)");
1447
1448 rdpContext* pContext = (rdpContext*)instance->context;
1449 CConnectFreeRDP* pThis = ((ClientContext*)pContext)->pThis;
1450 QMessageBox::StandardButton nRet = QMessageBox::No;
1451 bool bCheckBox = false;
1452 emit pThis->sigBlockShowMessageBox(tr("Gateway message"), msgType,
1453 QMessageBox::Yes|QMessageBox::No,
1454 nRet, bCheckBox);
1455 switch (nRet) {
1456 case QMessageBox::Yes:
1457 return TRUE;
1458 break;
1459 default:
1460 return FALSE;
1461 }
1462 }
1463 else
1464 return client_cli_present_gateway_message(
1465 instance, type, isDisplayMandatory,
1466 isConsentMandatory, length, message);
1467
1468 return TRUE;
1469}
1470
1471BOOL CConnectFreeRDP::cb_begin_paint(rdpContext *context)
1472{
1473 HGDI_DC hdc;
1474
1475 if (!context || !context->gdi || !context->gdi->primary
1476 || !context->gdi->primary->hdc)
1477 return FALSE;
1478
1479 hdc = context->gdi->primary->hdc;
1480
1481 if (!hdc || !hdc->hwnd || !hdc->hwnd->invalid)
1482 return FALSE;
1483
1484 hdc->hwnd->invalid->null = TRUE;
1485 hdc->hwnd->ninvalid = 0;
1486 return TRUE;
1487}
1488
1489BOOL CConnectFreeRDP::UpdateBuffer(INT32 x, INT32 y, INT32 w, INT32 h)
1490{
1491 if(x > m_Image.width() || y > m_Image.height()) {
1492 qCritical(log) << "The width and height out of range."
1493 << "Image width:" << m_Image.width()
1494 << "Image height:" << m_Image.height()
1495 << "w:" << w << "h:" << h;
1496 return FALSE;
1497 }
1498
1499 QRect rect(x, y, w, h);
1500 QImage img = m_Image.copy(rect);
1501 //qDebug(log) << "Image:" << rect << img.rect() << img;
1502 emit sigUpdateRect(rect, img);
1503 return TRUE;
1504}
1505
1506BOOL CConnectFreeRDP::cb_end_paint(rdpContext *context)
1507{
1508 //qDebug(log) << Q_FUNC_INFO;
1509 ClientContext* pContext = (ClientContext*)context;
1510 CConnectFreeRDP* pThis = pContext->pThis;
1511 INT32 ninvalid;
1512 HGDI_RGN cinvalid;
1513 REGION16 invalidRegion;
1514 RECTANGLE_16 invalidRect;
1515 const RECTANGLE_16* extents;
1516 HGDI_DC hdc;
1517 int i = 0;
1518
1519 if (!context || !context->gdi || !context->gdi->primary
1520 || !context->gdi->primary->hdc)
1521 return FALSE;
1522
1523 hdc = context->gdi->primary->hdc;
1524
1525 if (!hdc || !hdc->hwnd || !hdc->hwnd->invalid)
1526 return FALSE;
1527
1528 rdpGdi* gdi = context->gdi;
1529 if (gdi->suppressOutput)
1530 return TRUE;
1531
1532 HGDI_WND hwnd = context->gdi->primary->hdc->hwnd;
1533 ninvalid = hwnd->ninvalid; //无效区数量
1534 cinvalid = hwnd->cinvalid; //无效区数组
1535 if (ninvalid < 1)
1536 return TRUE;
1537
1538 region16_init(&invalidRegion);
1539
1540 for (i = 0; i < ninvalid; i++)
1541 {
1542 if(cinvalid[i].null)
1543 {
1544 qWarning(log) << "is null region" << cinvalid[i].x << cinvalid[i].y
1545 << cinvalid[i].w << cinvalid[i].h;
1546 continue;
1547 }
1548 invalidRect.left = cinvalid[i].x;
1549 invalidRect.top = cinvalid[i].y;
1550 invalidRect.right = cinvalid[i].x + cinvalid[i].w;
1551 invalidRect.bottom = cinvalid[i].y + cinvalid[i].h;
1552 region16_union_rect(&invalidRegion, &invalidRegion, &invalidRect);
1553 }
1554
1555 if (!region16_is_empty(&invalidRegion))
1556 {
1557 extents = region16_extents(&invalidRegion);
1558 //qDebug(log) << extents->left << extents->top << extents->right << extents->bottom;
1559 pThis->UpdateBuffer(extents->left,
1560 extents->top,
1561 extents->right - extents->left,
1562 extents->bottom - extents->top);
1563 }
1564
1565 region16_uninit(&invalidRegion);
1566
1567 return TRUE;
1568}
1569
1570BOOL CConnectFreeRDP::cb_desktop_resize(rdpContext* context)
1571{
1572 qDebug(log) << Q_FUNC_INFO;
1573 ClientContext* pContext = (ClientContext*)context;
1574 CConnectFreeRDP* pThis = pContext->pThis;
1575 rdpSettings* settings;
1576 if (!context || !context->settings)
1577 return FALSE;
1578 settings = context->settings;
1579 int desktopWidth = freerdp_settings_get_uint32(settings, FreeRDP_DesktopWidth);
1580 int desktopHeight = freerdp_settings_get_uint32(settings, FreeRDP_DesktopHeight);
1581
1582 if(!gdi_resize(context->gdi, desktopWidth, desktopHeight))
1583 return FALSE;
1584 if(!pThis->CreateImage(context))
1585 return FALSE;
1586
1587 emit pThis->sigSetDesktopSize(desktopWidth, desktopHeight);
1588 pThis->UpdateBuffer(0, 0, desktopWidth, desktopHeight);
1589 return TRUE;
1590}
1591
1592BOOL CConnectFreeRDP::cb_play_bell_sound(rdpContext *context, const PLAY_SOUND_UPDATE *play_sound)
1593{
1594 qDebug(log) << Q_FUNC_INFO;
1595 ClientContext* pContext = (ClientContext*)context;
1596 CConnectFreeRDP* pThis = pContext->pThis;
1597 WINPR_UNUSED(play_sound);
1598 QApplication::beep();
1599 return TRUE;
1600
1601 QString szFile;
1602#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
1603 QSoundEffect effect;
1604 effect.setSource(QUrl::fromLocalFile(szFile));
1605// effect.setLoopCount(1);
1606// effect.setVolume(1);
1607 effect.play();
1608#else
1609 QSound::play(szFile);
1610#endif
1611 return TRUE;
1612}
1613
1614/* This function is called to update the keyboard indicator LED */
1615BOOL CConnectFreeRDP::cb_keyboard_set_indicators(rdpContext *context, UINT16 led_flags)
1616{
1617 qDebug(log) << Q_FUNC_INFO;
1618 ClientContext* pContext = (ClientContext*)context;
1619 CConnectFreeRDP* pThis = pContext->pThis;
1620
1621 int state = CFrmViewer::LED_STATE::Unknown;
1622
1623 if (led_flags & KBD_SYNC_NUM_LOCK)
1624 state |= CFrmViewer::LED_STATE::NumLock;
1625 if (led_flags & KBD_SYNC_CAPS_LOCK)
1626 state |= CFrmViewer::LED_STATE::CapsLock;
1627 if (led_flags & KBD_SYNC_SCROLL_LOCK)
1628 state |= CFrmViewer::LED_STATE::ScrollLock;
1629
1630 emit pThis->sigUpdateLedState(state);
1631
1632 return TRUE;
1633}
1634
1635/* This function is called to set the IME state */
1636BOOL CConnectFreeRDP::cb_keyboard_set_ime_status(
1637 rdpContext* context, UINT16 imeId, UINT32 imeState, UINT32 imeConvMode)
1638{
1639 if (!context)
1640 return FALSE;
1641
1642 qWarning(log,
1643 "KeyboardSetImeStatus(unitId=%04" PRIx16 ", imeState=%08" PRIx32
1644 ", imeConvMode=%08" PRIx32 ") ignored",
1645 imeId, imeState, imeConvMode);
1646 return TRUE;
1647}
1648
1650{
1651 //qDebug(log) << Q_FUNC_INFO;
1652 SetEvent(m_writeEvent);
1653 return 0;
1654}
1655
1656// https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-rdpbcgr/2c1ced34-340a-46cd-be6e-fc8cab7c3b17
1657bool CConnectFreeRDP::SendMouseEvent(UINT16 flags, QPoint pos, bool isExtended)
1658{
1659 if(m_pParameter && m_pParameter->GetOnlyView()) return true;
1660 if(!m_pContext) return false;
1661
1662#if FreeRDP_VERSION_MAJOR >= 3
1663 if(isExtended)
1664 freerdp_client_send_extended_button_event(
1665 &m_pContext->Context, FALSE, flags, pos.x(), pos.y());
1666 else
1667 freerdp_client_send_button_event(
1668 &m_pContext->Context, FALSE, flags, pos.x(), pos.y());
1669#else
1670 if(!m_pContext->Context.input) return false;
1671 return freerdp_input_send_mouse_event(
1672 m_pContext->Context.input, flags, pos.x(), pos.y());
1673#endif
1674 return true;
1675}
1676
1677void CConnectFreeRDP::wheelEvent(QWheelEvent *event)
1678{
1679 qDebug(logMouse) << Q_FUNC_INFO << event;
1680 if(!m_pContext) return;
1681 if(m_pParameter && m_pParameter->GetOnlyView()) return;
1682
1683 UINT16 flags = 0;
1684 QPointF pos;
1685#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
1686 pos = event->position();
1687#else
1688 pos = event->pos();
1689#endif
1690 QPoint p = event->angleDelta();
1691 if(p.y() > 0)
1692 {
1693 flags |= PTR_FLAGS_WHEEL | p.y();
1694 }
1695 if(p.y() < 0)
1696 {
1697 flags |= PTR_FLAGS_WHEEL | PTR_FLAGS_WHEEL_NEGATIVE | -p.y();
1698 }
1699
1700 if(p.x() < 0)
1701 {
1702 flags |= PTR_FLAGS_HWHEEL | PTR_FLAGS_WHEEL_NEGATIVE | -p.x();
1703 }
1704 if(p.x() > 0)
1705 {
1706 flags |= PTR_FLAGS_HWHEEL | p.x();
1707 }
1708#if FreeRDP_VERSION_MAJOR >= 3
1709 freerdp_client_send_wheel_event(&m_pContext->Context, flags);
1710 /*
1711 freerdp_client_send_button_event(
1712 &m_pContext->Context, FALSE, flags, pos.x(), pos.y());//*/
1713#else
1714 freerdp_input_send_mouse_event(
1715 m_pContext->Context.input, flags, pos.x(), pos.y());
1716#endif
1717}
1718
1719// https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-rdpbcgr/2c1ced34-340a-46cd-be6e-fc8cab7c3b17
1720void CConnectFreeRDP::mouseMoveEvent(QMouseEvent *event)
1721{
1722 qDebug(logMouse) << Q_FUNC_INFO << event << event->buttons() << event->button();
1723 if(!m_pContext) return;
1724 if(m_pParameter && m_pParameter->GetOnlyView()) return;
1725 UINT16 flags = PTR_FLAGS_MOVE;
1726 SendMouseEvent(flags, event->pos(), false);
1727}
1728
1729void CConnectFreeRDP::mousePressEvent(QMouseEvent *event)
1730{
1731 qDebug(logMouse) << Q_FUNC_INFO << event << event->buttons() << event->button();
1732 if(!m_pContext) return;
1733 if(m_pParameter && m_pParameter->GetOnlyView()) return;
1734
1735 UINT16 flags = 0;
1736 bool isExtended = false;
1737 Qt::MouseButton button = event->button();
1738 if (button & Qt::MouseButton::LeftButton)
1739 {
1740 flags = PTR_FLAGS_DOWN | PTR_FLAGS_BUTTON1;
1741 }
1742 else if (button & Qt::MouseButton::RightButton)
1743 {
1744 flags = PTR_FLAGS_DOWN | PTR_FLAGS_BUTTON2;
1745 }
1746 else if (button & Qt::MouseButton::MiddleButton)
1747 {
1748 flags = PTR_FLAGS_DOWN | PTR_FLAGS_BUTTON3;
1749 }
1750 else if (button & Qt::MouseButton::ForwardButton)
1751 {
1752 flags = PTR_XFLAGS_DOWN | PTR_XFLAGS_BUTTON2;
1753 isExtended = true;
1754 }
1755 else if (button & Qt::MouseButton::BackButton)
1756 {
1757 flags = PTR_XFLAGS_DOWN | PTR_XFLAGS_BUTTON1;
1758 isExtended = true;
1759 }
1760 if (flags != 0)
1761 {
1762 SendMouseEvent(flags, event->pos(), isExtended);
1763 }
1764}
1765
1766void CConnectFreeRDP::mouseReleaseEvent(QMouseEvent *event)
1767{
1768 qDebug(logMouse) << Q_FUNC_INFO << event << event->buttons() << event->button();
1769 if(!m_pContext) return;
1770 if(m_pParameter && m_pParameter->GetOnlyView()) return;
1771
1772 UINT16 flags = 0;
1773 bool isExtended = false;
1774 Qt::MouseButton button = event->button();
1775 if (button & Qt::MouseButton::LeftButton)
1776 {
1777 flags = PTR_FLAGS_BUTTON1;
1778 }
1779 else if (button & Qt::MouseButton::MiddleButton)
1780 {
1781 flags = PTR_FLAGS_BUTTON3;
1782 }
1783 else if (button & Qt::MouseButton::RightButton)
1784 {
1785 flags = PTR_FLAGS_BUTTON2;
1786 }
1787 else if (button & Qt::MouseButton::ForwardButton)
1788 {
1789 flags = PTR_XFLAGS_BUTTON2;
1790 isExtended = true;
1791 }
1792 else if (button & Qt::MouseButton::BackButton)
1793 {
1794 flags = PTR_XFLAGS_BUTTON1;
1795 isExtended = true;
1796 }
1797 if (flags != 0)
1798 {
1799 SendMouseEvent(flags, event->pos(), isExtended);
1800 }
1801}
1802
1803void CConnectFreeRDP::keyPressEvent(QKeyEvent *event)
1804{
1805 qDebug(logKey) << Q_FUNC_INFO << event;
1806 if(!m_pContext) return;
1807 if(m_pParameter && m_pParameter->GetOnlyView()) return;
1808 // Convert to rdp scan code freerdp/scancode.h
1809 UINT32 k = CConvertKeyCode::QtToScanCode(event->key(), event->modifiers());
1810 if(RDP_SCANCODE_UNKNOWN != k)
1811#if FreeRDP_VERSION_MAJOR >= 3
1812 freerdp_input_send_keyboard_event_ex(
1813 m_pContext->Context.context.input, true, true, k);
1814#else
1815 freerdp_input_send_keyboard_event_ex(
1816 m_pContext->Context.input, true, k);
1817#endif
1818}
1819
1820void CConnectFreeRDP::keyReleaseEvent(QKeyEvent *event)
1821{
1822 qDebug(logKey) << Q_FUNC_INFO << event;
1823 if(!m_pContext) return;
1824 if(m_pParameter && m_pParameter->GetOnlyView()) return;
1825 UINT32 k = CConvertKeyCode::QtToScanCode(event->key(), event->modifiers());
1826 if(RDP_SCANCODE_UNKNOWN != k)
1827#if FreeRDP_VERSION_MAJOR >= 3
1828 freerdp_input_send_keyboard_event_ex(
1829 m_pContext->Context.context.input, false, false, k);
1830#else
1831 freerdp_input_send_keyboard_event_ex(
1832 m_pContext->Context.input, false, k);
1833#endif
1834}
1835
1836int CConnectFreeRDP::RedirectionSound()
1837{
1838 rdpContext* pRdpContext = (rdpContext*)m_pContext;
1839 freerdp* instance = freerdp_client_get_instance(pRdpContext);
1840 rdpSettings* settings = instance->context->settings;
1841 Q_ASSERT(settings);
1842
1843 if(m_pParameter->GetRedirectionSound()
1844 == CParameterFreeRDP::RedirecionSoundType::Disable)
1845 {
1846 /* Disable sound */
1847 freerdp_settings_set_bool(settings, FreeRDP_AudioPlayback, FALSE);
1848 freerdp_settings_set_bool(settings, FreeRDP_RemoteConsoleAudio, FALSE);
1849 return 0;
1850 } else if(m_pParameter->GetRedirectionSound()
1851 == CParameterFreeRDP::RedirecionSoundType::Local)
1852 {
1853 freerdp_settings_set_bool(settings, FreeRDP_AudioPlayback, TRUE);
1854 freerdp_settings_set_bool(settings, FreeRDP_AudioCapture, TRUE);
1855 } else if(m_pParameter->GetRedirectionSound()
1856 == CParameterFreeRDP::RedirecionSoundType::Remote)
1857 {
1858 freerdp_settings_set_bool(settings, FreeRDP_RemoteConsoleAudio, TRUE);
1859 return 0;
1860 }
1861
1862 // Sound:
1863 // rdpsnd channel parameters format see: rdpsnd_process_addin_args in FreeRDP/channels/rdpsnd/client/rdpsnd_main.c
1864 // rdpsnd devices see: rdpsnd_process_connect in FreeRDP/channels/rdpsnd/client/rdpsnd_main.c
1865 // Format ag: /rdpsnd:sys:oss,dev:1,format:1
1866 //
1867 size_t count = 0;
1868 union
1869 {
1870 char** p;
1871 const char** pc;
1872 } ptr;
1873 ptr.p = CommandLineParseCommaSeparatedValuesEx("rdpsnd",
1874 m_pParameter->GetRedirectionSoundParameters().toStdString().c_str(),
1875 &count);
1876 BOOL status = freerdp_client_add_static_channel(settings, count,
1877 #if FreeRDP_VERSION_MAJOR < 3
1878 ptr.p
1879 #else
1880 ptr.pc
1881 #endif
1882 );
1883 if (status)
1884 {
1885 status = freerdp_client_add_dynamic_channel(settings, count,
1886 #if FreeRDP_VERSION_MAJOR < 3
1887 ptr.p
1888 #else
1889 ptr.pc
1890 #endif
1891 );
1892 }
1893
1894 if(!status)
1895 {
1896 qCritical(log) << "Load rdpsnd fail";
1897 return -1;
1898 }
1899
1900 return 0;
1901}
1902
1903int CConnectFreeRDP::RedirectionMicrophone()
1904{
1905 if(m_pParameter->GetRedirectionSound()
1906 == CParameterFreeRDP::RedirecionSoundType::Remote)
1907 return 0;
1908 if(!m_pParameter->GetRedirectionMicrophone())
1909 return 0;
1910
1911 rdpContext* pRdpContext = (rdpContext*)m_pContext;
1912 freerdp* instance = freerdp_client_get_instance(pRdpContext);
1913
1914 rdpSettings* settings = instance->context->settings;
1915 Q_ASSERT(settings);
1916
1917 freerdp_settings_set_bool(settings, FreeRDP_AudioCapture, TRUE);
1918
1919 // Microphone:
1920 // Audin channel parameters format see: audin_process_addin_args in FreeRDP/channels/audin/client/audin_main.c
1921 // Audin channel devices see: audin_DVCPluginEntry in FreeRDP/channels/audin/client/audin_main.c
1922 size_t count = 0;
1923 union
1924 {
1925 char** p;
1926 const char** pc;
1927 } ptr;
1928 ptr.p = CommandLineParseCommaSeparatedValuesEx("audin",
1929 m_pParameter->GetRedirectionMicrophoneParameters().toStdString().c_str(),
1930 &count);
1931 BOOL status = freerdp_client_add_dynamic_channel(settings, count,
1932 #if FreeRDP_VERSION_MAJOR < 3
1933 ptr.p
1934 #else
1935 ptr.pc
1936 #endif
1937 );
1938
1939 if(!status)
1940 {
1941 qCritical(log) << "Load audin fail";
1942 return -1;
1943 }
1944
1945 return 0;
1946}
1947
1948int CConnectFreeRDP::RedirectionDriver()
1949{
1950 QStringList lstDrives = m_pParameter->GetRedirectionDrives();
1951 if(lstDrives.isEmpty())
1952 return 0;
1953
1954 rdpContext* pRdpContext = (rdpContext*)m_pContext;
1955 freerdp* instance = freerdp_client_get_instance(pRdpContext);
1956 rdpSettings* settings = instance->context->settings;
1957 Q_ASSERT(settings);
1958
1959 foreach (auto drive, lstDrives) {
1960 // Format: /drive:name,path
1961 char* pDrive = _strdup(drive.toStdString().c_str());
1962 const char* argvDrive[] = {"drive", pDrive};
1963 int count = sizeof(argvDrive) / sizeof(const char*);
1964 BOOL status = freerdp_client_add_device_channel(settings, count,
1965 #if FreeRDP_VERSION_MAJOR < 3
1966 (char**)
1967 #endif
1968 argvDrive);
1969 if(pDrive) free(pDrive);
1970 if(!status)
1971 {
1972 qCritical(log) << "Load drive fail";
1973 return -1;
1974 }
1975 }
1976
1977 return 0;
1978}
1979
1980int CConnectFreeRDP::RedirectionPrinter()
1981{
1982 if(!m_pParameter->GetRedirectionPrinter())
1983 return 0;
1984
1985 rdpContext* pRdpContext = (rdpContext*)m_pContext;
1986 freerdp* instance = freerdp_client_get_instance(pRdpContext);
1987 rdpSettings* settings = instance->context->settings;
1988 Q_ASSERT(settings);
1989 // 获取系统的打印机列表,并在combobox中显示
1990 QStringList printerList = QPrinterInfo::availablePrinterNames();
1991 if(printerList.isEmpty())
1992 {
1993 qCritical(log) << "The printer is empty";
1994 return -1;
1995 }
1996 qDebug(log) << printerList;
1997
1998 // Format: /printer:<device>,<driver>,[default]
1999 const char* argvPrinter[] = {"printer", nullptr, nullptr};
2000 int count = sizeof(argvPrinter) / sizeof(const char*);
2001 BOOL status = freerdp_client_add_device_channel(settings, count,
2002 #if FreeRDP_VERSION_MAJOR < 3
2003 (char**)
2004 #endif
2005 argvPrinter);
2006 if(!status) {
2007 qCritical(log) << "Load printer fail";
2008 return -2;
2009 }
2010
2011 return 0;
2012}
2013
2014int CConnectFreeRDP::RedirectionSerial()
2015{
2016 //TODO: FreeRDP don't support
2017 return 0;
2018 rdpContext* pRdpContext = (rdpContext*)m_pContext;
2019 freerdp* instance = freerdp_client_get_instance(pRdpContext);
2020 rdpSettings* settings = instance->context->settings;
2021 Q_ASSERT(settings);
2022
2023 QList<QSerialPortInfo> lstSerial = QSerialPortInfo::availablePorts();
2024
2025 int nNum = 1;
2026 foreach (auto serial, lstSerial) {
2027 // Format: /serial:<name>,<device>,[SerCx2|SerCx|Serial],[permissive]
2028 // ag: /serial:COM1,/dev/ttyS0
2029 qDebug(log) << "systemLocation:" << serial.systemLocation()
2030 << "portName:" << serial.portName()
2031 << "serialNumber:" << serial.serialNumber();
2032 char* pSerial = _strdup(serial.systemLocation().toStdString().c_str());
2033 char* pName = _strdup(serial.portName().toStdString().c_str());
2034 const char* argvSerial[] = {"serial", pName, pSerial};
2035 int count = sizeof(argvSerial) / sizeof(const char*);
2036 BOOL status = freerdp_client_add_device_channel(settings, count,
2037 #if FreeRDP_VERSION_MAJOR < 3
2038 (char**)
2039 #endif
2040 argvSerial);
2041 if(pSerial) free(pSerial);
2042 if(pName) free(pName);
2043
2044 if(!status)
2045 {
2046 qCritical(log) << "Load drive fail";
2047 return -1;
2048 }
2049 }
2050
2051 return 0;
2052}
2053
2054void CConnectFreeRDP::slotConnectProxyServer(QString szHost, quint16 nPort)
2055{
2056 qDebug(log) << "CConnectFreeRDP::slotConnectProxyServer" << nPort;
2057 rdpContext* pContext = (rdpContext*)m_pContext;
2058 rdpSettings* settings = pContext->settings;
2059 if(!settings) {
2060 qCritical(log) << "settings is null";
2061 }
2062
2063 freerdp_settings_set_string(
2064 settings, FreeRDP_ServerHostname,
2065 szHost.toStdString().c_str());
2066 freerdp_settings_set_uint32(
2067 settings, FreeRDP_ServerPort,
2068 nPort);
2069
2070 int nRet = freerdp_client_start(pContext);
2071 if(nRet)
2072 {
2073 qCritical(log) << "freerdp_client_start fail";
2074 }
2075 qDebug(log) << "CConnectFreeRDP::slotConnectProxyServer end";
2076}
远程桌面连接接口。它由协议插件实现。
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
CParameterUser m_User
[Instance user]
void sigChanged()
当参数改变时,触发 通常如果需要,则相应的参数会对应一个改变事件。
实现通过本地 SOCKET 与 SSH 隧道转发数据。适用于库没有实现传输层接口,只有 socket 的情况。