File indexing completed on 2024-04-14 04:52:02

0001 /***************************************************************************
0002  *   Copyright (C) 2007-2014 Lukas Appelhans <l.appelhans@gmx.de>          *
0003  *   Copyright (C) 2008 Dario Freddi <drf54321@gmail.com>                  *
0004  *   Copyright (C) 2010 Matthias Fuchs <mat69@gmx.net>                     *
0005  *                                                                         *
0006  *   This program is free software; you can redistribute it and/or modify  *
0007  *   it under the terms of the GNU General Public License as published by  *
0008  *   the Free Software Foundation; either version 2 of the License, or     *
0009  *   (at your option) any later version.                                   *
0010  *                                                                         *
0011  *   This program is distributed in the hope that it will be useful,       *
0012  *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
0013  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
0014  *   GNU General Public License for more details.                          *
0015  *                                                                         *
0016  *   You should have received a copy of the GNU General Public License     *
0017  *   along with this program; if not, write to the                         *
0018  *   Free Software Foundation, Inc.,                                       *
0019  *   51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA .        *
0020  ***************************************************************************/
0021 
0022 #include "urlchecker.h"
0023 #include "core/filedeleter.h"
0024 #include "core/kget.h"
0025 #include "core/transferhandler.h"
0026 #include "core/transfertreemodel.h"
0027 #include "mainwindow.h"
0028 #include "settings.h"
0029 #include "urlchecker_p.h"
0030 
0031 #include <algorithm>
0032 #include <boost/bind/bind.hpp>
0033 
0034 #include "kget_debug.h"
0035 
0036 #include <QCheckBox>
0037 #include <QDialogButtonBox>
0038 #include <QFileInfo>
0039 #include <QHBoxLayout>
0040 #include <QLabel>
0041 #include <QPushButton>
0042 
0043 #include <KIO/RenameDialog>
0044 #include <KLocalizedString>
0045 #include <KSeparator>
0046 #include <KStandardGuiItem>
0047 
0048 ExistingTransferDialog::ExistingTransferDialog(const QString &text, const QString &caption, QWidget *parent)
0049     : QDialog(parent)
0050 {
0051     setWindowTitle(caption.isEmpty() ? i18n("Question") : caption);
0052     setModal(true);
0053 
0054     auto *layout = new QVBoxLayout;
0055     auto *bottomLayout = new QHBoxLayout;
0056 
0057     auto *label = new QLabel(text, this);
0058     layout->addWidget(label);
0059     layout->addWidget(new KSeparator(Qt::Horizontal, this));
0060 
0061     m_applyAll = new QCheckBox(i18n("Appl&y to all"), this);
0062     bottomLayout->addStretch(1);
0063     bottomLayout->addWidget(m_applyAll);
0064 
0065     auto *buttonBox = new QDialogButtonBox(this);
0066     buttonBox->setStandardButtons(QDialogButtonBox::Yes | QDialogButtonBox::No | QDialogButtonBox::Cancel);
0067     connect(buttonBox->button(QDialogButtonBox::Yes), &QPushButton::clicked, this, &ExistingTransferDialog::slotYesClicked);
0068     connect(buttonBox->button(QDialogButtonBox::No), &QPushButton::clicked, this, &ExistingTransferDialog::slotNoClicked);
0069     connect(buttonBox->button(QDialogButtonBox::Cancel), &QPushButton::clicked, this, &ExistingTransferDialog::slotCancelClicked);
0070     bottomLayout->addWidget(buttonBox);
0071     layout->addLayout(bottomLayout, 0);
0072 
0073     setLayout(layout);
0074 }
0075 
0076 void ExistingTransferDialog::slotYesClicked()
0077 {
0078     done(m_applyAll->isChecked() ? YesAll : Yes);
0079 }
0080 
0081 void ExistingTransferDialog::slotNoClicked()
0082 {
0083     done(m_applyAll->isChecked() ? NoAll : No);
0084 }
0085 
0086 void ExistingTransferDialog::slotCancelClicked()
0087 {
0088     done(Cancel);
0089 }
0090 
0091 UrlChecker::UrlChecker(UrlType type)
0092     : m_type(type)
0093     , m_cancel(false)
0094     , m_overwriteAll(false)
0095     , m_autoRenameAll(false)
0096     , m_skipAll(false)
0097 {
0098 }
0099 
0100 UrlChecker::~UrlChecker()
0101 {
0102 }
0103 
0104 /// Static methods following
0105 
0106 struct lessThan {
0107     bool operator()(const QUrl &lhs, const QUrl &rhs) const
0108     {
0109         return lhs.url() < rhs.url();
0110     }
0111 };
0112 
0113 void UrlChecker::removeDuplicates(QList<QUrl> &urls)
0114 {
0115     std::sort(urls.begin(), urls.end(), lessThan()); // sort the urls, to find duplicates fast
0116     urls.erase(
0117         std::unique(urls.begin(),
0118                     urls.end(),
0119                     boost::bind(&QUrl::matches, boost::placeholders::_1, boost::placeholders::_2, QUrl::StripTrailingSlash | QUrl::NormalizePathSegments)),
0120         urls.end());
0121 }
0122 
0123 UrlChecker::UrlError UrlChecker::checkUrl(const QUrl &url, const UrlChecker::UrlType type, bool showNotification)
0124 {
0125     switch (type) {
0126     case Source:
0127         return checkSource(url, showNotification);
0128     case Destination:
0129         return checkDestination(url, showNotification);
0130     case Folder:
0131         return checkFolder(url, showNotification);
0132     }
0133 
0134     return NoError;
0135 }
0136 
0137 bool UrlChecker::wouldOverwrite(const QUrl &source, const QUrl &dest)
0138 {
0139     return (dest.isLocalFile() && QFile::exists(dest.toLocalFile()) && source != dest && !FileDeleter::isFileBeingDeleted(dest));
0140 }
0141 
0142 UrlChecker::UrlError UrlChecker::checkSource(const QUrl &src, bool showNotification)
0143 {
0144     // NOTE hasPath is not used, as this would disallow addresses like https://www.kde.org/ as there is no path
0145     UrlError error = NoError;
0146     if (src.isEmpty()) {
0147         return Empty;
0148     }
0149     if ((error == NoError) && !src.isValid()) {
0150         error = Invalid;
0151     }
0152     if ((error == NoError) && src.scheme().isEmpty()) {
0153         error = NoProtocol;
0154     }
0155     /*if ((error == NoError) && !src.hasHost()) {//FIXME deactivated to allow file://....metalink etc
0156         error = NoHost;
0157     }*/
0158 
0159     if (showNotification && (error != NoError)) {
0160         qCDebug(KGET_DEBUG) << "Source:" << src << "has error:" << error;
0161         KGet::showNotification("error", message(src, Source, error));
0162     }
0163 
0164     // TODO also check sourceUrl.url() != QUrl(sourceUrl.url()).fileName() as in NewTransferDialog::setSource?
0165 
0166     return error;
0167 }
0168 
0169 UrlChecker::UrlError UrlChecker::checkDestination(const QUrl &destination, bool showNotification)
0170 {
0171     UrlError error = NoError;
0172 
0173     if (destination.isEmpty()) {
0174         error = Empty;
0175     }
0176 
0177     if (error == NoError) {
0178         // not supposed to be a folder
0179         QFileInfo fileInfo(destination.toLocalFile());
0180         if (!destination.isValid() || fileInfo.isDir()) {
0181             error = Invalid;
0182         }
0183 
0184         qDebug() << "Adjusted destination:" << destination.adjusted(QUrl::RemoveFilename).path();
0185         if ((error == NoError) && !QFileInfo(destination.adjusted(QUrl::RemoveFilename).path()).isWritable()) {
0186             error = NotWriteable;
0187         }
0188     }
0189 
0190     qCDebug(KGET_DEBUG) << "Destination:" << destination << "has error:" << error;
0191 
0192     if (showNotification && (error != NoError)) {
0193         KGet::showNotification("error", message(destination, Destination, error));
0194     }
0195 
0196     return error;
0197 }
0198 
0199 UrlChecker::UrlError UrlChecker::checkFolder(const QUrl &folder, bool showNotification)
0200 {
0201     UrlError error = NoError;
0202 
0203     const QString destDir = folder.toLocalFile();
0204     if (folder.isEmpty() || destDir.isEmpty()) {
0205         error = Empty;
0206     }
0207 
0208     if (error == NoError) {
0209         // has to be a folder
0210         QFileInfo fileInfo(destDir);
0211         if (!folder.isValid() || !fileInfo.isDir()) {
0212             error = Invalid;
0213         }
0214 
0215         // has to be writeable
0216         if ((error == NoError) && !fileInfo.isWritable()) {
0217             error = NotWriteable;
0218         }
0219     }
0220 
0221     if (showNotification && (error != NoError)) {
0222         qCDebug(KGET_DEBUG) << "Folder:" << folder << "has error:" << error;
0223         KGet::showNotification("error", message(folder, Folder, error));
0224     }
0225 
0226     return error;
0227 }
0228 
0229 QUrl UrlChecker::destUrl(const QUrl &destOrFolder, const QUrl &source, const QString &fileName)
0230 {
0231     QUrl dest = destOrFolder;
0232     if (QFileInfo(dest.toLocalFile()).isDir()) {
0233         QString usedFileName = (fileName.isEmpty() ? source.fileName() : fileName);
0234         if (usedFileName.isEmpty()) {
0235             usedFileName = QUrl::toPercentEncoding(source.toString(), "/");
0236         }
0237         if (!dest.path().endsWith('/'))
0238             dest.setPath(dest.path() + '/');
0239         dest.setPath(dest.adjusted(QUrl::RemoveFilename).path() + usedFileName);
0240     } else if (!fileName.isEmpty()) {
0241         dest.setPath(dest.adjusted(QUrl::RemoveFilename).path() + fileName);
0242     }
0243 
0244     return dest;
0245 }
0246 
0247 TransferHandler *UrlChecker::existingTransfer(const QUrl &url, const UrlChecker::UrlType type, UrlChecker::UrlWarning *warning)
0248 {
0249     UrlWarning temp;
0250     UrlWarning &warn = (warning ? (*warning) : temp);
0251     warn = NoWarning;
0252 
0253     switch (type) {
0254     case Source:
0255         return existingSource(url, warn);
0256     case Destination:
0257         return existingDestination(url, warn);
0258     default:
0259         return nullptr;
0260     }
0261 }
0262 
0263 TransferHandler *UrlChecker::existingSource(const QUrl &source, UrlChecker::UrlWarning &warning)
0264 {
0265     // Check if a transfer with the same url already exists
0266     Transfer *transfer = KGet::m_transferTreeModel->findTransfer(source);
0267     if (transfer) {
0268         if (transfer->status() == Job::Finished) {
0269             warning = ExistingFinishedTransfer;
0270         } else {
0271             warning = ExistingTransfer;
0272         }
0273     }
0274 
0275     return (transfer ? transfer->handler() : nullptr);
0276 }
0277 
0278 TransferHandler *UrlChecker::existingDestination(const QUrl &url, UrlChecker::UrlWarning &warning)
0279 {
0280     Transfer *transfer = KGet::m_transferTreeModel->findTransferByDestination(url);
0281     if (transfer) {
0282         if (transfer->status() == Job::Finished) {
0283             warning = ExistingFinishedTransfer;
0284         } else {
0285             warning = ExistingTransfer;
0286         }
0287     } else if (QFile::exists(url.toString())) {
0288         warning = ExistingFile;
0289     }
0290 
0291     return (transfer ? transfer->handler() : nullptr);
0292 }
0293 
0294 QString UrlChecker::message(const QUrl &url, const UrlChecker::UrlType type, const UrlChecker::UrlError error)
0295 {
0296     if (url.isEmpty()) {
0297         if (type == Folder) {
0298             switch (error) {
0299             case Empty:
0300                 return i18n("No download directory specified.");
0301             case Invalid:
0302                 return i18n("Invalid download directory specified.");
0303             case NotWriteable:
0304                 return i18n("Download directory is not writeable.");
0305             default:
0306                 return QString();
0307             }
0308         }
0309         if (type == Destination) {
0310             switch (error) {
0311             case Empty:
0312                 return i18n("No download destination specified.");
0313             case Invalid:
0314                 return i18n("Invalid download destination specified.");
0315             case NotWriteable:
0316                 return i18n("Download destination is not writeable.");
0317             default:
0318                 return QString();
0319             }
0320         }
0321         if (type == Source) {
0322             switch (error) {
0323             case Empty:
0324                 return i18n("No URL specified.");
0325             case Invalid:
0326                 return i18n("Malformed URL.");
0327             case NoProtocol:
0328                 return i18n("Malformed URL, protocol missing.");
0329             case NoHost:
0330                 return i18n("Malformed URL, host missing.");
0331             default:
0332                 return QString();
0333             }
0334         }
0335     } else {
0336         const QString urlString = url.toString();
0337         if (type == Folder) {
0338             switch (error) {
0339             case Empty:
0340                 return i18n("No download directory specified.");
0341             case Invalid:
0342                 return i18n("Invalid download directory specified:\n%1", urlString);
0343             case NotWriteable:
0344                 return i18n("Download directory is not writeable:\n%1", urlString);
0345             default:
0346                 return QString();
0347             }
0348         }
0349         if (type == Destination) {
0350             switch (error) {
0351             case Empty:
0352                 return i18n("No download destination specified.");
0353             case Invalid:
0354                 return i18n("Invalid download destination specified:\n%1", urlString);
0355             case NotWriteable:
0356                 return i18n("Download destination is not writeable:\n%1", urlString);
0357             default:
0358                 return QString();
0359             }
0360         }
0361         if (type == Source) {
0362             switch (error) {
0363             case Empty:
0364                 return i18n("No URL specified.");
0365             case Invalid:
0366                 return i18n("Malformed URL:\n%1", urlString);
0367             case NoProtocol:
0368                 return i18n("Malformed URL, protocol missing:\n%1", urlString);
0369             case NoHost:
0370                 return i18n("Malformed URL, host missing:\n%1", urlString);
0371             default:
0372                 return QString();
0373             }
0374         }
0375     }
0376 
0377     return QString();
0378 }
0379 
0380 QString UrlChecker::message(const QUrl &url, const UrlChecker::UrlType type, const UrlChecker::UrlWarning warning)
0381 {
0382     if (url.isEmpty()) {
0383         if (type == Destination) {
0384             switch (warning) {
0385             case ExistingFile:
0386                 return i18n("File already exists. Overwrite it?");
0387             case ExistingFinishedTransfer:
0388                 return i18n("You have already downloaded that file from another location.\nDownload and delete the previous one?");
0389             case ExistingTransfer:
0390                 return i18n("You are already downloading that file from another location.\nDownload and delete the previous one?");
0391             default:
0392                 return QString();
0393             }
0394         }
0395         if (type == Source) {
0396             switch (warning) {
0397             case ExistingFile:
0398                 return i18n("File already exists. Overwrite it?");
0399             case ExistingFinishedTransfer:
0400                 return i18n("You have already completed a download from that location. Download it again?");
0401             case ExistingTransfer:
0402                 return i18n("You have a download in progress from that location.\nDelete it and download again?");
0403             default:
0404                 return QString();
0405             }
0406         }
0407     } else {
0408         const QString urlString = url.toString();
0409         if (type == Destination) {
0410             switch (warning) {
0411             case ExistingFile:
0412                 return i18n("File already exists:\n%1\nOverwrite it?", urlString);
0413             case ExistingFinishedTransfer:
0414                 return i18n("You have already downloaded that file from another location.\nDownload and delete the previous one?");
0415             case ExistingTransfer:
0416                 return i18n("You are already downloading that file from another location.\nDownload and delete the previous one?");
0417             default:
0418                 return QString();
0419             }
0420         }
0421         if (type == Source) {
0422             switch (warning) {
0423             case ExistingFinishedTransfer:
0424                 return i18n("You have already completed a download from the location: \n\n%1\n\nDownload it again?", urlString);
0425             case ExistingTransfer:
0426                 return i18n("You have a download in progress from the location: \n\n%1\n\nDelete it and download again?", urlString);
0427             default:
0428                 return QString();
0429             }
0430         }
0431     }
0432 
0433     return QString();
0434 }
0435 
0436 QString UrlChecker::message(const QList<QUrl> &urls, const UrlChecker::UrlType type, const UrlChecker::UrlError error)
0437 {
0438     QString urlsString;
0439     if (!urls.isEmpty()) {
0440         urlsString = urls.first().toString();
0441         for (int i = 1; i < urls.count(); ++i) {
0442             urlsString += '\n' + urls[i].toString();
0443         }
0444         urlsString = QString("<p style=\"font-size: small;\">\%1</p>").arg(urlsString);
0445     }
0446 
0447     if (urls.isEmpty()) {
0448         if ((type == Folder) || (type == Destination)) {
0449             return message(QUrl(), type, error);
0450         }
0451         if (type == Source) {
0452             switch (error) {
0453             case Empty:
0454                 return i18n("No URL specified.");
0455             case Invalid:
0456                 return i18n("Malformed URLs.");
0457             case NoProtocol:
0458                 return i18n("Malformed URLs, protocol missing.");
0459             case NoHost:
0460                 return i18n("Malformed URLs, host missing.");
0461             default:
0462                 return QString();
0463             }
0464         }
0465     } else {
0466         switch (error) {
0467         case Empty:
0468             return i18n("No URL specified.");
0469         case Invalid:
0470             return i18n("Malformed URLs:\n%1", urlsString);
0471         case NoProtocol:
0472             return i18n("Malformed URLs, protocol missing:\n%1", urlsString);
0473         case NoHost:
0474             return i18n("Malformed URLs, host missing:\n%1", urlsString);
0475         case NotWriteable:
0476             return i18n("Destinations are not writable:\n%1", urlsString);
0477         default:
0478             return QString();
0479         }
0480     }
0481 
0482     return QString();
0483 }
0484 
0485 QString UrlChecker::message(const QList<QUrl> &urls, const UrlChecker::UrlType type, const UrlChecker::UrlWarning warning)
0486 {
0487     QString urlsString;
0488     if (!urls.isEmpty()) {
0489         urlsString = urls.first().toString();
0490         for (int i = 1; i < urls.count(); ++i) {
0491             urlsString += '\n' + urls[i].toString();
0492         }
0493         urlsString = QString("<p style=\"font-size: small;\">\%1</p>").arg(urlsString);
0494     }
0495 
0496     if (urls.isEmpty()) {
0497         if (type == Destination) {
0498             switch (warning) {
0499             case ExistingFile:
0500                 return i18n("Files exist already. Overwrite them?");
0501             case ExistingFinishedTransfer:
0502                 return i18n("You have already completed downloads at those destinations. Download them again?");
0503             case ExistingTransfer:
0504                 return i18n("You have downloads in progress to these destinations.\nDelete them and download again?");
0505             default:
0506                 return QString();
0507             }
0508         }
0509         if (type == Source) {
0510             switch (warning) {
0511             case ExistingFinishedTransfer:
0512                 return i18n("You have already completed downloads from these locations. Download them again?");
0513             case ExistingTransfer:
0514                 return i18n("You have downloads in progress from these locations.\nDelete them and download again?");
0515             default:
0516                 return QString();
0517             }
0518         }
0519     } else {
0520         if (type == Destination) {
0521             switch (warning) {
0522             case ExistingFile:
0523                 return i18n("Files exist already:\n%1\nOverwrite them?", urlsString);
0524             case ExistingFinishedTransfer:
0525                 return i18n("You have already completed downloads at those destinations: \n\n%1\n\n Download them again?", urlsString);
0526             case ExistingTransfer:
0527                 return i18n("You have downloads in progress to these destinations: \n\n%1\n\nDelete them and download again?", urlsString);
0528             default:
0529                 return QString();
0530             }
0531         }
0532         if (type == Source) {
0533             switch (warning) {
0534             case ExistingFinishedTransfer:
0535                 return i18n("You have already completed downloads from these locations: \n\n%1\n\nDownload them again?", urlsString);
0536             case ExistingTransfer:
0537                 return i18n("You have downloads in progress from these locations: \n\n%1\n\nDelete them and download again?", urlsString);
0538             default:
0539                 QString();
0540             }
0541         }
0542     }
0543 
0544     return QString();
0545 }
0546 
0547 QList<QUrl> UrlChecker::hasExistingTransferMessages(const QList<QUrl> &urls, const UrlChecker::UrlType type)
0548 {
0549     UrlWarning warning;
0550     QHash<UrlWarning, QList<QPair<QUrl, TransferHandler *>>> splitWarnings;
0551     QList<QUrl> urlsToDownload;
0552 
0553     // collect all errors
0554     foreach (const QUrl &url, urls) {
0555         TransferHandler *transfer = existingTransfer(url, type, &warning);
0556         if (transfer) {
0557             splitWarnings[warning] << qMakePair(url, transfer);
0558         } else {
0559             urlsToDownload << url;
0560         }
0561     }
0562 
0563     // First ask about unfinished existing transfers
0564     QList<QPair<QUrl, TransferHandler *>>::const_iterator it;
0565     QList<QPair<QUrl, TransferHandler *>>::const_iterator itEnd;
0566     QList<UrlWarning> orderOfExecution;
0567     QList<TransferHandler *> toDelete;
0568     orderOfExecution << ExistingTransfer << ExistingFinishedTransfer;
0569     for (int i = 0; i < orderOfExecution.count(); ++i) {
0570         warning = orderOfExecution[i];
0571         if (splitWarnings.contains(warning)) {
0572             QList<QPair<QUrl, TransferHandler *>> existing = splitWarnings[warning];
0573             itEnd = existing.constEnd();
0574             bool isYesAll = false;
0575             bool isNoAll = false;
0576             for (it = existing.constBegin(); it != itEnd; ++it) {
0577                 if (isYesAll) {
0578                     urlsToDownload << it->first;
0579                     toDelete << it->second;
0580                     continue;
0581                 }
0582 
0583                 if (isNoAll) {
0584                     break;
0585                 }
0586 
0587                 int result;
0588                 if (Settings::filesOverwrite() || (Settings::filesAutomaticRename() && (warning != ExistingTransfer))) {
0589                     result = ExistingTransferDialog::ExistingDialogReturn::YesAll;
0590                 } else {
0591                     result = hasExistingDialog(it->first, type, warning);
0592                 }
0593                 switch (result) {
0594                 case ExistingTransferDialog::ExistingDialogReturn::YesAll:
0595                     isYesAll = true;
0596                     // fallthrough
0597                 case ExistingTransferDialog::ExistingDialogReturn::Yes:
0598                     urlsToDownload << it->first;
0599                     toDelete << it->second;
0600                     break;
0601                 case ExistingTransferDialog::ExistingDialogReturn::NoAll:
0602                     isNoAll = true;
0603                 case ExistingTransferDialog::ExistingDialogReturn::No:
0604                     break;
0605                 case ExistingTransferDialog::ExistingDialogReturn::Cancel:
0606                 default:
0607                     removeTransfers(toDelete);
0608                     return urlsToDownload;
0609                 }
0610             }
0611         }
0612     }
0613 
0614     removeTransfers(toDelete);
0615     return urlsToDownload;
0616 }
0617 
0618 void UrlChecker::removeTransfers(const QList<TransferHandler *> &toRemove)
0619 {
0620     QList<TransferHandler *> transfers = toRemove;
0621     transfers.removeAll(nullptr);
0622     if (!transfers.isEmpty()) {
0623         KGet::delTransfers(transfers);
0624     }
0625 }
0626 
0627 int UrlChecker::hasExistingDialog(const QUrl &url, const UrlChecker::UrlType type, const UrlChecker::UrlWarning warning)
0628 {
0629     QWidget *parent = KGet::m_mainWindow;
0630 
0631     // getting the caption
0632     QString caption;
0633     if (type == Source) {
0634         switch (warning) {
0635         case ExistingFinishedTransfer:
0636             caption = i18n("Delete it and download again?");
0637             break;
0638         case ExistingTransfer:
0639             caption = i18n("Download it again?");
0640             break;
0641         default:
0642             break;
0643         }
0644     } else if (type == Destination) {
0645         switch (warning) {
0646         case ExistingFinishedTransfer:
0647         case ExistingTransfer:
0648             caption = i18n("File already downloaded. Download anyway?");
0649             break;
0650         case ExistingFile:
0651             caption = i18n("File already exists");
0652             break;
0653         default:
0654             break;
0655         }
0656     }
0657 
0658     QScopedPointer<QDialog> dialog(new ExistingTransferDialog(message(url, type, warning), caption, parent));
0659 
0660     return dialog->exec();
0661 }
0662 
0663 /// Non static methods following
0664 
0665 void UrlChecker::clear()
0666 {
0667     m_correctUrls.clear();
0668     m_splitErrorUrls.clear();
0669     m_cancel = false;
0670     m_overwriteAll = false;
0671     m_autoRenameAll = false;
0672     m_skipAll = false;
0673 }
0674 
0675 UrlChecker::UrlType UrlChecker::type() const
0676 {
0677     return m_type;
0678 }
0679 
0680 void UrlChecker::setType(UrlChecker::UrlType type)
0681 {
0682     clear();
0683     m_type = type;
0684 }
0685 
0686 UrlChecker::UrlError UrlChecker::addUrl(const QUrl &url)
0687 {
0688     const UrlError error = checkUrl(url, m_type);
0689     if (error == NoError) {
0690         m_correctUrls << url;
0691     } else {
0692         m_splitErrorUrls[error] << url;
0693     }
0694 
0695     return error;
0696 }
0697 
0698 bool UrlChecker::addUrls(const QList<QUrl> &urls)
0699 {
0700     bool worked = true;
0701     foreach (const QUrl &url, urls) {
0702         const UrlError error = addUrl(url);
0703         if (error != NoError) {
0704             worked = false;
0705         }
0706     }
0707 
0708     return worked;
0709 }
0710 
0711 void UrlChecker::existingTransfers()
0712 {
0713     m_correctUrls = hasExistingTransferMessages(correctUrls(), m_type);
0714 }
0715 
0716 QUrl UrlChecker::checkExistingFile(const QUrl &source, const QUrl &destination)
0717 {
0718     QUrl newDestination = destination;
0719 
0720     // any url is ignored
0721     if (m_cancel) {
0722         return QUrl();
0723     }
0724 
0725     if (Settings::filesOverwrite()) {
0726         m_overwriteAll = true;
0727     } else if (Settings::filesAutomaticRename()) {
0728         m_autoRenameAll = true;
0729     }
0730 
0731     if (wouldOverwrite(source, destination)) {
0732         KIO::RenameDialog_Options args = KIO::RenameDialog_MultipleItems | KIO::RenameDialog_Skip | KIO::RenameDialog_Overwrite;
0733         QScopedPointer<KIO::RenameDialog> dlg(new KIO::RenameDialog(KGet::m_mainWindow, i18n("File already exists"), source, destination, args));
0734 
0735         /// in the following cases no dialog needs to be shown
0736         if (m_skipAll) { // only existing are ignored
0737             return QUrl();
0738         } else if (m_overwriteAll) {
0739             FileDeleter::deleteFile(newDestination);
0740             return newDestination;
0741         } else if (m_autoRenameAll) {
0742             newDestination = dlg->autoDestUrl();
0743             return newDestination;
0744         }
0745 
0746         /// now show the dialog and look at the result
0747         const int result = dlg->exec();
0748         switch (result) {
0749         case KIO::Result_Overwrite: {
0750             // delete the file, that way it won't show up in future calls of this method
0751             FileDeleter::deleteFile(newDestination);
0752             return newDestination;
0753         }
0754         case KIO::Result_OverwriteAll: {
0755             // delete the file, that way it won't show up in future calls of this method
0756             FileDeleter::deleteFile(newDestination);
0757             m_overwriteAll = true;
0758             return newDestination;
0759         }
0760         case KIO::Result_Rename:
0761             // call it again, as there is no check on the user input
0762             return checkExistingFile(source, dlg->newDestUrl());
0763         case KIO::Result_AutoRename:
0764             newDestination = dlg->autoDestUrl();
0765             m_autoRenameAll = true;
0766             return newDestination;
0767         case KIO::Result_Skip:
0768             return QUrl();
0769         case KIO::Result_AutoSkip:
0770             m_skipAll = true;
0771             return QUrl();
0772         case KIO::Result_Cancel:
0773             m_cancel = true;
0774             return QUrl();
0775         default:
0776             return QUrl();
0777         }
0778     }
0779 
0780     return newDestination;
0781 }
0782 
0783 QList<QUrl> UrlChecker::correctUrls() const
0784 {
0785     return m_correctUrls;
0786 }
0787 
0788 QList<QUrl> UrlChecker::errorUrls() const
0789 {
0790     QList<QUrl> urls;
0791 
0792     QHash<UrlChecker::UrlError, QList<QUrl>>::const_iterator it;
0793     QHash<UrlChecker::UrlError, QList<QUrl>>::const_iterator itEnd = m_splitErrorUrls.constEnd();
0794     for (it = m_splitErrorUrls.constBegin(); it != itEnd; ++it) {
0795         urls << (*it);
0796     }
0797 
0798     return urls;
0799 }
0800 
0801 QHash<UrlChecker::UrlError, QList<QUrl>> UrlChecker::splitErrorUrls() const
0802 {
0803     return m_splitErrorUrls;
0804 }
0805 
0806 void UrlChecker::displayErrorMessages()
0807 {
0808     QHash<UrlChecker::UrlError, QList<QUrl>>::const_iterator it;
0809     QHash<UrlChecker::UrlError, QList<QUrl>>::const_iterator itEnd = m_splitErrorUrls.constEnd();
0810     for (it = m_splitErrorUrls.constBegin(); it != itEnd; ++it) {
0811         QString m;
0812         if (it->count() > 1) {
0813             m = message(*it, m_type, it.key());
0814         } else if (!it->isEmpty()) {
0815             m = message(it->first(), m_type, it.key());
0816         }
0817 
0818         if (!m.isEmpty()) {
0819             KGet::showNotification("error", m);
0820         }
0821     }
0822 }
0823 
0824 #include "moc_urlchecker_p.cpp"