diff --git a/downloadfile.cpp b/downloadfile.cpp index 57e6ca6..9cae1bc 100644 --- a/downloadfile.cpp +++ b/downloadfile.cpp @@ -19,59 +19,70 @@ using namespace std; +// Initialization de la class downloadFile::downloadFile() { } +//Slot activated when download is cancelled void downloadFile::cancelled(int pid) { - if (kill(pid, SIGTERM) == -1) + if (pid == 0) { - //TODO gestion erreur kill + perror("Pid = 0 : I do not kill"); // Error rsync process not launched so it can't be killed + }else if (kill(pid, SIGTERM) == -1) + { + //TODO managing error of kill } } +// launch a rsync processus downloading a file void downloadFile::download(MainWindow *mw) { string line; string errorRsync; int pos; - array argv; + array argv; stringstream output; vector v; int value; char buffer[4096]; + // Populating array with command and parameters for popen2 argv[0] = "/usr/bin/rsync"; if (mw->connexion.bandwidthLimit == 0) { argv[1] = "--bwlimit=1000P"; }else { - output << mw->connexion.bandwidthLimit; - argv[1] = "--bwlimit=" + output.str() + mw->connexion.bandwidthLimitUnit; + argv[1] = "--bwlimit=" + to_string(mw->connexion.bandwidthLimit) + mw->connexion.bandwidthLimitUnit; } argv[2] = "--port=" + to_string(mw->connexion.port); argv[3] = "-P"; argv[4] = mw->connexion.server + "::" + mw->downloading.service + "/" + mw->downloading.path; argv[5] = mw->downloading.savePath + "/"; - argv[6] = ""; + argv[6].clear(); //launching downloading thread FILE * fp = popen2(argv, "r", mw->downloading.pid); - if (!fp) + if (fp <= (FILE *) 0) { - throw runtime_error("popen2() failed!"); + sprintf(buffer, "popen2() failed!: returning code:%d", fileno(fp)); + throw runtime_error(buffer); return; } + // waiting rsync output while (fgets(buffer, 4096, fp) != nullptr) { + // Downloading is cancelled, we return if (this->canceled == true) { return; } line = buffer; + + // extracting percentage of completion pos = line.find('%'); if (pos != -1) { @@ -81,9 +92,11 @@ void downloadFile::download(MainWindow *mw) { line.erase(0, pos); value = stoi(line); + // sending progress to Main window emit progressSignal(value); } } + // download ended } pclose2(fp, mw->downloading.pid); @@ -91,4 +104,3 @@ void downloadFile::download(MainWindow *mw) emit progressSignal(100); emit finishedSignal(true); } - diff --git a/languages/fr_FR/RsyncUI_fr_FR.qm b/languages/fr_FR/RsyncUI_fr_FR.qm index bb5f1ac..ceb7f90 100644 Binary files a/languages/fr_FR/RsyncUI_fr_FR.qm and b/languages/fr_FR/RsyncUI_fr_FR.qm differ diff --git a/languages/fr_FR/RsyncUI_fr_FR.ts b/languages/fr_FR/RsyncUI_fr_FR.ts index 0e669d4..3af1803 100644 --- a/languages/fr_FR/RsyncUI_fr_FR.ts +++ b/languages/fr_FR/RsyncUI_fr_FR.ts @@ -164,7 +164,7 @@ - + PB Po @@ -179,44 +179,49 @@ Taille - + Exiting will stop downloading, and will clear the download queue. Do you want to exit ? Soritr stoppera le téléchargement et effacera la file des téléchargements. Voulez-vous vraiment sortir du programme ? - + server does not exists Le serveur n'existe pas - + + Version + Version + + + Licence License - + Author Auteur - + EMail Courriel - + Source code Code source - + Choose directory to save file Choisissez le dossier où enregistrer - + Do you want to stop downloading and delete this file from download queue ? Vouslez-vous arrêter le téléchargement et enlever ce fichier de la file de téléchargement ? @@ -225,7 +230,7 @@ Voulez-vous vraiment sortir du programme ? Client pour serveur rsync - + Do you want to delete this file from download queue ? Voulez-vous enlever ce fichier de la file de téléchargement ? diff --git a/main.cpp b/main.cpp index 2d03fcd..ca39f1d 100644 --- a/main.cpp +++ b/main.cpp @@ -2,12 +2,14 @@ #include - int main(int argc, char *argv[]) { QApplication a(argc, argv); QTranslator myappTranslator; + QCoreApplication::setOrganizationName("RsyncUI"); + QCoreApplication::setApplicationName("RsyncUI"); + // Initialization of localization QLocale localeName = QLocale::system(); QString localeFile = "/usr/share/locale/" + localeName.name() + "/LC_MESSAGES/RsyncUI_" + localeName.name() + ".qm"; if (myappTranslator.load(localeFile)) diff --git a/mainwindow.cpp b/mainwindow.cpp index e546a54..f1660e0 100644 --- a/mainwindow.cpp +++ b/mainwindow.cpp @@ -54,15 +54,18 @@ MainWindow::~MainWindow() delete ui; } +// Closing window has been clicked void MainWindow::closeEvent (QCloseEvent *event) { QMessageBox::StandardButton reply; + // saving settings saveSettings(); - if (ui->listDownload->count() != 0) + if (ui->listDownload->count() != 0) // some downloads waiting { - reply = QMessageBox::question( + // Asking for stopping or continuing + reply = QMessageBox::question( this, "RsyncUI", tr("Exiting will stop downloading, and will clear the download queue.\n Do you want to exit ?"), @@ -70,10 +73,12 @@ void MainWindow::closeEvent (QCloseEvent *event) QMessageBox::No); if (reply == QMessageBox::No) { + // continuing event->ignore(); return; }else { + // emission of signal to downloading thread and stopping emit (stopDownloading(this->downloading.pid)); waitpid(this->downloading.pid, NULL, WUNTRACED); } @@ -81,24 +86,31 @@ void MainWindow::closeEvent (QCloseEvent *event) event->accept(); } +// Populate treeview with list of files void MainWindow::populateTree() { stringstream ss; vector path; + // Clear treewidget ui->treeWidget->clear(); if (!this->connexion.server.empty() and this->connexion.port > 0 and this->connexion.port < 65536) { + // setting cursor to "Wait" QGuiApplication::setOverrideCursor(Qt::WaitCursor); + if (validateServer(this->connexion.server)) { + // server is validated path = explode(ui->listWidget->currentItem()->text().toStdString(), '\n', 2); scanDir(this->connexion.server, this->connexion.port, NULL, path[0].append("/") ); } - QGuiApplication::restoreOverrideCursor(); //setOverrideCursor(Qt::ArrowCursor); + // Restoring cursor + QGuiApplication::restoreOverrideCursor(); } } +// Populate Listview with list of services void MainWindow::populateList() { stringstream ss; @@ -110,13 +122,16 @@ void MainWindow::populateList() port = ui->portEdit->text().toUInt(); if ((server.toStdString() != this->connexion.server) or (port != this->connexion.port)) { + // clearing listwidget ui->listWidget->clear(); this->connexion.server.assign(server.toStdString()); this->connexion.port = port; + // verify if server is in history this->settings.beginGroup("connexion/server"); if (this->settings.contains(server)) { + // server is in history and completing port value port = this->settings.value(server).toUInt(); ui->portEdit->setText(QString::number(port)); this->connexion.port = port; @@ -126,7 +141,7 @@ void MainWindow::populateList() { if (validateServer(server.toStdString())) { - //this->settings.beginGroup("connexion/server"); + if (!this->settings.contains(server)) { cout << server.toStdString() << endl; @@ -149,6 +164,7 @@ void MainWindow::populateList() } } +//list services of the rsync server void MainWindow::listServices() { char cmd[4096]; @@ -169,6 +185,7 @@ void MainWindow::listServices() } } +// connect to rsync server to get list of files void MainWindow::scanDir(string server, int portN, QTreeWidgetItem *parent, string path) { char cmd[4096]; @@ -224,6 +241,7 @@ void MainWindow::scanDir(string server, int portN, QTreeWidgetItem *parent, stri } +// Verify if server address is IP address bool MainWindow::isIpAddress(string server) { vector r; @@ -249,6 +267,7 @@ bool MainWindow::isIpAddress(string server) } } +// validate address server bool MainWindow::validateServer(string server) { char cmd[512]; @@ -300,22 +319,19 @@ bool MainWindow::validateServer(string server) return flag; } -void MainWindow::displayTree() -{ - populateTree(); - -} - +// slot activated when combobox is changed void MainWindow::on_khistorycombobox_currentIndexChanged(int i) { on_connectButton_clicked(); } +// slot activated when button connection is clicked void MainWindow::on_connectButton_clicked() { populateList(); } +// add a dir in treeview QTreeWidgetItem * MainWindow::addTreeRoot(QString name, QString fileSize) { // QTreeWidgetItem(QTreeWidget * parent, int type = Type) @@ -327,6 +343,7 @@ QTreeWidgetItem * MainWindow::addTreeRoot(QString name, QString fileSize) return treeItem; } +// add a file in treeview QTreeWidgetItem * MainWindow::addTreeChild(QTreeWidgetItem *parent, QString name, QString fileSize) { // QTreeWidgetItem(QTreeWidget * parent, int type = Type) @@ -341,6 +358,7 @@ QTreeWidgetItem * MainWindow::addTreeChild(QTreeWidgetItem *parent, QString name return treeItem; } +// Slot acivated when a service in the list is clicked void MainWindow::on_listWidget_clicked() { vector v; @@ -349,6 +367,7 @@ void MainWindow::on_listWidget_clicked() populateTree(); } +//Slot activated when a file is clicked in the treeview void MainWindow::on_treeWidget_itemClicked(QTreeWidgetItem *item) { QFuture future; @@ -373,6 +392,7 @@ void MainWindow::on_treeWidget_itemClicked(QTreeWidgetItem *item) ui->listDownload->addItem(QString::fromStdString(this->downloading.path)); } +// Launch the thread which download the file void MainWindow::startDownloading() { ui->progressBar->setValue(0); @@ -382,11 +402,13 @@ void MainWindow::startDownloading() } +// Slot stopping download void MainWindow::stoppingDownload() { emit (stopDownloading(this->downloading.pid)); } +// when download is finished, launch download of next file in queue void MainWindow::downloadFinished() { ui->progressBar->hide(); @@ -399,6 +421,7 @@ void MainWindow::downloadFinished() } } +// Slot activated when a line is clicked in queue list void MainWindow::on_listDownload_itemClicked(QListWidgetItem *item) { QFileDialog dialog; @@ -433,6 +456,7 @@ void MainWindow::on_listDownload_itemClicked(QListWidgetItem *item) } } +// load settings void MainWindow::loadSettings() { // restoring geometry and state of wondow and widgets @@ -460,7 +484,7 @@ void MainWindow::loadSettings() this->connexion.bandwidthLimitUnit = this->settings.value("bandwidthlimitunit").toString().toStdString(); } - +// save settings void MainWindow::saveSettings() { this->settings.setValue("window/geometry", saveGeometry()); @@ -473,21 +497,25 @@ void MainWindow::saveSettings() this->settings.sync(); } +// About void MainWindow::on_actionAbout_triggered() { QString text = this->about.description + "\n\n" + - tr("Licence" ) + ": " + this->about.licence + "\n" + + tr("Version") + ": " + this->about.version + "\n" + + tr("Licence") + ": " + this->about.licence + "\n" + tr("Author") + ": " + this->about.author + "\n" + tr("EMail") + ": " + this->about.email + "\n" + tr("Source code") + ": " + this->about.git; QMessageBox::about(this, this->about.title, text); } +// About QT void MainWindow::on_actionAbout_Qt_triggered() { QMessageBox::aboutQt(this); } +// Activated when menu "change folder" is clicked void MainWindow::on_DefaultSaveFolder_triggered() { QFileDialog dialog; @@ -498,6 +526,7 @@ void MainWindow::on_DefaultSaveFolder_triggered() this->settings.sync(); } +// Activated when menu "settings" is clicked void MainWindow::on_action_Settings_triggered() { config.UnitCombobox->setCurrentText(QString::fromStdString(this->connexion.bandwidthLimitUnit)); @@ -505,6 +534,7 @@ void MainWindow::on_action_Settings_triggered() Configuration.show(); } +// Acivated when "Ok" is clicked in Configuration window void MainWindow::on_buttonBox_accepted() { QString unit; diff --git a/mainwindow.h b/mainwindow.h index fa2ed58..431ac22 100644 --- a/mainwindow.h +++ b/mainwindow.h @@ -60,6 +60,7 @@ class About { public: QString title = "RsyncUI"; + QString version = "1.4"; QString author = "Daniel TARTAVEL-JEANNOT"; QString licence = "GPL_V3"; QString description = "Client for rsync server\n\nYou click on file to enqueue it, and RyncUI Download one file a time"; diff --git a/tools.cpp b/tools.cpp index 13eb514..d4e0ec2 100644 --- a/tools.cpp +++ b/tools.cpp @@ -5,6 +5,10 @@ using namespace std; #define READ 0 #define WRITE 1 +//Take a string and explode it in array +// s => string to explode +// c => character separator +// n => number of results in array, the last is the rest of string to end const vector explode(const string& s, const char& c, int n = 0) { string buff; @@ -37,7 +41,9 @@ const vector explode(const string& s, const char& c, int n = 0) return v; } -FILE * popen2(char * const argv, string type, int & pid) +// open a pipe, fork and return pid of child +// argv => array of string with command in first and parameters following +FILE * popen2(array argv, string type, int & pid) { pid_t child_pid; int fd[2]; @@ -51,6 +57,7 @@ FILE * popen2(char * const argv, string type, int & pid) NULL, "RsyncUI", message); + exit(-1); }else { if((child_pid = fork()) == -1) @@ -74,11 +81,7 @@ FILE * popen2(char * const argv, string type, int & pid) } setpgid(child_pid, child_pid); //Needed so negative PIDs can kill children of /bin/sh - //if (execlp(argv[0].c_str(), argv[0].c_str(), argv[1].c_str(), argv[2].c_str(), argv[3].c_str(), argv[4].c_str(), argv[5].c_str(), NULL ) == -1) - if (execvp(command.c_str(), &argv)) - { - perror("execl error => "); - } + if (execlp(argv[0].c_str(), argv[0].c_str(), argv[1].c_str(), argv[2].c_str(), argv[3].c_str(), argv[4].c_str(), argv[5].c_str(), NULL ) == -1) exit (0); } else @@ -103,6 +106,10 @@ FILE * popen2(char * const argv, string type, int & pid) return 0; } +// close pipe open by popen2 while pid is finished +// fp => file pointer +// pid => pid of the processus open bu popen2 + int pclose2(FILE * fp, pid_t pid) { int stat; diff --git a/tools.h b/tools.h index f91ea53..c6e1b78 100644 --- a/tools.h +++ b/tools.h @@ -9,7 +9,7 @@ using namespace std; const vector explode(const string& s, const char& c, int n); -FILE * popen2(char * const argv, string type, int & pid); +FILE * popen2(array argv, string type, int & pid); int pclose2(FILE * fp, pid_t pid);