Warning, file /office/calligra/libs/store/KoNetAccess.cpp was not indexed or was modified since last indexation (in which case cross-reference links may be missing, inaccurate or erroneous).

0001 /*
0002     This file is part of the KDE libraries
0003     Copyright (C) 1997 Torben Weis (weis@kde.org)
0004     Copyright (C) 1998 Matthias Ettrich (ettrich@kde.org)
0005     Copyright (C) 1999 David Faure (faure@kde.org)
0006 
0007     This library is free software; you can redistribute it and/or
0008     modify it under the terms of the GNU Library General Public
0009     License as published by the Free Software Foundation; either
0010     version 2 of the License, or (at your option) any later version.
0011 
0012     This library is distributed in the hope that it will be useful,
0013     but WITHOUT ANY WARRANTY; without even the implied warranty of
0014     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
0015     Library General Public License for more details.
0016 
0017     You should have received a copy of the GNU Library General Public License
0018     along with this library; see the file COPYING.LIB.  If not, write to
0019     the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
0020     Boston, MA 02110-1301, USA.
0021 */
0022 
0023 #include "KoNetAccess.h"
0024 
0025 #include <stdlib.h>
0026 #include <stdio.h>
0027 #include <signal.h>
0028 #include <unistd.h>
0029 
0030 #include <cstring>
0031 
0032 #include <QtCore/QCharRef>
0033 #include <QApplication>
0034 #include <QtCore/QFile>
0035 #include <QtCore/QFileInfo>
0036 #include <QtCore/QMetaClassInfo>
0037 #include <QtCore/QTextStream>
0038 #include <QtCore/QDataStream>
0039 #include <qtemporaryfile.h>
0040 
0041 #include <klocalizedstring.h>
0042 #include <kjobwidgets.h>
0043 
0044 #include "kio/job.h"
0045 #include "kio/mkdirjob.h"
0046 #include "kio/copyjob.h"
0047 #include "kio/deletejob.h"
0048 #include "kio/scheduler.h"
0049 
0050 namespace KIO
0051 {
0052 class NetAccessPrivate
0053 {
0054 public:
0055     NetAccessPrivate()
0056         : m_metaData(0)
0057         , bJobOK(true)
0058     {}
0059     UDSEntry m_entry;
0060     QString m_mimetype;
0061     QByteArray m_data;
0062     QUrl m_url;
0063     QMap<QString, QString> *m_metaData;
0064 
0065     /**
0066      * Whether the download succeeded or not
0067      */
0068     bool bJobOK;
0069 };
0070 
0071 } // namespace KIO
0072 
0073 using namespace KIO;
0074 
0075 /**
0076  * List of temporary files
0077  */
0078 static QStringList *tmpfiles;
0079 
0080 static QString *lastErrorMsg = 0;
0081 static int lastErrorCode = 0;
0082 
0083 NetAccess::NetAccess() :
0084     d(new NetAccessPrivate)
0085 {
0086 }
0087 
0088 NetAccess::~NetAccess()
0089 {
0090     delete d;
0091 }
0092 
0093 bool NetAccess::download(const QUrl &u, QString &target, QWidget *window)
0094 {
0095     if (u.isLocalFile()) {
0096         // file protocol. We do not need the network
0097         target = u.toLocalFile();
0098         const bool readable = QFileInfo(target).isReadable();
0099         if (!readable) {
0100             if (!lastErrorMsg) {
0101                 lastErrorMsg = new QString;
0102             }
0103             *lastErrorMsg = i18n("File '%1' is not readable", target);
0104             lastErrorCode = ERR_COULD_NOT_READ;
0105         }
0106         return readable;
0107     }
0108 
0109     if (target.isEmpty()) {
0110         QTemporaryFile tmpFile;
0111         tmpFile.setAutoRemove(false);
0112         tmpFile.open();
0113         target = tmpFile.fileName();
0114         if (!tmpfiles) {
0115             tmpfiles = new QStringList;
0116         }
0117         tmpfiles->append(target);
0118     }
0119 
0120     NetAccess kioNet;
0121     const QUrl dest = QUrl::fromLocalFile(target);
0122     return kioNet.filecopyInternal(u, dest, -1, KIO::Overwrite, window, false /*copy*/);
0123 }
0124 
0125 bool NetAccess::upload(const QString &src, const QUrl &target, QWidget *window)
0126 {
0127     if (target.isEmpty()) {
0128         return false;
0129     }
0130 
0131     // If target is local... well, just copy. This can be useful
0132     // when the client code uses a temp file no matter what.
0133     // Let's make sure it's not the exact same file though
0134     if (target.isLocalFile() && target.toLocalFile() == src) {
0135         return true;
0136     }
0137 
0138     NetAccess kioNet;
0139     const QUrl srcUrl = QUrl::fromLocalFile(src);
0140     return kioNet.filecopyInternal(srcUrl, target, -1, KIO::Overwrite, window, false /*copy*/);
0141 }
0142 
0143 #ifndef KDELIBS4SUPPORT_NO_DEPRECATED
0144 bool NetAccess::file_copy(const QUrl &src, const QUrl &target, QWidget *window)
0145 {
0146     NetAccess kioNet;
0147     return kioNet.filecopyInternal(src, target, -1, KIO::DefaultFlags,
0148                                    window, false /*copy*/);
0149 }
0150 #endif
0151 
0152 #ifndef KDELIBS4SUPPORT_NO_DEPRECATED
0153 bool NetAccess::copy(const QUrl &src, const QUrl &target, QWidget *window)
0154 {
0155     return file_copy(src, target, window);
0156 }
0157 #endif
0158 
0159 #ifndef KDELIBS4SUPPORT_NO_DEPRECATED
0160 bool NetAccess::dircopy(const QUrl &src, const QUrl &target, QWidget *window)
0161 {
0162     QList<QUrl> srcList;
0163     srcList.append(src);
0164     return NetAccess::dircopy(srcList, target, window);
0165 }
0166 #endif
0167 
0168 #ifndef KDELIBS4SUPPORT_NO_DEPRECATED
0169 bool NetAccess::dircopy(const QList<QUrl> &srcList, const QUrl &target, QWidget *window)
0170 {
0171     NetAccess kioNet;
0172     return kioNet.dircopyInternal(srcList, target, window, false /*copy*/);
0173 }
0174 #endif
0175 
0176 #ifndef KDELIBS4SUPPORT_NO_DEPRECATED
0177 bool NetAccess::move(const QUrl &src, const QUrl &target, QWidget *window)
0178 {
0179     QList<QUrl> srcList;
0180     srcList.append(src);
0181     NetAccess kioNet;
0182     return kioNet.dircopyInternal(srcList, target, window, true /*move*/);
0183 }
0184 #endif
0185 
0186 #ifndef KDELIBS4SUPPORT_NO_DEPRECATED
0187 bool NetAccess::move(const QList<QUrl> &srcList, const QUrl &target, QWidget *window)
0188 {
0189     NetAccess kioNet;
0190     return kioNet.dircopyInternal(srcList, target, window, true /*move*/);
0191 }
0192 #endif
0193 
0194 #ifndef KDELIBS4SUPPORT_NO_DEPRECATED
0195 bool NetAccess::exists(const QUrl &url, bool source, QWidget *window)
0196 {
0197     if (url.isLocalFile()) {
0198         return QFile::exists(url.toLocalFile());
0199     }
0200     NetAccess kioNet;
0201     return kioNet.statInternal(url, 0 /*no details*/,
0202                                source ? SourceSide : DestinationSide, window);
0203 }
0204 #endif
0205 
0206 bool NetAccess::exists(const QUrl &url, StatSide side, QWidget *window)
0207 {
0208     if (url.isLocalFile()) {
0209         return QFile::exists(url.toLocalFile());
0210     }
0211     NetAccess kioNet;
0212     return kioNet.statInternal(url, 0 /*no details*/, side, window);
0213 }
0214 
0215 bool NetAccess::stat(const QUrl &url, KIO::UDSEntry &entry, QWidget *window)
0216 {
0217     NetAccess kioNet;
0218     bool ret = kioNet.statInternal(url, 2 /*all details*/, SourceSide, window);
0219     if (ret) {
0220         entry = kioNet.d->m_entry;
0221     }
0222     return ret;
0223 }
0224 
0225 QUrl NetAccess::mostLocalUrl(const QUrl &url, QWidget *window)
0226 {
0227     if (url.isLocalFile()) {
0228         return url;
0229     }
0230 
0231     KIO::UDSEntry entry;
0232     if (!stat(url, entry, window)) {
0233         return url;
0234     }
0235 
0236     const QString path = entry.stringValue(KIO::UDSEntry::UDS_LOCAL_PATH);
0237     if (!path.isEmpty()) {
0238         QUrl new_url = QUrl::fromLocalFile(path);
0239         return new_url;
0240     }
0241 
0242     return url;
0243 }
0244 
0245 #ifndef KDELIBS4SUPPORT_NO_DEPRECATED
0246 bool NetAccess::del(const QUrl &url, QWidget *window)
0247 {
0248     NetAccess kioNet;
0249     return kioNet.delInternal(url, window);
0250 }
0251 #endif
0252 
0253 #ifndef KDELIBS4SUPPORT_NO_DEPRECATED
0254 bool NetAccess::mkdir(const QUrl &url, QWidget *window, int permissions)
0255 {
0256     NetAccess kioNet;
0257     return kioNet.mkdirInternal(url, permissions, window);
0258 }
0259 #endif
0260 
0261 QString NetAccess::fish_execute(const QUrl &url, const QString &command, QWidget *window)
0262 {
0263     NetAccess kioNet;
0264     return kioNet.fish_executeInternal(url, command, window);
0265 }
0266 
0267 bool NetAccess::synchronousRun(Job *job, QWidget *window, QByteArray *data,
0268                                QUrl *finalURL, QMap<QString, QString> *metaData)
0269 {
0270     NetAccess kioNet;
0271     // Disable autodeletion until we are back from this event loop (#170963)
0272     // We just have to hope people don't mess with setAutoDelete in slots connected to the job, though.
0273     const bool wasAutoDelete = job->isAutoDelete();
0274     job->setAutoDelete(false);
0275     const bool ok = kioNet.synchronousRunInternal(job, window, data, finalURL, metaData);
0276     if (wasAutoDelete) {
0277         job->deleteLater();
0278     }
0279     return ok;
0280 }
0281 
0282 QString NetAccess::mimetype(const QUrl &url, QWidget *window)
0283 {
0284     NetAccess kioNet;
0285     return kioNet.mimetypeInternal(url, window);
0286 }
0287 
0288 QString NetAccess::lastErrorString()
0289 {
0290     return lastErrorMsg ? *lastErrorMsg : QString();
0291 }
0292 
0293 int NetAccess::lastError()
0294 {
0295     return lastErrorCode;
0296 }
0297 
0298 void NetAccess::removeTempFile(const QString &name)
0299 {
0300     if (!tmpfiles) {
0301         return;
0302     }
0303     if (tmpfiles->contains(name)) {
0304         QFile::remove(name);
0305         tmpfiles->removeAll(name);
0306     }
0307 }
0308 
0309 bool NetAccess::filecopyInternal(const QUrl &src, const QUrl &target, int permissions,
0310                                  KIO::JobFlags flags, QWidget *window, bool move)
0311 {
0312     d->bJobOK = true; // success unless further error occurs
0313 
0314     KIO::Scheduler::checkSlaveOnHold(true);
0315     KIO::Job *job = move
0316                     ? KIO::file_move(src, target, permissions, flags)
0317                     : KIO::file_copy(src, target, permissions, flags);
0318     KJobWidgets::setWindow(job, window);
0319     connect(job, SIGNAL(result(KJob*)),
0320             this, SLOT(slotResult(KJob*)));
0321 
0322     enter_loop();
0323     return d->bJobOK;
0324 }
0325 
0326 bool NetAccess::dircopyInternal(const QList<QUrl> &src, const QUrl &target,
0327                                 QWidget *window, bool move)
0328 {
0329     d->bJobOK = true; // success unless further error occurs
0330 
0331     KIO::Job *job = move
0332                     ? KIO::move(src, target)
0333                     : KIO::copy(src, target);
0334     KJobWidgets::setWindow(job, window);
0335     connect(job, SIGNAL(result(KJob*)),
0336             this, SLOT(slotResult(KJob*)));
0337 
0338     enter_loop();
0339     return d->bJobOK;
0340 }
0341 
0342 bool NetAccess::statInternal(const QUrl &url, int details, StatSide side,
0343                              QWidget *window)
0344 {
0345     d->bJobOK = true; // success unless further error occurs
0346     KIO::JobFlags flags = url.isLocalFile() ? KIO::HideProgressInfo : KIO::DefaultFlags;
0347     KIO::StatJob *job = KIO::stat(url, flags);
0348     KJobWidgets::setWindow(job, window);
0349     job->setDetails(details);
0350     job->setSide(side == SourceSide ? StatJob::SourceSide : StatJob::DestinationSide);
0351     connect(job, SIGNAL(result(KJob*)),
0352             this, SLOT(slotResult(KJob*)));
0353     enter_loop();
0354     return d->bJobOK;
0355 }
0356 
0357 bool NetAccess::delInternal(const QUrl &url, QWidget *window)
0358 {
0359     d->bJobOK = true; // success unless further error occurs
0360     KIO::Job *job = KIO::del(url);
0361     KJobWidgets::setWindow(job, window);
0362     connect(job, SIGNAL(result(KJob*)),
0363             this, SLOT(slotResult(KJob*)));
0364     enter_loop();
0365     return d->bJobOK;
0366 }
0367 
0368 bool NetAccess::mkdirInternal(const QUrl &url, int permissions,
0369                               QWidget *window)
0370 {
0371     d->bJobOK = true; // success unless further error occurs
0372     KIO::Job *job = KIO::mkdir(url, permissions);
0373     KJobWidgets::setWindow(job, window);
0374     connect(job, SIGNAL(result(KJob*)),
0375             this, SLOT(slotResult(KJob*)));
0376     enter_loop();
0377     return d->bJobOK;
0378 }
0379 
0380 QString NetAccess::mimetypeInternal(const QUrl &url, QWidget *window)
0381 {
0382     d->bJobOK = true; // success unless further error occurs
0383     d->m_mimetype = QLatin1String("unknown");
0384     KIO::Job *job = KIO::mimetype(url);
0385     KJobWidgets::setWindow(job, window);
0386     connect(job, SIGNAL(result(KJob*)),
0387             this, SLOT(slotResult(KJob*)));
0388     connect(job, SIGNAL(mimetype(KIO::Job*,QString)),
0389             this, SLOT(slotMimetype(KIO::Job*,QString)));
0390     enter_loop();
0391     return d->m_mimetype;
0392 }
0393 
0394 void NetAccess::slotMimetype(KIO::Job *, const QString &type)
0395 {
0396     d->m_mimetype = type;
0397 }
0398 
0399 QString NetAccess::fish_executeInternal(const QUrl &url, const QString &command, QWidget *window)
0400 {
0401     QString target, remoteTempFileName, resultData;
0402     QTemporaryFile tmpFile;
0403     tmpFile.open();
0404 
0405     if (url.scheme() == "fish") {
0406         // construct remote temp filename
0407         QUrl tempPathUrl = url;
0408         remoteTempFileName = tmpFile.fileName();
0409         // We only need the filename. The directory might not exist on the remote side.
0410         int pos = remoteTempFileName.lastIndexOf('/');
0411         remoteTempFileName = "/tmp/fishexec_" + remoteTempFileName.mid(pos + 1);
0412         tempPathUrl.setPath(remoteTempFileName);
0413         d->bJobOK = true; // success unless further error occurs
0414         QByteArray packedArgs;
0415         QDataStream stream(&packedArgs, QIODevice::WriteOnly);
0416 
0417         stream << int('X') << tempPathUrl << command;
0418 
0419         KIO::Job *job = KIO::special(tempPathUrl, packedArgs);
0420         KJobWidgets::setWindow(job, window);
0421         connect(job, SIGNAL(result(KJob*)),
0422                 this, SLOT(slotResult(KJob*)));
0423         enter_loop();
0424 
0425         // since the KIO::special does not provide feedback we need to download the result
0426         if (NetAccess::download(tempPathUrl, target, window)) {
0427             QFile resultFile(target);
0428 
0429             if (resultFile.open(QIODevice::ReadOnly)) {
0430                 QTextStream ts(&resultFile);   // default encoding is Locale
0431                 resultData = ts.readAll();
0432                 resultFile.close();
0433                 NetAccess::del(tempPathUrl, window);
0434             }
0435         }
0436     } else {
0437         resultData = i18n("ERROR: Unknown protocol '%1'", url.scheme());
0438     }
0439     return resultData;
0440 }
0441 
0442 bool NetAccess::synchronousRunInternal(Job *job, QWidget *window, QByteArray *data,
0443                                        QUrl *finalURL, QMap<QString, QString> *metaData)
0444 {
0445     KJobWidgets::setWindow(job, window);
0446 
0447     d->m_metaData = metaData;
0448     if (d->m_metaData) {
0449         for (QMap<QString, QString>::iterator it = d->m_metaData->begin(); it != d->m_metaData->end(); ++it) {
0450             job->addMetaData(it.key(), it.value());
0451         }
0452     }
0453 
0454     if (finalURL) {
0455         SimpleJob *sj = qobject_cast<SimpleJob *>(job);
0456         if (sj) {
0457             d->m_url = sj->url();
0458         }
0459     }
0460 
0461     connect(job, SIGNAL(result(KJob*)),
0462             this, SLOT(slotResult(KJob*)));
0463 
0464     const QMetaObject *meta = job->metaObject();
0465 
0466     static const char dataSignal[] = "data(KIO::Job*,QByteArray)";
0467     if (meta->indexOfSignal(dataSignal) != -1) {
0468         connect(job, SIGNAL(data(KIO::Job*,QByteArray)),
0469                 this, SLOT(slotData(KIO::Job*,QByteArray)));
0470     }
0471 
0472     static const char redirSignal[] = "redirection(KIO::Job*,QUrl)";
0473     if (meta->indexOfSignal(redirSignal) != -1) {
0474         connect(job, SIGNAL(redirection(KIO::Job*,QUrl)),
0475                 this, SLOT(slotRedirection(KIO::Job*,QUrl)));
0476     }
0477 
0478     enter_loop();
0479 
0480     if (finalURL) {
0481         *finalURL = d->m_url;
0482     }
0483     if (data) {
0484         *data = d->m_data;
0485     }
0486 
0487     return d->bJobOK;
0488 }
0489 
0490 void NetAccess::enter_loop()
0491 {
0492     QEventLoop eventLoop;
0493     connect(this, SIGNAL(leaveModality()),
0494             &eventLoop, SLOT(quit()));
0495     eventLoop.exec(QEventLoop::ExcludeUserInputEvents);
0496 }
0497 
0498 void NetAccess::slotResult(KJob *job)
0499 {
0500     lastErrorCode = job->error();
0501     d->bJobOK = !job->error();
0502     if (!d->bJobOK) {
0503         if (!lastErrorMsg) {
0504             lastErrorMsg = new QString;
0505         }
0506         *lastErrorMsg = job->errorString();
0507     }
0508     KIO::StatJob *statJob = qobject_cast<KIO::StatJob *>(job);
0509     if (statJob) {
0510         d->m_entry = statJob->statResult();
0511     }
0512 
0513     KIO::Job *kioJob = qobject_cast<KIO::Job *>(job);
0514     if (kioJob && d->m_metaData) {
0515         *d->m_metaData = kioJob->metaData();
0516     }
0517 
0518     emit leaveModality();
0519 }
0520 
0521 void NetAccess::slotData(KIO::Job *, const QByteArray &data)
0522 {
0523     if (data.isEmpty()) {
0524         return;
0525     }
0526 
0527     unsigned offset = d->m_data.size();
0528     d->m_data.resize(offset + data.size());
0529     std::memcpy(d->m_data.data() + offset, data.data(), data.size());
0530 }
0531 
0532 void NetAccess::slotRedirection(KIO::Job *, const QUrl &url)
0533 {
0534     d->m_url = url;
0535 }
0536