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