diff options
author | Alex Merry <dev@randomguy3.me.uk> | 2011-11-14 19:43:35 +0000 |
---|---|---|
committer | Alex Merry <dev@randomguy3.me.uk> | 2011-11-14 19:54:09 +0000 |
commit | dfa9ee46c698418efe85c03988b31879714e3dee (patch) | |
tree | d214935cf8d598f08df6b93f5cb3a98765056a76 | |
parent | dbdd1b40ba27bd58fdbbc6a02fc7b74bf124dba5 (diff) |
Add desktop file and mimetype checking
-rw-r--r-- | mpris2/rootinterfacetest.cpp | 104 | ||||
-rw-r--r-- | mpris2/rootinterfacetest.h | 4 |
2 files changed, 101 insertions, 7 deletions
diff --git a/mpris2/rootinterfacetest.cpp b/mpris2/rootinterfacetest.cpp index 664b8bb..bd76f79 100644 --- a/mpris2/rootinterfacetest.cpp +++ b/mpris2/rootinterfacetest.cpp @@ -19,6 +19,10 @@ #include <QDBusInterface> #include <QDBusMessage> #include <QDBusReply> +#include <QDir> +#include <QSettings> +#include <QString> +#include <QTextStream> #define MPRIS2_ROOT_IFACE "org.mpris.MediaPlayer2" @@ -27,6 +31,47 @@ using namespace Mpris2; RootInterfaceTest::RootInterfaceTest(const QString& service, QObject* parent) : InterfaceTest(MPRIS2_ROOT_IFACE, service, parent) { + // http://standards.freedesktop.org/basedir-spec/0.6/ + QStringList dataPaths; + QByteArray xdgDataHomeVar = qgetenv("XDG_DATA_HOME"); + if (!xdgDataHomeVar.isEmpty()) { + dataPaths << QFile::decodeName(xdgDataHomeVar); + } else { + dataPaths << QDir::homePath() + "/.local/share"; + } + QByteArray xdgDataDirsVar = qgetenv("XDG_DATA_DIRS"); + if (xdgDataDirsVar.isEmpty()) { + xdgDataDirsVar = "/usr/local/share:/usr/share"; + } + Q_FOREACH(const QByteArray& dir, xdgDataDirsVar.split(':')) { + dataPaths << QFile::decodeName(dir); + } + QDir::setSearchPaths("xdgdata", dataPaths); + + // http://www.iana.org/assignments/media-types/index.html + m_rootMimetypes << "application" << "audio" << "example" + << "image" << "message" << "model" + << "multipart" << "text" << "video"; + QFile mimeTypesFile("/etc/mime.types"); + if (!mimeTypesFile.open(QIODevice::ReadOnly)) { + qWarning("Cannot open /etc/mime.types; full mimetype checking disabled"); + } else { + QTextStream mimeStream(&mimeTypesFile); + // assume /etc/mime.types doesn't have ridiculous lines + QString line = mimeStream.readLine(); + QRegExp wsRegExp("\\s"); + while (!line.isNull()) { + line = line.trimmed(); + if (!line.isEmpty() && !line.startsWith('#')) { + int wsPos = line.indexOf(wsRegExp); + if (wsPos > 0) { + line = line.left(wsPos); + } + m_mimeTypes.insert(line); + } + line = mimeStream.readLine(); + } + } } RootInterfaceTest::~RootInterfaceTest() @@ -36,7 +81,7 @@ RootInterfaceTest::~RootInterfaceTest() void RootInterfaceTest::checkPropertyIdentity(const QVariantMap& oldProps) { if (checkNonEmptyStringPropValid("Identity", oldProps)) { - QString identity = props["Identity"].toString(); + QString identity = props.value("Identity").toString(); if (("org.mpris.MediaPlayer2." + identity) == iface->service()) { emit interfaceWarning(Property, "Identity", "Identity is the same as the service name (one is user-readable, the other is the 'internal' name)"); } @@ -46,15 +91,32 @@ void RootInterfaceTest::checkPropertyIdentity(const QVariantMap& oldProps) void RootInterfaceTest::checkPropertyDesktopEntry(const QVariantMap& oldProps) { if (checkNonEmptyStringPropValid("DesktopEntry", oldProps)) { - // TODO: check for desktop file existence - // check that desktop name matches identity, warn otherwise + QString desktopEntry = props.value("DesktopEntry").toString(); + QFile file("xdgdata:applications/" + desktopEntry + ".desktop"); + if (!file.exists()) { + file.setFileName("xdgdata:applications/" + desktopEntry.replace('-', '/') + ".desktop"); + if (!file.exists()) { + emit interfaceWarning(Property, "DesktopEntry", "Could not find the desktop file"); + return; + } + } + + QSettings desktopFile(file.fileName(), QSettings::IniFormat); + desktopFile.beginGroup("Desktop Entry"); + QString generalName = desktopFile.value("Name").toString(); + if (generalName.isEmpty()) { + emit interfaceWarning(Property, "DesktopEntry", "Failed to read the Name entry of " + desktopFile.fileName()); + } else if (generalName != props.value("Identity").toString()) { + // TODO: translated names? http://standards.freedesktop.org/desktop-entry-spec/1.1/ar01s04.html + emit interfaceWarning(Property, "DesktopEntry", "The Name entry of " + desktopFile.fileName() + " (" + generalName + ") is different from Identity"); + } } } void RootInterfaceTest::checkPropertySupportedUriSchemes(const QVariantMap& oldProps) { if (checkPropValid("SupportedUriSchemes", QVariant::StringList, oldProps)) { - QStringList uriSchemes = props["SupportedUriSchemes"].toStringList(); + QStringList uriSchemes = props.value("SupportedUriSchemes").toStringList(); if (!uriSchemes.contains("file")) { emit interfaceWarning(Property, "SupportedUriSchemes", "\"file\" is not listed as a supported URI scheme (this is unusual)"); } @@ -66,12 +128,40 @@ void RootInterfaceTest::checkPropertySupportedUriSchemes(const QVariantMap& oldP void RootInterfaceTest::checkPropertySupportedMimeTypes(const QVariantMap& oldProps) { if (checkPropValid("SupportedMimeTypes", QVariant::StringList, oldProps)) { - QStringList mimeTypes = props["SupportedMimeTypes"].toStringList(); + QStringList mimeTypes = props.value("SupportedMimeTypes").toStringList(); if (mimeTypes.isEmpty()) { emit interfaceWarning(Property, "SupportedMimeTypes", "The media player claims not to support any mime types"); } - // TODO: check valid mimetypes - // check duplicates? + + QMap<QString,int> seenCount; + Q_FOREACH (const QString& mimeType, mimeTypes) { + ++seenCount[mimeType]; + if (!m_mimeTypes.contains(mimeType)) { + int slashIndex = mimeType.indexOf('/'); + if (slashIndex < 1) { + emit interfaceError(Property, "SupportedMimeTypes", "\"" + mimeType + "\" is not a valid mimetype"); + } else { + QString rootType = mimeType.left(slashIndex); + QString subType = mimeType.mid(slashIndex + 1); + if (!m_rootMimetypes.contains(rootType)) { + emit interfaceError(Property, "SupportedMimeTypes", + "\"" + mimeType + "\" is not a valid mimetype (\"" + + rootType + "\" is not a valid content type)"); + } else if (!m_mimeTypes.isEmpty() && !subType.startsWith("x-", Qt::CaseInsensitive)) { + emit interfaceWarning(Property, "SupportedMimeTypes", + "\"" + mimeType + "\" is not a recognized mimetype"); + } + } + } + } + + QMap<QString,int>::ConstIterator it = seenCount.constBegin(); + for (; it != seenCount.constEnd(); ++it) { + if (it.value() > 1) { + emit interfaceWarning(Property, "SupportedMimeTypes", + "\"" + it.key() + "\" appeared " + QString::number(it.value()) + " times"); + } + } } } diff --git a/mpris2/rootinterfacetest.h b/mpris2/rootinterfacetest.h index b29db35..43862a3 100644 --- a/mpris2/rootinterfacetest.h +++ b/mpris2/rootinterfacetest.h @@ -18,6 +18,7 @@ #define ROOT_INTERFACE_TEST_H #include "interfacetest.h" +#include <QSet> class QDBusInterface; @@ -64,6 +65,9 @@ namespace Mpris2 void checkPropertyDesktopEntry(const QVariantMap& oldProps = QVariantMap()); void checkPropertySupportedUriSchemes(const QVariantMap& oldProps = QVariantMap()); void checkPropertySupportedMimeTypes(const QVariantMap& oldProps = QVariantMap()); + + QStringList m_rootMimetypes; + QSet<QString> m_mimeTypes; }; } |