玉兔远程控制 0.0.31
载入中...
搜索中...
未找到
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}
远程桌面连接接口。它由协议插件实现。
void sigUpdateRect(const QRect &r, const QImage &image)
通知视图,图像更新
virtual OnInitReturnValue OnInit() override
具体的插件实现连接初始化
virtual int OnClean() override
清理
static int cb_verify_x509_certificate(freerdp *instance, const BYTE *data, size_t length, const char *hostname, UINT16 port, DWORD flags)
Callback used if user interaction is required to accept a certificate.
static DWORD cb_verify_changed_certificate_ex(freerdp *instance, const char *host, UINT16 port, const char *common_name, const char *subject, const char *issuer, const char *fingerprint, const char *old_subject, const char *old_issuer, const char *old_fingerprint, DWORD flags)
Callback set in the rdp_freerdp structure, and used to make a certificate validation when a stored ce...
virtual int WakeUp() override
唤醒连接线程(后台线程)
static DWORD cb_verify_certificate_ex(freerdp *instance, const char *host, UINT16 port, const char *common_name, const char *subject, const char *issuer, const char *fingerprint, DWORD flags)
Callback set in the rdp_freerdp structure, and used to make a certificate validation when the connect...
virtual int OnProcess() override
插件连接的具体操作处理。因为此插件是非Qt事件,所以在此函数中等待。
static BOOL cb_post_connect(freerdp *instance)
Callback given to freerdp_connect() to perform post-connection operations.
static BOOL cb_pre_connect(freerdp *instance)
Callback given to freerdp_connect() to process the pre-connect operations.
void sigError(const int nError, const QString &szError=QString())
当有错误产生时触发
void sigInformation(const QString &szInfo)
从后台线程中触发在主线程中显示信息,不阻塞后台线程
void sigBlockShowMessageBox(const QString &szTitle, const QString &szMessage, QMessageBox::StandardButtons buttons, QMessageBox::StandardButton &nRet, bool &checkBox, QString checkBoxContext=QString())
阻塞后台线程,并在前台线程中显示消息对话框(QMessageBox)
void sigShowMessageBox(const QString &szTitle, const QString &szMessage, const QMessageBox::Icon &icon=QMessageBox::Information)
从后台线程中触发在主线程中显示消息对话框(QMessageBox),不阻塞后台线程
void sigBlockInputDialog(const QString &szTitle, const QString &szLable, const QString &szMessage, QString &szText)
阻塞后台线程,并在前台线程中显示输入对话框 (QInputDialog)
void sigConnected()
当插件连接成功后触发。仅由插件触发
void sigDisconnect()
通知用户断开连接。仅由插件触发。 当从插件中需要要断开连接时触发。例如:对端断开连接、重置连接或者连接出错。
void sigBlockShowWidget(const QString &className, int &nRet, void *pContext)
阻塞后台线程,并在前台线程中显示窗口。
static UINT32 QtToScanCode(int key, Qt::KeyboardModifiers modifiers)
CConvertKeyCode::QtToScanCode
CParameterUser m_User
[Instance user]
void sigChanged()
当参数改变时,触发 通常如果需要,则相应的参数会对应一个改变事件。
实现通过本地 SOCKET 与 SSH 隧道转发数据。适用于库没有实现传输层接口,只有 socket 的情况。