Rabbit Remote Control 0.0.33
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")
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}
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.