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.
21 #include "favicons_adaptor.h"
27 #include <QtCore/QCache>
30 #include <QImageReader>
32 #include <kicontheme.h>
34 #include <kstandarddirs.h>
36 #include <kconfiggroup.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
; }
56 QMap
<KJob
*, DownloadInfo
> downloads
;
57 QStringList failedDownloads
;
59 QList
<KIO::Job
*> killJobs
;
60 KIO::MetaData metaData
;
62 QCache
<QString
,QString
> faviconsCache
;
65 FavIconsModule::FavIconsModule(QObject
* parent
, const QList
<QVariant
>&)
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()
87 static QString
removeSlash(QString result
)
89 for (unsigned int i
= result
.length() - 1; i
> 0; --i
)
92 result
.truncate(i
+ 1);
100 QString
FavIconsModule::iconForUrl(const KUrl
&url
)
102 if (url
.host().isEmpty())
106 QString simplifiedURL
= simplifyURL(url
);
108 QString
*iconURL
= d
->faviconsCache
[ removeSlash(simplifiedURL
) ];
112 icon
= d
->config
->group(QString()).readEntry( removeSlash(simplifiedURL
), QString() );
115 icon
= iconNameFromURL(KUrl( icon
));
119 icon
= "favicons/" + icon
;
121 if (QFile::exists(d
->faviconsDir
+icon
+".png"))
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
] == '=')
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
] == '/')
148 QString ext
= result
.right(4);
149 if (ext
== ".ico" || ext
== ".png" || ext
== ".xpm")
150 result
.remove(result
.length() - 4, 4);
155 bool FavIconsModule::isIconOld(const QString
&icon
)
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
);
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
))
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())) {
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();
228 QBuffer
buffer(&download
.iconData
);
229 buffer
.open(QIODevice::ReadOnly
);
230 QImageReader
ir( &buffer
);
231 QSize
desired( 16,16 );
234 while( ir
.imageCount() > 1
235 && ir
.currentImageRect() != QRect(0, 0, desired
.width(), desired
.height())) {
236 if (!ir
.jumpToNextImage()) {
240 ir
.setScaledSize( desired
);
241 QImage img
= ir
.read();
242 if( !img
.isNull() ) {
244 iconName
= download
.hostOrURL
;
246 iconName
= iconNameFromURL(iconURL
);
248 iconName
= "favicons/" + iconName
;
249 if( !img
.save( d
->faviconsDir
+ iconName
+ ".png", "PNG" ) )
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
);
273 #include "favicons.moc"