Make a branch to make krunner Good Enough For Aaron™.
[kdebase/uwolfer.git] / apps / lib / konq / favicons / favicons.cpp
blob75b4add36531cfc2fb3733358baad15e755cae48
1 /* This file is part of the KDE project
2 Copyright (C) 2001 Malte Starostik <malte@kde.org>
4 This library is free software; you can redistribute it and/or
5 modify it under the terms of the GNU Library General Public
6 License as published by the Free Software Foundation; either
7 version 2 of the License, or (at your option) any later version.
9 This library is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 Library General Public License for more details.
14 You should have received a copy of the GNU Library General Public License
15 along with this library; see the file COPYING.LIB. If not, write to
16 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
17 Boston, MA 02110-1301, USA.
20 #include "favicons.h"
21 #include "favicons_adaptor.h"
23 #include <time.h>
25 #include <QBuffer>
26 #include <QFile>
27 #include <QtCore/QCache>
28 #include <QImage>
29 #include <QTimer>
30 #include <QImageReader>
32 #include <kicontheme.h>
33 #include <kconfig.h>
34 #include <kstandarddirs.h>
35 #include <kio/job.h>
36 #include <kconfiggroup.h>
37 #include <kdebug.h>
38 #include <kpluginfactory.h>
39 #include <kpluginloader.h>
41 K_PLUGIN_FACTORY(FavIconsFactory,
42 registerPlugin<FavIconsModule>();
44 K_EXPORT_PLUGIN(FavIconsFactory("favicons"))
46 struct FavIconsModulePrivate
48 virtual ~FavIconsModulePrivate() { delete config; }
50 struct DownloadInfo
52 QString hostOrURL;
53 bool isHost;
54 QByteArray iconData;
56 QMap<KJob *, DownloadInfo> downloads;
57 QStringList failedDownloads;
58 KConfig *config;
59 QList<KIO::Job*> killJobs;
60 KIO::MetaData metaData;
61 QString faviconsDir;
62 QCache<QString,QString> faviconsCache;
65 FavIconsModule::FavIconsModule(QObject* parent, const QList<QVariant>&)
66 : KDEDModule(parent)
68 // create our favicons folder so that KIconLoader knows about it
69 d = new FavIconsModulePrivate;
70 d->faviconsDir = KGlobal::dirs()->saveLocation( "cache", "favicons/" );
71 d->faviconsDir.truncate(d->faviconsDir.length()-9); // Strip off "favicons/"
72 d->metaData.insert("ssl_no_client_cert", "TRUE");
73 d->metaData.insert("ssl_no_ui", "TRUE");
74 d->metaData.insert("UseCache", "false");
75 d->metaData.insert("cookies", "none");
76 d->metaData.insert("no-auth", "true");
77 d->config = new KConfig(KStandardDirs::locateLocal("data", "konqueror/faviconrc"));
79 new FavIconsAdaptor( this );
82 FavIconsModule::~FavIconsModule()
84 delete d;
87 static QString removeSlash(QString result)
89 for (unsigned int i = result.length() - 1; i > 0; --i)
90 if (result[i] != '/')
92 result.truncate(i + 1);
93 break;
96 return result;
100 QString FavIconsModule::iconForUrl(const KUrl &url)
102 if (url.host().isEmpty())
103 return QString();
105 QString icon;
106 QString simplifiedURL = simplifyURL(url);
108 QString *iconURL = d->faviconsCache[ removeSlash(simplifiedURL) ];
109 if (iconURL)
110 icon = *iconURL;
111 else
112 icon = d->config->group(QString()).readEntry( removeSlash(simplifiedURL), QString() );
114 if (!icon.isEmpty())
115 icon = iconNameFromURL(KUrl( icon ));
116 else
117 icon = url.host();
119 icon = "favicons/" + icon;
121 if (QFile::exists(d->faviconsDir+icon+".png"))
122 return icon;
124 return QString();
127 QString FavIconsModule::simplifyURL(const KUrl &url)
129 // splat any = in the URL so it can be safely used as a config key
130 QString result = url.host() + url.path();
131 for (int i = 0; i < result.length(); ++i)
132 if (result[i] == '=')
133 result[i] = '_';
134 return result;
137 QString FavIconsModule::iconNameFromURL(const KUrl &iconURL)
139 if (iconURL.path() == "/favicon.ico")
140 return iconURL.host();
142 QString result = simplifyURL(iconURL);
143 // splat / so it can be safely used as a file name
144 for (int i = 0; i < result.length(); ++i)
145 if (result[i] == '/')
146 result[i] = '_';
148 QString ext = result.right(4);
149 if (ext == ".ico" || ext == ".png" || ext == ".xpm")
150 result.remove(result.length() - 4, 4);
152 return result;
155 bool FavIconsModule::isIconOld(const QString &icon)
157 struct stat st;
158 if (stat(QFile::encodeName(icon), &st) != 0)
159 return true; // Trigger a new download on error
161 return (time(0) - st.st_mtime) > 604800; // arbitrary value (one week)
164 void FavIconsModule::setIconForUrl(const KUrl &url, const KUrl &iconURL)
166 const QString simplifiedURL = simplifyURL(url);
168 d->faviconsCache.insert(removeSlash(simplifiedURL), new QString(iconURL.url()) );
170 const QString iconName = "favicons/" + iconNameFromURL(iconURL);
171 const QString iconFile = d->faviconsDir + iconName + ".png";
173 if (!isIconOld(iconFile)) {
174 emit iconChanged(false, url.url(), iconName);
175 return;
178 startDownload(url.url(), false, iconURL);
181 void FavIconsModule::downloadHostIcon(const KUrl &url)
183 const QString iconFile = d->faviconsDir + "favicons/" + url.host() + ".png";
184 if (!isIconOld(iconFile))
185 return;
187 startDownload(url.host(), true, KUrl(url, "/favicon.ico"));
190 void FavIconsModule::startDownload(const QString &hostOrURL, bool isHost, const KUrl &iconURL)
192 if (d->failedDownloads.contains(iconURL.url())) {
193 return;
196 KIO::Job *job = KIO::get(iconURL, KIO::NoReload, KIO::HideProgressInfo);
197 job->addMetaData(d->metaData);
198 connect(job, SIGNAL(data(KIO::Job *, const QByteArray &)), SLOT(slotData(KIO::Job *, const QByteArray &)));
199 connect(job, SIGNAL(result(KJob *)), SLOT(slotResult(KJob *)));
200 connect(job, SIGNAL(infoMessage(KJob *, const QString &, const QString &)), SLOT(slotInfoMessage(KJob *, const QString &)));
201 FavIconsModulePrivate::DownloadInfo download;
202 download.hostOrURL = hostOrURL;
203 download.isHost = isHost;
204 d->downloads.insert(job, download);
207 void FavIconsModule::slotData(KIO::Job *job, const QByteArray &data)
209 FavIconsModulePrivate::DownloadInfo &download = d->downloads[job];
210 unsigned int oldSize = download.iconData.size();
211 if (oldSize > 0x10000)
213 d->killJobs.append(job);
214 QTimer::singleShot(0, this, SLOT(slotKill()));
216 download.iconData.resize(oldSize + data.size());
217 memcpy(download.iconData.data() + oldSize, data.data(), data.size());
220 void FavIconsModule::slotResult(KJob *job)
222 FavIconsModulePrivate::DownloadInfo download = d->downloads[job];
223 d->downloads.remove(job);
224 KUrl iconURL = static_cast<KIO::TransferJob *>(job)->url();
225 QString iconName;
226 if (!job->error())
228 QBuffer buffer(&download.iconData);
229 buffer.open(QIODevice::ReadOnly);
230 QImageReader ir( &buffer );
231 QSize desired( 16,16 );
232 if( ir.canRead() ) {
234 while( ir.imageCount() > 1
235 && ir.currentImageRect() != QRect(0, 0, desired.width(), desired.height())) {
236 if (!ir.jumpToNextImage()) {
237 break;
240 ir.setScaledSize( desired );
241 QImage img = ir.read();
242 if( !img.isNull() ) {
243 if (download.isHost)
244 iconName = download.hostOrURL;
245 else
246 iconName = iconNameFromURL(iconURL);
248 iconName = "favicons/" + iconName;
249 if( !img.save( d->faviconsDir + iconName + ".png", "PNG" ) )
250 iconName.clear();
251 else if (!download.isHost)
252 d->config->group(QString()).writeEntry( removeSlash(download.hostOrURL), iconURL.url());
256 if (iconName.isEmpty())
257 d->failedDownloads.append(iconURL.url());
259 emit iconChanged(download.isHost, download.hostOrURL, iconName);
262 void FavIconsModule::slotInfoMessage(KJob *job, const QString &msg)
264 emit infoMessage(static_cast<KIO::TransferJob *>( job )->url().url(), msg);
267 void FavIconsModule::slotKill()
269 qDeleteAll(d->killJobs);
270 d->killJobs.clear();
273 #include "favicons.moc"
275 // vim: ts=4 sw=4 et