diff options
Diffstat (limited to 'src/webtab/protocolhandler.cpp')
-rw-r--r-- | src/webtab/protocolhandler.cpp | 386 |
1 files changed, 386 insertions, 0 deletions
diff --git a/src/webtab/protocolhandler.cpp b/src/webtab/protocolhandler.cpp new file mode 100644 index 00000000..186b93d3 --- /dev/null +++ b/src/webtab/protocolhandler.cpp @@ -0,0 +1,386 @@ +/* ============================================================ +* +* This file is a part of the rekonq project +* +* Copyright (C) 2010-2012 by Andrea Diamantini <adjam7 at gmail dot com> +* +* This program is free software; you can redistribute it and/or +* modify it under the terms of the GNU General Public License as +* published by the Free Software Foundation; either version 2 of +* the License or (at your option) version 3 or any later version +* accepted by the membership of KDE e.V. (or its successor approved +* by the membership of KDE e.V.), which shall act as a proxy +* defined in Section 14 of version 3 of the license. +* +* This program 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 General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program. If not, see <http://www.gnu.org/licenses/>. +* +* ============================================================ */ + + +// Self Includes +#include "protocolhandler.h" +#include "protocolhandler.moc" + +// Auto Includes +#include "rekonq.h" + +// Local Includes +#include "application.h" +#include "historymanager.h" +#include "mainview.h" +#include "mainwindow.h" +#include "newtabpage.h" +#include "urlbar.h" +#include "webpage.h" +#include "webtab.h" + +// KDE Includes +#include <KIO/Job> +#include <KDirLister> +#include <KLocale> +#include <KLocalizedString> +#include <KMessageBox> +#include <KProcess> +#include <KStandardDirs> +#include <KToolInvocation> +#include <KProtocolInfo> +#include <KRun> + +// Qt Includes +#include <QNetworkRequest> +#include <QWebFrame> +#include <QTextDocument> + + +static bool fileItemListLessThan(const KFileItem &s1, const KFileItem &s2) +{ + return s1.name().toLower() < s2.name().toLower(); +} + + +static KFileItemList sortFileList(const KFileItemList &list) +{ + KFileItemList orderedList, dirList, fileList; + + // order dirs before files.. + Q_FOREACH(const KFileItem & item, list) + { + if (item.isDir()) + dirList << item; + else + fileList << item; + } + qStableSort(dirList.begin(), dirList.end(), fileItemListLessThan); + qStableSort(fileList.begin(), fileList.end(), fileItemListLessThan); + + orderedList << dirList; + orderedList << fileList; + + return orderedList; +} + + +// ------------------------------------------------------------------------------------------- + + +ProtocolHandler::ProtocolHandler(QObject *parent) + : QObject(parent) + , _lister(new KDirLister(this)) + , _frame(0) +{ + _lister->setMainWindow(rApp->mainWindow()); +} + + +bool ProtocolHandler::preHandling(const QNetworkRequest &request, QWebFrame *frame) +{ + _url = request.url(); + _frame = frame; + + // javascript handling + if (_url.protocol() == QL1S("javascript")) + { + QString scriptSource = _url.authority(); + if (scriptSource.isEmpty()) + { + // if javascript:<code here> then authority() returns + // an empty string. Extract the source manually + // Use the prettyUrl() since that is unencoded + + // 11 is length of 'javascript:' + // fromPercentEncoding() is used to decode all the % encoded + // characters to normal, so that it is treated as valid javascript + scriptSource = QUrl::fromPercentEncoding(_url.url().mid(11).toAscii()); + if (scriptSource.isEmpty()) + return false; + } + + QVariant result = frame->evaluateJavaScript(scriptSource); + return true; + } + + // "about" handling + if (_url.protocol() == QL1S("about")) + { + QByteArray encodedUrl = _url.toEncoded(); + // let webkit manage the about:blank url... + if (encodedUrl.startsWith(QByteArray("about:blank"))) + { + return false; + } + + if (encodedUrl == QByteArray("about:home")) + { + switch (ReKonfig::newTabStartPage()) + { + case 0: // favorites + _url = KUrl("about:favorites"); + break; + case 1: // closed tabs + _url = KUrl("about:closedTabs"); + break; + case 2: // bookmarks + _url = KUrl("about:bookmarks"); + break; + case 3: // history + _url = KUrl("about:history"); + break; + case 4: // downloads + _url = KUrl("about:downloads"); + break; + case 5: // tabs + _url = KUrl("about:tabs"); + default: // unuseful + break; + } + } + + WebPage *page = qobject_cast<WebPage *>(frame->page()); + page->setIsOnRekonqPage(true); + + NewTabPage p(frame); + p.generate(_url); + + return true; + } + + // "mailto" handling: It needs to be handled both in preHandling (mail url launched) + // and in postHandling (mail links clicked) + if (_url.protocol() == QL1S("mailto")) + { + KToolInvocation::invokeMailer(_url); + return true; + } + + // "apt" handling + // NOTE: this is a stupid workaround to ensure apt protocol works + if (_url.protocol() == QL1S("apt")) + { + kDebug() << "APT URL: " << _url; + (void)new KRun(_url, rApp->mainWindow(), 0, _url.isLocalFile()); + return true; + } + + // let webkit try to load a known (or missing) protocol... + if (KProtocolInfo::isKnownProtocol(_url)) + return false; + + // Error Message, for those protocols we cannot handle + KMessageBox::error(rApp->mainWindow(), i18nc("@info", "rekonq does not know how to handle this protocol: %1", _url.protocol())); + + return true; +} + + +bool ProtocolHandler::postHandling(const QNetworkRequest &request, QWebFrame *frame) +{ + _url = request.url(); + _frame = frame; + + // "http(s)" (fast) handling + if (_url.protocol() == QL1S("http") || _url.protocol() == QL1S("https")) + return false; + + // "mailto" handling: It needs to be handled both here(mail links clicked) + // and in prehandling (mail url launched) + if (_url.protocol() == QL1S("mailto")) + { + KToolInvocation::invokeMailer(_url); + return true; + } + + // "ftp" handling. A little bit "hard" handling this. Hope I found + // the best solution. + // My idea is: webkit cannot handle in any way ftp. So we have surely to return true here. + // We start trying to guess what the url represent: it's a dir? show its contents (and download them). + // it's a file? download it. It's another thing? beat me, but I don't know what to do... + if (_url.protocol() == QL1S("ftp")) + { + KIO::StatJob *job = KIO::stat(_url); + connect(job, SIGNAL(result(KJob*)), this, SLOT(slotMostLocalUrlResult(KJob*))); + return true; + } + + // "file" handling. This is quite trivial :) + if (_url.protocol() == QL1S("file")) + { + QFileInfo fileInfo(_url.path()); + if (fileInfo.isDir()) + { + connect(_lister, SIGNAL(newItems(KFileItemList)), this, SLOT(showResults(KFileItemList))); + _lister->openUrl(_url); + + return true; + } + + return false; + } + + // we cannot handle this protocol in any way. + // Try KRunning it... + if (KProtocolInfo::isKnownProtocol(_url)) + { + (void)new KRun(_url, rApp->mainWindow(), 0, _url.isLocalFile()); + return true; + } + + return false; +} + + +// --------------------------------------------------------------------------------------------------------------------------- + + +void ProtocolHandler::showResults(const KFileItemList &list) +{ + if (!_lister->rootItem().isNull() && _lister->rootItem().isReadable() && _lister->rootItem().isFile()) + { + emit downloadUrl(_lister->rootItem().url()); + } + else + { + QString html = dirHandling(list); + _frame->setHtml(html); + qobject_cast<WebPage *>(_frame->page())->setIsOnRekonqPage(true); + + rApp->mainWindow()->mainView()->currentUrlBar()->setQUrl(_url); + rApp->mainWindow()->currentTab()->setFocus(); + rApp->historyManager()->addHistoryEntry(_url, _url.prettyUrl()); + } +} + + +QString ProtocolHandler::dirHandling(const KFileItemList &list) +{ + if (!_lister) + { + return QString("rekonq error, sorry :("); + } + + // let me modify it.. + KUrl rootUrl = _url; + + // display "rekonq info" page + QString infoFilePath = KStandardDirs::locate("data", "rekonq/htmls/rekonqinfo.html"); + QFile file(infoFilePath); + + bool isOpened = file.open(QIODevice::ReadOnly); + if (!isOpened) + { + return QString("rekonq error, sorry :("); + } + + // 1. default data path + QString dataPath = QL1S("file://") + infoFilePath; + dataPath.remove(QL1S("/htmls/rekonqinfo.html")); + + // 2. title + QString title = _url.prettyUrl(); + + // 3. main content + QString msg = i18nc("%1=an URL", "<h2>Index of %1</h2>", _url.prettyUrl()); + + + if (rootUrl.cd("..")) + { + QString path = rootUrl.prettyUrl(); + QString uparrow = KIconLoader::global()->iconPath("arrow-up", KIconLoader::Small); + msg += "<img src=\"file://" + uparrow + "\" alt=\"up-arrow\" />"; + msg += "<a href=\"" + path + "\">" + i18n("Up to higher level directory") + "</a><br /><br />"; + } + + msg += QL1S("<table width=\"95%\" align=\"center\">"); + msg += QL1S("<tr>"); + msg += QL1S("<th align=\"left\">") + i18n("Name") + QL1S("</th>"); + msg += QL1S("<th align=\"center\">") + i18n("Size") + QL1S("</th>"); + msg += QL1S("<th align=\"right\">") + i18n("Last Modified") + QL1S("</th>"); + msg += QL1S("</tr>"); + + KFileItemList orderedList = sortFileList(list); + Q_FOREACH(const KFileItem & item, orderedList) + { + msg += QL1S("<tr>"); + QString fullPath = Qt::escape(item.url().prettyUrl()); + + QString iconName = item.iconName(); + QString icon = QString("file://") + KIconLoader::global()->iconPath(iconName, KIconLoader::Small); + + msg += QL1S("<td width=\"70%\">"); + msg += QL1S("<img src=\"") + icon + QL1S("\" alt=\"") + iconName + QL1S("\" /> "); + msg += QL1S("<a href=\"") + fullPath + QL1S("\">") + Qt::escape(item.name()) + QL1S("</a>"); + msg += QL1S("</td>"); + + msg += QL1S("<td align=\"right\">"); + if (item.isFile()) + { + msg += KGlobal::locale()->formatByteSize(item.size(), 1); + } + msg += QL1S("</td>"); + + msg += QL1S("<td align=\"right\">"); + msg += item.timeString(); + msg += QL1S("</td>"); + + msg += QL1S("</tr>"); + } + msg += QL1S("</table>"); + + // done. Replace variables and show it + QString html = QL1S(file.readAll()); + + html.replace(QL1S("$DEFAULT_PATH"), dataPath); + html.replace(QL1S("$PAGE_TITLE"), title); + html.replace(QL1S("$MAIN_CONTENT"), msg); + + return html; +} + + +void ProtocolHandler::slotMostLocalUrlResult(KJob *job) +{ + if (job->error()) + { + kDebug() << "JOB ERROR: " << job->errorString(); + // TODO + } + else + { + KIO::StatJob *statJob = static_cast<KIO::StatJob*>(job); + KIO::UDSEntry entry = statJob->statResult(); + if (entry.isDir()) + { + connect(_lister, SIGNAL(newItems(KFileItemList)), this, SLOT(showResults(KFileItemList))); + _lister->openUrl(_url); + } + else + { + emit downloadUrl(_url); + } + } +} |