diff --git a/RsyncUI.pro b/RsyncUI.pro new file mode 100644 index 0000000..7d096b4 --- /dev/null +++ b/RsyncUI.pro @@ -0,0 +1,38 @@ +QT += core gui concurrent +QT += KItemViews +QT += KCompletion +QT += widgets + +#LIBS += -lKF5WindowSystem +greaterThan(QT_MAJOR_VERSION, 4): QT += widgets + +CONFIG += c++11 + +# You can make your code fail to compile if it uses deprecated APIs. +# In order to do so, uncomment the following line. +#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0 + +SOURCES += \ + downloadfile.cpp \ + main.cpp \ + mainwindow.cpp \ + tools.cpp + +HEADERS += \ + downloadfile.h \ + mainwindow.h \ + tools.h + +FORMS += \ + mainwindow.ui + +TRANSLATIONS += \ + RsyncUI_fr_FR.ts + +INCLUDEPATH += \ + /usr/include/KF5 + +# Default rules for deployment. +qnx: target.path = /tmp/$${TARGET}/bin +else: unix:!android: target.path = /opt/$${TARGET}/bin +!isEmpty(target.path): INSTALLS += target diff --git a/RsyncUI.pro.user b/RsyncUI.pro.user new file mode 100644 index 0000000..5d12286 --- /dev/null +++ b/RsyncUI.pro.user @@ -0,0 +1,319 @@ + + + + + + EnvironmentId + {a3117c94-e673-4dca-aa4c-050bbea034fe} + + + ProjectExplorer.Project.ActiveTarget + 0 + + + ProjectExplorer.Project.EditorSettings + + true + false + true + + Cpp + + CppGlobal + + + + QmlJS + + QmlJSGlobal + + + 2 + UTF-8 + false + 4 + false + 80 + true + true + 1 + true + false + 0 + true + true + 0 + 8 + true + 1 + true + true + true + *.md, *.MD, Makefile + false + true + + + + ProjectExplorer.Project.PluginSettings + + + true + true + true + true + true + + + 0 + true + + true + Builtin.Questionable + + true + true + Builtin.DefaultTidyAndClazy + 2 + + + + true + + + + + ProjectExplorer.Project.Target.0 + + Desktop + Desktop + Desktop + {893f9ca6-0efa-4c08-a4a6-5a818f60a8a0} + 0 + 0 + 0 + + 0 + /home/daniel/develope/build-RsyncUI-Desktop-Debug + /home/daniel/develope/build-RsyncUI-Desktop-Debug + + + true + QtProjectManager.QMakeBuildStep + + false + + + + true + Qt4ProjectManager.MakeStep + + 2 + Build + Build + ProjectExplorer.BuildSteps.Build + + + + true + Qt4ProjectManager.MakeStep + clean + + 1 + Clean + Clean + ProjectExplorer.BuildSteps.Clean + + 2 + false + + + Debug + Qt4ProjectManager.Qt4BuildConfiguration + 2 + 0 + + + /home/daniel/develope/build-RsyncUI-Desktop-Release + /home/daniel/develope/build-RsyncUI-Desktop-Release + + + true + QtProjectManager.QMakeBuildStep + + false + + + + true + Qt4ProjectManager.MakeStep + + 2 + Build + Build + ProjectExplorer.BuildSteps.Build + + + + true + Qt4ProjectManager.MakeStep + clean + + 1 + Clean + Clean + ProjectExplorer.BuildSteps.Clean + + 2 + false + + + Release + Qt4ProjectManager.Qt4BuildConfiguration + 0 + 0 + 0 + + + 0 + /home/daniel/develope/build-RsyncUI-Desktop-Profile + /home/daniel/develope/build-RsyncUI-Desktop-Profile + + + true + QtProjectManager.QMakeBuildStep + + false + + + + true + Qt4ProjectManager.MakeStep + + 2 + Build + Build + ProjectExplorer.BuildSteps.Build + + + + true + Qt4ProjectManager.MakeStep + clean + + 1 + Clean + Clean + ProjectExplorer.BuildSteps.Clean + + 2 + false + + + Profile + Qt4ProjectManager.Qt4BuildConfiguration + 0 + 0 + 0 + 0 + + 3 + + + 0 + Deploy + Deploy + ProjectExplorer.BuildSteps.Deploy + + 1 + + false + ProjectExplorer.DefaultDeployConfiguration + + 1 + + dwarf + + cpu-cycles + + + 250 + + -e + cpu-cycles + --call-graph + dwarf,4096 + -F + 250 + + -F + true + 4096 + false + false + 1000 + + true + + false + false + false + false + true + 0.01 + 10 + true + kcachegrind + 1 + 25 + + 1 + true + false + true + valgrind + + 0 + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 + 13 + 14 + + + 2 + + Qt4ProjectManager.Qt4RunConfiguration:/home/daniel/develope/RsyncUI/RsyncUI.pro + /home/daniel/develope/RsyncUI/RsyncUI.pro + false + true + true + false + true + /home/daniel/develope/build-RsyncUI-Desktop-Debug + + 1 + + + + ProjectExplorer.Project.TargetCount + 1 + + + ProjectExplorer.Project.Updater.FileVersion + 22 + + + Version + 22 + + diff --git a/RsyncUI_fr_FR.qm b/RsyncUI_fr_FR.qm new file mode 100644 index 0000000..644c776 Binary files /dev/null and b/RsyncUI_fr_FR.qm differ diff --git a/RsyncUI_fr_FR.ts b/RsyncUI_fr_FR.ts new file mode 100644 index 0000000..531267a --- /dev/null +++ b/RsyncUI_fr_FR.ts @@ -0,0 +1,67 @@ + + + + + Dialog + + + Dialog + + + + + TextLabel + + + + + MainWindow + + + MainWindow + Fenêtre principale + + + + Server + Serveur + Serveur + + + + Port + Port + + + + %p% + Downloading + Téléchargement + + + + debug + debug + + + + Path + Chemin + + + + Size + Taille + + + + server does not exists + Le serveur n'existe pas + + + + Choose directory to save file + Choisissez le dossier où enregistrer + + + diff --git a/downloadfile.cpp b/downloadfile.cpp new file mode 100644 index 0000000..3de7369 --- /dev/null +++ b/downloadfile.cpp @@ -0,0 +1,103 @@ +#include "downloadfile.h" +#include "mainwindow.h" +#include "ui_mainwindow.h" +#include "tools.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace std; + +downloadFile::downloadFile() +{ +} + +void downloadFile::cancelled() +{ + this->canceled = true; +} + +void downloadFile::download(QString savePath, MainWindow *mw) +{ + string server; + string service; + string path; + string line; + string errorRsync; + char cmd[4096]; + int portN; + int pos; + int pid; + QTreeWidgetItem * item; + stringstream output; + // QString savePath = "."; + vector v; + int value; + //char command_out[1024] = {0}; + array buffer; + + server.assign(mw->ui->khistorycombobox->currentText().toStdString()); + portN = mw->ui->portEdit->text().toInt(); + service = mw->ui->listWidget->currentItem()->text().toStdString(); + pos = service.find_first_of('\n'); + service.resize(pos); + + item = mw->ui->treeWidget->currentItem(); + path = item->text(0).toStdString(); + while(item->parent() != NULL) + { + item = item->parent(); + path = item->text(0).toStdString() + "/" + path; + + }; + + + sprintf(cmd, "rsync --bwlimit=100K --port %i -P %s::\"%s/%s\" \"%s/\" 2>&1", portN, server.c_str(), service.c_str(), path.c_str(), savePath.toStdString().c_str()); + + + + //unique_ptr pipe(popen(cmd, "r"), pclose); + FILE * fp = popen2(cmd, "r", pid); + + if (!fp) + { + throw runtime_error("popen2() failed!"); + } + + while (fgets(buffer.data(), buffer.size(), fp) != nullptr) + { + buffer.data(); + if (this->canceled == true) + { + return; + } + line = buffer.data(); + //cout << line << endl; + pos = line.find('%'); + if (pos != -1) + { + line.erase(pos); + pos = line.find_last_of(' '); + if (pos != -1) + { + line.erase(0, pos); + value = stoi(line); + cout << value << endl; + emit progressSignal(value); + } + } + buffer.empty(); + } + + //cout << path << endl; +} + diff --git a/downloadfile.h b/downloadfile.h new file mode 100644 index 0000000..ed85adf --- /dev/null +++ b/downloadfile.h @@ -0,0 +1,24 @@ +#ifndef DOWNLOADFILE_H +#define DOWNLOADFILE_H + +#include +#include "ui_mainwindow.h" + +class MainWindow; + +class downloadFile : public QObject +{ + Q_OBJECT +public: + downloadFile(); + void download(QString savePath, MainWindow *parent = nullptr); + bool canceled; + +signals: + void progressSignal(int); + +public slots: + void cancelled(); +}; + +#endif // DOWNLOADFILE_H diff --git a/main.cpp b/main.cpp new file mode 100644 index 0000000..115a22b --- /dev/null +++ b/main.cpp @@ -0,0 +1,10 @@ +#include "mainwindow.h" +#include + +int main(int argc, char *argv[]) +{ + QApplication a(argc, argv); + MainWindow w; + w.show(); + return a.exec(); +} diff --git a/mainwindow.cpp b/mainwindow.cpp new file mode 100644 index 0000000..5799f9c --- /dev/null +++ b/mainwindow.cpp @@ -0,0 +1,344 @@ +#include "mainwindow.h" +#include "ui_mainwindow.h" +#include "downloadfile.h" +#include "tools.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace std; + +bool display = false; + +MainWindow::MainWindow(QWidget *parent) + : QMainWindow(parent) + , ui(new Ui::MainWindow) +{ + ui->setupUi(this); + ui->ktreewidgetsearchline->setTreeWidget(ui->treeWidget); + ui->ktreewidgetsearchline->setCaseSensitivity(Qt::CaseInsensitive); + ui->treeWidget->setHeaderLabels({tr("Path"), tr("Size")} ); + ui->progressBar->hide(); + populateList(); +} + +MainWindow::~MainWindow() +{ + delete ui; +} + +void MainWindow::populateTree() +{ + string server; + string port; + int portN; + stringstream ss; + vector path; + + server.assign(ui->khistorycombobox->currentText().toStdString()); + port.assign(ui->portEdit->text().toStdString()); + ss << port; + ss >> portN; + if (!server.empty() and !port.empty() and portN < 65536) + { + if (validateServer(server)) + { + ui->treeWidget->cursor().setShape(Qt::WaitCursor); + path = explode(ui->listWidget->currentItem()->text().toStdString(), '\n', 2); + scanDir(server, portN, NULL, path[0].append("/") ); + ui->treeWidget->cursor().setShape(Qt::ArrowCursor); + + } + } +} + +void MainWindow::populateList() +{ + string server; + string port; + int portN; + stringstream ss; + + server.assign(ui->khistorycombobox->currentText().toStdString()); + port.assign(ui->portEdit->text().toStdString()); + ss << port; + ss >> portN; + if (!server.empty() and !port.empty() and portN < 65536) + { + if (validateServer(server)) + { + ui->centralwidget->cursor().setShape(Qt::WaitCursor); + listServices(server, portN); + ui->centralwidget->cursor().setShape(Qt::ArrowCursor); + + } + } +} + +void MainWindow::listServices(string server, int portN) +{ + char cmd[4096]; + string line; + string errorRsync; + vector v; + char service[4096]; + + sprintf(cmd, "rsync --contimeout=10 -P \"%s::\" --port %d ", server.c_str(), portN ); + redi::ipstream in(cmd, redi::pstreams::pstdout | redi::pstreams::pstderr); + while (getline(in.out(), line)) + { + cout << "stdout: " << line << endl; + boost::replace_all(line," ",""); + boost::replace_all(line, "\t", " - "); + v = explode(line, ' ', 3 ); + sprintf(service, "%s\n\t%s", v[0].c_str(), v[2].c_str()); + ui->listWidget->addItem(service); + } +} + +void MainWindow::scanDir(string server, int portN, QTreeWidgetItem *parent, string path) +{ + char cmd[4096]; + string line; + string errorRsync; + vector v; + QTreeWidgetItem * item; + char npath[4096]; + + sprintf(cmd, "rsync --contimeout=10 -P \"%s::%s\" --port %d ", server.c_str(), path.c_str(), portN ); + redi::ipstream in(cmd, redi::pstreams::pstdout | redi::pstreams::pstderr); + + while (getline(in.out(), line)) + { + + v = explode(line, ' ', 5); + if (v.size() == 5) + { + if (v[4].at(0) != '.' and (v[0].at(0) == '-' or v[0].at(0) == 'd')) + { + if (parent != NULL) + { + item = addTreeChild(parent,QString::fromStdString(v[4]), QString::fromStdString(v[1])); + }else + { + item = addTreeRoot(QString::fromStdString(v[4]), QString::fromStdString(v[1])); + } + if (v[0].at(0) == 'd') + { + sprintf(npath, "%s%s/", path.c_str(), v[4].c_str()); + scanDir(server, portN, item, npath); + } + } + } + } + // if reading stdout stopped at EOF then reset the state: + if (in.eof() && in.fail()) + in.clear(); + // read child's stderr + while (getline(in.err(), line)) + { + cout << "stderr: " << line << endl; + errorRsync.append(line); + errorRsync.append("\n"); + } + if ( !errorRsync.empty()) + { + QMessageBox::warning( + this, + "RsyncUI", + errorRsync.c_str()); + } + +} + +bool MainWindow::isIpAddress(string server) +{ + bool returnCode = false; + vector r; + stringstream ss; + int elementN; + + r = explode(server, '.'); + if (r.size() == 4) + { + for (auto element : r) + { + ss << element; + ss >> elementN; + if (elementN >0 and elementN < 256) + { + returnCode &= true; + } + } + } + return returnCode; +} + +bool MainWindow::validateServer(string server) +{ + char cmd[512]; + string line; + string errorDig; + bool flag = false; + + sprintf(cmd, "dig %s", server.c_str()); + redi::ipstream in(cmd, redi::pstreams::pstdout | redi::pstreams::pstderr); + + while (getline(in.out(), line)) + { + cout << "stdout: " << line << '\n'; + if (line.find(";; ANSWER SECTION:") != string::npos) + { + flag = true; + } + } + // if reading stdout stopped at EOF then reset the state: + if (in.eof() && in.fail()) + in.clear(); + // read child's stderr + while (std::getline(in.err(), line)) + { + cout << "stderr: " << line << '\n'; + errorDig.append(line); + errorDig.append("\n"); + } + if ( !errorDig.empty()) + { + QMessageBox::warning( + this, + "RsyncUI", + errorDig.c_str() + ); + } + if ( flag == false) + { + flag = isIpAddress(server); + QMessageBox::warning( + this, + "RsyncUI", + tr("server does not exists" ) + ); + } + return flag; +} + +void MainWindow::displayTree() +{ + populateTree(); + +} + +void MainWindow::on_khistorycombobox_returnPressed() +{ + populateList(); +} + +/*void MainWindow::on_portEdit_userTextChanged() +{ + populateTree(); +}*/ + +void MainWindow::on_portEdit_returnPressed() +{ + populateList(); +} + +void MainWindow::on_khistorycombobox_textActivated() +{ + populateList(); +} + +void MainWindow::on_treeWidget_itemClicked(QTreeWidgetItem *item, int column) +{ + +} + +void MainWindow::on_treeWidget_customContextMenuRequested() +{ + +} + +void MainWindow::on_actionDownload_triggered() +{ + +} + +QTreeWidgetItem * MainWindow::addTreeRoot(QString name, QString fileSize) +{ + // QTreeWidgetItem(QTreeWidget * parent, int type = Type) + QTreeWidgetItem *treeItem = new QTreeWidgetItem(ui->treeWidget); + + // QTreeWidgetItem::setText(int column, const QString & text) + treeItem->setText(0, name); + treeItem->setText(1, fileSize); + return treeItem; +} + +QTreeWidgetItem * MainWindow::addTreeChild(QTreeWidgetItem *parent, QString name, QString fileSize) +{ + // QTreeWidgetItem(QTreeWidget * parent, int type = Type) + QTreeWidgetItem *treeItem = new QTreeWidgetItem(); + + // QTreeWidgetItem::setText(int column, const QString & text) + treeItem->setText(0, name); + treeItem->setText(1, fileSize); + + // QTreeWidgetItem::addChild(QTreeWidgetItem * child) + parent->addChild(treeItem); + return treeItem; +} + +void MainWindow::on_listWidget_clicked(const QModelIndex &index) +{ + populateTree(); +} + +void MainWindow::on_listDownload_currentItemChanged(QListWidgetItem *current, QListWidgetItem *previous) +{ + cout << current->text().toStdString() << endl; +} + +void MainWindow::on_treeWidget_itemDoubleClicked(QTreeWidgetItem *item, int column) +{ + string path; + QFuture future; + QFutureWatcher watcher; + QString savePath; + QFileDialog dialog; + QString dirPath; + /*int p[2]; + + if (pipe(p) < 0) + { + return; + }*/ + dirPath = getenv("HOME"); + dirPath.append("/Vidéos/"); + savePath = dialog.getExistingDirectory(this, tr("Choose directory to save file"), dirPath, QFileDialog::ShowDirsOnly | QFileDialog::DontResolveSymlinks); + downloadFile downloadO; + + + //QProgressDialog progress("Downloading file ...", "Abort Download", 0, 100, this); + + ui->progressBar->setWindowModality(Qt::WindowModal); + ui->progressBar->setValue(0); + ui->progressBar->show(); + connect(&watcher, &QFutureWatcherBase::finished, ui->progressBar, &QProgressBar::hide); + connect(&downloadO, &downloadFile::progressSignal, ui->progressBar, &QProgressBar::setValue); + future = QtConcurrent::run(&this->MyObject, &downloadFile::download, savePath, this); + watcher.setFuture(future); +} diff --git a/mainwindow.h b/mainwindow.h new file mode 100644 index 0000000..52bae5f --- /dev/null +++ b/mainwindow.h @@ -0,0 +1,61 @@ +#ifndef MAINWINDOW_H +#define MAINWINDOW_H + +#include +#include +#include +#include +#include "downloadfile.h" +#include + +QT_BEGIN_NAMESPACE +namespace Ui { class MainWindow; } +QT_END_NAMESPACE + +class MainWindow : public QMainWindow +{ + Q_OBJECT + +public: + Ui::MainWindow *ui; + MainWindow(QWidget *parent = nullptr); + ~MainWindow(); + QProgressDialog *progress; + void displayTree(); + void populateTree(); + void populateList(); + void listServices(std::string server, int portN); + bool validateServer(std::string server); + bool isIpAddress(std::string server); + QTreeWidgetItem * addTreeRoot(QString name, QString description); + QTreeWidgetItem * addTreeChild(QTreeWidgetItem *parent, QString name, QString size); + void scanDir(std::string server, int portN, QTreeWidgetItem *parent = NULL, std::string path = "" ); + +private slots: + void on_khistorycombobox_returnPressed(); + + //void on_portEdit_userTextChanged(); + + void on_portEdit_returnPressed(); + + void on_khistorycombobox_textActivated(); + + void on_treeWidget_itemClicked(QTreeWidgetItem *item, int column); + + void on_treeWidget_customContextMenuRequested(); + + void on_actionDownload_triggered(); + + void on_listWidget_clicked(const QModelIndex &index); + + void on_listDownload_currentItemChanged(QListWidgetItem *current, QListWidgetItem *previous); + + void on_treeWidget_itemDoubleClicked(QTreeWidgetItem *item, int column); + +public slots: + +private: + downloadFile MyObject; +}; + +#endif // MAINWINDOW_H diff --git a/mainwindow.ui b/mainwindow.ui new file mode 100644 index 0000000..594493a --- /dev/null +++ b/mainwindow.ui @@ -0,0 +1,326 @@ + + + DTux + MainWindow + + + + 0 + 0 + 500 + 571 + + + + + 0 + 0 + + + + MainWindow + + + false + + + + + 0 + 0 + + + + + 0 + 0 + + + + + 32763 + 32765 + + + + + 0 + 0 + + + + + 11 + + + + IBeamCursor + + + Qt::TabFocus + + + true + + + + + + + + + + + + 0 + 0 + + + + Server + + + false + + + + + + + + 0 + 0 + + + + + 0 + 0 + + + + + + + + + 0 + 0 + + + + Port + + + + + + + + 0 + 0 + + + + + 100 + 0 + + + + + 70 + 16777215 + + + + Qt::ImhPreferNumbers + + + + + + 6 + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + true + + + true + + + + + + + + + Qt::Vertical + + + + Qt::Horizontal + + + + + 0 + 0 + + + + QAbstractItemView::SelectedClicked + + + QListView::Adjust + + + true + + + + + + + + + 1 + 0 + + + + Qt::ImhNoAutoUppercase + + + + + + + + 1 + 0 + + + + Qt::CustomContextMenu + + + QAbstractItemView::NoEditTriggers + + + false + + + true + + + QAbstractItemView::DragOnly + + + true + + + QAbstractItemView::MultiSelection + + + QAbstractItemView::SelectItems + + + true + + + true + + + 1 + + + true + + + true + + + + 1 + + + + + + + + + + true + + + QAbstractItemView::DropOnly + + + + + + + + true + + + 0 + + + %p% + + + + + + + + + 0 + 0 + 500 + 30 + + + + + debug + + + + + + + + + KComboBox + QComboBox +
kcombobox.h
+
+ + KHistoryComboBox + KComboBox +
khistorycombobox.h
+
+ + KLineEdit + QLineEdit +
klineedit.h
+
+ + KTreeWidgetSearchLine + QLineEdit +
ktreewidgetsearchline.h
+
+
+ + +
diff --git a/tools.cpp b/tools.cpp new file mode 100644 index 0000000..654cc29 --- /dev/null +++ b/tools.cpp @@ -0,0 +1,113 @@ +#include +#include +#include +#include +#include +#include + +using namespace std; + +#define READ 0 +#define WRITE 1 + +const vector explode(const string& s, const char& c, int n = 0) +{ + string buff; + vector v; + size_t pos = 0; + size_t ppos = 0; + int i = 0; + + while (i < n - 1) + { + pos = s.find(c, ppos); + if (pos != string::npos) + { + buff = s.substr(ppos, pos - ppos); + if (buff != "") + { + i++; + v.push_back(s.substr(ppos, pos - ppos)); + } + ppos = pos + 1; + }else + { + break; + } + } + if (ppos < s.size()) + { + v.push_back(s.substr(ppos)); + } + return v; +} + +FILE * popen2(char * cmd, string type, int & pid) +{ + pid_t child_pid; + int fd[2]; + pipe(fd); + + if((child_pid = fork()) == -1) + { + perror("fork"); + exit(1); + } + + /* child process */ + if (child_pid == 0) + { + if (type == "r") + { + close(fd[READ]); //Close the READ end of the pipe since the child's fd is write-only + dup2(fd[WRITE], 1); //Redirect stdout to pipe + } + else + { + close(fd[WRITE]); //Close the WRITE end of the pipe since the child's fd is read-only + dup2(fd[READ], 0); //Redirect stdin to pipe + } + + setpgid(child_pid, child_pid); //Needed so negative PIDs can kill children of /bin/sh + execl(cmd, ""); + exit(0); + } + else + { + if (type == "r") + { + close(fd[WRITE]); //Close the WRITE end of the pipe since parent's fd is read-only + } + else + { + close(fd[READ]); //Close the READ end of the pipe since parent's fd is write-only + } + } + + pid = child_pid; + + if (type == "r") + { + return fdopen(fd[READ], "r"); + } + + return fdopen(fd[WRITE], "w"); +} + +int pclose2(FILE * fp, pid_t pid) +{ + int stat; + + fclose(fp); + while (waitpid(pid, &stat, 0) == -1) + { + if (errno != EINTR) + { + stat = -1; + break; + } + } + + return stat; +} + diff --git a/tools.h b/tools.h new file mode 100644 index 0000000..64ec011 --- /dev/null +++ b/tools.h @@ -0,0 +1,14 @@ +#ifndef TOOLS_H +#define TOOLS_H + +#include +#include +#include "mainwindow.h" + +using namespace std; + +const vector explode(const string& s, const char& c, int n = 0); +FILE * popen2(char * command, string type, int & pid); +int pclose2(FILE * fp, pid_t pid); + +#endif // TOOLS_H