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