diff options
Diffstat (limited to 'konq-plugins/webarchiver')
-rw-r--r-- | konq-plugins/webarchiver/Makefile.am | 32 | ||||
-rw-r--r-- | konq-plugins/webarchiver/archivedialog.cpp | 565 | ||||
-rw-r--r-- | konq-plugins/webarchiver/archivedialog.h | 82 | ||||
-rw-r--r-- | konq-plugins/webarchiver/archiveviewbase.ui | 128 | ||||
-rw-r--r-- | konq-plugins/webarchiver/cr16-action-webarchiver.png | bin | 0 -> 919 bytes | |||
-rw-r--r-- | konq-plugins/webarchiver/cr22-action-webarchiver.png | bin | 0 -> 1419 bytes | |||
-rw-r--r-- | konq-plugins/webarchiver/plugin_webarchiver.cpp | 116 | ||||
-rw-r--r-- | konq-plugins/webarchiver/plugin_webarchiver.desktop | 130 | ||||
-rw-r--r-- | konq-plugins/webarchiver/plugin_webarchiver.h | 42 | ||||
-rw-r--r-- | konq-plugins/webarchiver/plugin_webarchiver.rc | 11 | ||||
-rw-r--r-- | konq-plugins/webarchiver/webarchivecreator.cpp | 117 | ||||
-rw-r--r-- | konq-plugins/webarchiver/webarchivecreator.h | 51 | ||||
-rw-r--r-- | konq-plugins/webarchiver/webarchivethumbnail.desktop | 76 |
13 files changed, 1350 insertions, 0 deletions
diff --git a/konq-plugins/webarchiver/Makefile.am b/konq-plugins/webarchiver/Makefile.am new file mode 100644 index 0000000..53d519e --- /dev/null +++ b/konq-plugins/webarchiver/Makefile.am @@ -0,0 +1,32 @@ +INCLUDES = $(all_includes) +KDE_CXXFLAGS = $(USE_EXCEPTIONS) +METASOURCES = AUTO + +# Install this plugin in the KDE modules directory +kde_module_LTLIBRARIES = libwebarchiverplugin.la webarchivethumbnail.la + +libwebarchiverplugin_la_SOURCES = plugin_webarchiver.cpp archiveviewbase.ui archivedialog.cpp +libwebarchiverplugin_la_LIBADD = $(LIB_KPARTS) $(LIB_KHTML) +libwebarchiverplugin_la_LDFLAGS = -module $(KDE_PLUGIN) $(all_libraries) + +pluginsdir = $(kde_datadir)/khtml/kpartplugins +plugins_DATA = plugin_webarchiver.rc plugin_webarchiver.desktop + +appsdir = $(kde_appsdir)/.hidden +apps_DATA = plugin_webarchiver.desktop + +install-data-local: $(srcdir)/../uninstall.desktop + $(mkinstalldirs) $(DESTDIR)$(pluginsdir) + $(INSTALL_DATA) $(srcdir)/../uninstall.desktop $(DESTDIR)$(pluginsdir)/webarchiverplugin.desktop + +webarchivethumbnail_la_SOURCES = webarchivecreator.cpp +webarchivethumbnail_la_LIBADD = $(LIB_KHTML) +webarchivethumbnail_la_LDFLAGS = $(all_libraries) -module $(KDE_PLUGIN) + +servicesdir = $(kde_servicesdir) +services_DATA = webarchivethumbnail.desktop + +KDE_ICON = webarchiver + +messages: rc.cpp + $(XGETTEXT) *.cpp *.h -o $(podir)/webarchiver.pot diff --git a/konq-plugins/webarchiver/archivedialog.cpp b/konq-plugins/webarchiver/archivedialog.cpp new file mode 100644 index 0000000..71390c2 --- /dev/null +++ b/konq-plugins/webarchiver/archivedialog.cpp @@ -0,0 +1,565 @@ +/* + Copyright (C) 2001 Andreas Schlapbach <schlpbch@iam.unibe.ch> + Copyright (C) 2003 Antonio Larrosa <larrosa@kde.org> + + 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) any later version. + + 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; see the file COPYING. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#include "archivedialog.h" +#include <qwidget.h> +#include <khtml_part.h> +#include "archiveviewbase.h" +#include <kinstance.h> +#include <ktempfile.h> +#include <ktar.h> + +#include <kfiledialog.h> +#include <kmessagebox.h> +#include <kpassivepopup.h> +#include <klocale.h> +#include <kio/netaccess.h> +#include <khtml_part.h> +#include <kdebug.h> +#include <kgenericfactory.h> +#include <kactivelabel.h> +#include <qstylesheet.h> +#include <qiodevice.h> +#include <klistview.h> +#include <kio/job.h> +#include <kapplication.h> +#include <kurllabel.h> +#include <kprogress.h> +#include <kstringhandler.h> +#include <qpushbutton.h> + +#undef DEBUG_WAR + +#define CONTENT_TYPE "<meta http-equiv=\"content-type\" content=\"text/html; charset=utf-8\">" + +ArchiveDialog::ArchiveDialog(QWidget *parent, const QString &filename, + KHTMLPart *part) : + KDialogBase(parent, "WebArchiveDialog", false, i18n("Web Archiver"), + KDialogBase::Ok | KDialogBase::Cancel | KDialogBase::User1 ), + m_bPreserveWS(false), m_tmpFile(0), m_url(part->url()) +{ + m_widget=new ArchiveViewBase(this); + setMainWidget(m_widget); + setWFlags(getWFlags() | WDestructiveClose); + + m_widget->urlLabel->setText(QString("<a href=\"")+m_url.url()+"\">"+KStringHandler::csqueeze( m_url.url(), 80 )+"</a>"); + m_widget->targetLabel->setText(QString("<a href=\"")+filename+"\">"+KStringHandler::csqueeze( filename, 80 )+"</a>"); + + if(part->document().ownerDocument().isNull()) + m_document = part->document(); + else + m_document = part->document().ownerDocument(); + + enableButtonOK( false ); + showButton( KDialogBase::User1, false ); + setButtonOK( KStdGuiItem::close() ); + + m_tarBall = new KTar(filename,"application/x-gzip"); +} + +void ArchiveDialog::archive() +{ + m_iterator=0; + m_currentLVI=0; + if (m_tarBall->open(IO_WriteOnly)) { +#ifdef DEBUG_WAR + kdDebug(90110) << "Web Archive opened " << endl; +#endif + + m_linkDict.insert(QString("index.html"), QString("")); + saveFile("index.html"); + + } else { + const QString title = i18n( "Unable to Open Web-Archive" ); + const QString text = i18n( "Unable to open \n %1 \n for writing." ).arg(m_tarBall->fileName()); + KMessageBox::sorry( 0L, text, title ); + } +} + +ArchiveDialog::~ArchiveDialog() +{ + delete m_tarBall; +} + +/* Store the HTMLized DOM-Tree to a temporary file and add it to the Tar-Ball */ + +void ArchiveDialog::saveFile( const QString&) +{ + KTempFile tmpFile; + if (!(tmpFile.status())) { + + QString temp; + + m_state=Retrieving; + QTextStream *tempStream = new QTextStream(&temp, IO_ReadOnly); + + saveToArchive(tempStream); + + delete tempStream; + + m_downloadedURLDict.clear(); + + m_state=Downloading; + m_widget->progressBar->setTotalSteps(m_urlsToDownload.count()); + m_widget->progressBar->setProgress(0); + downloadNext(); + + } else { + const QString title = i18n( "Could Not Open Temporary File" ); + const QString text = i18n( "Could not open a temporary file" ); + KMessageBox::sorry( 0, text, title ); + } +} + +void ArchiveDialog::setSavingState() +{ + KTempFile tmpFile; + QTextStream* textStream = tmpFile.textStream(); + textStream->setEncoding(QTextStream::UnicodeUTF8); + + m_widget->progressBar->setProgress(m_widget->progressBar->totalSteps()); + + m_state=Saving; + saveToArchive(textStream); + + tmpFile.close(); + + QString fileName="index.html"; + QFile file(tmpFile.name()); + file.open(IO_ReadOnly); + m_tarBall->writeFile(fileName, QString::null, QString::null, file.size(), file.readAll()); +#ifdef DEBUG_WAR + kdDebug(90110) << "HTML-file written: " << fileName << endl; +#endif + file.close(); + + // Cleaning up + file.remove(); + m_tarBall->close(); + + KPassivePopup::message( m_url.prettyURL() , i18n( "Archiving webpage completed." ), this ); + + enableButtonOK(true); + setEscapeButton(Ok); + actionButton(Ok)->setFocus(); + enableButtonCancel(false); +} + +/* Recursively travers the DOM-Tree */ + +void ArchiveDialog::saveToArchive(QTextStream* _textStream) +{ + if (!_textStream) return; + + // Add a doctype + + (*_textStream) <<"<!-- saved from:" << endl << m_url.url() << " -->" << endl; + + try + { + saveArchiveRecursive(m_document.documentElement(), m_url, _textStream, 0); + } + catch (...) + { + kdDebug(90110) << "exception" << endl; + } +} + +static bool hasAttribute(const DOM::Node &pNode, const QString &attrName, const QString &attrValue) +{ + const DOM::Element element = (const DOM::Element) pNode; + DOM::Attr attr; + DOM::NamedNodeMap attrs = element.attributes(); + unsigned long lmap = attrs.length(); + for( unsigned int j=0; j<lmap; j++ ) { + attr = static_cast<DOM::Attr>(attrs.item(j)); + if ((attr.name().string().upper() == attrName) && + (attr.value().string().upper() == attrValue)) + return true; + } + return false; +} + +static bool hasChildNode(const DOM::Node &pNode, const QString &nodeName) +{ + DOM::Node child; + try + { + // We might throw a DOM exception + child = pNode.firstChild(); + } + catch (...) + { + // No children, stop recursion here + child = DOM::Node(); + } + + while(!child.isNull()) { + if (child.nodeName().string().upper() == nodeName) + return true; + child = child.nextSibling(); + } + return false; +} + +/* Transform DOM-Tree to HTML */ + +void ArchiveDialog::saveArchiveRecursive(const DOM::Node &pNode, const KURL& baseURL, + QTextStream* _textStream, int indent) +{ + const QString nodeNameOrig(pNode.nodeName().string()); + const QString nodeName(pNode.nodeName().string().upper()); + QString text; + QString strIndent; + strIndent.fill(' ', indent); + const DOM::Element element = (const DOM::Element) pNode; + DOM::Node child; + + if ( !element.isNull() ) { + if (nodeName.at(0)=='-') { + /* Don't save khtml internal tags '-konq..' + * Approximating it with <DIV> + */ + text += "<DIV> <!-- -KONQ_BLOCK -->"; + } else if (nodeName == "BASE") { + /* Skip BASE, everything is relative to index.html + * Saving SCRIPT but they can cause trouble! + */ + } else if ((nodeName == "META") && hasAttribute(pNode, "HTTP-EQUIV", "CONTENT-TYPE")) { + /* Skip content-type meta tag, we provide our own. + */ + } else { + if (!m_bPreserveWS) { + if (nodeName == "PRE") { + m_bPreserveWS = true; + } + text = strIndent; + } + text += "<" + nodeNameOrig; + QString attributes; + QString attrNameOrig, attrName, attrValue; + DOM::Attr attr; + DOM::NamedNodeMap attrs = element.attributes(); + unsigned long lmap = attrs.length(); + for( unsigned int j=0; j<lmap; j++ ) { + attr = static_cast<DOM::Attr>(attrs.item(j)); + attrNameOrig = attr.name().string(); + attrName = attrNameOrig.upper(); + attrValue = attr.value().string(); + +#if 0 + if ((nodeName == "FRAME" || nodeName == "IFRAME") && attrName == "SRC") { + //attrValue = handleLink(baseURL, attrValue); + + /* Going recursively down creating a DOM-Tree for the Frame, second Level of recursion */ + //## Add Termination criteria, on the other hand frames are not indefinetly nested, are they :) + + KHTMLPart* part = new KHTMLPart(); + KURL absoluteURL = getAbsoluteURL(baseURL, attrValue); + part->openURL(absoluteURL); + saveFile(getUniqueFileName(absoluteURL.fileName()), part); + delete part; + + } else if +#endif + if ((nodeName == "LINK" && attrName == "HREF") || // Down load stylesheets, js-script, .. + ((nodeName == "FRAME" || nodeName == "IFRAME") && attrName == "SRC") || + ((nodeName == "IMG" || nodeName == "INPUT" || nodeName == "SCRIPT") && attrName == "SRC") || + ((nodeName == "BODY" || nodeName == "TABLE" || nodeName == "TH" || nodeName == "TD") && attrName == "BACKGROUND")) { + // Some people use carriage return in file names and browsers support that! + attrValue = handleLink(baseURL, attrValue.replace(QRegExp("\\s"), "")); + } + /* + * ## Make recursion level configurable + */ + /* + } else if (nodeName == "A" && attrName == "HREF") { + attrValue = handleLink(baseURL, attrValue); + */ + + attributes += " " + attrName + "=\"" + attrValue + "\""; + } + if (!(attributes.isEmpty())){ + text += " "; + } + text += attributes.simplifyWhiteSpace(); + text += ">"; + + if (nodeName == "HTML") { + /* Search for a HEAD tag, if not found, generate one. + */ + if (!hasChildNode(pNode, "HEAD")) + text += "\n" + strIndent + " <HEAD>" CONTENT_TYPE "</HEAD>"; + } + else if (nodeName == "HEAD") { + text += "\n" + strIndent + " " + CONTENT_TYPE; + } + } + } else { + const QString& nodeValue(pNode.nodeValue().string()); + if (!(nodeValue.isEmpty())) { + // Don't escape < > in JS or CSS + QString parentNodeName = pNode.parentNode().nodeName().string().upper(); + if (parentNodeName == "STYLE") { + text = analyzeInternalCSS(baseURL, pNode.nodeValue().string()); + } else if (m_bPreserveWS) { + text = QStyleSheet::escape(pNode.nodeValue().string()); + } else if (parentNodeName == "SCRIPT") { + text = pNode.nodeValue().string(); + } else { + text = strIndent + QStyleSheet::escape(pNode.nodeValue().string()); + } + } + } + +#ifdef DEBUG_WAR + kdDebug(90110) << "text:" << text << endl; +#endif + if (!(text.isEmpty())) { + (*_textStream) << text; + if (!m_bPreserveWS) { + (*_textStream) << endl; + } + } + + try + { + // We might throw a DOM exception + child = pNode.firstChild(); + } + catch (...) + { + // No children, stop recursion here + child = DOM::Node(); + } + + while(!child.isNull()) { + saveArchiveRecursive(child, baseURL, _textStream, indent+2); + child = child.nextSibling(); + } + + if (!(element.isNull())) { + if (nodeName == "AREA" || nodeName == "BASE" || nodeName == "BASEFONT" || + nodeName == "BR" || nodeName == "COL" || nodeName == "FRAME" || + nodeName == "HR" || nodeName == "IMG" || nodeName == "INPUT" || + nodeName == "ISINDEX" || nodeName == "META" || nodeName == "PARAM") { + + /* Closing Tag is forbidden, see HTML 4.01 Specs: Index of Elements */ + + } else { + if (!m_bPreserveWS) { + text = strIndent; + } else { + text =""; + } + if (nodeName.at(0)=='-') { + text += "</DIV> <!-- -KONQ_BLOCK -->"; + } else { + text += "</" + pNode.nodeName().string() + ">"; + if (nodeName == "PRE") { + m_bPreserveWS = false; + } + } +#ifdef DEBUG_WAR + kdDebug(90110) << text << endl; +#endif + if (!(text.isEmpty())) { + (*_textStream) << text; + if (!m_bPreserveWS) { + (*_textStream) << endl; + } + } + } + } +} + +/* Extract the URL, download it's content and return an unique name for the link */ + +QString ArchiveDialog::handleLink(const KURL& _url, const QString& _link) +{ + KURL url(getAbsoluteURL(_url, _link)); + + QString tarFileName; + if (kapp->authorizeURLAction("redirect", _url, url)) + { + if (m_state==Retrieving) + m_urlsToDownload.append(url); + else if (m_state==Saving) + tarFileName = m_downloadedURLDict[url.url()]; + } + + return tarFileName; +} + +void ArchiveDialog::downloadNext() +{ + if (m_iterator>=m_urlsToDownload.count()) + { + // We've already downloaded all the files we wanted, let's save them + setSavingState(); + return; + } + + KURL url=m_urlsToDownload[m_iterator]; + +#ifdef DEBUG_WAR + kdDebug(90110) << "URL : " << url.url() << endl; +#endif + QString tarFileName; + + // Only download file once + if (m_downloadedURLDict.contains(url.url())) { + tarFileName = m_downloadedURLDict[url.url()]; +#ifdef DEBUG_WAR + kdDebug(90110) << "File already downloaded: " << url.url() + << m_downloadedURLDict.count() << endl; +#endif + m_iterator++; + downloadNext(); + return; + } else { + + // Gets the name of a temporary file into m_tmpFileName + delete m_tmpFile; + m_tmpFile=new KTempFile(); + m_tmpFile->close(); + QFile::remove(m_tmpFile->name()); + kdDebug(90110) << "downloading: " << url.url() << " to: " << m_tmpFile->name() << endl; + KURL dsturl; + dsturl.setPath(m_tmpFile->name()); + KIO::Job *job=KIO::file_copy(url, dsturl, -1, false, false, false); + job->addMetaData("cache", "cache"); // Use entry from cache if available. + connect(job, SIGNAL(result( KIO::Job *)), this, SLOT(finishedDownloadingURL( KIO::Job *)) ); + + m_currentLVI=new QListViewItem(m_widget->listView, url.prettyURL()); + m_widget->listView->insertItem( m_currentLVI ); + m_currentLVI->setText(1,i18n("Downloading")); + } +#ifdef DEBUG_WAR + kdDebug(90110) << "TarFileName: [" << tarFileName << "]" << endl << endl; +#endif +} + +void ArchiveDialog::finishedDownloadingURL( KIO::Job *job ) +{ + if ( job->error() ) + { +// QString s=job->errorString(); + m_currentLVI->setText(1,i18n("Error")); + } + else + m_currentLVI->setText(1,i18n("Ok")); + + m_widget->progressBar->advance(1); + + + KURL url=m_urlsToDownload[m_iterator]; + + QString tarFileName = getUniqueFileName(url.fileName()); + + // Add file to Tar-Ball + QFile file(m_tmpFile->name()); + file.open(IO_ReadOnly); + m_tarBall->writeFile(tarFileName, QString::null, QString::null, file.size(), file.readAll()); + file.close(); + m_tmpFile->unlink(); + delete m_tmpFile; + m_tmpFile=0; + + // Add URL to downloaded URLs + + m_downloadedURLDict.insert(url.url(), tarFileName); + m_linkDict.insert(tarFileName, QString("")); + + m_iterator++; + downloadNext(); +} + +/* Create an absolute URL for download */ + +KURL ArchiveDialog::getAbsoluteURL(const KURL& _url, const QString& _link) +{ + // Does all the magic for me + return KURL(_url, _link); +} + +/* Adds an id to a fileName to make it unique relative to the Tar-Ball */ + +QString ArchiveDialog::getUniqueFileName(const QString& fileName) +{ + // Name clash -> add unique id + static int id=2; + QString uniqueFileName(fileName); + +#ifdef DEBUG_WAR + kdDebug(90110) << "getUniqueFileName(..): [" << fileName << "]" << endl; +#endif + + while (uniqueFileName.isEmpty() || m_linkDict.contains(uniqueFileName)) + uniqueFileName = QString::number(id++) + fileName; + + return uniqueFileName; +} + +/* Search for Images in CSS, extract them and adjust CSS */ + +QString ArchiveDialog::analyzeInternalCSS(const KURL& _url, const QString& string) +{ +#ifdef DEBUG_WAR + kdDebug () << "analyzeInternalCSS" << endl; +#endif + + QString str(string); + int pos = 0; + int startUrl = 0; + int endUrl = 0; + int length = string.length(); + while (pos < length && pos >= 0) { + pos = str.find("url(", pos); + if (pos!=-1) { + pos += 4; // url( + + if (str[pos]=='"' || str[pos]=='\'') // CSS 'feature' + pos++; + startUrl = pos; + pos = str.find(")",startUrl); + endUrl = pos; + if (str[pos-1]=='"' || str[pos-1]=='\'') // CSS 'feature' + endUrl--; + QString url = str.mid(startUrl, endUrl-startUrl); + +#ifdef DEBUG_WAR + kdDebug () << "url: " << url << endl; +#endif + + url = handleLink(_url, url); + +#ifdef DEBUG_WAR + kdDebug () << "url: " << url << endl; +#endif + + str = str.replace(startUrl, endUrl-startUrl, url); + pos++; + } + } + return str; +} + +#include "archivedialog.moc" diff --git a/konq-plugins/webarchiver/archivedialog.h b/konq-plugins/webarchiver/archivedialog.h new file mode 100644 index 0000000..1dc5ff8 --- /dev/null +++ b/konq-plugins/webarchiver/archivedialog.h @@ -0,0 +1,82 @@ +/* + Copyright (C) 2003 Antonio Larrosa <larrosa@kde.org> + + 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) any later version. + + 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; see the file COPYING. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#ifndef _ARCHIVEDIALOG_H_ +#define _ARCHIVEDIALOG_H_ + +#include <dom/dom_core.h> +#include <dom/html_document.h> + +#include <kdialogbase.h> +#include <ktempfile.h> +#include <kio/job.h> + +#include <qstring.h> +#include <qmap.h> +#include <qvaluelist.h> + +class QWidget; +class KHTMLPart; +class ArchiveViewBase; +class KURL; +class KTar; +class QTextStream; +class QListViewItem; + +class ArchiveDialog : public KDialogBase +{ + Q_OBJECT +public: + ArchiveDialog(QWidget *parent, const QString &targetFilename, KHTMLPart *part); + ~ArchiveDialog(); + + void archive(); + +public slots: + void finishedDownloadingURL( KIO::Job *job ); + void setSavingState(); +protected: + void saveFile( const QString& fileName); + void saveToArchive(QTextStream* _textStream); + void saveArchiveRecursive(const DOM::Node &node, const KURL& baseURL, + QTextStream* _textStream, int ident); + QString handleLink(const KURL& _url, const QString & _link); + KURL getAbsoluteURL(const KURL& _url, const QString& _link); + QString getUniqueFileName(const QString& fileName); + QString stringToHTML(const QString& string); + QString analyzeInternalCSS(const KURL& _url, const QString& string); + void downloadNext(); + + ArchiveViewBase *m_widget; + QMap<QString, QString> m_downloadedURLDict; + QMap<QString, QString> m_linkDict; + KTar* m_tarBall; + bool m_bPreserveWS; + QListViewItem *m_currentLVI; + unsigned int m_iterator; + enum State { Retrieving=0, Downloading, Saving }; + State m_state; + QValueList <KURL>m_urlsToDownload; + KTempFile *m_tmpFile; + KURL m_url; + DOM::Document m_document; + +}; + +#endif // _ARCHIVEDIALOG_H_ diff --git a/konq-plugins/webarchiver/archiveviewbase.ui b/konq-plugins/webarchiver/archiveviewbase.ui new file mode 100644 index 0000000..a2aceb2 --- /dev/null +++ b/konq-plugins/webarchiver/archiveviewbase.ui @@ -0,0 +1,128 @@ +<!DOCTYPE UI><UI version="3.2" stdsetdef="1"> +<class>ArchiveViewBase</class> +<widget class="QWidget"> + <property name="name"> + <cstring>ArchiveViewBase</cstring> + </property> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>600</width> + <height>483</height> + </rect> + </property> + <property name="caption"> + <string>Web Archiver</string> + </property> + <vbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QLayoutWidget"> + <property name="name"> + <cstring>layout4</cstring> + </property> + <grid> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="KActiveLabel" row="1" column="1"> + <property name="name"> + <cstring>targetLabel</cstring> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>7</hsizetype> + <vsizetype>1</vsizetype> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="text"> + <string>Local File</string> + </property> + </widget> + <widget class="QLabel" row="1" column="0"> + <property name="name"> + <cstring>textLabel1_2</cstring> + </property> + <property name="text"> + <string>To:</string> + </property> + </widget> + <widget class="QLabel" row="0" column="0"> + <property name="name"> + <cstring>textLabel1</cstring> + </property> + <property name="text"> + <string>Archiving:</string> + </property> + </widget> + <widget class="KActiveLabel" row="0" column="1"> + <property name="name"> + <cstring>urlLabel</cstring> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>7</hsizetype> + <vsizetype>1</vsizetype> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="text"> + <string>Original URL</string> + </property> + </widget> + </grid> + </widget> + <widget class="KProgress"> + <property name="name"> + <cstring>progressBar</cstring> + </property> + </widget> + <widget class="KListView"> + <column> + <property name="text"> + <string>URL</string> + </property> + <property name="clickable"> + <bool>true</bool> + </property> + <property name="resizable"> + <bool>true</bool> + </property> + </column> + <column> + <property name="text"> + <string>State</string> + </property> + <property name="clickable"> + <bool>true</bool> + </property> + <property name="resizable"> + <bool>true</bool> + </property> + </column> + <property name="name"> + <cstring>listView</cstring> + </property> + <property name="resizeMode"> + <enum>AllColumns</enum> + </property> + <property name="fullWidth"> + <bool>true</bool> + </property> + </widget> + </vbox> +</widget> +<customwidgets> +</customwidgets> +<layoutdefaults spacing="6" margin="11"/> +<includehints> + <includehint>kactivelabel.h</includehint> + <includehint>kactivelabel.h</includehint> + <includehint>klistview.h</includehint> +</includehints> +</UI> diff --git a/konq-plugins/webarchiver/cr16-action-webarchiver.png b/konq-plugins/webarchiver/cr16-action-webarchiver.png Binary files differnew file mode 100644 index 0000000..aa60f00 --- /dev/null +++ b/konq-plugins/webarchiver/cr16-action-webarchiver.png diff --git a/konq-plugins/webarchiver/cr22-action-webarchiver.png b/konq-plugins/webarchiver/cr22-action-webarchiver.png Binary files differnew file mode 100644 index 0000000..ddf14ac --- /dev/null +++ b/konq-plugins/webarchiver/cr22-action-webarchiver.png diff --git a/konq-plugins/webarchiver/plugin_webarchiver.cpp b/konq-plugins/webarchiver/plugin_webarchiver.cpp new file mode 100644 index 0000000..fca9bc7 --- /dev/null +++ b/konq-plugins/webarchiver/plugin_webarchiver.cpp @@ -0,0 +1,116 @@ +/* This file is part of Webarchiver + * Copyright (C) 2001 by Andreas Schlapbach <schlpbch@iam.unibe.ch> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + **/ + +/* $Id$ */ + +/* + * There are two recursions within this code: + * - Recursively create DOM-Tree for referenced links which get recursively + * converted to HTML + * + * => This code has the potential to download whole sites to a TarGz-Archive + */ + +//#define DEBUG_WAR + +#include <qdir.h> +#include <qfile.h> + +#include <kaction.h> +#include <kinstance.h> + +#include <kfiledialog.h> +#include <kmessagebox.h> +#include <klocale.h> +#include <khtml_part.h> +#include <kdebug.h> +#include <kgenericfactory.h> +#include <kglobalsettings.h> + +#include "plugin_webarchiver.h" +#include "archivedialog.h" + +typedef KGenericFactory<PluginWebArchiver> PluginWebArchiverFactory; +K_EXPORT_COMPONENT_FACTORY( libwebarchiverplugin, + PluginWebArchiverFactory( "webarchiver" ) ) + +PluginWebArchiver::PluginWebArchiver( QObject* parent, const char* name, + const QStringList & ) + : Plugin( parent, name ) +{ + (void) new KAction( i18n("Archive &Web Page..."), + "webarchiver", 0, + this, SLOT(slotSaveToArchive()), + actionCollection(), "archivepage" ); +} + +PluginWebArchiver::~PluginWebArchiver() +{ +} + +void PluginWebArchiver::slotSaveToArchive() +{ + // ## Unicode ok? + if( !parent() || !parent()->inherits("KHTMLPart")) + return; + KHTMLPart *part = static_cast<KHTMLPart *>( parent() ); + + QString archiveName = QString::fromUtf8(part->htmlDocument().title().string().utf8()); + + if (archiveName.isEmpty()) + archiveName = i18n("Untitled"); + + // Replace space with underscore, proposed Frank Pieczynski <pieczy@knuut.de> + + archiveName = archiveName.simplifyWhiteSpace(); + archiveName.replace( "\\s:", " "); + archiveName.replace( "?", ""); + archiveName.replace( ":", ""); + archiveName.replace( "/", ""); + archiveName = archiveName.replace( QRegExp("\\s+"), " "); + + archiveName = KGlobalSettings::documentPath() + "/" + archiveName + ".war" ; + + KURL url = KFileDialog::getSaveURL(archiveName, i18n("*.war *.tgz|Web Archives"), part->widget(), + i18n("Save Page as Web-Archive") ); + + if (url.isEmpty()) { return; } + + if (!(url.isValid())) { + const QString title = i18n( "Invalid URL" ); + const QString text = i18n( "The URL\n%1\nis not valid." ).arg(url.prettyURL()); + KMessageBox::sorry(part->widget(), text, title ); + return; + } + + const QFile file(url.path()); + if (file.exists()) { + const QString title = i18n( "File Exists" ); + const QString text = i18n( "Do you really want to overwrite:\n%1?" ).arg(url.prettyURL()); + if (KMessageBox::Continue != KMessageBox::warningContinueCancel( part->widget(), text, title, i18n("Overwrite") ) ) { + return; + } + } + + ArchiveDialog *dialog=new ArchiveDialog(0L, url.path(), part); + dialog->show(); + dialog->archive(); +} + +#include "plugin_webarchiver.moc" diff --git a/konq-plugins/webarchiver/plugin_webarchiver.desktop b/konq-plugins/webarchiver/plugin_webarchiver.desktop new file mode 100644 index 0000000..3e8f55b --- /dev/null +++ b/konq-plugins/webarchiver/plugin_webarchiver.desktop @@ -0,0 +1,130 @@ +[Desktop Entry] +X-KDE-Library=webarchiver +X-KDE-PluginInfo-Author=Andreas Schlapbach +X-KDE-PluginInfo-Email=schlpbch@iam.unibe.ch +X-KDE-PluginInfo-Name=webarchiver +X-KDE-PluginInfo-Version=3.3 +X-KDE-PluginInfo-Website= +X-KDE-PluginInfo-Category=Tools +X-KDE-PluginInfo-Depends= +X-KDE-PluginInfo-License=GPL +X-KDE-PluginInfo-EnabledByDefault=true +Name=Web Archiver +Name[bg]=Уеб архиватор +Name[br]=Dieller ar gwiad +Name[bs]=Web arhiver +Name[ca]=Arxivador de webs +Name[cs]=Archivátor webu +Name[cy]=Archifydd Gwe +Name[da]=Netarkivør +Name[de]=Web-Archivierung +Name[el]=Δημιουργός αρχειοθήκης Ιστού +Name[eo]=TTT-arĥivilo +Name[es]=Archivador Web +Name[et]=Veebiarhiivid +Name[eu]=Web artxibalaria +Name[fa]=بایگانیکنندۀ وب +Name[fi]=WWW arkistot +Name[fr]=Archiveur Internet +Name[fy]=Webargiven +Name[ga]=Cartlannaí Gréasáin +Name[gl]=Arquivador Web +Name[he]=ארכיוני רשת +Name[hi]=वेब अभिलेखागार +Name[hr]=Web-arhiviranje +Name[hu]=Weboldal-archiváló +Name[is]=Safnvistuð vefgögn +Name[it]=Immagazzinatore Web +Name[ja]=ウェブアーカイバ +Name[ka]=ვებ არქივატორი +Name[kk]=Веб архивтеуіші +Name[km]=កម្មវិធីទុកបណ្ដាញជាប័ណ្ណសារ +Name[lt]=Žiniatinklių puslapių archyvavimo priemonė +Name[mk]=Веб-архивер +Name[ms]=Pengarkib Web +Name[nb]=Nett-arkivar +Name[nds]=Nettarchiv-Maker +Name[ne]=वेब सङ्ग्रहकर्ता +Name[nl]=Webarchieven +Name[nn]=Vevarkiverar +Name[pa]=ਵੈਬ ਆਰਚੀਵਰ +Name[pl]=Archiwizator stron WWW +Name[pt]=Arquivos Web +Name[pt_BR]=Arquivador Web +Name[ru]=Web-архиватор +Name[sk]=Web archívy +Name[sl]=Spletni arhivirnik +Name[sr]=Веб архивер +Name[sr@Latn]=Veb arhiver +Name[sv]=Webbarkiv +Name[ta]=வலை காப்பு +Name[tg]=Веб-архивчӣ +Name[tr]=Web Arşivleyici +Name[uk]=Архіватор Тенет +Name[uz]=Veb-arxivlagich +Name[uz@cyrillic]=Веб-архивлагич +Name[vi]=Bộ lưu trữ Mạng +Name[zh_CN]=Web 存档器 +Name[zh_TW]=Web 檔案館 +Comment=Creates archives of websites +Comment[ar]=يقوم بإنشاء أرشيفات للمواقع الشبكة +Comment[az]=Veb saytlarını arxivləyir +Comment[bg]=Създаване на архиви от уеб сайтове +Comment[bs]=Pravi arhive web stranica +Comment[ca]=Crea arxius de les pàgines web +Comment[cs]=Vytvoří archív webové stránky +Comment[cy]=Creu archifau o wefannau +Comment[da]=Opretter arkiver af netsider +Comment[de]=Erstellt ein Archiv von Webseiten +Comment[el]=Δημιουργεί αρχειοθήκες από ιστοσελίδες +Comment[eo]=Kreas arĥivojn el retsituojn +Comment[es]=Crea copias de sitios web +Comment[et]=Loob veebilehtede arhiivi +Comment[eu]=Weblekuen artxiboak sortzen ditu +Comment[fa]=بایگانیهای وبگاهها را ایجاد میکند +Comment[fi]=Luo webbisivustojen arkistoja +Comment[fr]=Crée des archives de sites Internet +Comment[fy]=Makket argiven fan websteën oan +Comment[ga]=Cruthaigh cartlann de shuímh Ghréasáin +Comment[gl]=Cria ficheiros de páxinas web +Comment[he]=יצירת ארכיונים של אתרי אינטרנט +Comment[hi]=वेबसाइटों के अभिलेखागार बनाए +Comment[hr]=Izrada arhiva od web-lokacija +Comment[hu]=Website-archiválás +Comment[is]=Býr til safnskrár af vefsetrum +Comment[it]=Crea archivi dei siti web +Comment[ja]=ウェブサイトのアーカイブを作成 +Comment[ka]=ვებ გვერდების არქივებს ქმნის +Comment[kk]=Вебсайттың архивін құру +Comment[km]=បង្កើតប័ណ្ណសាររបស់តំបន់បណ្ដាញ +Comment[lt]=Sukuria archyvus iš žiniatinklio puslapių +Comment[mk]=Креира архиви од веб-страници +Comment[ms]=Bina arkib laman web +Comment[nb]=Lager arkiver av nettsteder +Comment[nds]=Stellt Nettsiedenarchiven op +Comment[ne]=वेबसाइटहरूको सङ्ग्रह सिर्जना गर्छ +Comment[nl]=Maakt archieven van websites aan +Comment[nn]=Lagar arkiv av nettstader +Comment[pl]=Tworzy archiwa stron WWW +Comment[pt]=Cria arquivos de páginas web +Comment[pt_BR]=Cria arquivos de sites web +Comment[ro]=Creează arhive ale site-urilor web +Comment[ru]=Создание архивов web-сайтов +Comment[sk]=Vytvára archívy webových stránok +Comment[sl]=Ustvari arhive spletnih strani +Comment[sr]=Прави архиве од веб сајтова +Comment[sr@Latn]=Pravi arhive od veb sajtova +Comment[sv]=Skapar arkiv av webbplatser +Comment[ta]=வலைதளங்களின் காப்பகத்தை உருவாக்குகிறது +Comment[tg]=Эҷод кардани архивҳои веб-сайтҳо +Comment[tr]=Web sayfalarının arşivini oluşturur +Comment[uk]=Створює архіви сайтів Тенет +Comment[uz]=Veb-saytlarning arxivini yaratish +Comment[uz@cyrillic]=Веб-сайтларнинг архивини яратиш +Comment[vi]=Tạo kho lưu chỗ Mạng +Comment[xh]=Yenza iindawo zokugcina ze websites +Comment[zh_CN]=创建网站存档 +Comment[zh_TW]=建立網站的檔案 +Icon=webarchiver +X-KDE-ParentApp=konqueror +DocPath=konq-plugins/webarchiver/index.html diff --git a/konq-plugins/webarchiver/plugin_webarchiver.h b/konq-plugins/webarchiver/plugin_webarchiver.h new file mode 100644 index 0000000..2353fe1 --- /dev/null +++ b/konq-plugins/webarchiver/plugin_webarchiver.h @@ -0,0 +1,42 @@ +/* This file is part of Webarchiver + * Copyright (C) 2001 by Andreas Schlapbach <schlpbch@iam.unibe.ch> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + **/ + +/* $Id$ */ + +#ifndef plugin_webarchiver_h +#define plugin_webarchiver_h + +#include <kparts/plugin.h> +#include <klibloader.h> + +class PluginWebArchiver : public KParts::Plugin +{ + Q_OBJECT + + public: + PluginWebArchiver( QObject* parent, const char* name, + const QStringList & ); + virtual ~PluginWebArchiver(); + + public slots: + void slotSaveToArchive(); + +}; + +#endif diff --git a/konq-plugins/webarchiver/plugin_webarchiver.rc b/konq-plugins/webarchiver/plugin_webarchiver.rc new file mode 100644 index 0000000..d0369c8 --- /dev/null +++ b/konq-plugins/webarchiver/plugin_webarchiver.rc @@ -0,0 +1,11 @@ +<!DOCTYPE kpartgui> +<kpartplugin name="webarchiver" library="libwebarchiverplugin"> +<MenuBar> + <Menu name="tools"><Text>&Tools</Text> + <Action name="archivepage"/> + </Menu> +</MenuBar> +<ToolBar name="extraToolBar"><text>Extra Toolbar</text> + <Action name="archivepage"/> +</ToolBar> +</kpartplugin> diff --git a/konq-plugins/webarchiver/webarchivecreator.cpp b/konq-plugins/webarchiver/webarchivecreator.cpp new file mode 100644 index 0000000..cba7f18 --- /dev/null +++ b/konq-plugins/webarchiver/webarchivecreator.cpp @@ -0,0 +1,117 @@ +/* + Copyright (C) 2001 Malte Starostik <malte@kde.org> + + 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) any later version. + + 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; see the file COPYING. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +// $Id$ + +#include <time.h> + +#include <qpixmap.h> +#include <qimage.h> +#include <qpainter.h> + +#include <kapplication.h> +#include <khtml_part.h> + +#include "webarchivecreator.moc" + +extern "C" +{ + ThumbCreator * KDE_EXPORT new_creator() + { + return new WebArchiveCreator; + } +} + +WebArchiveCreator::WebArchiveCreator() + : m_html(0) +{ +} + +WebArchiveCreator::~WebArchiveCreator() +{ + delete m_html; +} + +bool WebArchiveCreator::create(const QString &path, int width, int height, QImage &img) +{ + if (!m_html) + { + m_html = new KHTMLPart; + connect(m_html, SIGNAL(completed()), SLOT(slotCompleted())); + m_html->setJScriptEnabled(false); + m_html->setJavaEnabled(false); + m_html->setPluginsEnabled(false); + } + KURL url; + url.setProtocol( "tar" ); + url.setPath( path ); + url.addPath( "index.html" ); + m_html->openURL( url ); + m_completed = false; + startTimer(5000); + while (!m_completed) + kapp->processOneEvent(); + killTimers(); + + // render the HTML page on a bigger pixmap and use smoothScale, + // looks better than directly scaling with the QPainter (malte) + QPixmap pix; + if (width > 400 || height > 600) + { + if (height * 3 > width * 4) + pix.resize(width, width * 4 / 3); + else + pix.resize(height * 3 / 4, height); + } + else + pix.resize(400, 600); + // light-grey background, in case loadind the page failed + pix.fill( QColor( 245, 245, 245 ) ); + + int borderX = pix.width() / width, + borderY = pix.height() / height; + QRect rc(borderX, borderY, pix.width() - borderX * 2, pix.height() - borderY * +2); + + QPainter p; + p.begin(&pix); + m_html->paint(&p, rc); + p.end(); + + img = pix.convertToImage(); + return true; +} + +void WebArchiveCreator::timerEvent(QTimerEvent *) +{ + m_html->closeURL(); + m_completed = true; +} + +void WebArchiveCreator::slotCompleted() +{ + m_completed = true; +} + +ThumbCreator::Flags WebArchiveCreator::flags() const +{ + return DrawFrame; +} + +// vim: ts=4 sw=4 et diff --git a/konq-plugins/webarchiver/webarchivecreator.h b/konq-plugins/webarchiver/webarchivecreator.h new file mode 100644 index 0000000..eae653b --- /dev/null +++ b/konq-plugins/webarchiver/webarchivecreator.h @@ -0,0 +1,51 @@ +/* + Copyright (C) 2001 Malte Starostik <malte@kde.org> + + 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) any later version. + + 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; see the file COPYING. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +// $Id$ +// +#ifndef __webarchivecreator_h__ +#define __webarchivecreator_h__ + +#include <kio/thumbcreator.h> + +class KHTMLPart; + +class WebArchiveCreator : public QObject, public ThumbCreator +{ + Q_OBJECT +public: + WebArchiveCreator(); + virtual ~WebArchiveCreator(); + virtual bool create(const QString &path, int width, int height, QImage &img); + virtual Flags flags() const; + +protected: + virtual void timerEvent(QTimerEvent *); + +private slots: + void slotCompleted(); + +private: + KHTMLPart *m_html; + bool m_completed; +}; + +#endif + +// vim: ts=4 sw=4 et diff --git a/konq-plugins/webarchiver/webarchivethumbnail.desktop b/konq-plugins/webarchiver/webarchivethumbnail.desktop new file mode 100644 index 0000000..171ed05 --- /dev/null +++ b/konq-plugins/webarchiver/webarchivethumbnail.desktop @@ -0,0 +1,76 @@ +[Desktop Entry] +Type=Service +Name=Web Archives +Name[af]=Web Argiewe +Name[ar]=أرشيفات الشبكة +Name[az]=Veb Arxivləri +Name[bg]=Уеб архиви +Name[br]=Dielloù ar gwiad +Name[bs]=Web arhive +Name[ca]=Arxius web +Name[cs]=Webové archívy +Name[cy]=Archifau Wefannau +Name[da]=Netarkiver +Name[de]=Web-Archive +Name[el]=Αρχειοθήκες ιστού +Name[eo]=TTT-arĥivoj +Name[es]=Sitios web guardados +Name[et]=Veebiarhiivid +Name[eu]=Web artxiboak +Name[fa]=بایگانیهای وب +Name[fi]=WWW arkistot +Name[fo]=Vevskjalasavn +Name[fr]=Archives Internet +Name[fy]=Webargiven +Name[ga]=Cartlanna Gréasáin +Name[gl]=Arquivos Web +Name[he]=ארכיוני רשת +Name[hi]=वेब अभिलेखागार +Name[hr]=Web arhive +Name[hu]=Webes archívumok +Name[is]=Safnvistuð vefgögn +Name[it]=Archivi Web +Name[ja]=ウェブアーカイブ +Name[ka]=ვებ არქივატორები +Name[kk]=Веб ахивтеуіші +Name[km]=ប័ណ្ណសារបណ្ដាញ +Name[ko]=웹 저장고 +Name[lt]=Žiniatinklio archyvai +Name[lv]=Web Arhīvi +Name[mk]=Веб-архиви +Name[ms]=Arkib Web +Name[mt]=Arkivji webb +Name[nb]=Vev-arkiver +Name[nds]=Nettarchiven +Name[ne]=वेब सङ्ग्रह +Name[nl]=Webarchieven +Name[nn]=Vevarkiv +Name[nso]=Dipolokelo tsa Web +Name[pa]=ਵੈਬ ਆਰਚੀਵ +Name[pl]=Archiwa WWW +Name[pt]=Arquivos Web +Name[pt_BR]=Arquivos Web +Name[ro]=Arhive web +Name[ru]=Web-архивы +Name[sk]=Web archívy +Name[sl]=Spletni arhivi +Name[sr]=Веб архиве +Name[sr@Latn]=Veb arhive +Name[sv]=Webbarkiv +Name[ta]=வலை காப்புகள் +Name[tg]=Веб-архивҳо +Name[th]=แฟ้มบีบอัดของเว็บ +Name[tr]=Web Arşivleri +Name[uk]=Архіви Тенет +Name[uz]=Veb-arxivlar +Name[uz@cyrillic]=Веб-архивлар +Name[ven]=Dziwebu dzau vhulunga zwa kale +Name[vi]=Kho lưu Mạng +Name[xh]=Iindawo zokugcina ze web +Name[zh_CN]=Web 存档 +Name[zh_TW]=Web 檔案館 +Name[zu]=Ushicilelo lukawonke umuntu kanye nemiqulu emidala yeWeb +ServiceTypes=ThumbCreator +MimeTypes=application/x-webarchive +X-KDE-Library=webarchivethumbnail +CacheThumbnail=true |