From a76f32ea30b78ba28c83f605a73e8defa004e78e Mon Sep 17 00:00:00 2001 From: Daniel Tartavel Date: Sat, 7 Jan 2023 12:44:45 +0100 Subject: [PATCH] first commit --- RsyncUI.pro | 38 ++++++ RsyncUI.pro.user | 319 +++++++++++++++++++++++++++++++++++++++++++ RsyncUI_fr_FR.qm | Bin 0 -> 33 bytes RsyncUI_fr_FR.ts | 67 +++++++++ downloadfile.cpp | 103 ++++++++++++++ downloadfile.h | 24 ++++ main.cpp | 10 ++ mainwindow.cpp | 344 +++++++++++++++++++++++++++++++++++++++++++++++ mainwindow.h | 61 +++++++++ mainwindow.ui | 326 ++++++++++++++++++++++++++++++++++++++++++++ tools.cpp | 113 ++++++++++++++++ tools.h | 14 ++ 12 files changed, 1419 insertions(+) create mode 100644 RsyncUI.pro create mode 100644 RsyncUI.pro.user create mode 100644 RsyncUI_fr_FR.qm create mode 100644 RsyncUI_fr_FR.ts create mode 100644 downloadfile.cpp create mode 100644 downloadfile.h create mode 100644 main.cpp create mode 100644 mainwindow.cpp create mode 100644 mainwindow.h create mode 100644 mainwindow.ui create mode 100644 tools.cpp create mode 100644 tools.h 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 0000000000000000000000000000000000000000..644c77682fc91fa218711b0bfdad79317096f95d GIT binary patch literal 33 ocmcE7ks@*G{hX<16=n7(EZlo{IRgU&Yg$pfTTlm(#l*}A0Q>w4$N&HU literal 0 HcmV?d00001 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