00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023 #include "bundle.h"
00024
00025 #include <QBuffer>
00026 #include <QDebug>
00027 #include <QDir>
00028 #include <QFile>
00029 #include <QXmlStreamReader>
00030
00031 #include <KIO/CopyJob>
00032 #include <KIO/Job>
00033
00034 #include <Plasma/PackageMetadata>
00035 #include <Plasma/Package>
00036
00037 void recursive_print(const KArchiveDirectory *dir, const QString &path)
00038 {
00039 const QStringList l = dir->entries();
00040 QStringList::const_iterator it = l.constBegin();
00041 for (; it != l.end(); ++it)
00042 {
00043 const KArchiveEntry* entry = dir->entry((*it));
00044 printf("mode=%07o %s %s size: %lld pos: %lld %s%s isdir=%d%s",
00045 entry->permissions(),
00046 entry->user().toLatin1().constData(),
00047 entry->group().toLatin1().constData(),
00048 entry->isDirectory() ? 0 : ((KArchiveFile*)entry)->size(),
00049 entry->isDirectory() ? 0 : ((KArchiveFile*)entry)->position(),
00050 path.toLatin1().constData(),
00051 (*it).toLatin1().constData(), entry->isDirectory(),
00052 entry->symLinkTarget().isEmpty() ? "" :
00053 QString(" symlink: %1").arg(
00054 entry->symLinkTarget()).toLatin1().constData());
00055
00056
00057
00058 printf("\n");
00059 if (entry->isDirectory())
00060 recursive_print((KArchiveDirectory *)entry, path+(*it)+'/');
00061 }
00062 }
00063
00064
00065 static const KArchiveDirectory *recursiveFind(const KArchiveDirectory *dir)
00066 {
00067 const QStringList l = dir->entries();
00068 QStringList::const_iterator it;
00069 for (it = l.constBegin(); it != l.constEnd(); ++it) {
00070 const KArchiveEntry* entry = dir->entry((*it));
00071 if (entry->isDirectory()) {
00072 QString name = *it;
00073 if (name.startsWith(QLatin1String("__MACOSX"))) {
00074
00075 continue;
00076 } else if (name.endsWith(QLatin1String(".wdgt"))) {
00077
00078 return static_cast<const KArchiveDirectory*>(entry);
00079 } else {
00080 const KArchiveDirectory *fd =
00081 recursiveFind(static_cast<const KArchiveDirectory*>(entry));
00082 if (fd)
00083 return fd;
00084 }
00085 }
00086 }
00087 return 0;
00088 }
00089
00090 Bundle::Bundle(const QString &path)
00091 : PackageStructure(0, "MacDashboard"),
00092 m_isValid(false),
00093 m_width(0), m_height(0)
00094 {
00095 setContentsPrefix(QString());
00096 QFile f(path);
00097 f.open(QIODevice::ReadOnly);
00098 m_data = f.readAll();
00099 f.close();
00100 initTempDir();
00101 open();
00102 }
00103
00104 Bundle::Bundle(const QByteArray &data)
00105 : PackageStructure(0, "MacDashboard"),
00106 m_isValid(false),
00107 m_width(0),
00108 m_height(0)
00109 {
00110 setContentsPrefix(QString());
00111 m_data = data;
00112 initTempDir();
00113 open();
00114 }
00115
00116 Bundle::Bundle(QObject *parent, QVariantList args)
00117 : PackageStructure(parent, "MacDashboard"),
00118 m_isValid(false),
00119 m_tempDir(0),
00120 m_width(0),
00121 m_height(0)
00122 {
00123 Q_UNUSED(args)
00124 setContentsPrefix(QString());
00125 }
00126
00127 Bundle::~Bundle()
00128 {
00129 close();
00130 qWarning("done");
00131 }
00132
00133 void Bundle::setData(const QByteArray &data)
00134 {
00135 m_data = data;
00136 close();
00137 open();
00138 }
00139
00140 QByteArray Bundle::data() const
00141 {
00142 return m_data;
00143 }
00144
00145 bool Bundle::open()
00146 {
00147 if (!m_tempDir) {
00148 initTempDir();
00149 }
00150
00151 if (m_data.isEmpty()) {
00152 return false;
00153 }
00154
00155 QBuffer buffer(&m_data);
00156 KZip zip(&buffer);
00157 if (!zip.open(QIODevice::ReadOnly)) {
00158 qWarning("Couldn't open the bundle!");
00159 return false;
00160 }
00161
00162 const KArchiveDirectory *dir = zip.directory();
00163
00164 const KArchiveDirectory *foundDir = recursiveFind(dir);
00165 if (!foundDir) {
00166 qWarning("not a bundle");
00167 m_isValid = false;
00168 zip.close();
00169 return 0;
00170 }
00171
00172 m_isValid = extractArchive(foundDir, QLatin1String(""));
00173 qDebug()<<"Dir = "<<foundDir->name() << m_isValid;
00174
00175 if (m_isValid) {
00176 setPath(m_tempDir->name());
00177 }
00178
00179 zip.close();
00180
00181 return m_isValid;
00182 }
00183
00184 bool Bundle::close()
00185 {
00186 bool ret = m_tempDir;
00187 delete m_tempDir;
00188 m_tempDir = 0;
00189 return ret;
00190 }
00191
00192 bool Bundle::extractArchive(const KArchiveDirectory *dir, const QString &path)
00193 {
00194 const QStringList l = dir->entries();
00195
00196 QStringList::const_iterator it;
00197 for (it = l.constBegin(); it != l.constEnd(); ++it) {
00198 const KArchiveEntry* entry = dir->entry((*it));
00199 QString fullPath = QString("%1/%2").arg(path).arg(*it);
00200 if (entry->isDirectory()) {
00201 QString outDir = QString("%1%2").arg(m_tempDir->name()).arg(path);
00202 QDir qdir(outDir);
00203 qdir.mkdir(*it);
00204 extractArchive(static_cast<const KArchiveDirectory*>(entry), fullPath);
00205 } else if (entry->isFile()) {
00206 QString outName = QString("%1%2").arg(m_tempDir->name()).arg(fullPath.remove(0, 1));
00207
00208 QFile f(outName);
00209 if (!f.open(QIODevice::WriteOnly)) {
00210 qWarning("Couldn't create %s", qPrintable(outName));
00211 continue;
00212 }
00213 const KArchiveFile *archiveFile = static_cast<const KArchiveFile*>(entry);
00214 f.write(archiveFile->data());
00215 f.close();
00216 } else {
00217 qWarning("Unidentified entry at %s", qPrintable(fullPath));
00218 }
00219 }
00220 return true;
00221 }
00222
00223 void Bundle::pathChanged()
00224 {
00225
00226 m_isValid = extractInfo();
00227 }
00228
00229 bool Bundle::extractInfo()
00230 {
00231 QString plistLocation = QString("%1Info.plist").arg(path());
00232 QString configXml = QString("%1config.xml").arg(path());
00233 if (QFile::exists(plistLocation)) {
00234
00235 return parsePlist(plistLocation);
00236 } else if (QFile::exists(configXml)) {
00237 return parseConfigXml(configXml);
00238 }
00239
00240 return false;
00241 }
00242
00243 bool Bundle::parsePlist(const QString &loc)
00244 {
00245 QFile f(loc);
00246 if (!f.open(QIODevice::ReadOnly)) {
00247 qWarning("Couldn't open info file: '%s'", qPrintable(loc));
00248 return false;
00249 }
00250
00251 QMap<QString, QString> infoMap;
00252 QString str = f.readAll();
00253 QXmlStreamReader reader(str);
00254 while (!reader.atEnd()) {
00255 reader.readNext();
00256
00257 if (reader.isStartElement()) {
00258
00259 if (reader.name() == "key") {
00260 QString key, value;
00261 reader.readNext();
00262 if (reader.isCharacters()) {
00263 QString str = reader.text().toString();
00264 str = str.trimmed();
00265 if (!str.isEmpty())
00266 key = str;
00267 }
00268 if (key.isEmpty())
00269 continue;
00270 while (!reader.isStartElement())
00271 reader.readNext();
00272 if (reader.name() != "string" &&
00273 reader.name() != "integer") {
00274 qDebug()<<"Unrecognized val "<<reader.name().toString()
00275 <<" for key "<<key;
00276 continue;
00277 }
00278 reader.readNext();
00279 if (reader.isCharacters()) {
00280 QString str = reader.text().toString();
00281 str = str.trimmed();
00282 if (!str.isEmpty())
00283 value = str;
00284 }
00285
00286 infoMap.insert(key, value);
00287 }
00288 }
00289 }
00290
00291 QMap<QString, QString>::const_iterator itr;
00292 for (itr = infoMap.constBegin(); itr != infoMap.constEnd(); ++itr) {
00293 kDebug() << itr.key() << itr.value();
00294 if (itr.key() == QLatin1String("CFBundleIdentifier")) {
00295 m_bundleId = itr.value();
00296 } else if (itr.key() == QLatin1String("CFBundleName")) {
00297 m_description = itr.value();
00298 } else if (itr.key() == QLatin1String("CFBundleDisplayName")) {
00299 m_name = itr.value();
00300 } else if (itr.key() == QLatin1String("CFBundleVersion")) {
00301 m_version = itr.value();
00302 } else if (itr.key() == QLatin1String("CloseBoxInsetX")) {
00303
00304 } else if (itr.key() == QLatin1String("CloseBoxInsetY")) {
00305
00306 } else if (itr.key() == QLatin1String("Height")) {
00307 m_height = itr.value().toInt();
00308 } else if (itr.key() == QLatin1String("Width")) {
00309 m_width = itr.value().toInt();
00310 } else if (itr.key() == QLatin1String("MainHTML")) {
00311 m_htmlLocation = QString("%1%2").arg(path()).arg(itr.value());
00312 addFileDefinition("mainscript", itr.value(), i18n("Main Webpage"));
00313 } else {
00314 qDebug()<<"Unrecognized key = "<<itr.key();
00315 }
00316 }
00317 m_iconLocation = QString("%1Icon.png").arg(path());
00318 kDebug() << path();
00319 addDirectoryDefinition("root", "/", i18n("Root HTML directory"));
00320
00321
00322
00323
00324
00325
00326 return !m_bundleId.isEmpty();
00327 }
00328
00329 bool Bundle::installPackage(const QString &archivePath, const QString &packageRoot)
00330 {
00331
00332 QFile f(archivePath);
00333 f.open(QIODevice::ReadOnly);
00334 m_data = f.readAll();
00335 f.close();
00336 open();
00337
00338 if (m_isValid) {
00339 m_tempDir->setAutoRemove(false);
00340 QString pluginName = "dashboard_" + m_bundleId;
00341
00342 KIO::CopyJob* job = KIO::move(m_tempDir->name(), packageRoot + pluginName, KIO::HideProgressInfo);
00343 m_isValid = job->exec();
00344
00345 if (m_isValid) {
00346
00347 Plasma::PackageMetadata data;
00348 data.setName(m_name);
00349 data.setDescription(m_description);
00350 data.setPluginName(pluginName);
00351 data.setImplementationApi("dashboard");
00352 Plasma::Package::registerPackage(data, m_iconLocation);
00353 }
00354 }
00355
00356 if (!m_isValid) {
00357
00358 m_tempDir->setAutoRemove(true);
00359 }
00360
00361 return m_isValid;
00362 }
00363
00364 bool Bundle::parseConfigXml(const QString &loc)
00365 {
00366 QFile f(loc);
00367 if (!f.open(QIODevice::ReadOnly)) {
00368 qWarning("Couldn't open info file: '%s'", qPrintable(loc));
00369 return false;
00370 }
00371
00372 qWarning("FIXME: Widgets 1.0 not implemented");
00373
00374 return false;
00375 }
00376
00377 void Bundle::initTempDir()
00378 {
00379 m_tempDir = new KTempDir();
00380
00381 m_tempDir->setAutoRemove(true);
00382 }
00383
00384 QString Bundle::bundleId() const
00385 {
00386 return m_bundleId;
00387 }
00388
00389 QString Bundle::name() const
00390 {
00391 return m_name;
00392 }
00393
00394 QString Bundle::version() const
00395 {
00396 return m_version;
00397 }
00398
00399 QString Bundle::description() const
00400 {
00401 return m_description;
00402 }
00403
00404 int Bundle::width() const
00405 {
00406 return m_width;
00407 }
00408
00409 int Bundle::height() const
00410 {
00411 return m_height;
00412 }
00413
00414 QString Bundle::htmlLocation() const
00415 {
00416 return m_htmlLocation;
00417 }
00418
00419 QString Bundle::iconLocation() const
00420 {
00421 return m_iconLocation;
00422 }
00423
00424 bool Bundle::isValid() const
00425 {
00426 return m_isValid;
00427 }
00428
00429