File indexing completed on 2024-04-21 05:01:39

0001 /*
0002     This class handles the homes shares
0003 
0004     SPDX-FileCopyrightText: 2006-2023 Alexander Reinholdt <alexander.reinholdt@kdemail.net>
0005     SPDX-License-Identifier: GPL-2.0-or-later
0006 */
0007 
0008 // application specific includes
0009 #include "smb4khomesshareshandler.h"
0010 #include "smb4knotification.h"
0011 #include "smb4kprofilemanager.h"
0012 #include "smb4ksettings.h"
0013 #include "smb4kshare.h"
0014 
0015 // Qt includes
0016 #include <QFile>
0017 #include <QXmlStreamReader>
0018 #include <QXmlStreamWriter>
0019 
0020 // KDE includes
0021 #include <KLocalizedString>
0022 
0023 class Smb4KHomesUsers
0024 {
0025 public:
0026     Smb4KHomesUsers(const SharePtr &share, const QStringList &users)
0027     {
0028         m_workgroupName = share->workgroupName();
0029         m_url = share->url();
0030         m_userList = users;
0031     }
0032 
0033     Smb4KHomesUsers(const Smb4KHomesUsers &users)
0034     {
0035         m_workgroupName = users.workgroupName();
0036         m_url = users.url();
0037         m_userList = users.userList();
0038         m_profile = users.profile();
0039     }
0040 
0041     Smb4KHomesUsers()
0042     {
0043     }
0044 
0045     ~Smb4KHomesUsers()
0046     {
0047     }
0048 
0049     QString workgroupName() const
0050     {
0051         return m_workgroupName;
0052     }
0053 
0054     void setWorkgroupName(const QString &workgroupName)
0055     {
0056         m_workgroupName = workgroupName;
0057     }
0058 
0059     QUrl url() const
0060     {
0061         return m_url;
0062     }
0063 
0064     void setUrl(const QUrl &url)
0065     {
0066         m_url = url;
0067     }
0068 
0069     QStringList userList() const
0070     {
0071         return m_userList;
0072     }
0073 
0074     void setUserList(const QStringList &userList)
0075     {
0076         m_userList = userList;
0077     }
0078 
0079     QString profile() const
0080     {
0081         return m_profile;
0082     }
0083 
0084     void setProfile(const QString &profile)
0085     {
0086         m_profile = profile;
0087     }
0088 
0089 private:
0090     QString m_workgroupName;
0091     QUrl m_url;
0092     QStringList m_userList;
0093     QString m_profile;
0094 };
0095 
0096 class Smb4KHomesSharesHandlerPrivate
0097 {
0098 public:
0099     QList<Smb4KHomesUsers *> homesUsers;
0100 };
0101 
0102 class Smb4KHomesSharesHandlerStatic
0103 {
0104 public:
0105     Smb4KHomesSharesHandler instance;
0106 };
0107 
0108 Q_GLOBAL_STATIC(Smb4KHomesSharesHandlerStatic, p);
0109 
0110 Smb4KHomesSharesHandler::Smb4KHomesSharesHandler(QObject *parent)
0111     : QObject(parent)
0112     , d(new Smb4KHomesSharesHandlerPrivate)
0113 {
0114     // First we need the directory.
0115     QString path = dataLocation();
0116 
0117     QDir dir;
0118 
0119     if (!dir.exists(path)) {
0120         dir.mkpath(path);
0121     }
0122 
0123     readUserNames();
0124 }
0125 
0126 Smb4KHomesSharesHandler::~Smb4KHomesSharesHandler()
0127 {
0128     while (!d->homesUsers.isEmpty()) {
0129         delete d->homesUsers.takeFirst();
0130     }
0131 }
0132 
0133 Smb4KHomesSharesHandler *Smb4KHomesSharesHandler::self()
0134 {
0135     return &p->instance;
0136 }
0137 
0138 QStringList Smb4KHomesSharesHandler::homesUsers(const SharePtr &share)
0139 {
0140     Q_ASSERT(share);
0141 
0142     QStringList userList;
0143 
0144     if (!d->homesUsers.isEmpty()) {
0145         for (const Smb4KHomesUsers *users : qAsConst(d->homesUsers)) {
0146             if (users->profile() == Smb4KSettings::activeProfile()
0147                 && QString::compare(share->url().toString(QUrl::RemoveUserInfo | QUrl::RemovePort),
0148                                     users->url().toString(QUrl::RemoveUserInfo | QUrl::RemovePort))
0149                     == 0) {
0150                 userList = users->userList();
0151                 break;
0152             }
0153         }
0154     }
0155 
0156     return userList;
0157 }
0158 
0159 void Smb4KHomesSharesHandler::addHomesUsers(const SharePtr &share, const QStringList &userList)
0160 {
0161     Q_ASSERT(share);
0162 
0163     bool found = false;
0164 
0165     if (!d->homesUsers.isEmpty()) {
0166         QMutableListIterator<Smb4KHomesUsers *> it(d->homesUsers);
0167 
0168         while (it.hasNext()) {
0169             Smb4KHomesUsers *users = it.next();
0170 
0171             if (users->profile() == Smb4KSettings::activeProfile()
0172                 && QString::compare(share->url().toString(QUrl::RemoveUserInfo | QUrl::RemovePort),
0173                                     users->url().toString(QUrl::RemoveUserInfo | QUrl::RemovePort))
0174                     == 0) {
0175                 users->setUserList(userList);
0176                 found = true;
0177                 break;
0178             }
0179         }
0180     }
0181 
0182     if (!found) {
0183         Smb4KHomesUsers *users = new Smb4KHomesUsers(share, userList);
0184         users->setProfile(Smb4KProfileManager::self()->activeProfile());
0185         d->homesUsers << users;
0186     }
0187 
0188     writeUserNames();
0189 }
0190 
0191 void Smb4KHomesSharesHandler::readUserNames()
0192 {
0193     // Locate the XML file.
0194     QFile xmlFile(dataLocation() + QDir::separator() + QStringLiteral("homes_shares.xml"));
0195 
0196     if (xmlFile.open(QIODevice::ReadOnly | QIODevice::Text)) {
0197         QXmlStreamReader xmlReader(&xmlFile);
0198 
0199         QString versionString;
0200 
0201         while (!xmlReader.atEnd()) {
0202             xmlReader.readNext();
0203 
0204             if (xmlReader.isStartElement()) {
0205                 if (xmlReader.name() == QStringLiteral("homes_shares") && xmlReader.attributes().value(QStringLiteral("version")) != QStringLiteral("1.0")
0206                     && xmlReader.attributes().value(QStringLiteral("version")) != QStringLiteral("2.0")) {
0207                     xmlReader.raiseError(i18n("The format of %1 is not supported.", xmlFile.fileName()));
0208                     break;
0209                 } else {
0210                     // NOTE: Forbackward compatibility. Remove with version >> 4.0
0211                     if (xmlReader.name() == QStringLiteral("homes_shares")) {
0212                         versionString = xmlReader.attributes().value(QStringLiteral("version")).toString();
0213                     }
0214 
0215                     if (versionString == QStringLiteral("1.0")) {
0216                         if (xmlReader.name() == QStringLiteral("homes")) {
0217                             QString profile = xmlReader.attributes().value(QStringLiteral("profile")).toString();
0218 
0219                             Smb4KHomesUsers *users = new Smb4KHomesUsers();
0220                             users->setProfile(profile);
0221 
0222                             QUrl url;
0223                             url.setScheme(QStringLiteral("smb"));
0224                             url.setPath(xmlReader.name().toString());
0225 
0226                             while (!(xmlReader.isEndElement() && xmlReader.name() == QStringLiteral("homes"))) {
0227                                 xmlReader.readNext();
0228 
0229                                 if (xmlReader.isStartElement()) {
0230                                     if (xmlReader.name() == QStringLiteral("host")) {
0231                                         url.setHost(xmlReader.readElementText());
0232                                     } else if (xmlReader.name() == QStringLiteral("workgroup")) {
0233                                         users->setWorkgroupName(xmlReader.readElementText());
0234                                     } else if (xmlReader.name() == QStringLiteral("users")) {
0235                                         QStringList u;
0236 
0237                                         while (!(xmlReader.isEndElement() && xmlReader.name() == QStringLiteral("users"))) {
0238                                             xmlReader.readNext();
0239 
0240                                             if (xmlReader.isStartElement() && xmlReader.name() == QStringLiteral("user")) {
0241                                                 u << xmlReader.readElementText();
0242                                             }
0243                                         }
0244 
0245                                         users->setUserList(u);
0246                                     }
0247                                 }
0248                             }
0249 
0250                             users->setUrl(url);
0251 
0252                             d->homesUsers << users;
0253                         }
0254                     } else if (versionString == QStringLiteral("2.0")) {
0255                         if (xmlReader.name() == QStringLiteral("homes_share")) {
0256                             QUrl url(xmlReader.attributes().value(QStringLiteral("url")).toString());
0257                             QString profile = xmlReader.attributes().value(QStringLiteral("profile")).toString();
0258 
0259                             Smb4KHomesUsers *users = new Smb4KHomesUsers();
0260                             users->setProfile(profile);
0261                             users->setUrl(url);
0262 
0263                             while (!(xmlReader.isEndElement() && xmlReader.name() == QStringLiteral("homes_share"))) {
0264                                 xmlReader.readNext();
0265 
0266                                 if (xmlReader.isStartElement()) {
0267                                     if (xmlReader.name() == QStringLiteral("workgroup")) {
0268                                         users->setWorkgroupName(xmlReader.readElementText());
0269                                     } else if (xmlReader.name() == QStringLiteral("users")) {
0270                                         QStringList u;
0271 
0272                                         while (!(xmlReader.isEndElement() && xmlReader.name() == QStringLiteral("users"))) {
0273                                             xmlReader.readNext();
0274 
0275                                             if (xmlReader.isStartElement() && xmlReader.name() == QStringLiteral("user")) {
0276                                                 u << xmlReader.readElementText();
0277                                             }
0278                                         }
0279 
0280                                         users->setUserList(u);
0281                                     }
0282                                 }
0283                             }
0284 
0285                             d->homesUsers << users;
0286                         }
0287                     }
0288                 }
0289             }
0290         }
0291 
0292         xmlFile.close();
0293 
0294         if (xmlReader.hasError()) {
0295             Smb4KNotification::readingFileFailed(xmlFile, xmlReader.errorString());
0296         }
0297     } else {
0298         if (xmlFile.exists()) {
0299             Smb4KNotification::openingFileFailed(xmlFile);
0300         }
0301     }
0302 }
0303 
0304 void Smb4KHomesSharesHandler::writeUserNames()
0305 {
0306     // FIXME: Use the workgroup at all? We really only need the URL.
0307     QFile xmlFile(dataLocation() + QDir::separator() + QStringLiteral("homes_shares.xml"));
0308 
0309     if (!d->homesUsers.isEmpty()) {
0310         if (xmlFile.open(QIODevice::WriteOnly | QIODevice::Text)) {
0311             QXmlStreamWriter xmlWriter(&xmlFile);
0312             xmlWriter.setAutoFormatting(true);
0313             xmlWriter.writeStartDocument();
0314             xmlWriter.writeStartElement(QStringLiteral("homes_shares"));
0315             xmlWriter.writeAttribute(QStringLiteral("version"), QStringLiteral("2.0"));
0316 
0317             for (Smb4KHomesUsers *users : qAsConst(d->homesUsers)) {
0318                 xmlWriter.writeStartElement(QStringLiteral("homes_share"));
0319                 xmlWriter.writeAttribute(QStringLiteral("url"), users->url().toString(QUrl::RemoveUserInfo | QUrl::StripTrailingSlash));
0320                 xmlWriter.writeAttribute(QStringLiteral("profile"), users->profile());
0321                 xmlWriter.writeTextElement(QStringLiteral("workgroup"), users->workgroupName());
0322                 xmlWriter.writeStartElement(QStringLiteral("users"));
0323 
0324                 QStringList userList = users->userList();
0325 
0326                 for (const QString &user : qAsConst(userList)) {
0327                     xmlWriter.writeTextElement(QStringLiteral("user"), user);
0328                 }
0329 
0330                 xmlWriter.writeEndElement();
0331                 xmlWriter.writeEndElement();
0332             }
0333 
0334             xmlWriter.writeEndDocument();
0335             xmlFile.close();
0336         } else {
0337             Smb4KNotification::openingFileFailed(xmlFile);
0338         }
0339     } else {
0340         xmlFile.remove();
0341     }
0342 }
0343 
0344 /////////////////////////////////////////////////////////////////////////////
0345 // SLOT IMPLEMENTATIONS
0346 /////////////////////////////////////////////////////////////////////////////
0347 
0348 void Smb4KHomesSharesHandler::slotProfileRemoved(const QString &name)
0349 {
0350     QMutableListIterator<Smb4KHomesUsers *> it(d->homesUsers);
0351 
0352     while (it.hasNext()) {
0353         Smb4KHomesUsers *user = it.next();
0354 
0355         if (name == user->profile()) {
0356             it.remove();
0357         }
0358     }
0359 
0360     writeUserNames();
0361 }
0362 
0363 void Smb4KHomesSharesHandler::slotProfileMigrated(const QString &oldName, const QString &newName)
0364 {
0365     for (int i = 0; i < d->homesUsers.size(); i++) {
0366         if (oldName == d->homesUsers.at(i)->profile()) {
0367             d->homesUsers[i]->setProfile(newName);
0368         }
0369     }
0370 
0371     writeUserNames();
0372 }