config file is now ~/.config/RsyncUI.conf

This commit is contained in:
Daniel Tartavel 2023-01-23 23:42:20 +01:00
parent d1e45b8ba8
commit eb7795c791
8 changed files with 96 additions and 39 deletions

View File

@ -19,59 +19,70 @@
using namespace std; using namespace std;
// Initialization de la class
downloadFile::downloadFile() downloadFile::downloadFile()
{ {
} }
//Slot activated when download is cancelled
void downloadFile::cancelled(int pid) 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) void downloadFile::download(MainWindow *mw)
{ {
string line; string line;
string errorRsync; string errorRsync;
int pos; int pos;
array<string, 7> argv; array<string,8> argv;
stringstream output; stringstream output;
vector<string> v; vector<string> v;
int value; int value;
char buffer[4096]; char buffer[4096];
// Populating array with command and parameters for popen2
argv[0] = "/usr/bin/rsync"; argv[0] = "/usr/bin/rsync";
if (mw->connexion.bandwidthLimit == 0) if (mw->connexion.bandwidthLimit == 0)
{ {
argv[1] = "--bwlimit=1000P"; argv[1] = "--bwlimit=1000P";
}else }else
{ {
output << mw->connexion.bandwidthLimit; argv[1] = "--bwlimit=" + to_string(mw->connexion.bandwidthLimit) + mw->connexion.bandwidthLimitUnit;
argv[1] = "--bwlimit=" + output.str() + mw->connexion.bandwidthLimitUnit;
} }
argv[2] = "--port=" + to_string(mw->connexion.port); argv[2] = "--port=" + to_string(mw->connexion.port);
argv[3] = "-P"; argv[3] = "-P";
argv[4] = mw->connexion.server + "::" + mw->downloading.service + "/" + mw->downloading.path; argv[4] = mw->connexion.server + "::" + mw->downloading.service + "/" + mw->downloading.path;
argv[5] = mw->downloading.savePath + "/"; argv[5] = mw->downloading.savePath + "/";
argv[6] = ""; argv[6].clear();
//launching downloading thread //launching downloading thread
FILE * fp = popen2(argv, "r", mw->downloading.pid); 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; return;
} }
// waiting rsync output
while (fgets(buffer, 4096, fp) != nullptr) while (fgets(buffer, 4096, fp) != nullptr)
{ {
// Downloading is cancelled, we return
if (this->canceled == true) if (this->canceled == true)
{ {
return; return;
} }
line = buffer; line = buffer;
// extracting percentage of completion
pos = line.find('%'); pos = line.find('%');
if (pos != -1) if (pos != -1)
{ {
@ -81,9 +92,11 @@ void downloadFile::download(MainWindow *mw)
{ {
line.erase(0, pos); line.erase(0, pos);
value = stoi(line); value = stoi(line);
// sending progress to Main window
emit progressSignal(value); emit progressSignal(value);
} }
} }
// download ended
} }
pclose2(fp, mw->downloading.pid); pclose2(fp, mw->downloading.pid);
@ -91,4 +104,3 @@ void downloadFile::download(MainWindow *mw)
emit progressSignal(100); emit progressSignal(100);
emit finishedSignal(true); emit finishedSignal(true);
} }

Binary file not shown.

View File

@ -164,7 +164,7 @@
</message> </message>
<message> <message>
<location filename="../../mainwindow.cpp" line="21"/> <location filename="../../mainwindow.cpp" line="21"/>
<location filename="../../mainwindow.cpp" line="517"/> <location filename="../../mainwindow.cpp" line="547"/>
<source>PB</source> <source>PB</source>
<translation>Po</translation> <translation>Po</translation>
</message> </message>
@ -179,44 +179,49 @@
<translation>Taille</translation> <translation>Taille</translation>
</message> </message>
<message> <message>
<location filename="../../mainwindow.cpp" line="68"/> <location filename="../../mainwindow.cpp" line="71"/>
<source>Exiting will stop downloading, and will clear the download queue. <source>Exiting will stop downloading, and will clear the download queue.
Do you want to exit ?</source> Do you want to exit ?</source>
<translation>Soritr stoppera le téléchargement et effacera la file des téléchargements. <translation>Soritr stoppera le téléchargement et effacera la file des téléchargements.
Voulez-vous vraiment sortir du programme ?</translation> Voulez-vous vraiment sortir du programme ?</translation>
</message> </message>
<message> <message>
<location filename="../../mainwindow.cpp" line="297"/> <location filename="../../mainwindow.cpp" line="316"/>
<source>server does not exists</source> <source>server does not exists</source>
<translation>Le serveur n&apos;existe pas</translation> <translation>Le serveur n&apos;existe pas</translation>
</message> </message>
<message> <message>
<location filename="../../mainwindow.cpp" line="479"/> <location filename="../../mainwindow.cpp" line="504"/>
<source>Version</source>
<translation>Version</translation>
</message>
<message>
<location filename="../../mainwindow.cpp" line="505"/>
<source>Licence</source> <source>Licence</source>
<translation>License</translation> <translation>License</translation>
</message> </message>
<message> <message>
<location filename="../../mainwindow.cpp" line="480"/> <location filename="../../mainwindow.cpp" line="506"/>
<source>Author</source> <source>Author</source>
<translation>Auteur</translation> <translation>Auteur</translation>
</message> </message>
<message> <message>
<location filename="../../mainwindow.cpp" line="481"/> <location filename="../../mainwindow.cpp" line="507"/>
<source>EMail</source> <source>EMail</source>
<translation>Courriel</translation> <translation>Courriel</translation>
</message> </message>
<message> <message>
<location filename="../../mainwindow.cpp" line="482"/> <location filename="../../mainwindow.cpp" line="508"/>
<source>Source code</source> <source>Source code</source>
<translation>Code source</translation> <translation>Code source</translation>
</message> </message>
<message> <message>
<location filename="../../mainwindow.cpp" line="495"/> <location filename="../../mainwindow.cpp" line="523"/>
<source>Choose directory to save file</source> <source>Choose directory to save file</source>
<translation>Choisissez le dossier enregistrer</translation> <translation>Choisissez le dossier enregistrer</translation>
</message> </message>
<message> <message>
<location filename="../../mainwindow.cpp" line="413"/> <location filename="../../mainwindow.cpp" line="436"/>
<source>Do you want to stop downloading and delete this file from download queue ?</source> <source>Do you want to stop downloading and delete this file from download queue ?</source>
<translation>Vouslez-vous arrêter le téléchargement et enlever ce fichier de la file de téléchargement ?</translation> <translation>Vouslez-vous arrêter le téléchargement et enlever ce fichier de la file de téléchargement ?</translation>
</message> </message>
@ -225,7 +230,7 @@ Voulez-vous vraiment sortir du programme ?</translation>
<translation type="vanished">Client pour serveur rsync</translation> <translation type="vanished">Client pour serveur rsync</translation>
</message> </message>
<message> <message>
<location filename="../../mainwindow.cpp" line="425"/> <location filename="../../mainwindow.cpp" line="448"/>
<source>Do you want to delete this file from download queue ?</source> <source>Do you want to delete this file from download queue ?</source>
<translation>Voulez-vous enlever ce fichier de la file de téléchargement ?</translation> <translation>Voulez-vous enlever ce fichier de la file de téléchargement ?</translation>
</message> </message>

View File

@ -2,12 +2,14 @@
#include <QTranslator> #include <QTranslator>
int main(int argc, char *argv[]) int main(int argc, char *argv[])
{ {
QApplication a(argc, argv); QApplication a(argc, argv);
QTranslator myappTranslator; QTranslator myappTranslator;
QCoreApplication::setOrganizationName("RsyncUI");
QCoreApplication::setApplicationName("RsyncUI");
// Initialization of localization
QLocale localeName = QLocale::system(); QLocale localeName = QLocale::system();
QString localeFile = "/usr/share/locale/" + localeName.name() + "/LC_MESSAGES/RsyncUI_" + localeName.name() + ".qm"; QString localeFile = "/usr/share/locale/" + localeName.name() + "/LC_MESSAGES/RsyncUI_" + localeName.name() + ".qm";
if (myappTranslator.load(localeFile)) if (myappTranslator.load(localeFile))

View File

@ -54,15 +54,18 @@ MainWindow::~MainWindow()
delete ui; delete ui;
} }
// Closing window has been clicked
void MainWindow::closeEvent (QCloseEvent *event) void MainWindow::closeEvent (QCloseEvent *event)
{ {
QMessageBox::StandardButton reply; QMessageBox::StandardButton reply;
// saving settings
saveSettings(); 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, this,
"RsyncUI", "RsyncUI",
tr("Exiting will stop downloading, and will clear the download queue.\n Do you want to exit ?"), 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); QMessageBox::No);
if (reply == QMessageBox::No) if (reply == QMessageBox::No)
{ {
// continuing
event->ignore(); event->ignore();
return; return;
}else }else
{ {
// emission of signal to downloading thread and stopping
emit (stopDownloading(this->downloading.pid)); emit (stopDownloading(this->downloading.pid));
waitpid(this->downloading.pid, NULL, WUNTRACED); waitpid(this->downloading.pid, NULL, WUNTRACED);
} }
@ -81,24 +86,31 @@ void MainWindow::closeEvent (QCloseEvent *event)
event->accept(); event->accept();
} }
// Populate treeview with list of files
void MainWindow::populateTree() void MainWindow::populateTree()
{ {
stringstream ss; stringstream ss;
vector<string> path; vector<string> path;
// Clear treewidget
ui->treeWidget->clear(); ui->treeWidget->clear();
if (!this->connexion.server.empty() and this->connexion.port > 0 and this->connexion.port < 65536) if (!this->connexion.server.empty() and this->connexion.port > 0 and this->connexion.port < 65536)
{ {
// setting cursor to "Wait"
QGuiApplication::setOverrideCursor(Qt::WaitCursor); QGuiApplication::setOverrideCursor(Qt::WaitCursor);
if (validateServer(this->connexion.server)) if (validateServer(this->connexion.server))
{ {
// server is validated
path = explode(ui->listWidget->currentItem()->text().toStdString(), '\n', 2); path = explode(ui->listWidget->currentItem()->text().toStdString(), '\n', 2);
scanDir(this->connexion.server, this->connexion.port, NULL, path[0].append("/") ); 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() void MainWindow::populateList()
{ {
stringstream ss; stringstream ss;
@ -110,13 +122,16 @@ void MainWindow::populateList()
port = ui->portEdit->text().toUInt(); port = ui->portEdit->text().toUInt();
if ((server.toStdString() != this->connexion.server) or (port != this->connexion.port)) if ((server.toStdString() != this->connexion.server) or (port != this->connexion.port))
{ {
// clearing listwidget
ui->listWidget->clear(); ui->listWidget->clear();
this->connexion.server.assign(server.toStdString()); this->connexion.server.assign(server.toStdString());
this->connexion.port = port; this->connexion.port = port;
// verify if server is in history
this->settings.beginGroup("connexion/server"); this->settings.beginGroup("connexion/server");
if (this->settings.contains(server)) if (this->settings.contains(server))
{ {
// server is in history and completing port value
port = this->settings.value(server).toUInt(); port = this->settings.value(server).toUInt();
ui->portEdit->setText(QString::number(port)); ui->portEdit->setText(QString::number(port));
this->connexion.port = port; this->connexion.port = port;
@ -126,7 +141,7 @@ void MainWindow::populateList()
{ {
if (validateServer(server.toStdString())) if (validateServer(server.toStdString()))
{ {
//this->settings.beginGroup("connexion/server");
if (!this->settings.contains(server)) if (!this->settings.contains(server))
{ {
cout << server.toStdString() << endl; cout << server.toStdString() << endl;
@ -149,6 +164,7 @@ void MainWindow::populateList()
} }
} }
//list services of the rsync server
void MainWindow::listServices() void MainWindow::listServices()
{ {
char cmd[4096]; 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) void MainWindow::scanDir(string server, int portN, QTreeWidgetItem *parent, string path)
{ {
char cmd[4096]; 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) bool MainWindow::isIpAddress(string server)
{ {
vector<string> r; vector<string> r;
@ -249,6 +267,7 @@ bool MainWindow::isIpAddress(string server)
} }
} }
// validate address server
bool MainWindow::validateServer(string server) bool MainWindow::validateServer(string server)
{ {
char cmd[512]; char cmd[512];
@ -300,22 +319,19 @@ bool MainWindow::validateServer(string server)
return flag; return flag;
} }
void MainWindow::displayTree() // slot activated when combobox is changed
{
populateTree();
}
void MainWindow::on_khistorycombobox_currentIndexChanged(int i) void MainWindow::on_khistorycombobox_currentIndexChanged(int i)
{ {
on_connectButton_clicked(); on_connectButton_clicked();
} }
// slot activated when button connection is clicked
void MainWindow::on_connectButton_clicked() void MainWindow::on_connectButton_clicked()
{ {
populateList(); populateList();
} }
// add a dir in treeview
QTreeWidgetItem * MainWindow::addTreeRoot(QString name, QString fileSize) QTreeWidgetItem * MainWindow::addTreeRoot(QString name, QString fileSize)
{ {
// QTreeWidgetItem(QTreeWidget * parent, int type = Type) // QTreeWidgetItem(QTreeWidget * parent, int type = Type)
@ -327,6 +343,7 @@ QTreeWidgetItem * MainWindow::addTreeRoot(QString name, QString fileSize)
return treeItem; return treeItem;
} }
// add a file in treeview
QTreeWidgetItem * MainWindow::addTreeChild(QTreeWidgetItem *parent, QString name, QString fileSize) QTreeWidgetItem * MainWindow::addTreeChild(QTreeWidgetItem *parent, QString name, QString fileSize)
{ {
// QTreeWidgetItem(QTreeWidget * parent, int type = Type) // QTreeWidgetItem(QTreeWidget * parent, int type = Type)
@ -341,6 +358,7 @@ QTreeWidgetItem * MainWindow::addTreeChild(QTreeWidgetItem *parent, QString name
return treeItem; return treeItem;
} }
// Slot acivated when a service in the list is clicked
void MainWindow::on_listWidget_clicked() void MainWindow::on_listWidget_clicked()
{ {
vector<string> v; vector<string> v;
@ -349,6 +367,7 @@ void MainWindow::on_listWidget_clicked()
populateTree(); populateTree();
} }
//Slot activated when a file is clicked in the treeview
void MainWindow::on_treeWidget_itemClicked(QTreeWidgetItem *item) void MainWindow::on_treeWidget_itemClicked(QTreeWidgetItem *item)
{ {
QFuture<void> future; QFuture<void> future;
@ -373,6 +392,7 @@ void MainWindow::on_treeWidget_itemClicked(QTreeWidgetItem *item)
ui->listDownload->addItem(QString::fromStdString(this->downloading.path)); ui->listDownload->addItem(QString::fromStdString(this->downloading.path));
} }
// Launch the thread which download the file
void MainWindow::startDownloading() void MainWindow::startDownloading()
{ {
ui->progressBar->setValue(0); ui->progressBar->setValue(0);
@ -382,11 +402,13 @@ void MainWindow::startDownloading()
} }
// Slot stopping download
void MainWindow::stoppingDownload() void MainWindow::stoppingDownload()
{ {
emit (stopDownloading(this->downloading.pid)); emit (stopDownloading(this->downloading.pid));
} }
// when download is finished, launch download of next file in queue
void MainWindow::downloadFinished() void MainWindow::downloadFinished()
{ {
ui->progressBar->hide(); 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) void MainWindow::on_listDownload_itemClicked(QListWidgetItem *item)
{ {
QFileDialog dialog; QFileDialog dialog;
@ -433,6 +456,7 @@ void MainWindow::on_listDownload_itemClicked(QListWidgetItem *item)
} }
} }
// load settings
void MainWindow::loadSettings() void MainWindow::loadSettings()
{ {
// restoring geometry and state of wondow and widgets // restoring geometry and state of wondow and widgets
@ -460,7 +484,7 @@ void MainWindow::loadSettings()
this->connexion.bandwidthLimitUnit = this->settings.value("bandwidthlimitunit").toString().toStdString(); this->connexion.bandwidthLimitUnit = this->settings.value("bandwidthlimitunit").toString().toStdString();
} }
// save settings
void MainWindow::saveSettings() void MainWindow::saveSettings()
{ {
this->settings.setValue("window/geometry", saveGeometry()); this->settings.setValue("window/geometry", saveGeometry());
@ -473,21 +497,25 @@ void MainWindow::saveSettings()
this->settings.sync(); this->settings.sync();
} }
// About
void MainWindow::on_actionAbout_triggered() void MainWindow::on_actionAbout_triggered()
{ {
QString text = this->about.description + "\n\n" + 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("Author") + ": " + this->about.author + "\n" +
tr("EMail") + ": " + this->about.email + "\n" + tr("EMail") + ": " + this->about.email + "\n" +
tr("Source code") + ": " + this->about.git; tr("Source code") + ": " + this->about.git;
QMessageBox::about(this, this->about.title, text); QMessageBox::about(this, this->about.title, text);
} }
// About QT
void MainWindow::on_actionAbout_Qt_triggered() void MainWindow::on_actionAbout_Qt_triggered()
{ {
QMessageBox::aboutQt(this); QMessageBox::aboutQt(this);
} }
// Activated when menu "change folder" is clicked
void MainWindow::on_DefaultSaveFolder_triggered() void MainWindow::on_DefaultSaveFolder_triggered()
{ {
QFileDialog dialog; QFileDialog dialog;
@ -498,6 +526,7 @@ void MainWindow::on_DefaultSaveFolder_triggered()
this->settings.sync(); this->settings.sync();
} }
// Activated when menu "settings" is clicked
void MainWindow::on_action_Settings_triggered() void MainWindow::on_action_Settings_triggered()
{ {
config.UnitCombobox->setCurrentText(QString::fromStdString(this->connexion.bandwidthLimitUnit)); config.UnitCombobox->setCurrentText(QString::fromStdString(this->connexion.bandwidthLimitUnit));
@ -505,6 +534,7 @@ void MainWindow::on_action_Settings_triggered()
Configuration.show(); Configuration.show();
} }
// Acivated when "Ok" is clicked in Configuration window
void MainWindow::on_buttonBox_accepted() void MainWindow::on_buttonBox_accepted()
{ {
QString unit; QString unit;

View File

@ -60,6 +60,7 @@ class About
{ {
public: public:
QString title = "RsyncUI"; QString title = "RsyncUI";
QString version = "1.4";
QString author = "Daniel TARTAVEL-JEANNOT"; QString author = "Daniel TARTAVEL-JEANNOT";
QString licence = "GPL_V3"; 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"; QString description = "Client for rsync server\n\nYou click on file to enqueue it, and RyncUI Download one file a time";

View File

@ -5,6 +5,10 @@ using namespace std;
#define READ 0 #define READ 0
#define WRITE 1 #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<string> explode(const string& s, const char& c, int n = 0) const vector<string> explode(const string& s, const char& c, int n = 0)
{ {
string buff; string buff;
@ -37,7 +41,9 @@ const vector<string> explode(const string& s, const char& c, int n = 0)
return v; 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<string,8> argv, string type, int & pid)
{ {
pid_t child_pid; pid_t child_pid;
int fd[2]; int fd[2];
@ -51,6 +57,7 @@ FILE * popen2(char * const argv, string type, int & pid)
NULL, NULL,
"RsyncUI", "RsyncUI",
message); message);
exit(-1);
}else }else
{ {
if((child_pid = fork()) == -1) 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 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 (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 => ");
}
exit (0); exit (0);
} }
else else
@ -103,6 +106,10 @@ FILE * popen2(char * const argv, string type, int & pid)
return 0; 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 pclose2(FILE * fp, pid_t pid)
{ {
int stat; int stat;

View File

@ -9,7 +9,7 @@ using namespace std;
const vector<string> explode(const string& s, const char& c, int n); const vector<string> explode(const string& s, const char& c, int n);
FILE * popen2(char * const argv, string type, int & pid); FILE * popen2(array<string,8> argv, string type, int & pid);
int pclose2(FILE * fp, pid_t pid); int pclose2(FILE * fp, pid_t pid);