00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
#include <string.h>
00021
#include <time.h>
00022
00023
#include <qbuffer.h>
00024
#include <qfile.h>
00025
#include <qcache.h>
00026
#include <qimage.h>
00027
#include <qtimer.h>
00028
00029
#include <kdatastream.h>
00030
#include <kicontheme.h>
00031
#include <kimageio.h>
00032
#include <ksimpleconfig.h>
00033
#include <kstandarddirs.h>
00034
#include <kio/job.h>
00035
00036
#include "favicons.moc"
00037
00038
struct FaviconsModulePrivate
00039 {
00040
virtual ~FaviconsModulePrivate() {
delete config; }
00041
00042
struct DownloadInfo
00043 {
00044 QString hostOrURL;
00045
bool isHost;
00046 QByteArray iconData;
00047 };
00048 QMap<KIO::Job *, DownloadInfo> downloads;
00049 QStringList failedDownloads;
00050 KSimpleConfig *config;
00051 QPtrList<KIO::Job> killJobs;
00052 KIO::MetaData metaData;
00053 QString faviconsDir;
00054 QCache<QString> faviconsCache;
00055 };
00056
00057 FaviconsModule::FaviconsModule(
const QCString &obj)
00058 : KDEDModule(obj)
00059 {
00060
00061 d =
new FaviconsModulePrivate;
00062 d->faviconsDir = KGlobal::dirs()->saveLocation(
"cache",
"favicons/" );
00063 d->faviconsDir.truncate(d->faviconsDir.length()-9);
00064 d->metaData.insert(
"ssl_no_client_cert",
"TRUE");
00065 d->metaData.insert(
"ssl_militant",
"TRUE");
00066 d->metaData.insert(
"UseCache",
"false");
00067 d->metaData.insert(
"cookies",
"none");
00068 d->metaData.insert(
"no-auth",
"true");
00069 d->config =
new KSimpleConfig(locateLocal(
"data",
"konqueror/faviconrc"));
00070 d->killJobs.setAutoDelete(
true);
00071 d->faviconsCache.setAutoDelete(
true);
00072 }
00073
00074 FaviconsModule::~FaviconsModule()
00075 {
00076
delete d;
00077 }
00078
00079 QString removeSlash(QString result)
00080 {
00081
for (
unsigned int i = result.length() - 1; i > 0; --i)
00082
if (result[i] !=
'/')
00083 {
00084 result.truncate(i + 1);
00085
break;
00086 }
00087
00088
return result;
00089 }
00090
00091
00092 QString
FaviconsModule::iconForURL(
const KURL &url)
00093 {
00094
if (url.host().isEmpty())
00095
return QString::null;
00096
00097 QString icon;
00098 QString simplifiedURL = simplifyURL(url);
00099
00100 QString *iconURL = d->faviconsCache.find( removeSlash(simplifiedURL) );
00101
if (iconURL)
00102 icon = *iconURL;
00103
else
00104 icon = d->config->readEntry( removeSlash(simplifiedURL) );
00105
00106
if (!icon.isEmpty())
00107 icon = iconNameFromURL(KURL( icon ));
00108
else
00109 icon = url.host();
00110
00111 icon =
"favicons/" + icon;
00112
00113
if (QFile::exists(d->faviconsDir+icon+
".png"))
00114
return icon;
00115
00116
return QString::null;
00117 }
00118
00119 QString FaviconsModule::simplifyURL(
const KURL &url)
00120 {
00121
00122 QString result = url.host() + url.path();
00123
for (
unsigned int i = 0; i < result.length(); ++i)
00124
if (result[i] ==
'=')
00125 result[i] =
'_';
00126
return result;
00127 }
00128
00129 QString FaviconsModule::iconNameFromURL(
const KURL &iconURL)
00130 {
00131
if (iconURL.path() ==
"/favicon.ico")
00132
return iconURL.host();
00133
00134 QString result = simplifyURL(iconURL);
00135
00136
for (
unsigned int i = 0; i < result.length(); ++i)
00137
if (result[i] ==
'/')
00138 result[i] =
'_';
00139
00140 QString ext = result.right(4);
00141
if (ext ==
".ico" || ext ==
".png" || ext ==
".xpm")
00142 result.remove(result.length() - 4, 4);
00143
00144
return result;
00145 }
00146
00147
bool FaviconsModule::isIconOld(
const QString &icon)
00148 {
00149
struct stat st;
00150
if (stat(QFile::encodeName(icon), &st) != 0)
00151
return true;
00152
00153
return (time(0) - st.st_mtime) > 604800;
00154 }
00155
00156 void FaviconsModule::setIconForURL(
const KURL &url,
const KURL &iconURL)
00157 {
00158 QString simplifiedURL = simplifyURL(url);
00159
00160 d->faviconsCache.insert(removeSlash(simplifiedURL),
new QString(iconURL.url()) );
00161
00162 QString iconName =
"favicons/" + iconNameFromURL(iconURL);
00163 QString iconFile = d->faviconsDir + iconName +
".png";
00164
00165
if (!isIconOld(iconFile)) {
00166 emit iconChanged(
false, simplifiedURL, iconName);
00167
return;
00168 }
00169
00170 startDownload(simplifiedURL,
false, iconURL);
00171 }
00172
00173 void FaviconsModule::downloadHostIcon(
const KURL &url)
00174 {
00175 QString iconFile = d->faviconsDir +
"favicons/" + url.host() +
".png";
00176
if (!isIconOld(iconFile))
00177
return;
00178
00179 startDownload(url.host(),
true, KURL(url,
"/favicon.ico"));
00180 }
00181
00182
void FaviconsModule::startDownload(
const QString &hostOrURL,
bool isHost,
const KURL &iconURL)
00183 {
00184
if (d->failedDownloads.contains(iconURL.url()))
00185
return;
00186
00187 KIO::Job *job = KIO::get(iconURL,
false,
false);
00188 job->addMetaData(d->metaData);
00189 connect(job, SIGNAL(data(KIO::Job *,
const QByteArray &)), SLOT(slotData(KIO::Job *,
const QByteArray &)));
00190 connect(job, SIGNAL(result(KIO::Job *)), SLOT(slotResult(KIO::Job *)));
00191 connect(job, SIGNAL(infoMessage(KIO::Job *,
const QString &)), SLOT(slotInfoMessage(KIO::Job *,
const QString &)));
00192 FaviconsModulePrivate::DownloadInfo download;
00193 download.hostOrURL = hostOrURL;
00194 download.isHost = isHost;
00195 d->downloads.insert(job, download);
00196 }
00197
00198
void FaviconsModule::slotData(KIO::Job *job,
const QByteArray &data)
00199 {
00200 FaviconsModulePrivate::DownloadInfo &download = d->downloads[job];
00201
unsigned int oldSize = download.iconData.size();
00202
if (oldSize > 0x10000)
00203 {
00204 d->killJobs.append(job);
00205 QTimer::singleShot(0,
this, SLOT(slotKill()));
00206 }
00207 download.iconData.resize(oldSize + data.size());
00208 memcpy(download.iconData.data() + oldSize, data.data(), data.size());
00209 }
00210
00211
void FaviconsModule::slotResult(KIO::Job *job)
00212 {
00213 FaviconsModulePrivate::DownloadInfo download = d->downloads[job];
00214 d->downloads.remove(job);
00215 KURL iconURL = static_cast<KIO::TransferJob *>(job)->url();
00216 QString iconName;
00217
if (!job->error())
00218 {
00219 QBuffer buffer(download.iconData);
00220 buffer.open(IO_ReadOnly);
00221 QImageIO io;
00222 io.setIODevice(&buffer);
00223 io.setParameters(
"16");
00224
00225
00226
00227
if (io.read())
00228 {
00229
00230
00231
00232
if (io.image().width() != KIcon::SizeSmall || io.image().height() != KIcon::SizeSmall)
00233 io.setImage(io.image().smoothScale(KIcon::SizeSmall, KIcon::SizeSmall));
00234
00235
if (download.isHost)
00236 iconName = download.hostOrURL;
00237
else
00238 iconName = iconNameFromURL(iconURL);
00239
00240 iconName =
"favicons/" + iconName;
00241
00242 io.setIODevice(0);
00243 io.setFileName(d->faviconsDir + iconName +
".png");
00244 io.setFormat(
"PNG");
00245
if (!io.write())
00246 iconName = QString::null;
00247
else if (!download.isHost)
00248 d->config->writeEntry( removeSlash(download.hostOrURL), iconURL.url());
00249 }
00250 }
00251
if (iconName.isEmpty())
00252 d->failedDownloads.append(iconURL.url());
00253
00254 emit iconChanged(download.isHost, download.hostOrURL, iconName);
00255 }
00256
00257
void FaviconsModule::slotInfoMessage(KIO::Job *job,
const QString &msg)
00258 {
00259 emit infoMessage(static_cast<KIO::TransferJob *>( job )->url(), msg);
00260 }
00261
00262
void FaviconsModule::slotKill()
00263 {
00264 d->killJobs.clear();
00265 }
00266
00267
extern "C" {
00268 KDEDModule *create_favicons(
const QCString &obj)
00269 {
00270 KImageIO::registerFormats();
00271
return new FaviconsModule(obj);
00272 }
00273 }
00274
00275