From b1a8ec6d7652f375a3ab51dd13d4f232f5cbcd5a Mon Sep 17 00:00:00 2001 From: Maxime Gimeno Date: Wed, 11 Sep 2019 15:01:33 +0200 Subject: [PATCH] Add a way to upload a scene through ssh. --- Installation/cmake/modules/FindLibSSH.cmake | 39 +++ Polyhedron/demo/Polyhedron/CMakeLists.txt | 12 +- Polyhedron/demo/Polyhedron/MainWindow.cpp | 254 +++++++++++++++++- Polyhedron/demo/Polyhedron/MainWindow.h | 1 + Polyhedron/demo/Polyhedron/MainWindow.ui | 7 +- Polyhedron/demo/Polyhedron/Preferences.ui | 16 +- Polyhedron/demo/Polyhedron/SSH_dialog.ui | 130 +++++++++ Polyhedron/demo/Polyhedron/Use_ssh.cpp | 244 +++++++++++++++++ .../demo/Polyhedron/include/CGAL/Use_ssh.h | 25 ++ 9 files changed, 710 insertions(+), 18 deletions(-) create mode 100644 Installation/cmake/modules/FindLibSSH.cmake create mode 100644 Polyhedron/demo/Polyhedron/SSH_dialog.ui create mode 100644 Polyhedron/demo/Polyhedron/Use_ssh.cpp create mode 100644 Polyhedron/demo/Polyhedron/include/CGAL/Use_ssh.h diff --git a/Installation/cmake/modules/FindLibSSH.cmake b/Installation/cmake/modules/FindLibSSH.cmake new file mode 100644 index 00000000000..e2c49ee2fce --- /dev/null +++ b/Installation/cmake/modules/FindLibSSH.cmake @@ -0,0 +1,39 @@ +# - Try to find the LibSSH libraries +# This module defines: +# LIBSSH_FOUND - system has LibSSH lib +# LIBSSH_INCLUDE_DIR - the LibSSH include directory +# LIBSSH_LIBRARIES_DIR - directory where the LibSSH libraries are located +# LIBSSH_LIBRARIES - Link these to use LibSSH + + +include(FindPackageHandleStandardArgs) +include(${CMAKE_CURRENT_LIST_DIR}/CGAL_GeneratorSpecificSettings.cmake) + +if(LIBSSH_INCLUDE_DIR) + set(LIBSSH_in_cache TRUE) +else() + set(LIBSSH_in_cache FALSE) +endif() +if(NOT LIBSSH_LIBRARIES) + set(LIBSSH_in_cache FALSE) +endif() + +# Is it already configured? +if( NOT LIBSSH_in_cache ) + + find_path(LIBSSH_INCLUDE_DIR + NAMES "libssh/libssh.h" + ) + + find_library(LIBSSH_LIBRARIES NAMES ssh libssh + HINTS "/usr/lib" + "usr/lib/x86_64-linux-gnu" + PATH_SUFFIXES lib + DOC "Path to the LIBSSH library" + ) +endif() + +SET(LIBSSH_FOUND TRUE) +if( NOT LIBSSH_LIBRARIES OR NOT LIBSSH_INCLUDE_DIR) + SET(LIBSSH_FOUND FALSE) +endif() diff --git a/Polyhedron/demo/Polyhedron/CMakeLists.txt b/Polyhedron/demo/Polyhedron/CMakeLists.txt index fc4afa3bb09..72853cfd237 100644 --- a/Polyhedron/demo/Polyhedron/CMakeLists.txt +++ b/Polyhedron/demo/Polyhedron/CMakeLists.txt @@ -95,6 +95,11 @@ if( POLYHEDRON_DEMO_ACTIVATE_CONCURRENCY ) endif() endif() +#find libssh for scene sharing +find_package(LibSSH) +if( NOT LIBSSH_FOUND ) + message("NOTICE : The SSH features will be disabled.") +endif() # Activate concurrency ? (turned OFF by default) option(CGAL_ACTIVATE_CONCURRENT_MESH_3 @@ -131,7 +136,7 @@ if(CGAL_Qt5_FOUND AND Qt5_FOUND) qt5_wrap_ui( statisticsUI_FILES Statistics_on_item_dialog.ui) qt5_wrap_ui( FileLoaderDialogUI_files FileLoaderDialog.ui ) qt5_wrap_ui( Show_point_dialogUI_FILES Show_point_dialog.ui ) - qt5_wrap_ui( PreferencesUI_FILES Preferences.ui Details.ui) + qt5_wrap_ui( PreferencesUI_FILES Preferences.ui Details.ui SSH_dialog.ui) qt5_wrap_ui( Show_point_dialogUI_FILES Show_point_dialog.ui ) qt5_wrap_ui( ViewerUI_FILES LightingDialog.ui) qt5_generate_moc( "File_loader_dialog.h" "${CMAKE_CURRENT_BINARY_DIR}/File_loader_dialog_moc.cpp" ) @@ -322,11 +327,16 @@ if(CGAL_Qt5_FOUND AND Qt5_FOUND) MainWindow.cpp Polyhedron_demo.cpp File_loader_dialog_moc.cpp + Use_ssh.cpp ${CGAL_Qt5_RESOURCE_FILES} ${CGAL_Qt5_MOC_FILES} ${FileLoaderDialogUI_files} ${MainWindowUI_files} ${PreferencesUI_FILES} ${statisticsUI_FILES} ${SubViewerUI_files}) target_link_libraries(polyhedron_demo PUBLIC demo_framework point_dialog Qt5::Gui Qt5::OpenGL Qt5::Widgets Qt5::Script) + if(LIBSSH_FOUND) + add_definitions(-DCGAL_USE_SSH) + target_link_libraries(polyhedron_demo PUBLIC ${LIBSSH_LIBRARIES}) + endif() #libssh add_executable ( Polyhedron_3 Polyhedron_3.cpp ) target_link_libraries( Polyhedron_3 PRIVATE polyhedron_demo ) add_to_cached_list( CGAL_EXECUTABLE_TARGETS Polyhedron_3 ) diff --git a/Polyhedron/demo/Polyhedron/MainWindow.cpp b/Polyhedron/demo/Polyhedron/MainWindow.cpp index 3cae43a185f..5c4a45dd6da 100644 --- a/Polyhedron/demo/Polyhedron/MainWindow.cpp +++ b/Polyhedron/demo/Polyhedron/MainWindow.cpp @@ -59,6 +59,7 @@ #include "ui_Preferences.h" #include "ui_Details.h" #include "ui_Statistics_on_item_dialog.h" +#include "ui_SSH_dialog.h" #include "Show_point_dialog.h" #include "File_loader_dialog.h" #include "Viewer.h" @@ -70,6 +71,11 @@ # include # include #include "Color_map.h" + +#ifdef CGAL_USE_SSH +# include "CGAL/Use_ssh.h" +#endif + using namespace CGAL::Three; QScriptValue myScene_itemToScriptValue(QScriptEngine *engine, @@ -151,6 +157,7 @@ MainWindow::MainWindow(const QStringList &keywords, bool verbose, QWidget* paren // remove the Load Script menu entry, when the demo has not been compiled with QT_SCRIPT_LIB #if !defined(QT_SCRIPT_LIB) ui->menuBar->removeAction(ui->actionLoadScript); + ui->menuBar->removeAction(ui->on_actionLoad_a_Scene_from_a_Script_File); #endif // Save some pointers from ui, for latter use. sceneView = ui->sceneView; @@ -1891,14 +1898,7 @@ void MainWindow::throw_exception() { void MainWindow::on_actionLoadScript_triggered() { #if defined(QT_SCRIPT_LIB) - QString filename = QFileDialog::getOpenFileName( - this, - tr("Select a script to run..."), - ".", - "QTScripts (*.js);;All Files (*)"); - if(filename.isEmpty()) - return; - loadScript(QFileInfo(filename)); + #endif } @@ -2198,7 +2198,10 @@ void MainWindow::on_actionPreferences_triggered() QDialog dialog(this); Ui::PreferencesDialog prefdiag; prefdiag.setupUi(&dialog); +#ifdef CGAL_USE_SSH + prefdiag.sshButton->setEnabled(true); +#endif float lineWidth[2]; if(!viewer->isOpenGL_4_3()) viewer->glGetFloatv(GL_LINE_WIDTH_RANGE, lineWidth); @@ -2337,6 +2340,52 @@ void MainWindow::on_actionPreferences_triggered() }); dialog.exec(); }); + connect(prefdiag.sshButton, &QPushButton::clicked, + this, [this, prefdiag](){ + QDialog dialog(this); + Ui::SSHDialog sshdiag; + sshdiag.setupUi(&dialog); + sshdiag.userEdit->setText(settings.value("ssh_user", QString()).toString()); + sshdiag.serverEdit->setText(settings.value("ssh_server", QString()).toString()); + sshdiag.publicEdit->setText(settings.value("ssh_public_key", QString()).toString()); + sshdiag.privkEdit->setText(settings.value("ssh_priv_key", QString()).toString()); + connect(sshdiag.pubButton, &QPushButton::clicked, + this, [this, sshdiag](){ + QFileDialog diag(this, + "Public Key", + "", + "All Files (*)"); + diag.setFilter(QDir::Hidden|QDir::Files|QDir::Dirs|QDir::NoDotAndDotDot); + if(!diag.exec()) + return; + sshdiag.publicEdit->setText(diag.selectedFiles().front()); + }); + connect(sshdiag.privButton, &QPushButton::clicked, + this, [this, sshdiag](){ + QFileDialog diag(this, + "Private Key", + "", + "All Files (*)"); + diag.setFilter(QDir::Hidden|QDir::Files|QDir::Dirs|QDir::NoDotAndDotDot); + if(!diag.exec()) + return; + sshdiag.privkEdit->setText(diag.selectedFiles().front()); + }); + connect(prefdiag.sshButton, &QPushButton::clicked, + this, [this, prefdiag](){}); + dialog.exec(); + if ( dialog.result() ) + { + settings.setValue("ssh_user", + sshdiag.userEdit->text()); + settings.setValue("ssh_server", + sshdiag.serverEdit->text()); + settings.setValue("ssh_public_key", + sshdiag.publicEdit->text()); + settings.setValue("ssh_priv_key", + sshdiag.privkEdit->text()); + } + }); dialog.exec(); if ( dialog.result() ) @@ -2842,11 +2891,41 @@ void MainWindow::on_actionSa_ve_Scene_as_Script_triggered() { if(scene->numberOfEntries() == 0) return; - QString filename = - QFileDialog::getSaveFileName(this, - "Save the Scene as a Script File", - last_saved_dir, - "Qt Script files (*.js)"); + bool do_upload = false; +#ifdef CGAL_USE_SSH + QString user = settings.value("ssh_user", QString()).toString(); + QString pass; + if(!user.isEmpty()) + { + QMessageBox::StandardButton doyou = + QMessageBox::question(this, tr("Upload ?"), tr("Do you wish to upload the scene" + " using the SSH preferences ?")); + bool ok; + do_upload = (doyou == QMessageBox::Yes); + if(do_upload) + { + pass = QInputDialog::getText(this, "SSH Password", + "Enter ssh key password:", + QLineEdit::Password, + tr(""), + &ok); + if(!ok) + return; + pass = pass.trimmed(); + } + } +#endif + + QString filename; + + if(do_upload){ + filename = QString("%1/save_scene.js").arg(QDir::tempPath()); + }else{ + filename = QFileDialog::getSaveFileName(this, + "Save the Scene as a Script File", + last_saved_dir, + "Qt Script files (*.js)"); + } CGAL::Three::Three::CursorScopeGuard cs(Qt::WaitCursor); std::ofstream os(filename.toUtf8(), std::ofstream::binary); if(!os) @@ -2961,6 +3040,58 @@ void MainWindow::on_actionSa_ve_Scene_as_Script_triggered() "Items Not Saved", QString("The following items could not be saved: %1").arg( not_saved.join(", "))); +#ifdef CGAL_USE_SSH + using namespace CGAL::ssh_internal; + if(do_upload) + { + QString server = settings.value("ssh_server", QString()).toString(); + QString pk = settings.value("ssh_public_key", QString()).toString(); + QString privK = settings.value("ssh_priv_key", QString()).toString(); + user = user.trimmed(); + server = server.trimmed(); + pk = pk.trimmed(); + privK=privK.trimmed(); + if(user.isEmpty()){ + return; + } + QString path; + path = QInputDialog::getText(this, + "", + tr("Enter the destination path for your file.")); + if(path.isEmpty()) + return; + try{ + ssh_session session; + bool res = establish_ssh_session(session, + user.toStdString().c_str(), + server.toStdString().c_str(), + pk.toStdString().c_str(), + privK.toStdString().c_str(), + pass.toStdString().c_str()); + if(!res) + { + QMessageBox::warning(this, + "Error", + "The SSH session could not be started."); + return; + } + res = push_file(session,path.toStdString().c_str(), filename.toStdString().c_str()); + if(!res) + { + QMessageBox::warning(this, + "Error", + "The file could not be uploaded. Check your console for more information."); + close_connection(session); + return; + } + close_connection(session); + } catch( ssh::SshException e ) + { + std::cout << "Error during connection : "; + std::cout << e.getError() << std::endl; + } + } +#endif } void MainWindow::setTransparencyPasses(int val) { @@ -3358,3 +3489,100 @@ void MainWindow::on_action_Save_triggered() } } } + +void MainWindow::on_actionLoad_a_Scene_from_a_Script_File_triggered() +{ + bool do_download = false; + QString filename; + +#ifdef CGAL_USE_SSH + QString user = settings.value("ssh_user", QString()).toString(); + QString pass; + if(!user.isEmpty()) + { + QMessageBox::StandardButton doyou = + QMessageBox::question(this, tr("Download ?"), tr("Do you wish to download the scene" + " using the SSH preferences ?")); + bool ok; + do_download= (doyou == QMessageBox::Yes); + if(do_download) + { + pass = QInputDialog::getText(this, "SSH Password", + "Enter ssh key password:", + QLineEdit::Password, + tr(""), + &ok); + if(!ok) + return; + pass = pass.trimmed(); + } + } +#endif + + if(do_download) + { + using namespace CGAL::ssh_internal; + QString server = settings.value("ssh_server", QString()).toString(); + QString pk = settings.value("ssh_public_key", QString()).toString(); + QString privK = settings.value("ssh_priv_key", QString()).toString(); + user = user.trimmed(); + server = server.trimmed(); + pk = pk.trimmed(); + privK=privK.trimmed(); + QString path; + path = QInputDialog::getText(this, + "", + tr("Enter the remote path for your file.")); + if(path.isEmpty()) + return; + try{ + ssh_session session; + bool res = establish_ssh_session(session, + user.toStdString().c_str(), + server.toStdString().c_str(), + pk.toStdString().c_str(), + privK.toStdString().c_str(), + pass.toStdString().c_str()); + if(!res) + { + QMessageBox::warning(this, + "Error", + "The SSH session could not be started."); + return; + } + filename = QString("%1/load_scene.js").arg(QDir::tempPath()); + path = tr("%1/%2").arg(QDir::tempPath()).arg(path); + res = pull_file(session,path.toStdString().c_str(), filename.toStdString().c_str()); + if(!res) + { + QMessageBox::warning(this, + "Error", + "The file could not be fetched. Check your console for more info."); + close_connection(session); + return; + } + close_connection(session); + } catch( ssh::SshException e ) + { + std::cout << "Error during connection : "; + std::cout << e.getError() << std::endl; + } + } + else + { + filename = QFileDialog::getOpenFileName( + this, + tr("Select a Whole Scene file..."), + ".", + "Whole Scene files (*.js)"); + if(filename.isEmpty()) + return; + } + + + + + loadScript(QFileInfo(filename)); + + +} diff --git a/Polyhedron/demo/Polyhedron/MainWindow.h b/Polyhedron/demo/Polyhedron/MainWindow.h index a0758610429..98ed3417ba7 100644 --- a/Polyhedron/demo/Polyhedron/MainWindow.h +++ b/Polyhedron/demo/Polyhedron/MainWindow.h @@ -449,6 +449,7 @@ public: #endif public Q_SLOTS: void on_actionSa_ve_Scene_as_Script_triggered(); + void on_actionLoad_a_Scene_from_a_Script_File_triggered(); void toggleFullScreen(); void setDefaultSaveDir(); void invalidate_bbox(bool do_recenter); diff --git a/Polyhedron/demo/Polyhedron/MainWindow.ui b/Polyhedron/demo/Polyhedron/MainWindow.ui index a011dedab64..0ba2d19b535 100644 --- a/Polyhedron/demo/Polyhedron/MainWindow.ui +++ b/Polyhedron/demo/Polyhedron/MainWindow.ui @@ -58,6 +58,7 @@ + @@ -463,10 +464,14 @@ &Save + + + Load a Scene &from a Script File... + + - diff --git a/Polyhedron/demo/Polyhedron/Preferences.ui b/Polyhedron/demo/Polyhedron/Preferences.ui index 34613871e8d..3eef949ea8e 100644 --- a/Polyhedron/demo/Polyhedron/Preferences.ui +++ b/Polyhedron/demo/Polyhedron/Preferences.ui @@ -7,7 +7,7 @@ 0 0 631 - 526 + 628 @@ -59,8 +59,8 @@ 0 0 - 278 - 499 + 275 + 534 @@ -285,6 +285,16 @@ + + + + false + + + SSH Settings + + + diff --git a/Polyhedron/demo/Polyhedron/SSH_dialog.ui b/Polyhedron/demo/Polyhedron/SSH_dialog.ui new file mode 100644 index 00000000000..ce100341261 --- /dev/null +++ b/Polyhedron/demo/Polyhedron/SSH_dialog.ui @@ -0,0 +1,130 @@ + + + SSHDialog + + + + 0 + 0 + 466 + 399 + + + + SSH Settings + + + + + + + + User + + + + + + + + + + + + Server + + + + + + + + + + + + Public Key + + + + + + + + + Browse... + + + + + + + + + + Private Key + + + + + + + + + Browse... + + + + + + + + + + + + Qt::Horizontal + + + QDialogButtonBox::Cancel|QDialogButtonBox::Ok + + + + + + + + + buttonBox + accepted() + SSHDialog + accept() + + + 248 + 254 + + + 157 + 274 + + + + + buttonBox + rejected() + SSHDialog + reject() + + + 316 + 260 + + + 286 + 274 + + + + + diff --git a/Polyhedron/demo/Polyhedron/Use_ssh.cpp b/Polyhedron/demo/Polyhedron/Use_ssh.cpp new file mode 100644 index 00000000000..663e10ac7ea --- /dev/null +++ b/Polyhedron/demo/Polyhedron/Use_ssh.cpp @@ -0,0 +1,244 @@ +#ifdef CGAL_USE_SSH +#include "CGAL/Use_ssh.h" +#include +#include +#include +#include + +#include + +bool test_result(int res) +{ + switch(res){ + + case SSH_AUTH_ERROR: + { + std::cerr<<"Auth failed with error: "< buffer(size); + if (!file.read(buffer.data(), size)) + { + std::cerr<<"error while reading file."< buffer; + + ssh_scp scp = ssh_scp_new( + session, SSH_SCP_READ | SSH_SCP_RECURSIVE, from_path); + if (scp == NULL) + { + std::cerr<<"Error allocating scp session: %s\n" + << ssh_get_error(session)< +namespace CGAL{ +namespace ssh_internal{ +//should be used inside a try/catch(ssh::SshException e) + +//give an unitialized session. +bool establish_ssh_session(ssh_session& session, + const char *user, + const char *server, + const char *pub_key_path, + const char *priv_key_path, + const char *priv_key_password); +void close_connection(ssh_session& session); + +bool push_file(ssh_session& session, + const char* dest_path, + const char* filepath); +bool pull_file(ssh_session &session, + const char *from_path, + const char *to_path); + +}} +#endif