File indexing completed on 2024-04-28 05:27:04

0001 /*  This file is part of the KDE project
0002     SPDX-FileCopyrightText: 2007, 2008 David Faure <faure@kde.org>
0003 
0004     SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
0005 */
0006 
0007 #include "mimetypewriter.h"
0008 
0009 #include <QDebug>
0010 #include <QDir>
0011 #include <QFile>
0012 #include <QStandardPaths>
0013 #include <QXmlStreamWriter>
0014 
0015 #include <KProcess>
0016 
0017 class MimeTypeWriterPrivate
0018 {
0019 public:
0020     QString localFilePath() const;
0021 
0022     QString m_mimeType;
0023     QString m_comment;
0024     QString m_iconName;
0025     QStringList m_patterns;
0026     QString m_marker;
0027 };
0028 
0029 MimeTypeWriter::MimeTypeWriter(const QString &mimeType)
0030     : d(new MimeTypeWriterPrivate)
0031 {
0032     d->m_mimeType = mimeType;
0033     Q_ASSERT(!mimeType.isEmpty());
0034 }
0035 
0036 MimeTypeWriter::~MimeTypeWriter()
0037 {
0038     delete d;
0039 }
0040 
0041 void MimeTypeWriter::setComment(const QString &comment)
0042 {
0043     d->m_comment = comment;
0044 }
0045 
0046 void MimeTypeWriter::setPatterns(const QStringList &patterns)
0047 {
0048     d->m_patterns = patterns;
0049 }
0050 
0051 void MimeTypeWriter::setIconName(const QString &iconName)
0052 {
0053     d->m_iconName = iconName;
0054 }
0055 
0056 void MimeTypeWriter::setMarker(const QString &marker)
0057 {
0058     d->m_marker = marker;
0059 }
0060 
0061 bool MimeTypeWriter::write()
0062 {
0063     const QString packageFileName = d->localFilePath();
0064     qDebug() << "writing" << packageFileName;
0065     QFile packageFile(packageFileName);
0066     if (!packageFile.open(QIODevice::WriteOnly)) {
0067         qCritical() << "Couldn't open" << packageFileName << "for writing";
0068         return false;
0069     }
0070     QXmlStreamWriter writer(&packageFile);
0071     writer.setAutoFormatting(true);
0072     writer.writeStartDocument();
0073     if (!d->m_marker.isEmpty()) {
0074         writer.writeComment(d->m_marker);
0075     }
0076     const QString nsUri = QStringLiteral("http://www.freedesktop.org/standards/shared-mime-info");
0077     writer.writeDefaultNamespace(nsUri);
0078     writer.writeStartElement(QStringLiteral("mime-info"));
0079     writer.writeStartElement(nsUri, QStringLiteral("mime-type"));
0080     writer.writeAttribute(QStringLiteral("type"), d->m_mimeType);
0081 
0082     if (!d->m_comment.isEmpty()) {
0083         writer.writeStartElement(nsUri, QStringLiteral("comment"));
0084         writer.writeCharacters(d->m_comment);
0085         writer.writeEndElement(); // comment
0086     }
0087 
0088     if (!d->m_iconName.isEmpty()) {
0089         // User-specified icon name
0090         writer.writeStartElement(nsUri, QStringLiteral("icon"));
0091         writer.writeAttribute(QStringLiteral("name"), d->m_iconName);
0092         writer.writeEndElement(); // icon
0093     }
0094 
0095     // Allow this local definition to override the global definition
0096     writer.writeStartElement(nsUri, QStringLiteral("glob-deleteall"));
0097     writer.writeEndElement(); // glob-deleteall
0098 
0099     for (const QString &pattern : std::as_const(d->m_patterns)) {
0100         writer.writeStartElement(nsUri, QStringLiteral("glob"));
0101         writer.writeAttribute(QStringLiteral("pattern"), pattern);
0102         writer.writeEndElement(); // glob
0103     }
0104 
0105     writer.writeEndElement(); // mime-info
0106     writer.writeEndElement(); // mime-type
0107     writer.writeEndDocument();
0108     return true;
0109 }
0110 
0111 void MimeTypeWriter::runUpdateMimeDatabase()
0112 {
0113     const QString localPackageDir = QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation) + QLatin1String("/mime/");
0114     Q_ASSERT(!localPackageDir.isEmpty());
0115     KProcess proc;
0116     proc << QStringLiteral("update-mime-database");
0117     proc << localPackageDir;
0118     const int exitCode = proc.execute();
0119     if (exitCode) {
0120         qWarning() << proc.program() << "exited with error code" << exitCode;
0121     }
0122 }
0123 
0124 QString MimeTypeWriterPrivate::localFilePath() const
0125 {
0126     // XDG shared mime: we must write into a <kdehome>/share/mime/packages/ file...
0127     // To simplify our job, let's use one "input" file per mimetype, in the user's dir.
0128     // (this writes into $HOME/.local/share/mime by default)
0129     //
0130     // We could also use Override.xml, says the spec, but then we'd need to merge with other mimetypes,
0131     // and in ~/.local we don't really expect other packages to be installed anyway...
0132     QString baseName = m_mimeType;
0133     baseName.replace(QLatin1Char('/'), QLatin1Char('-'));
0134     QString packagesDirName = QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation) + QLatin1String("/mime/") + QStringLiteral("packages/");
0135     // create the directory, the saving will fail if it doesn't exist (bug#356237)
0136     QDir(packagesDirName).mkpath(QStringLiteral("."));
0137     return packagesDirName + baseName + QStringLiteral(".xml");
0138 }
0139 
0140 static QString existingDefinitionFile(const QString &mimeType)
0141 {
0142     QString baseName = mimeType;
0143     baseName.replace(QLatin1Char('/'), QLatin1Char('-'));
0144     return QStandardPaths::locate(QStandardPaths::GenericDataLocation,
0145                                   QLatin1String("mime/") + QStringLiteral("packages/") + baseName + QStringLiteral(".xml"));
0146 }
0147 
0148 bool MimeTypeWriter::hasDefinitionFile(const QString &mimeType)
0149 {
0150     return !existingDefinitionFile(mimeType).isEmpty();
0151 }
0152 
0153 void MimeTypeWriter::removeOwnMimeType(const QString &mimeType)
0154 {
0155     const QString file = existingDefinitionFile(mimeType);
0156     Q_ASSERT(!file.isEmpty());
0157     QFile::remove(file);
0158     // We must also remove the generated XML file, update-mime-database doesn't do that, for unknown media types
0159     QString xmlFile = QStandardPaths::locate(QStandardPaths::GenericDataLocation, QLatin1String("mime/") + mimeType + QStringLiteral(".xml"));
0160     QFile::remove(xmlFile);
0161 }
0162 
0163 /// WARNING: this code is duplicated between apps/nsplugins and runtime/filetypes