/* Copyright (c) 2007 Zack Rusin Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #include "bundle.h" #include #include #include #include #include #include #include #include #include #include void recursive_print(const KArchiveDirectory *dir, const QString &path) { const QStringList l = dir->entries(); QStringList::const_iterator it = l.constBegin(); for (; it != l.end(); ++it) { const KArchiveEntry* entry = dir->entry((*it)); printf("mode=%07o %s %s size: %lld pos: %lld %s%s isdir=%d%s", entry->permissions(), entry->user().toLatin1().constData(), entry->group().toLatin1().constData(), entry->isDirectory() ? 0 : ((KArchiveFile*)entry)->size(), entry->isDirectory() ? 0 : ((KArchiveFile*)entry)->position(), path.toLatin1().constData(), (*it).toLatin1().constData(), entry->isDirectory(), entry->symLinkTarget().isEmpty() ? "" : QString(" symlink: %1").arg( entry->symLinkTarget()).toLatin1().constData()); //if (!entry->isDirectory()) printf("%d", // ((KArchiveFile*)entry)->size()); printf("\n"); if (entry->isDirectory()) recursive_print((KArchiveDirectory *)entry, path+(*it)+'/'); } } static const KArchiveDirectory *recursiveFind(const KArchiveDirectory *dir) { const QStringList l = dir->entries(); QStringList::const_iterator it; for (it = l.constBegin(); it != l.constEnd(); ++it) { const KArchiveEntry* entry = dir->entry((*it)); if (entry->isDirectory()) { QString name = *it; if (name.startsWith(QLatin1String("__MACOSX"))) { //skip this continue; } else if (name.endsWith(QLatin1String(".wdgt"))) { //got our bad boy return static_cast(entry); } else { const KArchiveDirectory *fd = recursiveFind(static_cast(entry)); if (fd) return fd; } } } return 0; } Bundle::Bundle(const QString &path) : PackageStructure(0, "MacDashboard"), m_isValid(false), m_width(0), m_height(0) { setContentsPrefixPaths(QStringList()); QFile f(path); f.open(QIODevice::ReadOnly); m_data = f.readAll(); f.close(); initTempDir(); open(); } Bundle::Bundle(const QByteArray &data) : PackageStructure(0, "MacDashboard"), m_isValid(false), m_width(0), m_height(0) { setContentsPrefixPaths(QStringList()); m_data = data; initTempDir(); open(); } Bundle::Bundle(QObject *parent, QVariantList args) : PackageStructure(parent, "MacDashboard"), m_isValid(false), m_tempDir(0), m_width(0), m_height(0) { Q_UNUSED(args) setContentsPrefixPaths(QStringList()); } Bundle::~Bundle() { close(); } void Bundle::setData(const QByteArray &data) { m_data = data; close(); open(); } QByteArray Bundle::data() const { return m_data; } bool Bundle::open() { if (!m_tempDir) { initTempDir(); } if (m_data.isEmpty()) { return false; } QBuffer buffer(&m_data); KZip zip(&buffer); if (!zip.open(QIODevice::ReadOnly)) { qWarning("Couldn't open the bundle!"); return false; } const KArchiveDirectory *dir = zip.directory(); const KArchiveDirectory *foundDir = recursiveFind(dir); if (!foundDir) { qWarning("not a bundle"); m_isValid = false; zip.close(); return 0; } m_isValid = extractArchive(foundDir, QLatin1String("")); qDebug()<<"Dir = "<name() << m_isValid; if (m_isValid) { setPath(m_tempDir->name()); } zip.close(); return m_isValid; } bool Bundle::close() { bool ret = m_tempDir; delete m_tempDir; m_tempDir = 0; return ret; } bool Bundle::extractArchive(const KArchiveDirectory *dir, const QString &path) { const QStringList l = dir->entries(); QStringList::const_iterator it; for (it = l.constBegin(); it != l.constEnd(); ++it) { const KArchiveEntry* entry = dir->entry((*it)); QString fullPath = QString("%1/%2").arg(path).arg(*it); if (entry->isDirectory()) { QString outDir = QString("%1%2").arg(m_tempDir->name()).arg(path); QDir qdir(outDir); qdir.mkdir(*it); extractArchive(static_cast(entry), fullPath); } else if (entry->isFile()) { QString outName = QString("%1%2").arg(m_tempDir->name()).arg(fullPath.remove(0, 1)); //qDebug()<<"-------- "<(entry); f.write(archiveFile->data()); f.close(); } else { qWarning("Unidentified entry at %s", qPrintable(fullPath)); } } return true; } void Bundle::pathChanged() { //qDebug() << "path changed"; m_isValid = extractInfo(); } bool Bundle::extractInfo() { QString plistLocation = QString("%1Info.plist").arg(path()); QString configXml = QString("%1config.xml").arg(path()); if (QFile::exists(plistLocation)) { //qDebug() << "doing plist"; return parsePlist(plistLocation); } else if (QFile::exists(configXml)) { return parseConfigXml(configXml); } return false; } bool Bundle::parsePlist(const QString &loc) { QFile f(loc); if (!f.open(QIODevice::ReadOnly)) { qWarning("Couldn't open info file: '%s'", qPrintable(loc)); return false; } QMap infoMap; QString str = f.readAll(); QXmlStreamReader reader(str); while (!reader.atEnd()) { reader.readNext(); // do processing if (reader.isStartElement()) { //qDebug() << reader.name().toString(); if (reader.name() == "key") { QString key, value; reader.readNext(); if (reader.isCharacters()) { QString str = reader.text().toString(); str = str.trimmed(); if (!str.isEmpty()) key = str; } if (key.isEmpty()) continue; while (!reader.isStartElement()) reader.readNext(); if (reader.name() != "string" && reader.name() != "integer") { qDebug()<<"Unrecognized val "<setAutoRemove(false); QString pluginName = "dashboard_" + m_bundleId; //kDebug() << "valid, so going to move it in to" << pluginName; KIO::CopyJob* job = KIO::move(m_tempDir->name(), QString(packageRoot + pluginName), KIO::HideProgressInfo); m_isValid = job->exec(); if (m_isValid) { //kDebug() << "still so good ... registering"; Plasma::PackageMetadata data; data.setName(m_name); data.setDescription(m_description); data.setPluginName(pluginName); data.setImplementationApi("dashboard"); Plasma::Package::registerPackage(data, m_iconLocation); } } if (!m_isValid) { // make sure we clean up after ourselves afterwards on failure m_tempDir->setAutoRemove(true); } return m_isValid; } bool Bundle::parseConfigXml(const QString &loc) { QFile f(loc); if (!f.open(QIODevice::ReadOnly)) { qWarning("Couldn't open info file: '%s'", qPrintable(loc)); return false; } qWarning("FIXME: Widgets 1.0 not implemented"); return false; } void Bundle::initTempDir() { m_tempDir = new KTempDir(); //make it explicit m_tempDir->setAutoRemove(true); } QString Bundle::bundleId() const { return m_bundleId; } QString Bundle::name() const { return m_name; } QString Bundle::version() const { return m_version; } QString Bundle::description() const { return m_description; } int Bundle::width() const { return m_width; } int Bundle::height() const { return m_height; } QString Bundle::htmlLocation() const { return m_htmlLocation; } QString Bundle::iconLocation() const { return m_iconLocation; } bool Bundle::isValid() const { return m_isValid; }