From e7eafb31172201bd99bd25958c06e1a38db6dcff Mon Sep 17 00:00:00 2001 From: Daniel Tartavel Date: Mon, 27 Feb 2023 23:48:05 +0100 Subject: [PATCH] added password protected connexion correction bug on detection of already downloaded file --- RsyncUI.pro | 1 + RsyncUI.pro.user | 2 +- downloadfile.cpp | 12 ++- login.ui | 120 ++++++++++++++++++++++++++++ mainwindow.cpp | 200 +++++++++++++++++++++++++++++++++++++---------- mainwindow.h | 14 +++- mainwindow.ui | 4 +- tools.cpp | 7 +- tools.h | 4 +- 9 files changed, 314 insertions(+), 50 deletions(-) create mode 100644 login.ui diff --git a/RsyncUI.pro b/RsyncUI.pro index 33a8270..ac30c58 100644 --- a/RsyncUI.pro +++ b/RsyncUI.pro @@ -29,6 +29,7 @@ HEADERS += \ FORMS += \ about.ui \ configuration.ui \ + login.ui \ mainwindow.ui TRANSLATIONS += \ diff --git a/RsyncUI.pro.user b/RsyncUI.pro.user index c282129..4d9d8cf 100644 --- a/RsyncUI.pro.user +++ b/RsyncUI.pro.user @@ -1,6 +1,6 @@ - + EnvironmentId diff --git a/downloadfile.cpp b/downloadfile.cpp index 1bbd803..4dce85a 100644 --- a/downloadfile.cpp +++ b/downloadfile.cpp @@ -33,7 +33,7 @@ void MainWindow::cancelled(QProcess * process) n = process->waitForFinished(30000); if (n == false) { - process->kill(); + process->close(); } } @@ -42,7 +42,15 @@ void MainWindow::download() { QString cmd; QStringList param; + QProcessEnvironment env = QProcessEnvironment::systemEnvironment(); + this->downloading.process = new QProcess(this); + if (!this->downloading.user.isEmpty()) + { + this->downloading.server.prepend(this->connexion.user + "@"); + env.insert("RSYNC_PASSWORD", this->downloading.password); // Add an environment variable + this->downloading.process->setProcessEnvironment(env); + } // Populating array with command and parameters for popen2 cmd = "rsync"; if (this->connexion.bandwidthLimit != 0) @@ -53,7 +61,7 @@ void MainWindow::download() param << "-aXP"; param << this->downloading.server + "::" + this->downloading.service + "/" + this->downloading.path << this->downloading.savePath + "/"; - this->downloading.process = new QProcess(this); + connect(this->downloading.process, SIGNAL(finished(int,QProcess::ExitStatus)), this, SLOT(downloadFinished(int, QProcess::ExitStatus))); //connect(this->downloading.process, SIGNAL(errorOccurred(QProcess::ProcessError error)), this, SLOT(downloadProcessError(QProcess::ProcessError error))); diff --git a/login.ui b/login.ui new file mode 100644 index 0000000..029cfff --- /dev/null +++ b/login.ui @@ -0,0 +1,120 @@ + + + LoginDialog + + + + 0 + 0 + 400 + 194 + + + + Dialog + + + + + 50 + 150 + 341 + 32 + + + + Qt::Horizontal + + + QDialogButtonBox::Cancel|QDialogButtonBox::Ok + + + + + + 10 + 10 + 381 + 121 + + + + + + + Login name + + + Qt::PlainText + + + Qt::NoTextInteraction + + + + + + + Enter login name + + + 128 + + + Enter login + + + + + + + Password + + + + + + + Enter password + + + + + + + + + + loginBox + accepted() + LoginDialog + accept() + + + 248 + 254 + + + 157 + 274 + + + + + loginBox + rejected() + LoginDialog + reject() + + + 316 + 260 + + + 286 + 274 + + + + + diff --git a/mainwindow.cpp b/mainwindow.cpp index 7fe1a91..a66a2f9 100644 --- a/mainwindow.cpp +++ b/mainwindow.cpp @@ -47,6 +47,9 @@ MainWindow::MainWindow(QWidget *parent) // init about window AboutW.setupUi(&aboutDialog); + //init login dialog + loginD.setupUi(&loginDialog); + // text of About QString aboutText = tr("

Client for rsync server

") + "" + tr("Version") + ": " + this->about.version + "
" + @@ -66,6 +69,7 @@ MainWindow::MainWindow(QWidget *parent) connect(this, &MainWindow::stopDownloading, this, &MainWindow::cancelled); connect(config.buttonBox, SIGNAL(accepted()), this, SLOT(on_buttonBox_accepted())); connect(config.comboBox, QOverload::of(&QComboBox::currentIndexChanged), this, &MainWindow::on_comboBox_currentIndexChanged); + connect(loginD.loginBox, SIGNAL(accepted()), this, SLOT(on_loginBox_accepted())); // init of widgets ui->ktreewidgetsearchline->setTreeWidget(ui->treeWidget); // attach search widget to treewidget @@ -284,7 +288,7 @@ void MainWindow::populateTree(QTreeWidgetItem * parent) // validating server's address if (validateServer(this->connexion.server)) { - // server is validated + // server is validated, scanning directory path = ui->listWidget->currentItem()->text().section('\n', 0, 0) + "/"; scanDir(this->connexion.server, this->connexion.port, parent, path); } @@ -392,7 +396,8 @@ void MainWindow::listServices() } // verifying error code - testRsyncReturn(myProcess); + testRsyncReturn(this, myProcess); + myProcess->close(); } // connect to rsync server to get list of files @@ -406,61 +411,116 @@ void MainWindow::scanDir(QString server, int portN, QTreeWidgetItem *parent, QSt QProcess * myProcess; bool isDir = false; bool flag = false; + bool readOk = false; int nChild = 0; + QMessageBox::StandardButton reply; + QProcessEnvironment env = QProcessEnvironment::systemEnvironment(); - if (parent != NULL) + myProcess = new QProcess(this); + if (!this->connexion.user.isEmpty()) + { + server.prepend(this->connexion.user + "@"); + env.insert("RSYNC_PASSWORD", "Test"); // Add an environment variable + myProcess->setProcessEnvironment(env); + } + if (parent != nullptr) { nChild = parent->childCount(); } if (nChild == 0) { + cmd = "rsync"; param << "--contimeout=10" << "--port=" + QString::number(portN) << server + "::" + path; - myProcess = new QProcess(this); + myProcess->start(cmd, param); - // waiting for responsiteme of the server with a timeout of 10 seconds - while(myProcess->waitForReadyRead(100000)) + // waiting for response of the server with a timeout of 10 seconds + do { - while (!flag) + readOk = myProcess->waitForReadyRead(5000); + if (readOk) { - line = QString::fromUtf8(myProcess->readLine()); - // line empty then buffer is empty so returning to wait new datas - if (line.isEmpty()) + while (!flag) { - flag = true; - break; - } - // extracting name, size and is dir/file - line = line.simplified(); - size = line.section(" ", 1, 1); - filename = line.section(" ", 4); - if (filename != '.') - { - if (line[0] == "d") + line = QString::fromUtf8(myProcess->readLine()); + // line empty then buffer is empty so returning to wait new datas + if (line.isEmpty()) { - isDir = true; - }else - { - isDir = false; + flag = true; + break; } - if (parent != NULL) + // extracting name, size and is dir/file + line = line.simplified(); + size = line.section(" ", 1, 1); + filename = line.section(" ", 4); + if (filename != '.') { - //adding item to tree - addTreeChild(parent, filename, size, isDir); - }else + if (line[0] == "d") + { + isDir = true; + }else + { + isDir = false; + } + if (parent != NULL) + { + //adding item to tree + addTreeChild(parent, filename, size, isDir); + }else + { + //adding item to tree (as directory) + addTreeRoot(filename, size, isDir); + } + } + } + flag = false; + }else + { + if (myProcess->state() == QProcess::Running) + { + if (myProcess->write("\n") == -1) { - //adding item to tree (as directory) - addTreeRoot(filename, size, isDir); + QMessageBox::warning( + this, + "RsyncUI", + tr("Can't write to processus: ") + myProcess->errorString()); + } + if (myProcess->waitForBytesWritten(5000) == 0) + { + QMessageBox::warning( + this, + "RsyncUI", + tr("writing to processus did not respond: ") + myProcess->errorString()); + } + if (myProcess->state() == QProcess::Running) + { + /* if (myProcess->waitForFinished(10000) == 0) + { + QMessageBox::warning( + this, + "RsyncUI", + tr("The processus does'nt respond: do you need a password ? ") + myProcess->errorString()); + }*/ + reply = QMessageBox::question( + this, + "RsyncUI", + tr("The processus does'nt respond: do you need a password ? "), + QMessageBox::Yes|QMessageBox::No, + QMessageBox::No); + if (reply == QMessageBox::Yes) + { + loginDialog.show(); + } } } } - - flag = false; - } + }while(readOk); // buffer empty go to waiting new datas - testRsyncReturn(myProcess); + + testRsyncReturn(this, myProcess); + myProcess->close(); } } @@ -540,6 +600,7 @@ bool MainWindow::validateServer(QString server) tr("server does not exists" ) ); } + myProcess->close(); return flag; } @@ -602,8 +663,10 @@ QTreeWidgetItem * MainWindow::addTreeChild(QTreeWidgetItem *parent, QString name void MainWindow::on_listWidget_clicked() { QString str; + QStringList logins; - this->connexion.service = ui->listWidget->currentItem()->text().section("\n", 0 ,0); + this->connexion.user = nullptr; + this->connexion.password = nullptr; this->connexion.service = ui->listWidget->currentItem()->text().section("\n", 0 ,0); str = "Folder/" + this->connexion.server + "/" + this->connexion.service; // if service exists in settings for this server if (this->settings.contains(str)) @@ -611,9 +674,41 @@ void MainWindow::on_listWidget_clicked() // setting savePath from settings this->downloading.savePath = this->settings.value(str).toString(); } + this->settings.beginGroup("Passwords/" + this->connexion.server + "/" + this->connexion.service); + logins = this->settings.allKeys(); + //TODO choose login + if (logins.count() != 0) + { + this->connexion.user = logins[0]; + this->connexion.password = this->settings.value(logins[0]).toString(); + } + this->settings.endGroup(); populateTree(NULL); } +bool MainWindow::getUserPassword() +{ + QStringList logins; + bool returnValue; + + this->settings.beginGroup("Passwords/" + this->connexion.server + "/" + this->connexion.service); + logins = this->settings.allKeys(); + //TODO choose login in case of multiples logins + if (logins.count() != 0) + { + this->downloading.user = logins[0]; + this->downloading.password = this->settings.value(logins[0]).toString(); + returnValue = true; + }else + { + this->downloading.user = nullptr; + this->downloading.password = nullptr; + returnValue = false; + } + this->settings.endGroup(); + return returnValue; +} + //Slot activated when a file is clicked in the treeview void MainWindow::on_treeWidget_itemClicked(QTreeWidgetItem *item, bool downloadDir) { @@ -629,6 +724,7 @@ void MainWindow::on_treeWidget_itemClicked(QTreeWidgetItem *item, bool downloadD // assembling path from treewidget path = item->text(0); + sizeFromRsync = item->text(2).remove(',').toUInt(); // exists saving path in settings ? str = "Folder/" + this->connexion.server + "/" + this->connexion.service; @@ -651,16 +747,15 @@ void MainWindow::on_treeWidget_itemClicked(QTreeWidgetItem *item, bool downloadD itemR = itemR->parent(); // concatening parent to path path.prepend(itemR->text(0) + "/"); - sizeFromRsync = itemR->text(1).toUInt(); }; - QFileInfo info(path); + QFileInfo info(this->downloading.savePath + "/" + path); if (item->text(1) == tr("File") or downloadDir == true) { // Item is a file // searching if file exists in savepath if (QFile::exists(this->downloading.savePath + "/" + path)) { - if (info.size() >= sizeFromRsync) + if (info.size() < sizeFromRsync) { reply = QMessageBox::question( this, @@ -737,8 +832,10 @@ void MainWindow::on_treeWidget_itemClicked(QTreeWidgetItem *item, bool downloadD // Launch the thread which download the file void MainWindow::startDownloading() { + ui->progressBar->setValue(0); ui->progressBar->show(); + getUserPassword(); //QtConcurrent::run(&this->downloadO, &downloadFile::download, this); this->download(); @@ -778,16 +875,19 @@ void MainWindow::downloadFinished(int exitCode, QProcess::ExitStatus exitStatus) }else if (exitCode == 20) { aborted = tr("stopped by user"); + }else if (exitCode == 5) // password asked + { + //TODO + loginDialog.show(); } - this->trayIcon->showMessage("RsyncUI", tr("Download ") + aborted + "\n" + this->downloading.path, QSystemTrayIcon::Information); // disconnecting signals to slots disconnect(this->downloading.process, 0, 0, 0); // reset variables and window - this->downloading.process = nullptr; + this->downloading.process->close(); ui->progressBar->hide(); delete ui->listDownload->takeItem(0); this->downloading.clear(); @@ -1069,6 +1169,11 @@ void Downloading::clear() this->server.clear(); this->savePath.clear(); this->service.clear(); + this->user.clear(); + this->password.clear(); + this->port = 0; + this->process = nullptr; + this->quit = false; } // Context menu of file list clicked @@ -1102,7 +1207,22 @@ void MainWindow::on_actionExit_triggered() quitApp(); } +void MainWindow::on_loginBox_accepted() +{ + if (!loginD.loginEdit->text().isEmpty()) + { + this->connexion.user = loginD.loginEdit->text(); + if (!loginD.passwordEdit->text().isEmpty()) + { + this->connexion.password = loginD.passwordEdit->text(); + this->settings.setValue("Passwords/" + this->connexion.server + "/" + this->connexion.service + "/" + this->connexion.user, this->connexion.password); + this->settings.sync(); + } + } +} + void MainWindow::setDlSpeed(QString speed) { speed.squeeze(); } + diff --git a/mainwindow.h b/mainwindow.h index dbd7901..34d01ad 100644 --- a/mainwindow.h +++ b/mainwindow.h @@ -5,6 +5,7 @@ #include "ui_mainwindow.h" #include "ui_configuration.h" #include "ui_about.h" +#include "ui_login.h" #include "downloadfile.h" #include "tools.h" #include @@ -43,7 +44,8 @@ #include #include #include -#include +#include +#include QT_BEGIN_NAMESPACE namespace Ui { class MainWindow; } @@ -58,6 +60,8 @@ class Connexion int bandwidthLimitUnit; QString server; QString service; + QString user; + QString password; int port = 873; bool comboboxChanged; }; @@ -69,6 +73,8 @@ class Downloading QString service; QString path; QString savePath; + QString user; + QString password; int port; QProcess * process = nullptr; bool quit = false; @@ -98,13 +104,14 @@ class MainWindow : public QMainWindow QProgressDialog *progress; Connexion connexion; Downloading downloading; - //downloadFile downloadO; QSettings settings; About about; QDialog Configuration; Ui::Configuration config; QDialog aboutDialog; Ui::windowAbout AboutW; + QDialog loginDialog; + Ui::LoginDialog loginD; std::vector serversList; QSystemTrayIcon * trayIcon; QString icon = "/usr/share/icons/RsyncUI.png"; @@ -153,6 +160,7 @@ class MainWindow : public QMainWindow void hideWindow(); void showWindow(); void init(); + bool getUserPassword(); private slots: @@ -202,6 +210,8 @@ class MainWindow : public QMainWindow void setDlSpeed(QString speed); + void on_loginBox_accepted(); + signals: void stopDownloading(QProcess *); void progressSignal(int); diff --git a/mainwindow.ui b/mainwindow.ui index f3efe40..cdfd5a2 100644 --- a/mainwindow.ui +++ b/mainwindow.ui @@ -275,10 +275,10 @@ false - true + false - QAbstractItemView::DragOnly + QAbstractItemView::NoDragDrop true diff --git a/tools.cpp b/tools.cpp index 2eb3d32..6413b35 100644 --- a/tools.cpp +++ b/tools.cpp @@ -44,7 +44,7 @@ const vector explode(const string& s, const char& c, int n = 0) } // test return code of rsync -bool testRsyncReturn(QProcess * myProcess) +bool testRsyncReturn(MainWindow * w, QProcess * myProcess) { if (myProcess->exitStatus() != 0) { @@ -55,6 +55,9 @@ bool testRsyncReturn(QProcess * myProcess) QMessageBox::Ok, QMessageBox::Ok); return true; + }else if (myProcess->exitCode() == 5) + { + w->loginDialog.show(); }else if (myProcess->exitCode() != 0) { QMessageBox::warning( @@ -67,3 +70,5 @@ bool testRsyncReturn(QProcess * myProcess) } return false; } + + diff --git a/tools.h b/tools.h index 22c7420..e37572f 100644 --- a/tools.h +++ b/tools.h @@ -1,6 +1,7 @@ #ifndef TOOLS_H #define TOOLS_H +#include "mainwindow.h" #include #include #include @@ -17,7 +18,6 @@ FILE * popen2(array argv, string type, int & pid); int pclose2(FILE * fp, pid_t pid); -bool testRsyncReturn(QProcess *); - +bool testRsyncReturn(MainWindow *, QProcess *); #endif // TOOLS_H