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