File indexing completed on 2024-04-21 05:50:36

0001 /*
0002     SPDX-FileCopyrightText: 2008-2022 Rolf Eike Beer <kde@opensource.sf-tec.de>
0003 
0004     SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
0005 */
0006 #include "KGpgGroupNode.h"
0007 
0008 #include "kgpg_general_debug.h"
0009 #include "KGpgGroupMemberNode.h"
0010 #include "KGpgRootNode.h"
0011 #include "kgpgsettings.h"
0012 
0013 #include <KLocalizedString>
0014 
0015 
0016 #include <QFile>
0017 #include <QRegularExpression>
0018 #include <QTextStream>
0019 
0020 class KGpgGroupNodePrivate {
0021 public:
0022     explicit KGpgGroupNodePrivate(const QString &name);
0023 
0024     QString m_name;
0025 
0026     /**
0027      * @brief find the line that defines this group in the configuration
0028      * @param conffile file object (will be initialized)
0029      * @param stream text stream (will be initialized and connected to conffile)
0030      * @param lines the lines found in conffile (will be filled)
0031      * @return the index in lines of the entry defining this group
0032      * @retval -1 no entry defining this group was found
0033      *
0034      * stream will be positioned at the beginning.
0035      */
0036     int findGroupEntry(QFile &conffile, QTextStream &stream, QStringList &lines);
0037 
0038     static const QRegularExpression &groupPattern();
0039     static const QString &groupTag();
0040 };
0041 
0042 KGpgGroupNodePrivate::KGpgGroupNodePrivate(const QString &name)
0043     : m_name(name)
0044 {
0045 }
0046 
0047 int
0048 KGpgGroupNodePrivate::findGroupEntry(QFile &conffile, QTextStream &stream, QStringList &lines)
0049 {
0050     conffile.setFileName(KGpgSettings::gpgConfigPath());
0051 
0052     if (!conffile.exists())
0053         return -1;
0054 
0055     if (!conffile.open(QIODevice::ReadWrite))
0056         return -1;
0057 
0058     stream.setDevice(&conffile);
0059     int index = -1;
0060     int i = -1;
0061 
0062     while (!stream.atEnd()) {
0063         const QString rawLine = stream.readLine();
0064         i++;
0065         QString parsedLine = rawLine.simplified().section(QLatin1Char('#'), 0, 0);
0066 
0067         if (groupPattern().match(parsedLine).hasMatch()) {
0068             // remove "group "
0069             parsedLine.remove(0, 6);
0070             if (parsedLine.startsWith(m_name)) {
0071                 if (QStringView(parsedLine).mid(m_name.length()).trimmed().startsWith(QLatin1Char('='))) {
0072                     if (index >= 0) {
0073                         // multiple definitions of the same group, drop the second one
0074                         continue;
0075                     } else {
0076                         index = i;
0077                     }
0078                 }
0079             }
0080         }
0081 
0082         lines << rawLine;
0083     }
0084 
0085     stream.seek(0);
0086 
0087     return index;
0088 }
0089 
0090 const QRegularExpression &
0091 KGpgGroupNodePrivate::groupPattern()
0092 {
0093     static const QRegularExpression groupre(QStringLiteral("^group [^ ]+ ?= ?([0-9a-fA-F]{8,} ?)*$"));
0094 
0095     return groupre;
0096 }
0097 
0098 const QString &
0099 KGpgGroupNodePrivate::groupTag()
0100 {
0101     static const QString grouptag(QLatin1String("group "));
0102 
0103     return grouptag;
0104 }
0105 
0106 KGpgGroupNode::KGpgGroupNode(KGpgRootNode *parent, const QString &name, const QStringList &members)
0107     : KGpgExpandableNode(parent),
0108     d_ptr(new KGpgGroupNodePrivate(name))
0109 {
0110     for (const QString &id : members)
0111         if (id.startsWith(QLatin1String("0x")))
0112             new KGpgGroupMemberNode(this, id.mid(2));
0113         else
0114             new KGpgGroupMemberNode(this, id);
0115 
0116     parent->m_groups++;
0117 }
0118 
0119 KGpgGroupNode::KGpgGroupNode(KGpgRootNode *parent, const QString &name, const KGpgKeyNode::List &members)
0120     : KGpgExpandableNode(parent),
0121     d_ptr(new KGpgGroupNodePrivate(name))
0122 {
0123     Q_ASSERT(!members.isEmpty());
0124 
0125     for (KGpgKeyNode *nd : members)
0126         new KGpgGroupMemberNode(this, nd);
0127 
0128     parent->m_groups++;
0129 }
0130 
0131 KGpgGroupNode::~KGpgGroupNode()
0132 {
0133     if (parent() != nullptr)
0134         m_parent->toRootNode()->m_groups--;
0135 }
0136 
0137 KgpgCore::KgpgItemType
0138 KGpgGroupNode::getType() const
0139 {
0140     return ITYPE_GROUP;
0141 }
0142 
0143 QString
0144 KGpgGroupNode::getName() const
0145 {
0146     const Q_D(KGpgGroupNode);
0147 
0148     return d->m_name;
0149 }
0150 
0151 QString
0152 KGpgGroupNode::getSize() const
0153 {
0154     return i18np("1 key", "%1 keys", children.count());
0155 }
0156 
0157 void
0158 KGpgGroupNode::readChildren()
0159 {
0160 }
0161 
0162 void
0163 KGpgGroupNode::rename(const QString &newName)
0164 {
0165     Q_D(KGpgGroupNode);
0166 
0167     QFile conffile;
0168     QTextStream t;
0169     QStringList lines;
0170     int index = d->findGroupEntry(conffile, t, lines);
0171 
0172     // check if file opening failed
0173     if (!t.device())
0174         return;
0175 
0176     if (index < 0) {
0177         qCDebug(KGPG_LOG_GENERAL) << "Group " << d->m_name << " not renamed, group does not exist";
0178         return;
0179     }
0180 
0181     // 6 = groupTag().length()
0182     const QString values = lines[index].simplified().mid(6 + d->m_name.length());
0183     lines[index] = d->groupTag() + newName + QLatin1Char(' ') + values;
0184 
0185     conffile.resize(0);
0186     t << lines.join(QLatin1String("\n")) + QLatin1Char('\n');
0187 
0188     d->m_name = newName;
0189 }
0190 
0191 void
0192 KGpgGroupNode::saveMembers()
0193 {
0194     Q_D(KGpgGroupNode);
0195 
0196     QFile conffile;
0197     QTextStream t;
0198     QStringList lines;
0199     int index = d->findGroupEntry(conffile, t, lines);
0200 
0201     // check if file opening failed
0202     if (!t.device())
0203         return;
0204 
0205     QStringList memberIds;
0206 
0207     for (int j = getChildCount() - 1; j >= 0; j--)
0208         memberIds << getChild(j)->toGroupMemberNode()->getId();
0209 
0210     const QString groupEntry = d->groupTag() + d->m_name + QLatin1String(" = ") +
0211             memberIds.join(QLatin1Char(' '));
0212 
0213     if (index >= 0)
0214         lines[index] = groupEntry;
0215     else
0216         lines << groupEntry;
0217 
0218     conffile.resize(0);
0219     t << lines.join(QLatin1String("\n")) + QLatin1Char('\n');
0220 }
0221 
0222 void
0223 KGpgGroupNode::remove()
0224 {
0225     Q_D(KGpgGroupNode);
0226 
0227     QFile conffile;
0228     QTextStream t;
0229     QStringList lines;
0230     int index = d->findGroupEntry(conffile, t, lines);
0231 
0232     // check if file opening failed
0233     if (!t.device())
0234         return;
0235 
0236     if (index < 0)
0237         return;
0238 
0239     lines.removeAt(index);
0240     conffile.resize(0);
0241     t << lines.join(QLatin1String("\n")) + QLatin1Char('\n');
0242 }