"Fossies" - the Fresh Open Source Software Archive

Member "cb2bib-2.0.1/src/c2b/network.cpp" (12 Feb 2021, 13098 Bytes) of package /linux/privat/cb2bib-2.0.1.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "network.cpp" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 2.0.0_vs_2.0.1.

    1 /***************************************************************************
    2  *   Copyright (C) 2004-2021 by Pere Constans
    3  *   constans@molspaces.com
    4  *   cb2Bib version 2.0.1. Licensed under the GNU GPL version 3.
    5  *   See the LICENSE file that comes with this distribution.
    6  ***************************************************************************/
    7 #include "network.h"
    8 
    9 #include "cb2bib_utilities.h"
   10 #include "settings.h"
   11 
   12 #include <QNetworkCookie>
   13 #include <QNetworkCookieJar>
   14 #include <QNetworkProxy>
   15 #include <QNetworkReply>
   16 #include <QTimer>
   17 
   18 
   19 network::network(QObject* parento) : QObject(parento), _max_redirections(15)
   20 {
   21     _is_fetching = false;
   22     _fetcher = new QNetworkAccessManager(this);
   23     connect(_fetcher, SIGNAL(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*)), this,
   24             SIGNAL(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*)));
   25     loadSettings();
   26     connect(settings::instance(), SIGNAL(newSettings()), this, SLOT(loadSettings()));
   27     // Set predefined cookies
   28     QNetworkCookieJar* ncj = _fetcher->cookieJar();
   29     QNetworkCookie nc("GSP", "ID=d093ce1ea042ad2b:IN=54afcd58e3b38df9:HIN=ff7e3a3ab3fbae0a+7e6cc990821af63:CF=4");
   30     ncj->setCookiesFromUrl(QList<QNetworkCookie>() << nc, QUrl("https://scholar.google.com"));
   31 }
   32 
   33 
   34 /****************************************************************************
   35 
   36   PUBLIC PART
   37 
   38 *****************************************************************************/
   39 
   40 void network::getFile(const QString& source, const QString& destination, const Action action, QObject* receiver,
   41                       const char* callback, const bool overwrite)
   42 {
   43     if (_is_fetching)
   44     {
   45         c2bUtils::warn(tr("network::getFile: Requesting network while still fetching previous request. Returned"));
   46         return;
   47     }
   48     setup(source, destination);
   49     disconnect(this, SIGNAL(requestFinished(bool)), 0, 0);
   50     if (receiver)
   51         connect(this, SIGNAL(requestFinished(bool)), receiver, callback);
   52     if (overwrite)
   53         if (QFileInfo::exists(destination))
   54             QFile::remove(destination);
   55     getFilePrivate(action);
   56 }
   57 
   58 void network::headFile(const QString& source, QObject* receiver, const char* callback)
   59 {
   60     if (_is_fetching)
   61     {
   62         c2bUtils::warn(tr("network::headFile: Requesting network while still fetching previous request. Returned"));
   63         return;
   64     }
   65     setup(source);
   66     disconnect(this, SIGNAL(requestFinished(bool)), 0, 0);
   67     if (receiver)
   68         connect(this, SIGNAL(requestFinished(bool)), receiver, callback);
   69     headFilePrivate();
   70 }
   71 
   72 void network::cancelDownload()
   73 {
   74     if (_is_fetching)
   75         _current_reply->abort();
   76 }
   77 
   78 
   79 /****************************************************************************
   80 
   81   PRIVATE PART
   82 
   83 *****************************************************************************/
   84 
   85 void network::getFilePrivate(const Action action)
   86 {
   87     if (!checkDestination())
   88     {
   89         _emit_request_finished(false);
   90         return;
   91     }
   92     if (_source_filename.startsWith("<<post>>")) // cb2Bib keyword to use post http method
   93     {
   94         _source_filename.remove(QRegExp("^<<post>>"));
   95         _fetch_c2b(action, QNetworkAccessManager::PostOperation);
   96         return;
   97     }
   98     if (FmClient)
   99         if ((action == Copy && !FmClientCopyBin.isEmpty()) || (action == Move && !FmClientMoveBin.isEmpty()))
  100         {
  101             _fetch_client(action);
  102             return;
  103         }
  104     _fetch_c2b(action);
  105 }
  106 
  107 void network::headFilePrivate()
  108 {
  109     const QUrl u(_source_filename, QUrl::TolerantMode);
  110     if (u.scheme() == "file" || QFileInfo::exists(_source_filename))
  111     {
  112         // Local File
  113         const QString fn(u.scheme() == "file" ? u.toLocalFile() : _source_filename);
  114         const bool succeeded(QFileInfo::exists(fn));
  115         if (!succeeded)
  116             _request_error_string = tr("File does not exist.");
  117         _emit_request_finished(succeeded);
  118     }
  119     else
  120     {
  121         // Network File
  122         _head(u);
  123     }
  124 }
  125 
  126 void network::_emit_request_finished(bool succeeded)
  127 {
  128     _request_succeeded = succeeded;
  129     // Give some time to cleanup events and to return all network functions
  130     // before passing the control to the callback routine
  131     QTimer::singleShot(50, this, SLOT(_emit_request_finished()));
  132 }
  133 
  134 void network::_emit_request_finished()
  135 {
  136     _is_fetching = false;
  137     // Assumed events are clean, all functions returned, then make the callback
  138     emit requestFinished(_request_succeeded);
  139 }
  140 
  141 bool network::checkDestination()
  142 {
  143     // Checks whether or not writing to destination is safe
  144     // Returns false if file exists
  145     if (QFileInfo::exists(_destination_filename))
  146     {
  147         _request_error_string = tr("Destination file '%1' already exists.").arg(_destination_filename);
  148         return false;
  149     }
  150     else
  151         return true;
  152 }
  153 
  154 void network::loadSettings()
  155 {
  156     settings* s(settings::instance());
  157     FmClient = s->value("cb2Bib/FmClient").toBool();
  158     FmClientCopyBin = s->fileName("cb2Bib/FmClientCopyBin");
  159     FmClientMoveBin = s->fileName("cb2Bib/FmClientMoveBin");
  160     FmClientCopyArg = s->value("cb2Bib/FmClientCopyArg").toString();
  161     FmClientMoveArg = s->value("cb2Bib/FmClientMoveArg").toString();
  162     QNetworkProxy proxy;
  163     if (s->value("cb2Bib/UseProxy").toBool())
  164     {
  165         const QString hn(s->value("cb2Bib/ProxyHostName", QString()).toString());
  166         if (!hn.isEmpty())
  167         {
  168             if (s->value("cb2Bib/ProxyType").toInt() == 0)
  169                 proxy = QNetworkProxy::HttpProxy;
  170             else
  171                 proxy = QNetworkProxy::Socks5Proxy;
  172             proxy.setHostName(hn);
  173             proxy.setPort(quint16(s->value("cb2Bib/ProxyPort").toInt()));
  174         }
  175     }
  176     _fetcher->setProxy(proxy);
  177 }
  178 
  179 
  180 /****************************************************************************
  181 
  182   PRIVATE PART: FILEMANAGER CLIENT
  183 
  184 *****************************************************************************/
  185 
  186 void network::_fetch_client(const Action action)
  187 {
  188     // Getting NetworkFile through kfmclient
  189     Action act(action);
  190     // Only move local files
  191     QUrl u(_source_filename);
  192     if (!(u.scheme() == "file" || QFileInfo::exists(_source_filename)))
  193         if (action == Move)
  194             act = Copy; // Copy network files
  195 
  196     QStringList arglist;
  197     QString fmclient_bin;
  198     if (act == Copy)
  199     {
  200         fmclient_bin = FmClientCopyBin;
  201         arglist = FmClientCopyArg.split(' ', QString::SkipEmptyParts);
  202     }
  203     else if (act == Move)
  204     {
  205         fmclient_bin = FmClientMoveBin;
  206         arglist = FmClientMoveArg.split(' ', QString::SkipEmptyParts);
  207     }
  208     arglist.append(_source_filename);
  209     arglist.append(_destination_filename);
  210     _fetcher_client = new QProcess(this);
  211     connect(_fetcher_client, SIGNAL(finished(int,QProcess::ExitStatus)), this,
  212             SLOT(_client_finished(int,QProcess::ExitStatus)));
  213     _fetcher_client->start(fmclient_bin, arglist);
  214     if (!_fetcher_client->waitForStarted())
  215     {
  216         delete _fetcher_client;
  217         _request_error_string = tr("FM Client '%1' could not be launched.").arg(fmclient_bin);
  218         _emit_request_finished(false);
  219     }
  220 }
  221 
  222 void network::_client_finished(int exitCode, QProcess::ExitStatus exitStatus)
  223 {
  224     bool succeeded(false);
  225     if (exitStatus == QProcess::CrashExit)
  226         _request_error_string = tr("FM Client crashed.");
  227     else
  228     {
  229         if (QFileInfo::exists(_destination_filename))
  230             succeeded = true;
  231         else
  232             _request_error_string =
  233                 tr("File '%1' has not been written. Exit code '%2'.").arg(_source_filename).arg(exitCode);
  234     }
  235     delete _fetcher_client;
  236     _emit_request_finished(succeeded);
  237 }
  238 
  239 
  240 /****************************************************************************
  241 
  242   PRIVATE PART: C2B FETCHER
  243 
  244 *****************************************************************************/
  245 
  246 void network::_head(const QUrl& url)
  247 {
  248     QNetworkRequest request;
  249     request.setUrl(url);
  250     request.setRawHeader(
  251         "User-Agent",
  252         QString("cb2Bib/" + C2B_VERSION +
  253                 " (https://www.molspaces.com/cb2bib/; mailto:cb2bib@molspaces.com; Bibliographic Browser Tool)")
  254         .toLatin1());
  255     _current_reply = _fetcher->head(request);
  256     connect(_current_reply, SIGNAL(finished()), SLOT(_head_finished()));
  257 }
  258 
  259 void network::_head_finished()
  260 {
  261     if (_redirection_count++ < _max_redirections)
  262     {
  263         const QUrl redirection(_current_reply->attribute(QNetworkRequest::RedirectionTargetAttribute).toUrl());
  264         if (redirection.isValid())
  265         {
  266             const QUrl ru(_current_reply->url().resolved(redirection));
  267             _source_filename = ru.toString();
  268             _current_reply->deleteLater();
  269             _head(ru);
  270             return;
  271         }
  272     }
  273     const bool succeeded(_current_reply->error() == QNetworkReply::NoError);
  274     if (succeeded)
  275         _file_mimetype_string = _current_reply->header(QNetworkRequest::ContentTypeHeader).toString();
  276     else
  277         _request_error_string = _current_reply->errorString() + '.';
  278     _current_reply->deleteLater();
  279     _emit_request_finished(succeeded);
  280 }
  281 
  282 void network::_fetch_c2b(const Action action, const QNetworkAccessManager::Operation operation)
  283 {
  284     _fetch_operation = operation;
  285     _fetch_url_query.clear();
  286     QString url_str;
  287     if (_fetch_operation == QNetworkAccessManager::PostOperation)
  288     {
  289         const int qmark(_source_filename.indexOf('?'));
  290         url_str = _source_filename.mid(0, qmark);
  291         if (qmark > -1)
  292         {
  293             url_str += '/';
  294             _fetch_url_query = _source_filename.mid(qmark + 1).toUtf8();
  295         }
  296     }
  297     else
  298         url_str = _source_filename;
  299 
  300     QUrl u(url_str, QUrl::TolerantMode);
  301     if (u.scheme() == "file" || QFileInfo::exists(_source_filename))
  302     {
  303         // Local File
  304         QFile source(u.scheme() == "file" ? u.toLocalFile() : _source_filename);
  305         bool succeeded(false);
  306         if (action == Copy)
  307             succeeded = source.copy(_destination_filename);
  308         else if (action == Move)
  309             succeeded = source.rename(_destination_filename);
  310         if (!succeeded)
  311             _request_error_string = source.errorString();
  312         _emit_request_finished(succeeded);
  313     }
  314     else
  315     {
  316         // Network File
  317         _fetch(u);
  318     }
  319 }
  320 
  321 void network::_fetch(const QUrl& url)
  322 {
  323     _destination_file.setFileName(_destination_filename);
  324     if (!_destination_file.open(QIODevice::WriteOnly))
  325     {
  326         _request_error_string =
  327             tr("File '%1' cannot be written. %2").arg(_destination_filename, _destination_file.errorString());
  328         _emit_request_finished(false);
  329         return;
  330     }
  331     QNetworkRequest request;
  332     request.setUrl(url);
  333     request.setRawHeader(
  334         "User-Agent",
  335         QString("cb2Bib/" + C2B_VERSION +
  336                 " (https://www.molspaces.com/cb2bib/; mailto:cb2bib@molspaces.com; Bibliographic Browser Tool)")
  337         .toLatin1());
  338     if (_fetch_operation == QNetworkAccessManager::PostOperation)
  339     {
  340         request.setHeader(QNetworkRequest::ContentTypeHeader, "application/x-www-form-urlencoded");
  341         _current_reply = _fetcher->post(request, _fetch_url_query);
  342     }
  343     else
  344         _current_reply = _fetcher->get(request);
  345     connect(_current_reply, SIGNAL(readyRead()), this, SLOT(_fetch_ready_read()));
  346     connect(_current_reply, SIGNAL(finished()), SLOT(_fetch_finished()));
  347     connect(_current_reply, SIGNAL(error(QNetworkReply::NetworkError)), this, SLOT(logError()));
  348     connect(_current_reply, SIGNAL(downloadProgress(qint64,qint64)), this, SIGNAL(downloadProgress(qint64,qint64)));
  349 }
  350 
  351 void network::_fetch_finished()
  352 {
  353     _destination_file.close();
  354     if (_current_reply->error() == QNetworkReply::OperationCanceledError)
  355         _destination_file.remove(); // Delete file
  356     else if (_redirection_count++ < _max_redirections)
  357     {
  358         const QUrl redirection(_current_reply->attribute(QNetworkRequest::RedirectionTargetAttribute).toUrl());
  359         if (redirection.isValid())
  360         {
  361             const QUrl ru(_current_reply->url().resolved(redirection));
  362             _source_filename = ru.toString();
  363             const int status(_current_reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt());
  364             if ((status >= 301 && status <= 303) || status == 307)
  365                 _fetch_operation = QNetworkAccessManager::GetOperation;
  366             _current_reply->deleteLater();
  367             _fetch(ru);
  368             return;
  369         }
  370     }
  371     const bool succeeded(_current_reply->error() == QNetworkReply::NoError);
  372     if (succeeded)
  373         _file_mimetype_string = _current_reply->header(QNetworkRequest::ContentTypeHeader).toString();
  374     else
  375         _request_error_string = _current_reply->errorString() + '.';
  376     _current_reply->deleteLater();
  377     _emit_request_finished(succeeded);
  378 }
  379 
  380 void network::_fetch_ready_read()
  381 {
  382     _destination_file.write(_current_reply->readAll());
  383 }
  384 
  385 void network::logError()
  386 {
  387     c2bUtils::warn(tr("network::QNetworkReply log: %1").arg(_current_reply->errorString()));
  388 }