Files
create/src/Gui/NetworkRetriever.cpp
luzpaz 129d5882a7 Migrate domain name from freecadweb to freecad (#9352)
* Migrate domain name from freecadweb to freecad
* Migrate src/Mod/Material files
* Migrate Stylesheet related files
* Migrate *.svg files
* Migrate miscellaneous files
* Migrate some build files
* Migrate recently added TD AR_IRAM template files

Closes #6415
2023-04-24 15:19:20 -05:00

558 lines
17 KiB
C++

/***************************************************************************
* Copyright (c) 2004 Werner Mayer <wmayer[at]users.sourceforge.net> *
* *
* This file is part of the FreeCAD CAx development system. *
* *
* This library is free software; you can redistribute it and/or *
* modify it under the terms of the GNU Library General Public *
* License as published by the Free Software Foundation; either *
* version 2 of the License, or (at your option) any later version. *
* *
* This library is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU Library General Public License for more details. *
* *
* You should have received a copy of the GNU Library General Public *
* License along with this library; see the file COPYING.LIB. If not, *
* write to the Free Software Foundation, Inc., 59 Temple Place, *
* Suite 330, Boston, MA 02111-1307, USA *
* *
***************************************************************************/
#include "PreCompiled.h"
#ifndef _PreComp_
# include <QApplication>
# include <QDir>
# include <QFileInfo>
# include <QMessageBox>
# include <QTimer>
#endif
#include <App/Application.h>
#include <Base/Console.h>
#include "NetworkRetriever.h"
#include "Action.h"
#include "BitmapFactory.h"
#include "FileDialog.h"
#include "MainWindow.h"
#include "ui_DlgAuthorization.h"
using namespace Gui;
using namespace Gui::Dialog;
namespace Gui {
struct NetworkRetrieverP
{
// wget options
int tries;
int level;
QString outputFile;
QString user;
QString passwd;
bool timeStamp;
bool img;
bool convert;
bool recurse;
bool folRel;
bool html;
bool nop;
// wget argument
QString startUrl;
QString proxy;
QString dir;
bool fail;
};
} // namespace Gui
/* TRANSLATOR Gui::NetworkRetriever */
NetworkRetriever::NetworkRetriever( QObject * parent )
: QObject( parent )
{
d = new NetworkRetrieverP;
d->tries = 3;
d->level = 1;
d->timeStamp = false;
d->img = false;
d->html = false;
d->convert = true;
d->recurse = false;
d->folRel = false;
d->nop = false;
wget = new QProcess(this);
// if wgets exits emit signal
connect(wget, qOverload<int, QProcess::ExitStatus>(&QProcess::finished),
this, &NetworkRetriever::wgetFinished);
// if application quits kill wget immediately to avoid dangling processes
connect(qApp, &QApplication::lastWindowClosed, wget, &QProcess::kill);
}
NetworkRetriever::~NetworkRetriever()
{
delete wget;
delete d;
}
/**
* This method is connected to QTimer::singleShot() and executed after 5 seconds. If wget then is still running
* we can assume that everything is fine.
* \note This test is necessary since \a wget writes all its output on stderr and we cannot determine surely
* if an error occurred or not.
*
* There is still a problem that is not solved so far. If wget requires the proxy settings and if these
* are not set, wget could take more than 5 seconds without downloading anything.
*/
void NetworkRetriever::testFailure()
{
if ( wget->state() == QProcess::Running )
{
d->fail = false;
QString msg = tr("Download started...");
Base::Console().Message("%s\n", msg.toUtf8().constData());
}
}
/**
* Sets the number of retries to \a tries. If \a tries is 0 the number of tries
* is unlimited. The default value of the tries property is set to 3.
*/
void NetworkRetriever::setNumberOfTries( int tries )
{
d->tries = tries;
}
/**
* Sets output file to \a out where documents are written to.
*/
void NetworkRetriever::setOutputFile( const QString& out )
{
d->outputFile = out;
}
/**
* If \a ts is true the timestamping is enabled, otherwise timestamping is
* disabled. If timestamping is enabled files are no more re-retrieved unless
* they are newer than the local files. As default the timestamping property is disabled.
*/
void NetworkRetriever::setEnableTimestamp(bool ts)
{
d->timeStamp = ts;
}
/**
* If you are behind a proxy server then you have to specify your proxy url with \a proxy.
* Moreover, if the proxy requires user authentication then you can specify the username
* with \a user and the password with \a passwd.
*/
void NetworkRetriever::setProxy( const QString& proxy, const QString& user, const QString& passwd )
{
d->proxy = proxy;
d->user = user;
d->passwd = passwd;
}
/**
* If \a recursive is true all referenced files are downloaded recursively.
* As default recursion is disabled. \a level specifies the maximum recursion
* depth. If \a level is 0 the recursion depth is infinite. As default the level
* property is 1.
* \note: Use this with care!
*/
void NetworkRetriever::setEnableRecursive( bool recursive, int level )
{
d->recurse = recursive;
d->level = level;
}
/**
* If \a folRel is true wget follows relative links only. As default
* the follows relative property is false.
*/
void NetworkRetriever::setFollowRelative( bool folRel )
{
d->folRel = folRel;
}
/**
* If \a convert is true all non-relative links are converted to
* relative links. As default the convert property is true.
*/
void NetworkRetriever::setEnableConvert( bool convert )
{
d->convert = convert;
}
/**
* If \a img is true wget tries to get all needed image files
* to display the HTML page. As default this behaviour is disabled..
*/
void NetworkRetriever::setFetchImages( bool img )
{
d->img = img;
}
/**
* Saves all text/html documents with .html extionsion if \a html is true.
* As default the html property is false.
*/
void NetworkRetriever::setEnableHTMLExtension( bool html )
{
d->html = html;
}
/**
* Do not ever ascend to the parent directory when retrieving recursively.
*/
void NetworkRetriever::setNoParent( bool nop )
{
d->nop = nop;
}
/**
* Sets the output directory to \a dir where all downloaded are written into.
*/
void NetworkRetriever::setOutputDirectory( const QString& dir )
{
d->dir = dir;
}
/**
* wget starts to download \a startUrl and all referenced pages.
*/
bool NetworkRetriever::startDownload( const QString& startUrl )
{
if ( !testWget() )
return false;
d->startUrl = startUrl;
// proxy as environment variable
if ( !d->proxy.isEmpty() )
{
QStringList env = wget->environment();
env << QString::fromLatin1("http_proxy=%1").arg(d->proxy);
env << QString::fromLatin1("ftp_proxy=%1").arg(d->proxy);
wget->setEnvironment(env);
}
else
{
QStringList env = wget->environment();
env.removeAll(QString::fromLatin1("http_proxy=%1").arg(d->proxy));
env.removeAll(QString::fromLatin1("ftp_proxy=%1").arg(d->proxy));
wget->setEnvironment(env);
}
QStringList wgetArguments;
// since the wget option '--directory-prefix' seems not to work as expected
// and QProcess::setWorkingDirectory() fails if the 'doc' directory doesn't
// exist we must check for this and create it if needed.
if ( !d->dir.isEmpty() )
{
QDir dir(d->dir);
if (!dir.exists(d->dir))
{
if (!dir.mkdir(d->dir))
{
Base::Console().Error("Directory '%s' could not be created.", (const char*)d->dir.toLatin1());
return true; // please, no error message
}
}
wget->setWorkingDirectory( dir.path() );
}
// user authentication
if ( !d->proxy.isEmpty() )
{
if ( !d->user.isEmpty() )
{
wgetArguments << QString::fromLatin1("--proxy-user=%1").arg( d->user );
if ( !d->passwd.isEmpty() )
{
wgetArguments << QString::fromLatin1("--proxy-passwd=%1").arg( d->passwd );
}
}
}
// output file
if ( !d->outputFile.isEmpty() )
wgetArguments << QString::fromLatin1("--output-document=%1").arg( d->outputFile );
// timestamping enabled -> update newer files only
if ( d->timeStamp )
wgetArguments << QString::fromLatin1("-N");
// get all needed image files
if ( d->img )
wgetArguments << QString::fromLatin1("-p");
// follow relative links only
if ( d->folRel )
wgetArguments<< QString::fromLatin1("-L");
if ( d->recurse )
{
wgetArguments << QString::fromLatin1("-r");
wgetArguments << QString::fromLatin1("--level=%1").arg( d->level );
}
if ( d->nop )
wgetArguments << QString::fromLatin1("-np");
// convert absolute links in to relative
if ( d->convert )
wgetArguments << QString::fromLatin1("-k");
// number of tries
wgetArguments << QString::fromLatin1("--tries=%1").arg( d->tries );
// use HTML file extension
if ( d->html )
wgetArguments << QString::fromLatin1("-E");
// start URL
wgetArguments << startUrl;
#ifdef FC_OS_LINUX
// on Linux it seems that we have to change cwd
QString cwd = QDir::currentPath ();
if ( !d->dir.isEmpty() )
{
QDir::setCurrent(d->dir);
}
wget->start(QString::fromLatin1("wget"), wgetArguments);
QDir::setCurrent( cwd );
#else
wget->start(QString::fromLatin1("wget"), wgetArguments);
#endif
return wget->state() == QProcess::Running;
}
/**
* Returns true if wget is still downloading, otherwise returns false.
*/
bool NetworkRetriever::isDownloading() const
{
return wget->state() == QProcess::Running;
}
/**
* Kills wget if it is still running.
*/
void NetworkRetriever::abort()
{
if ( wget->state() == QProcess::Running)
{
QTimer::singleShot( 2000, wget, &QProcess::kill);
}
}
void NetworkRetriever::wgetFinished(int exitCode, QProcess::ExitStatus status)
{
Q_UNUSED(exitCode);
Q_UNUSED(status);
wget->setReadChannel(QProcess::StandardError);
if (wget->canReadLine()) {
QByteArray data = wget->readAll();
Base::Console().Warning(data);
}
Q_EMIT wgetExited();
}
/**
* This is a test if wget is in PATH environment or not.
* If the test succeeds true is returned, false otherwise.
*/
bool NetworkRetriever::testWget()
{
QProcess proc;
proc.setProgram(QString::fromLatin1("wget"));
proc.start();
bool ok = proc.state() == QProcess::Running;
proc.kill();
proc.waitForFinished();
return ok;
}
// --------------------------------------------------------------------
StdCmdDownloadOnlineHelp::StdCmdDownloadOnlineHelp( QObject * parent)
: QObject(parent), Command("Std_DownloadOnlineHelp")
{
sGroup ="Help";
sMenuText = QT_TR_NOOP("Download online help");
sToolTipText = QT_TR_NOOP("Download %1's online help");
sWhatsThis = "Std_DownloadOnlineHelp";
sStatusTip = QT_TR_NOOP("Download %1's online help");
sPixmap = "help";
wget = new NetworkRetriever( this );
// downloading recursively and depth 5
wget->setEnableRecursive( true, 5 );
wget->setNumberOfTries( 3 );
wget->setEnableHTMLExtension( true );
wget->setEnableConvert( true );
wget->setEnableTimestamp( true );
wget->setFetchImages( true );
wget->setFollowRelative( false );
wget->setNoParent( true );
connect(wget, &NetworkRetriever::wgetExited, this, &StdCmdDownloadOnlineHelp::wgetFinished);
}
StdCmdDownloadOnlineHelp::~StdCmdDownloadOnlineHelp()
{
delete wget;
}
Action * StdCmdDownloadOnlineHelp::createAction()
{
Action *pcAction;
QString exe = QString::fromStdString(App::Application::getExecutableName());
pcAction = new Action(this,getMainWindow());
pcAction->setText(QCoreApplication::translate(
this->className(), getMenuText()));
pcAction->setToolTip(QCoreApplication::translate(
this->className(), getToolTipText()).arg(exe));
pcAction->setStatusTip(QCoreApplication::translate(
this->className(), getStatusTip()).arg(exe));
pcAction->setWhatsThis(QCoreApplication::translate(
this->className(), getWhatsThis()).arg(exe));
pcAction->setIcon(Gui::BitmapFactory().pixmap(getPixmap()));
pcAction->setShortcut(QString::fromLatin1(getAccel()));
return pcAction;
}
void StdCmdDownloadOnlineHelp::languageChange()
{
if (_pcAction) {
QString exe = QString::fromStdString(App::Application::getExecutableName());
_pcAction->setText(QCoreApplication::translate(
this->className(), getMenuText()));
_pcAction->setToolTip(QCoreApplication::translate(
this->className(), getToolTipText()).arg(exe));
_pcAction->setStatusTip(QCoreApplication::translate(
this->className(), getStatusTip()).arg(exe));
_pcAction->setWhatsThis(QCoreApplication::translate(
this->className(), getWhatsThis()).arg(exe));
}
}
void StdCmdDownloadOnlineHelp::activated(int iMsg)
{
Q_UNUSED(iMsg);
if (!wget->isDownloading()) {
ParameterGrp::handle hGrp = App::GetApplication().GetUserParameter().GetGroup("BaseApp");
hGrp = hGrp->GetGroup("Preferences")->GetGroup("OnlineHelp");
std::string url = hGrp->GetASCII("DownloadURL", "www.freecad.org/wiki/");
std::string prx = hGrp->GetASCII("ProxyText", "");
bool bUseProxy = hGrp->GetBool ("UseProxy", false);
bool bAuthor = hGrp->GetBool ("Authorize", false);
if (bUseProxy) {
QString username;
QString password;
if (bAuthor) {
QDialog dlg(getMainWindow());
dlg.setModal(true);
Ui_DlgAuthorization ui;
ui.setupUi(&dlg);
if (dlg.exec() == QDialog::Accepted) {
username = ui.username->text();
password = ui.password->text();
}
}
wget->setProxy(QString::fromLatin1(prx.c_str()), username, password);
}
int loop=3;
bool canStart = false;
// set output directory
QString path = QString::fromStdString(App::Application::getHomePath());
path += QString::fromLatin1("/doc/");
ParameterGrp::handle hURLGrp = App::GetApplication().GetParameterGroupByPath("User parameter:BaseApp/Preferences/OnlineHelp");
path = QString::fromUtf8(hURLGrp->GetASCII( "DownloadLocation", path.toLatin1() ).c_str());
while (loop > 0) {
loop--;
QFileInfo fi( path);
if (!fi.exists()) {
if (QMessageBox::critical(getMainWindow(), tr("Non-existing directory"),
tr("The directory '%1' does not exist.\n\n"
"Do you want to specify an existing directory?").arg(fi.filePath()),
QMessageBox::Yes | QMessageBox::No) !=
QMessageBox::Yes)
{
// exit the command
return;
}
else
{
path = FileDialog::getExistingDirectory();
if ( path.isEmpty() )
return;
}
}
if (!fi.permission( QFile::WriteUser)) {
if (QMessageBox::critical(getMainWindow(), tr("Missing permission"),
tr("You don't have write permission to '%1'\n\n"
"Do you want to specify another directory?").arg(fi.filePath()),
QMessageBox::Yes | QMessageBox::No) !=
QMessageBox::Yes)
{
// exit the command
return;
}
else {
path = FileDialog::getExistingDirectory();
if ( path.isEmpty() )
return;
}
}
else {
wget->setOutputDirectory( path );
canStart = true;
break;
}
}
if (canStart) {
bool ok = wget->startDownload(QString::fromLatin1(url.c_str()));
if (!ok)
Base::Console().Error("The tool 'wget' couldn't be found. Please check your installation.");
else if ( wget->isDownloading() && _pcAction )
_pcAction->setText(tr("Stop downloading"));
}
}
else // kill the process now
{
wget->abort();
}
}
void StdCmdDownloadOnlineHelp::wgetFinished()
{
if (_pcAction)
_pcAction->setText(QCoreApplication::translate(
this->className(), getMenuText()));
}
#include "moc_NetworkRetriever.cpp"