File indexing completed on 2024-05-12 09:01:21
0001 /* 0002 * SPDX-FileCopyrightText: 2023 Arjen Hiemstra <ahiemstra@heimr.nl> 0003 * SPDX-License-Identifier: GPL-2.0-or-later 0004 */ 0005 0006 #include "rdpsession.h" 0007 0008 #include <memory> 0009 0010 #include <QKeyEvent> 0011 #include <QMouseEvent> 0012 0013 #include <KLocalizedString> 0014 #include <KMessageBox> 0015 #include <KMessageDialog> 0016 #include <KPasswordDialog> 0017 0018 #include <freerdp/addin.h> 0019 #include <freerdp/event.h> 0020 #include <freerdp/freerdp.h> 0021 #include <freerdp/input.h> 0022 #include <freerdp/client.h> 0023 #include <freerdp/client/channels.h> 0024 #include <freerdp/client/cliprdr.h> 0025 #include <freerdp/client/cmdline.h> 0026 #include <freerdp/client/rdpgfx.h> 0027 #include <freerdp/channels/rdpgfx.h> 0028 #include <freerdp/gdi/gdi.h> 0029 #include <freerdp/gdi/gfx.h> 0030 #include <winpr/synch.h> 0031 #ifdef Q_OS_UNIX 0032 #include <freerdp/locale/keyboard.h> 0033 #endif 0034 0035 #include "rdpview.h" 0036 0037 #include "krdc_debug.h" 0038 0039 BOOL preConnect(freerdp *rdp) 0040 { 0041 auto session = reinterpret_cast<RdpContext*>(rdp->context)->session; 0042 if (session->onPreConnect()) { 0043 return TRUE; 0044 } 0045 return FALSE; 0046 } 0047 0048 BOOL postConnect(freerdp *rdp) 0049 { 0050 auto session = reinterpret_cast<RdpContext*>(rdp->context)->session; 0051 if (session->onPostConnect()) { 0052 return TRUE; 0053 } 0054 return FALSE; 0055 } 0056 0057 void postDisconnect(freerdp *rdp) 0058 { 0059 auto session = reinterpret_cast<RdpContext*>(rdp->context)->session; 0060 session->onPostDisconnect(); 0061 } 0062 0063 BOOL authenticate(freerdp *rdp, char** username, char** password, char** domain) 0064 { 0065 auto session = reinterpret_cast<RdpContext*>(rdp->context)->session; 0066 if (session->onAuthenticate(username, password, domain)) { 0067 return TRUE; 0068 } 0069 0070 return FALSE; 0071 } 0072 0073 DWORD verifyChangedCertificate(freerdp* rdp, const char* host, UINT16 port, const char* common_name, const char* subject, 0074 const char* issuer, const char* new_fingerprint, const char* old_subject, const char* old_issuer, 0075 const char* old_fingerprint, DWORD flags) 0076 { 0077 auto session = reinterpret_cast<RdpContext*>(rdp->context)->session; 0078 0079 Certificate oldCertificate; 0080 oldCertificate.host = QString::fromLocal8Bit(host); 0081 oldCertificate.port = port; 0082 oldCertificate.commonName = QString::fromLocal8Bit(common_name); 0083 oldCertificate.subject = QString::fromLocal8Bit(old_subject); 0084 oldCertificate.issuer = QString::fromLocal8Bit(old_issuer); 0085 oldCertificate.fingerprint = QString::fromLocal8Bit(old_fingerprint); 0086 oldCertificate.flags = flags; 0087 0088 Certificate newCertificate; 0089 newCertificate.host = oldCertificate.host; 0090 newCertificate.port = oldCertificate.port; 0091 newCertificate.commonName = oldCertificate.commonName; 0092 newCertificate.subject = QString::fromLocal8Bit(subject); 0093 newCertificate.issuer = QString::fromLocal8Bit(issuer); 0094 newCertificate.fingerprint = QString::fromLocal8Bit(new_fingerprint); 0095 newCertificate.flags = flags; 0096 0097 switch (session->onVerifyChangedCertificate(oldCertificate, newCertificate)) { 0098 case RdpSession::CertificateResult::DoNotAccept: 0099 return 0; 0100 case RdpSession::CertificateResult::AcceptTemporarily: 0101 return 2; 0102 case RdpSession::CertificateResult::AcceptPermanently: 0103 return 1; 0104 } 0105 0106 return 0; 0107 } 0108 0109 DWORD verifyCertificate(freerdp* rdp, const char* host, UINT16 port, const char* common_name, const char* subject, 0110 const char* issuer, const char* fingerprint, DWORD flags) 0111 { 0112 auto session = reinterpret_cast<RdpContext*>(rdp->context)->session; 0113 0114 Certificate certificate; 0115 certificate.host = QString::fromLocal8Bit(host); 0116 certificate.port = port; 0117 certificate.commonName = QString::fromLocal8Bit(common_name); 0118 certificate.subject = QString::fromLocal8Bit(subject); 0119 certificate.issuer = QString::fromLocal8Bit(issuer); 0120 certificate.fingerprint = QString::fromLocal8Bit(fingerprint); 0121 certificate.flags = flags; 0122 0123 switch (session->onVerifyCertificate(certificate)) { 0124 case RdpSession::CertificateResult::DoNotAccept: 0125 return 0; 0126 case RdpSession::CertificateResult::AcceptTemporarily: 0127 return 2; 0128 case RdpSession::CertificateResult::AcceptPermanently: 0129 return 1; 0130 } 0131 0132 return 0; 0133 } 0134 0135 int logonErrorInfo(freerdp* rdp, UINT32 data, UINT32 type) 0136 { 0137 auto dataString = QString::fromLocal8Bit(freerdp_get_logon_error_info_data(data)); 0138 auto typeString = QString::fromLocal8Bit(freerdp_get_logon_error_info_type(type)); 0139 0140 if (!rdp || !rdp->context) 0141 return -1; 0142 0143 KMessageBox::error(nullptr, typeString + QStringLiteral(" ") + dataString, i18nc("@title:dialog", "Logon Error")); 0144 0145 return 1; 0146 } 0147 0148 BOOL endPaint(rdpContext *context) 0149 { 0150 auto session = reinterpret_cast<RdpContext*>(context)->session; 0151 if (session->onEndPaint()) { 0152 return TRUE; 0153 } 0154 return FALSE; 0155 } 0156 0157 BOOL resizeDisplay(rdpContext *context) 0158 { 0159 auto session = reinterpret_cast<RdpContext*>(context)->session; 0160 if (session->onResizeDisplay()) { 0161 return TRUE; 0162 } 0163 return FALSE; 0164 } 0165 0166 void channelConnected(void* context, ChannelConnectedEventArgs* e) 0167 { 0168 auto rdpC = reinterpret_cast<rdpContext*>(context); 0169 if (strcmp(e->name, RDPGFX_DVC_CHANNEL_NAME) == 0) { 0170 gdi_graphics_pipeline_init(rdpC->gdi, (RdpgfxClientContext*)e->pInterface); 0171 } else if (strcmp(e->name, CLIPRDR_SVC_CHANNEL_NAME) == 0) { 0172 CliprdrClientContext* clip = (CliprdrClientContext*)e->pInterface; 0173 clip->custom = context; 0174 } 0175 } 0176 0177 void channelDisconnected(void* context, ChannelDisconnectedEventArgs* e) 0178 { 0179 auto rdpC = reinterpret_cast<rdpContext*>(context); 0180 if (strcmp(e->name, RDPGFX_DVC_CHANNEL_NAME) == 0) { 0181 gdi_graphics_pipeline_uninit(rdpC->gdi, (RdpgfxClientContext*)e->pInterface); 0182 } else if (strcmp(e->name, CLIPRDR_SVC_CHANNEL_NAME) == 0) { 0183 CliprdrClientContext* clip = (CliprdrClientContext*)e->pInterface; 0184 clip->custom = nullptr; 0185 } 0186 } 0187 0188 QString Certificate::toString() const 0189 { 0190 return i18nc("@label", "Host: %1:%2\nCommon Name: %3\nSubject: %4\nIssuer: %5\nFingerprint: %6\n", 0191 host, port, commonName, subject, issuer, fingerprint); 0192 } 0193 0194 RdpSession::RdpSession(RdpView *view) 0195 : QObject(nullptr) 0196 , m_view(view) 0197 { 0198 } 0199 0200 RdpSession::~RdpSession() 0201 { 0202 stop(); 0203 } 0204 0205 RdpSession::State RdpSession::state() const 0206 { 0207 return m_state; 0208 } 0209 0210 QString RdpSession::host() const 0211 { 0212 return m_host; 0213 } 0214 0215 void RdpSession::setHost(const QString &newHost) 0216 { 0217 m_host = newHost; 0218 } 0219 0220 QString RdpSession::user() const 0221 { 0222 return m_user; 0223 } 0224 0225 void RdpSession::setUser(const QString &newUser) 0226 { 0227 m_user = newUser; 0228 } 0229 0230 QString RdpSession::domain() const 0231 { 0232 return m_domain; 0233 } 0234 0235 void RdpSession::setDomain(const QString& newDomain) 0236 { 0237 m_domain = newDomain; 0238 } 0239 0240 QString RdpSession::password() const 0241 { 0242 return m_password; 0243 } 0244 0245 void RdpSession::setPassword(const QString &newPassword) 0246 { 0247 m_password = newPassword; 0248 } 0249 0250 int RdpSession::port() const 0251 { 0252 return m_port; 0253 } 0254 0255 void RdpSession::setPort(int port) 0256 { 0257 m_port = port; 0258 } 0259 0260 RdpHostPreferences *RdpSession::preferences() const 0261 { 0262 return m_preferences; 0263 } 0264 0265 void RdpSession::setHostPreferences(RdpHostPreferences *preferences) 0266 { 0267 m_preferences = preferences; 0268 } 0269 0270 QSize RdpSession::size() const 0271 { 0272 return m_size; 0273 } 0274 0275 void RdpSession::setSize(QSize size) 0276 { 0277 m_size = size; 0278 } 0279 0280 bool RdpSession::start() 0281 { 0282 setState(State::Starting); 0283 0284 qCInfo(KRDC) << "Starting RDP session"; 0285 0286 m_freerdp = freerdp_new(); 0287 0288 m_freerdp->ContextSize = sizeof(RdpContext); 0289 m_freerdp->ContextNew = nullptr; 0290 m_freerdp->ContextFree = nullptr; 0291 0292 m_freerdp->Authenticate = authenticate; 0293 m_freerdp->VerifyCertificateEx = verifyCertificate; 0294 m_freerdp->VerifyChangedCertificateEx = verifyChangedCertificate; 0295 m_freerdp->LogonErrorInfo = logonErrorInfo; 0296 0297 m_freerdp->PreConnect = preConnect; 0298 m_freerdp->PostConnect = postConnect; 0299 m_freerdp->PostDisconnect = postDisconnect; 0300 0301 freerdp_context_new(m_freerdp); 0302 0303 m_context = reinterpret_cast<RdpContext*>(m_freerdp->context); 0304 m_context->session = this; 0305 0306 if (freerdp_register_addin_provider(freerdp_channels_load_static_addin_entry, 0) != CHANNEL_RC_OK) { 0307 return false; 0308 } 0309 0310 auto settings = m_freerdp->settings; 0311 settings->ServerHostname = qstrdup(m_host.toLocal8Bit().data()); 0312 settings->ServerPort = m_port; 0313 0314 settings->Username = qstrdup(m_user.toLocal8Bit().data()); 0315 settings->Password = qstrdup(m_password.toLocal8Bit().data()); 0316 0317 if (m_size.width() > 0 && m_size.height() > 0) { 0318 settings->DesktopWidth = m_size.width(); 0319 settings->DesktopHeight = m_size.height(); 0320 } 0321 0322 switch (m_preferences->acceleration()) { 0323 case RdpHostPreferences::Acceleration::ForceGraphicsPipeline: 0324 settings->SupportGraphicsPipeline = true; 0325 settings->GfxAVC444 = true; 0326 settings->GfxAVC444v2 = true; 0327 settings->GfxH264 = true; 0328 settings->RemoteFxCodec = false; 0329 settings->ColorDepth = 32; 0330 break; 0331 case RdpHostPreferences::Acceleration::ForceRemoteFx: 0332 settings->SupportGraphicsPipeline = false; 0333 settings->GfxAVC444 = false; 0334 settings->GfxAVC444v2 = false; 0335 settings->GfxH264 = false; 0336 settings->RemoteFxCodec = true; 0337 settings->ColorDepth = 32; 0338 break; 0339 case RdpHostPreferences::Acceleration::Disabled: 0340 settings->SupportGraphicsPipeline = false; 0341 settings->GfxAVC444 = false; 0342 settings->GfxAVC444v2 = false; 0343 settings->GfxH264 = false; 0344 settings->RemoteFxCodec = false; 0345 break; 0346 case RdpHostPreferences::Acceleration::Auto: 0347 settings->SupportGraphicsPipeline = true; 0348 settings->GfxAVC444 = true; 0349 settings->GfxAVC444v2 = true; 0350 settings->GfxH264 = true; 0351 settings->RemoteFxCodec = true; 0352 settings->ColorDepth = 32; 0353 break; 0354 } 0355 0356 switch (m_preferences->colorDepth()) { 0357 case RdpHostPreferences::ColorDepth::Auto: 0358 case RdpHostPreferences::ColorDepth::Depth32: 0359 settings->ColorDepth = 32; 0360 break; 0361 case RdpHostPreferences::ColorDepth::Depth24: 0362 settings->ColorDepth = 24; 0363 break; 0364 case RdpHostPreferences::ColorDepth::Depth16: 0365 settings->ColorDepth = 16; 0366 break; 0367 case RdpHostPreferences::ColorDepth::Depth8: 0368 settings->ColorDepth = 8; 0369 } 0370 0371 settings->FastPathOutput = true; 0372 settings->FastPathInput = true; 0373 settings->FrameMarkerCommandEnabled = true; 0374 0375 settings->SupportDynamicChannels = true; 0376 0377 switch (m_preferences->sound()) { 0378 case RdpHostPreferences::Sound::Local: 0379 settings->AudioPlayback = true; 0380 settings->AudioCapture = true; 0381 break; 0382 case RdpHostPreferences::Sound::Remote: 0383 settings->RemoteConsoleAudio = true; 0384 break; 0385 case RdpHostPreferences::Sound::Disabled: 0386 settings->AudioPlayback = false; 0387 settings->AudioCapture = false; 0388 break; 0389 } 0390 0391 if (!m_preferences->shareMedia().isEmpty()) { 0392 char* params[2] = {strdup("drive"), m_preferences->shareMedia().toLocal8Bit().data()}; 0393 freerdp_client_add_device_channel(settings, 1, params); 0394 } 0395 0396 settings->KeyboardLayout = m_preferences->rdpKeyboardLayout(); 0397 0398 if (!freerdp_connect(m_freerdp)) { 0399 qWarning(KRDC) << "Unable to connect"; 0400 emitErrorMessage(); 0401 return false; 0402 } 0403 0404 m_thread = std::thread(std::bind(&RdpSession::run, this)); 0405 pthread_setname_np(m_thread.native_handle(), "rdp_session"); 0406 0407 return true; 0408 } 0409 0410 void RdpSession::stop() 0411 { 0412 freerdp_abort_connect(m_freerdp); 0413 if (m_thread.joinable()) { 0414 m_thread.join(); 0415 } 0416 0417 if (m_freerdp) { 0418 freerdp_context_free(m_freerdp); 0419 freerdp_free(m_freerdp); 0420 0421 m_context = nullptr; 0422 m_freerdp = nullptr; 0423 } 0424 } 0425 0426 const QImage *RdpSession::videoBuffer() const 0427 { 0428 return &m_videoBuffer; 0429 } 0430 0431 bool RdpSession::sendEvent(QEvent *event, QWidget *source) 0432 { 0433 auto input = m_freerdp->context->input; 0434 0435 switch(event->type()) { 0436 case QEvent::KeyPress: 0437 case QEvent::KeyRelease: { 0438 auto keyEvent = static_cast<QKeyEvent *>(event); 0439 auto code = freerdp_keyboard_get_rdp_scancode_from_x11_keycode(keyEvent->nativeScanCode()); 0440 freerdp_input_send_keyboard_event_ex(input, keyEvent->type() == QEvent::KeyPress, code); 0441 return true; 0442 } 0443 case QEvent::MouseButtonPress: 0444 case QEvent::MouseButtonRelease: 0445 case QEvent::MouseButtonDblClick: 0446 case QEvent::MouseMove: { 0447 auto mouseEvent = static_cast<QMouseEvent *>(event); 0448 auto position = mouseEvent->localPos(); 0449 auto sourceSize = QSizeF{source->size()}; 0450 0451 auto x = (position.x() / sourceSize.width()) * m_size.width(); 0452 auto y = (position.y() / sourceSize.height()) * m_size.height(); 0453 0454 bool extendedEvent = false; 0455 UINT16 flags = 0; 0456 0457 switch (mouseEvent->button()) { 0458 case Qt::LeftButton: 0459 flags |= PTR_FLAGS_BUTTON1; 0460 break; 0461 case Qt::RightButton: 0462 flags |= PTR_FLAGS_BUTTON2; 0463 break; 0464 case Qt::MiddleButton: 0465 flags |= PTR_FLAGS_BUTTON3; 0466 break; 0467 case Qt::BackButton: 0468 flags |= PTR_XFLAGS_BUTTON1; 0469 extendedEvent = true; 0470 break; 0471 case Qt::ForwardButton: 0472 flags |= PTR_XFLAGS_BUTTON2; 0473 extendedEvent = true; 0474 break; 0475 default: 0476 break; 0477 } 0478 0479 if (mouseEvent->type() == QEvent::MouseButtonPress || mouseEvent->type() == QEvent::MouseButtonDblClick) { 0480 if (extendedEvent) { 0481 flags |= PTR_XFLAGS_DOWN; 0482 } else { 0483 flags |= PTR_FLAGS_DOWN; 0484 } 0485 } else if (mouseEvent->type() == QEvent::MouseMove) { 0486 flags |= PTR_FLAGS_MOVE; 0487 } 0488 0489 if (extendedEvent) { 0490 freerdp_input_send_extended_mouse_event(input, flags, uint16_t(x), uint16_t(y)); 0491 } else { 0492 freerdp_input_send_mouse_event(input, flags, uint16_t(x), uint16_t(y)); 0493 } 0494 0495 return true; 0496 } 0497 case QEvent::Wheel: { 0498 auto wheelEvent = static_cast<QWheelEvent *>(event); 0499 auto delta = wheelEvent->angleDelta(); 0500 0501 uint16_t flags = 0; 0502 uint16_t value = 0; 0503 if (delta.y() != 0) { 0504 value = std::clamp(std::abs(delta.y()), 0, 0xFF); 0505 flags |= PTR_FLAGS_WHEEL; 0506 if (wheelEvent->angleDelta().y() < 0) { 0507 flags |= PTR_FLAGS_WHEEL_NEGATIVE; 0508 flags = (flags & 0xFF00) | (0x100 - value); 0509 } else { 0510 flags |= value; 0511 } 0512 } else if (wheelEvent->angleDelta().x() != 0) { 0513 value = std::clamp(std::abs(delta.x()), 0, 0xFF); 0514 flags |= PTR_FLAGS_HWHEEL; 0515 if (wheelEvent->angleDelta().x() < 0) { 0516 flags |= PTR_FLAGS_WHEEL_NEGATIVE; 0517 flags = (flags & 0xFF00) | (0x100 - value); 0518 } else { 0519 flags |= value; 0520 } 0521 } 0522 0523 auto position = wheelEvent->position(); 0524 auto sourceSize = QSizeF{source->size()}; 0525 0526 auto x = (position.x() / sourceSize.width()) * m_size.width(); 0527 auto y = (position.y() / sourceSize.height()) * m_size.height(); 0528 0529 freerdp_input_send_mouse_event(input, flags, uint16_t(x), uint16_t(y)); 0530 } 0531 default: 0532 break; 0533 } 0534 0535 return QObject::event(event); 0536 } 0537 0538 void RdpSession::setState(RdpSession::State newState) 0539 { 0540 if (newState == m_state) { 0541 return; 0542 } 0543 0544 m_state = newState; 0545 Q_EMIT stateChanged(); 0546 } 0547 0548 bool RdpSession::onPreConnect() 0549 { 0550 auto settings = m_freerdp->settings; 0551 settings->OsMajorType = OSMAJORTYPE_UNIX; 0552 settings->OsMinorType = OSMINORTYPE_UNSPECIFIED; 0553 0554 PubSub_SubscribeChannelConnected(m_freerdp->context->pubSub, channelConnected); 0555 PubSub_SubscribeChannelDisconnected(m_freerdp->context->pubSub, channelDisconnected); 0556 0557 if (!freerdp_client_load_addins(m_freerdp->context->channels, settings)) { 0558 return false; 0559 } 0560 0561 return true; 0562 } 0563 0564 bool RdpSession::onPostConnect() 0565 { 0566 setState(State::Connected); 0567 0568 auto settings = m_freerdp->settings; 0569 0570 m_videoBuffer = QImage(settings->DesktopWidth, settings->DesktopHeight, QImage::Format_RGBA8888); 0571 0572 if (!gdi_init_ex(m_freerdp, PIXEL_FORMAT_RGBA32, m_videoBuffer.bytesPerLine(), m_videoBuffer.bits(), nullptr)) { 0573 qCWarning(KRDC) << "Could not initialize GDI subsystem"; 0574 return false; 0575 } 0576 0577 auto gdi = reinterpret_cast<rdpContext*>(m_context)->gdi; 0578 if (!gdi || gdi->width < 0 || gdi->height < 0) { 0579 return false; 0580 } 0581 0582 m_size = QSize(gdi->width, gdi->height); 0583 Q_EMIT sizeChanged(); 0584 0585 m_freerdp->update->EndPaint = endPaint; 0586 m_freerdp->update->DesktopResize = resizeDisplay; 0587 0588 freerdp_keyboard_init_ex(settings->KeyboardLayout, settings->KeyboardRemappingList); 0589 0590 return true; 0591 } 0592 0593 void RdpSession::onPostDisconnect() 0594 { 0595 setState(State::Closed); 0596 gdi_free(m_freerdp); 0597 } 0598 0599 bool RdpSession::onAuthenticate(char **username, char **password, char **domain) 0600 { 0601 Q_UNUSED(domain); 0602 0603 std::unique_ptr<KPasswordDialog> dialog; 0604 bool hasUsername = qstrlen(*username) != 0; 0605 if (hasUsername) { 0606 dialog = std::make_unique<KPasswordDialog>(nullptr, KPasswordDialog::ShowKeepPassword); 0607 dialog->setPrompt(i18nc("@label", "Access to this system requires a password.")); 0608 } else { 0609 dialog = std::make_unique<KPasswordDialog>(nullptr, KPasswordDialog::ShowUsernameLine | KPasswordDialog::ShowKeepPassword); 0610 dialog->setPrompt(i18nc("@label", "Access to this system requires a username and password.")); 0611 } 0612 0613 if (!dialog->exec()) { 0614 return false; 0615 } 0616 0617 *password = qstrdup(dialog->password().toLocal8Bit().data()); 0618 0619 if (!hasUsername) { 0620 *username = qstrdup(dialog->username().toLocal8Bit().data()); 0621 } 0622 0623 if (dialog->keepPassword()) { 0624 m_view->savePassword(dialog->password()); 0625 } 0626 0627 return true; 0628 } 0629 0630 RdpSession::CertificateResult RdpSession::onVerifyCertificate(const Certificate &certificate) 0631 { 0632 KMessageDialog dialog{KMessageDialog::QuestionTwoActions, i18nc("@label", "The certificate for this system is unknown. Do you wish to continue?")}; 0633 dialog.setCaption(i18nc("@title:dialog", "Verify Certificate")); 0634 dialog.setIcon(QIcon::fromTheme(QStringLiteral("view-certficate"))); 0635 0636 dialog.setDetails(certificate.toString()); 0637 0638 dialog.setDontAskAgainText(i18nc("@label", "Remember this certificate")); 0639 0640 dialog.setButtons(KStandardGuiItem::cont(), KStandardGuiItem::cancel()); 0641 0642 if (!dialog.exec()) { 0643 return CertificateResult::DoNotAccept; 0644 } 0645 0646 if (dialog.isDontAskAgainChecked()) { 0647 return CertificateResult::AcceptPermanently; 0648 } else { 0649 return CertificateResult::AcceptTemporarily; 0650 } 0651 } 0652 0653 RdpSession::CertificateResult RdpSession::onVerifyChangedCertificate(const Certificate &oldCertificate, const Certificate &newCertificate) 0654 { 0655 KMessageDialog dialog{KMessageDialog::QuestionTwoActions, i18nc("@label", "The certificate for this system has changed. Do you wish to continue?")}; 0656 dialog.setCaption(i18nc("@title:dialog", "Certificate has Changed")); 0657 dialog.setIcon(QIcon::fromTheme(QStringLiteral("view-certficate"))); 0658 0659 dialog.setDetails(i18nc("@label", "Previous certificate:\n%1\nNew Certificate:\n%2", oldCertificate.toString(), newCertificate.toString())); 0660 0661 dialog.setDontAskAgainText(i18nc("@label", "Remember this certificate")); 0662 0663 dialog.setButtons(KStandardGuiItem::cont(), KStandardGuiItem::cancel()); 0664 0665 if (!dialog.exec()) { 0666 return CertificateResult::DoNotAccept; 0667 } 0668 0669 if (dialog.isDontAskAgainChecked()) { 0670 return CertificateResult::AcceptPermanently; 0671 } else { 0672 return CertificateResult::AcceptTemporarily; 0673 } 0674 } 0675 0676 bool RdpSession::onEndPaint() 0677 { 0678 if (!m_context) { 0679 return false; 0680 } 0681 0682 auto gdi = reinterpret_cast<rdpContext*>(m_context)->gdi; 0683 if (!gdi || !gdi->primary) { 0684 return false; 0685 } 0686 0687 auto invalid = gdi->primary->hdc->hwnd->invalid; 0688 if (invalid->null) { 0689 return true; 0690 } 0691 0692 auto rect = QRect{invalid->x, invalid->y, invalid->w, invalid->h}; 0693 Q_EMIT rectangleUpdated(rect); 0694 0695 return true; 0696 } 0697 0698 bool RdpSession::onResizeDisplay() 0699 { 0700 auto gdi = reinterpret_cast<rdpContext*>(m_context)->gdi; 0701 auto settings = m_freerdp->settings; 0702 0703 m_videoBuffer = QImage(settings->DesktopWidth, settings->DesktopHeight, QImage::Format_RGBA8888); 0704 0705 if (!gdi_resize_ex(gdi, settings->DesktopWidth, settings->DesktopHeight, m_videoBuffer.bytesPerLine(), PIXEL_FORMAT_RGBA32, m_videoBuffer.bits(), nullptr)) { 0706 qCWarning(KRDC) << "Failed resizing GDI subsystem"; 0707 return false; 0708 } 0709 0710 m_size = QSize(settings->DesktopWidth, settings->DesktopHeight); 0711 Q_EMIT sizeChanged(); 0712 0713 return true; 0714 } 0715 0716 void RdpSession::run() 0717 { 0718 auto rdpC = reinterpret_cast<rdpContext*>(m_context); 0719 0720 auto timer = CreateWaitableTimerA(nullptr, FALSE, "rdp-session-timer"); 0721 if (!timer) { 0722 return; 0723 } 0724 0725 LARGE_INTEGER due; 0726 due.QuadPart = 0; 0727 if (!SetWaitableTimer(timer, &due, 1, nullptr, nullptr, false)) { 0728 return; 0729 } 0730 0731 setState(State::Running); 0732 0733 HANDLE handles[MAXIMUM_WAIT_OBJECTS] = {}; 0734 while (!freerdp_shall_disconnect(m_freerdp)) { 0735 handles[0] = timer; 0736 auto count = freerdp_get_event_handles(rdpC, &handles[1], ARRAYSIZE(handles) - 1); 0737 0738 auto status = WaitForMultipleObjects(count, handles, FALSE, INFINITE); 0739 if (status == WAIT_FAILED) { 0740 emitErrorMessage(); 0741 break; 0742 } 0743 0744 if (freerdp_check_event_handles(rdpC) != TRUE) { 0745 emitErrorMessage(); 0746 break; 0747 } 0748 } 0749 0750 freerdp_disconnect(m_freerdp); 0751 } 0752 0753 void RdpSession::emitErrorMessage() 0754 { 0755 auto error = freerdp_get_last_error(m_freerdp->context); 0756 0757 if (error == FREERDP_ERROR_CONNECT_CANCELLED) { 0758 return; 0759 } 0760 0761 auto name = freerdp_get_last_error_name(error); 0762 auto description = freerdp_get_last_error_string(error); 0763 0764 qCWarning(KRDC) << name << description; 0765 0766 QString title; 0767 QString message; 0768 0769 switch (error) { 0770 case FREERDP_ERROR_AUTHENTICATION_FAILED: 0771 case FREERDP_ERROR_CONNECT_LOGON_FAILURE: 0772 case FREERDP_ERROR_CONNECT_WRONG_PASSWORD: 0773 title = i18nc("@title:dialog", "Login Failure"); 0774 message = i18nc("@label", "Unable to login with the provided credentials. Please double check the user and password."); 0775 break; 0776 case FREERDP_ERROR_CONNECT_ACCOUNT_LOCKED_OUT: 0777 case FREERDP_ERROR_CONNECT_ACCOUNT_EXPIRED: 0778 case FREERDP_ERROR_CONNECT_ACCOUNT_DISABLED: 0779 case FREERDP_ERROR_SERVER_INSUFFICIENT_PRIVILEGES: 0780 title = i18nc("@title:dialog", "Account Problems"); 0781 message = i18nc("@label", "The provided account is not allowed to log in to this machine. Please contact your system administrator."); 0782 break; 0783 case FREERDP_ERROR_CONNECT_PASSWORD_EXPIRED: 0784 case FREERDP_ERROR_CONNECT_PASSWORD_CERTAINLY_EXPIRED: 0785 case FREERDP_ERROR_CONNECT_PASSWORD_MUST_CHANGE: 0786 title = i18nc("@title:dialog", "Password Problems"); 0787 message = i18nc("@label", "Unable to login with the provided password. Please contact your system administrator to change it."); 0788 break; 0789 case FREERDP_ERROR_CONNECT_FAILED: 0790 title = i18nc("@title:dialog", "Connection Lost"); 0791 message = i18nc("@label", "Lost connection to the server."); 0792 break; 0793 case FREERDP_ERROR_DNS_ERROR: 0794 case FREERDP_ERROR_DNS_NAME_NOT_FOUND: 0795 title = i18nc("@title:dialog", "Server not Found"); 0796 message = i18nc("@label", "Could not find the server."); 0797 break; 0798 case FREERDP_ERROR_SERVER_DENIED_CONNECTION: 0799 title = i18nc("@title:dialog", "Connection Refused"); 0800 message = i18nc("@label", "The server refused the connection request."); 0801 break; 0802 case FREERDP_ERROR_TLS_CONNECT_FAILED: 0803 case FREERDP_ERROR_CONNECT_TRANSPORT_FAILED: 0804 title = i18nc("@title:dialog", "Could not Connect"); 0805 message = i18nc("@label", "Could not connect to the server."); 0806 break; 0807 case FREERDP_ERROR_LOGOFF_BY_USER: 0808 case FREERDP_ERROR_DISCONNECTED_BY_OTHER_CONNECTION: 0809 case FREERDP_ERROR_BASE: 0810 title = i18nc("@title:dialog", "Connection Closed"); 0811 message = i18nc("@label", "The connection to the server was closed."); 0812 break; 0813 default: 0814 title = i18nc("@title:dialog", "Connection Failed"); 0815 message = i18nc("@label", "An unknown error occurred"); 0816 break; 0817 } 0818 0819 Q_EMIT errorMessage(title, message); 0820 }