21 #include "favicons_adaptor.h"
23 #include <kicontheme.h>
27 #include <kstandarddirs.h>
29 #include <kconfiggroup.h>
31 #include <kpluginfactory.h>
32 #include <kpluginloader.h>
34 #include <QtCore/QBuffer>
35 #include <QtCore/QFile>
36 #include <QtCore/QCache>
37 #include <QtCore/QTimer>
39 #include <QImageReader>
45 registerPlugin<FavIconsModule>();
47 K_EXPORT_PLUGIN(FavIconsFactory(
"favicons"))
49 static QString portForUrl(const KUrl& url)
52 return (QString(QLatin1Char(
'_')) + QString::number(url.port()));
60 QString result = url.host() + portForUrl(url) + url.path();
61 for (
int i = 0; i < result.length(); ++i)
69 if (iconURL.path() == QLatin1String(
"/favicon.ico"))
70 return iconURL.host() + portForUrl(iconURL);
74 for (
int i = 0; i < result.length(); ++i)
78 QString ext = result.right(4);
79 if (ext == QLatin1String(
".ico") || ext == QLatin1String(
".png") || ext == QLatin1String(
".xpm"))
80 result.remove(result.length() - 4, 4);
85 struct FavIconsModulePrivate
87 virtual ~FavIconsModulePrivate() {
delete config; }
95 QString makeIconName(
const DownloadInfo& download,
const KUrl& iconURL)
97 QString iconName (QLatin1String(
"favicons/"));
98 iconName += (download.isHost ? download.hostOrURL :
iconNameFromURL(iconURL));
102 QMap<KJob *, DownloadInfo> downloads;
103 KUrl::List failedDownloads;
106 KIO::MetaData metaData;
108 QCache<QString,QString> faviconsCache;
115 d =
new FavIconsModulePrivate;
116 d->faviconsDir = KGlobal::dirs()->saveLocation(
"cache", QLatin1String(
"favicons/"));
117 d->faviconsDir.truncate(d->faviconsDir.length()-9);
118 d->metaData.insert(QLatin1String(
"ssl_no_client_cert"), QLatin1String(
"true"));
119 d->metaData.insert(QLatin1String(
"ssl_no_ui"), QLatin1String(
"true"));
120 d->metaData.insert(QLatin1String(
"UseCache"),
"false");
121 d->metaData.insert(QLatin1String(
"cookies"),
"none");
122 d->metaData.insert(QLatin1String(
"no-www-auth"), QLatin1String(
"true"));
123 d->metaData.insert(QLatin1String(
"errorPage"), QLatin1String(
"false"));
124 d->config =
new KConfig(KStandardDirs::locateLocal(
"data", QLatin1String(
"konqueror/faviconrc")));
126 new FavIconsAdaptor(
this );
136 for (
unsigned int i = result.length() - 1; i > 0; --i) {
137 if (result[i] !=
'/') {
138 result.truncate(i + 1);
148 if (url.host().isEmpty())
154 QString *iconURL = d->faviconsCache[simplifiedURL];
155 QString icon = (iconURL ? *iconURL : d->config->group(QString()).readEntry(simplifiedURL, QString()));
162 icon = QLatin1String(
"favicons/") + icon;
164 kDebug() <<
"URL:" << url <<
"ICON:" << icon;
166 if (QFile::exists(d->faviconsDir+icon+QLatin1String(
".png")))
172 bool FavIconsModule::isIconOld(
const QString &icon)
175 if (KDE::stat(QFile::encodeName(icon), &st) != 0) {
181 return (time(0) - st.st_mtime) > 604800;
189 d->faviconsCache.insert(
removeSlash(simplifiedURL),
new QString(iconURL.url()) );
191 const QString iconName = QLatin1String(
"favicons/") +
iconNameFromURL(iconURL);
192 const QString iconFile = d->faviconsDir + iconName + QLatin1String(
".png");
194 if (!isIconOld(iconFile)) {
200 startDownload(url.url(),
false, iconURL);
206 const QString iconFile = d->faviconsDir + QLatin1String(
"favicons/") + url.host() + QLatin1String(
".png");
207 if (!isIconOld(iconFile)) {
211 startDownload(url.host(),
true, KUrl(url, QLatin1String(
"/favicon.ico")));
217 KUrl iconURL = KUrl(url, QLatin1String(
"/favicon.ico"));
218 d->failedDownloads.removeAll(iconURL);
219 startDownload(url.host(),
true, iconURL);
222 void FavIconsModule::startDownload(
const QString &hostOrURL,
bool isHost,
const KUrl &iconURL)
224 if (d->failedDownloads.contains(iconURL)) {
226 emit
error(isHost, hostOrURL, i18n(
"No favicon found"));
231 KIO::Job *job = KIO::get(iconURL, KIO::NoReload, KIO::HideProgressInfo);
232 job->addMetaData(d->metaData);
233 connect(job, SIGNAL(data(KIO::Job*,QByteArray)), SLOT(slotData(KIO::Job*,QByteArray)));
234 connect(job, SIGNAL(result(KJob*)), SLOT(slotResult(KJob*)));
235 connect(job, SIGNAL(
infoMessage(KJob*,QString,QString)), SLOT(slotInfoMessage(KJob*,QString)));
236 FavIconsModulePrivate::DownloadInfo download;
237 download.hostOrURL = hostOrURL;
238 download.isHost = isHost;
239 d->downloads.insert(job, download);
242 void FavIconsModule::slotData(KIO::Job *job,
const QByteArray &data)
244 KIO::TransferJob* tjob =
static_cast<KIO::TransferJob*
>(job);
245 FavIconsModulePrivate::DownloadInfo &download = d->downloads[job];
246 unsigned int oldSize = download.iconData.size();
249 if (oldSize > 0x10000) {
250 kDebug() <<
"Favicon too big, aborting download of" << tjob->url();
251 d->killJobs.append(job);
252 QTimer::singleShot(0,
this, SLOT(slotKill()));
253 const KUrl iconURL = tjob->url();
254 d->failedDownloads.append(iconURL);
256 download.iconData.resize(oldSize + data.size());
257 memcpy(download.iconData.data() + oldSize, data.data(), data.size());
260 void FavIconsModule::slotResult(KJob *job)
262 KIO::TransferJob* tjob =
static_cast<KIO::TransferJob*
>(job);
263 FavIconsModulePrivate::DownloadInfo download = d->downloads[job];
264 d->killJobs.removeAll(tjob);
265 d->downloads.remove(job);
266 const KUrl iconURL = tjob->url();
268 QString errorMessage;
271 QBuffer buffer(&download.iconData);
272 buffer.open(QIODevice::ReadOnly);
273 QImageReader ir( &buffer );
274 QSize desired( 16,16 );
276 while( ir.imageCount() > 1
277 && ir.currentImageRect() != QRect(0, 0, desired.width(), desired.height())) {
278 if (!ir.jumpToNextImage()) {
282 ir.setScaledSize( desired );
283 const QImage img = ir.read();
284 if( !img.isNull() ) {
285 iconName = d->makeIconName(download, iconURL);
286 const QString localPath = d->faviconsDir + iconName + QLatin1String(
".png");
287 if( !img.save(localPath,
"PNG") ) {
289 errorMessage = i18n(
"Error saving image to %1", localPath);
290 }
else if (!download.isHost)
291 d->config->group(QString()).writeEntry(
removeSlash(download.hostOrURL), iconURL.url());
295 errorMessage = job->errorString();
297 if (iconName.isEmpty()) {
299 d->failedDownloads.append(iconURL);
300 emit
error(download.isHost, download.hostOrURL, errorMessage);
303 emit
iconChanged(download.isHost, download.hostOrURL, iconName);
307 void FavIconsModule::slotInfoMessage(KJob *job,
const QString &msg)
309 emit
infoMessage(static_cast<KIO::TransferJob *>( job )->url().url(), msg);
312 void FavIconsModule::slotKill()
315 Q_FOREACH(KIO::Job* job, d->killJobs) {
321 #include "favicons.moc"
static QString iconNameFromURL(const KUrl &iconURL)
void infoMessage(QString iconURL, QString msg)
Progress info while downloading an icon.
void downloadHostIcon(const KUrl &url)
Downloads the icon for a given host if it was not downloaded before or the download was too long ago...
virtual ~FavIconsModule()
void iconChanged(bool isHost, QString hostOrURL, QString iconName)
Emitted once a new icon is available, for a host or url.
static QString removeSlash(QString result)
void error(bool isHost, QString hostOrURL, QString errorString)
Emitted if an error occurred while downloading the icon for the given host or url.
QString iconForUrl(const KUrl &url)
Looks up an icon name for a given URL.
FavIconsModule(QObject *parent, const QList< QVariant > &)
K_PLUGIN_FACTORY(FavIconsFactory, registerPlugin< FavIconsModule >();) static QString portForUrl(const KUrl &url)
static QString simplifyURL(const KUrl &url)
void setIconForUrl(const KUrl &url, const KUrl &iconURL)
Associates an icon with the given URL.
void forceDownloadHostIcon(const KUrl &url)
Downloads the icon for a given host, even if we tried very recently.