File indexing completed on 2024-04-21 15:42:48
0001 /*************************************************************************** 0002 This class handles the homes shares 0003 ------------------- 0004 begin : Do Aug 10 2006 0005 copyright : (C) 2006-2019 by Alexander Reinholdt 0006 email : alexander.reinholdt@kdemail.net 0007 ***************************************************************************/ 0008 0009 /*************************************************************************** 0010 * This program is free software; you can redistribute it and/or modify * 0011 * it under the terms of the GNU General Public License as published by * 0012 * the Free Software Foundation; either version 2 of the License, or * 0013 * (at your option) any later version. * 0014 * * 0015 * This program is distributed in the hope that it will be useful, but * 0016 * WITHOUT ANY WARRANTY; without even the implied warranty of * 0017 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * 0018 * General Public License for more details. * 0019 * * 0020 * You should have received a copy of the GNU General Public License * 0021 * along with this program; if not, write to the * 0022 * Free Software Foundation, Inc., 51 Franklin Street, Suite 500, Boston,* 0023 * MA 02110-1335 USA * 0024 ***************************************************************************/ 0025 0026 #ifdef HAVE_CONFIG_H 0027 #include <config.h> 0028 #endif 0029 0030 // application specific includes 0031 #include "smb4khomesshareshandler.h" 0032 #include "smb4khomesshareshandler_p.h" 0033 #include "smb4kshare.h" 0034 #include "smb4ksettings.h" 0035 #include "smb4kauthinfo.h" 0036 #include "smb4knotification.h" 0037 #include "smb4kprofilemanager.h" 0038 0039 // Qt includes 0040 #include <QFile> 0041 #include <QTextCodec> 0042 #include <QXmlStreamWriter> 0043 #include <QXmlStreamReader> 0044 #include <QApplication> 0045 #include <QPointer> 0046 0047 // KDE includes 0048 #define TRANSLATION_DOMAIN "smb4k-core" 0049 #include <KI18n/KLocalizedString> 0050 0051 Q_GLOBAL_STATIC(Smb4KHomesSharesHandlerStatic, p); 0052 0053 0054 Smb4KHomesSharesHandler::Smb4KHomesSharesHandler(QObject *parent) 0055 : QObject(parent), d(new Smb4KHomesSharesHandlerPrivate) 0056 { 0057 // First we need the directory. 0058 QString path = dataLocation(); 0059 0060 QDir dir; 0061 0062 if (!dir.exists(path)) 0063 { 0064 dir.mkpath(path); 0065 } 0066 0067 d->homesUsers = readUserNames(false); 0068 0069 // 0070 // Connections 0071 // 0072 connect(QCoreApplication::instance(), SIGNAL(aboutToQuit()), this, SLOT(slotAboutToQuit())); 0073 connect(Smb4KProfileManager::self(), SIGNAL(activeProfileChanged(QString)), this, SLOT(slotActiveProfileChanged(QString))); 0074 } 0075 0076 0077 Smb4KHomesSharesHandler::~Smb4KHomesSharesHandler() 0078 { 0079 while (!d->homesUsers.isEmpty()) 0080 { 0081 delete d->homesUsers.takeFirst(); 0082 } 0083 } 0084 0085 0086 Smb4KHomesSharesHandler *Smb4KHomesSharesHandler::self() 0087 { 0088 return &p->instance; 0089 } 0090 0091 0092 bool Smb4KHomesSharesHandler::specifyUser(const SharePtr &share, bool overwrite) 0093 { 0094 Q_ASSERT(share); 0095 bool success = false; 0096 0097 // Avoid that the dialog is opened although the homes 0098 // user name has already been defined. 0099 if (share->isHomesShare() && (share->homeUrl().isEmpty() || overwrite)) 0100 { 0101 QStringList users = findHomesUsers(share); 0102 0103 QPointer<Smb4KHomesUserDialog> dlg = new Smb4KHomesUserDialog(share, QApplication::activeWindow()); 0104 dlg->setUserNames(users); 0105 0106 if (dlg->exec() == QDialog::Accepted) 0107 { 0108 QString login = dlg->login(); 0109 users = dlg->userNames(); 0110 addHomesUsers(share, users); 0111 0112 if (!login.isEmpty()) 0113 { 0114 // If the login names do not match, clear the password. 0115 if (!share->login().isEmpty() && QString::compare(share->login(), login) != 0) 0116 { 0117 share->setPassword(QString()); 0118 } 0119 0120 // Set the login name. 0121 share->setLogin(login); 0122 success = true; 0123 } 0124 0125 writeUserNames(d->homesUsers); 0126 } 0127 0128 delete dlg; 0129 } 0130 else 0131 { 0132 // The user name has already been set. 0133 success = true; 0134 } 0135 0136 return success; 0137 } 0138 0139 0140 QStringList Smb4KHomesSharesHandler::homesUsers(const SharePtr &share) 0141 { 0142 Q_ASSERT(share); 0143 QStringList users = findHomesUsers(share); 0144 return users; 0145 } 0146 0147 0148 const QList<Smb4KHomesUsers *> Smb4KHomesSharesHandler::readUserNames(bool allUsers) 0149 { 0150 QList<Smb4KHomesUsers *> list; 0151 0152 // Locate the XML file. 0153 QFile xmlFile(dataLocation()+QDir::separator()+"homes_shares.xml"); 0154 0155 if (xmlFile.open(QIODevice::ReadOnly | QIODevice::Text)) 0156 { 0157 QXmlStreamReader xmlReader(&xmlFile); 0158 0159 while (!xmlReader.atEnd()) 0160 { 0161 xmlReader.readNext(); 0162 0163 if (xmlReader.isStartElement()) 0164 { 0165 if (xmlReader.name() == "homes_shares" && xmlReader.attributes().value("version") != "1.0") 0166 { 0167 xmlReader.raiseError(i18n("%1 is not a version 1.0 file.", xmlFile.fileName())); 0168 break; 0169 } 0170 else 0171 { 0172 if (xmlReader.name() == "homes") 0173 { 0174 QString profile = xmlReader.attributes().value("profile").toString(); 0175 0176 // FIXME: Remove the last check in the if statement with Smb4K > 2.0. 0177 // It was introduced for migration, because the default profile 0178 // (e.g. use of no profiles) was not empty but named "Default"... 0179 if (allUsers || QString::compare(profile, Smb4KProfileManager::self()->activeProfile(), Qt::CaseSensitive) == 0 || 0180 (!Smb4KProfileManager::self()->useProfiles() && QString::compare(profile, "Default", Qt::CaseSensitive) == 0)) 0181 { 0182 Smb4KHomesUsers *users = new Smb4KHomesUsers(); 0183 users->setProfile(profile); 0184 users->setShareName(xmlReader.name().toString()); 0185 0186 while (!(xmlReader.isEndElement() && xmlReader.name() == "homes")) 0187 { 0188 xmlReader.readNext(); 0189 0190 if (xmlReader.isStartElement()) 0191 { 0192 if (xmlReader.name() == "host") 0193 { 0194 users->setHostName(xmlReader.readElementText()); 0195 } 0196 else if (xmlReader.name() == "workgroup") 0197 { 0198 users->setWorkgroupName(xmlReader.readElementText()); 0199 } 0200 else if (xmlReader.name() == "ip") 0201 { 0202 users->setHostIP(xmlReader.readElementText()); 0203 } 0204 else if (xmlReader.name() == "users") 0205 { 0206 QStringList u; 0207 0208 while (!(xmlReader.isEndElement() && xmlReader.name() == "users")) 0209 { 0210 xmlReader.readNext(); 0211 0212 if (xmlReader.isStartElement() && xmlReader.name() == "user") 0213 { 0214 u << xmlReader.readElementText(); 0215 } 0216 } 0217 0218 users->setUsers(u); 0219 } 0220 0221 continue; 0222 } 0223 else 0224 { 0225 continue; 0226 } 0227 } 0228 0229 list << users; 0230 } 0231 else 0232 { 0233 continue; 0234 } 0235 } 0236 else 0237 { 0238 continue; 0239 } 0240 } 0241 } 0242 else 0243 { 0244 continue; 0245 } 0246 } 0247 0248 xmlFile.close(); 0249 0250 if (xmlReader.hasError()) 0251 { 0252 Smb4KNotification::readingFileFailed(xmlFile, xmlReader.errorString()); 0253 } 0254 } 0255 else 0256 { 0257 if (xmlFile.exists()) 0258 { 0259 Smb4KNotification::openingFileFailed(xmlFile); 0260 } 0261 } 0262 0263 return list; 0264 } 0265 0266 0267 void Smb4KHomesSharesHandler::writeUserNames(const QList<Smb4KHomesUsers *> &list, bool listOnly) 0268 { 0269 QList<Smb4KHomesUsers *> allUsers; 0270 0271 if (!listOnly) 0272 { 0273 // First read all entries. Then remove all, that belong to 0274 // the currently active profile. 0275 allUsers = readUserNames(true); 0276 0277 QMutableListIterator<Smb4KHomesUsers *> it(allUsers); 0278 0279 while (it.hasNext()) 0280 { 0281 Smb4KHomesUsers *users = it.next(); 0282 0283 if (QString::compare(users->profile(), Smb4KProfileManager::self()->activeProfile()) == 0) 0284 { 0285 it.remove(); 0286 } 0287 } 0288 } 0289 0290 for (Smb4KHomesUsers *users : list) 0291 { 0292 allUsers << new Smb4KHomesUsers(*users); 0293 } 0294 0295 QFile xmlFile(dataLocation()+QDir::separator()+"homes_shares.xml"); 0296 0297 if (!allUsers.isEmpty()) 0298 { 0299 if (xmlFile.open(QIODevice::WriteOnly|QIODevice::Text)) 0300 { 0301 QXmlStreamWriter xmlWriter(&xmlFile); 0302 xmlWriter.setAutoFormatting(true); 0303 xmlWriter.writeStartDocument(); 0304 xmlWriter.writeStartElement("homes_shares"); 0305 xmlWriter.writeAttribute("version", "1.0"); 0306 0307 for (Smb4KHomesUsers *users : allUsers) 0308 { 0309 xmlWriter.writeStartElement("homes"); 0310 0311 // FIXME: Remove this block with Smb4K > 2.0 and use the commented line below. 0312 // This block was introduced for migration, because the default profile 0313 // (i.e. use of no profiles) was not empty but named "Default"... 0314 if (!Smb4KProfileManager::self()->useProfiles()) 0315 { 0316 xmlWriter.writeAttribute("profile", Smb4KSettings::self()->activeProfile()); 0317 } 0318 else 0319 { 0320 xmlWriter.writeAttribute("profile", users->profile()); 0321 } 0322 // xmlWriter.writeAttribute("profile", users->profile()); 0323 xmlWriter.writeTextElement("host", users->hostName()); 0324 xmlWriter.writeTextElement("workgroup", users->workgroupName()); 0325 xmlWriter.writeTextElement("ip", users->hostIP()); 0326 xmlWriter.writeStartElement("users"); 0327 0328 for (const QString &user : users->users()) 0329 { 0330 xmlWriter.writeTextElement("user", user); 0331 } 0332 0333 xmlWriter.writeEndElement(); 0334 xmlWriter.writeEndElement(); 0335 } 0336 0337 xmlWriter.writeEndDocument(); 0338 xmlFile.close(); 0339 } 0340 else 0341 { 0342 Smb4KNotification::openingFileFailed(xmlFile); 0343 } 0344 } 0345 else 0346 { 0347 xmlFile.remove(); 0348 } 0349 0350 while (!allUsers.isEmpty()) 0351 { 0352 delete allUsers.takeFirst(); 0353 } 0354 } 0355 0356 0357 const QStringList Smb4KHomesSharesHandler::findHomesUsers(const SharePtr &share) 0358 { 0359 Q_ASSERT(share); 0360 0361 QStringList users; 0362 0363 if (!d->homesUsers.isEmpty()) 0364 { 0365 for (int i = 0; i < d->homesUsers.size(); ++i) 0366 { 0367 if (QString::compare(share->hostName(), d->homesUsers.at(i)->hostName(), Qt::CaseInsensitive) == 0 && 0368 QString::compare(share->shareName(), d->homesUsers.at(i)->shareName(), Qt::CaseInsensitive) == 0 && 0369 ((d->homesUsers.at(i)->workgroupName().isEmpty() || share->workgroupName().isEmpty()) || 0370 QString::compare(share->workgroupName(), d->homesUsers.at(i)->workgroupName(), Qt::CaseInsensitive) == 0)) 0371 { 0372 users = d->homesUsers.at(i)->users(); 0373 break; 0374 } 0375 else 0376 { 0377 continue; 0378 } 0379 } 0380 } 0381 0382 return users; 0383 } 0384 0385 0386 void Smb4KHomesSharesHandler::addHomesUsers(const SharePtr &share, const QStringList &users) 0387 { 0388 Q_ASSERT(share); 0389 0390 bool found = false; 0391 0392 if (!d->homesUsers.isEmpty()) 0393 { 0394 for (int i = 0; i < d->homesUsers.size(); ++i) 0395 { 0396 if (QString::compare(share->hostName(), d->homesUsers.at(i)->hostName(), Qt::CaseInsensitive) == 0 && 0397 QString::compare(share->shareName(), d->homesUsers.at(i)->shareName(), Qt::CaseInsensitive) == 0 && 0398 ((d->homesUsers.at(i)->workgroupName().isEmpty() || share->workgroupName().isEmpty()) || 0399 QString::compare(share->workgroupName(), d->homesUsers.at(i)->workgroupName(), Qt::CaseInsensitive) == 0)) 0400 { 0401 d->homesUsers[i]->setUsers(users); 0402 found = true; 0403 break; 0404 } 0405 else 0406 { 0407 continue; 0408 } 0409 } 0410 } 0411 0412 if (!found) 0413 { 0414 Smb4KHomesUsers *u = new Smb4KHomesUsers(share, users); 0415 u->setProfile(Smb4KProfileManager::self()->activeProfile()); 0416 d->homesUsers << u; 0417 } 0418 } 0419 0420 0421 void Smb4KHomesSharesHandler::migrateProfile(const QString& from, const QString& to) 0422 { 0423 // Read all entries for later conversion. 0424 QList<Smb4KHomesUsers *> allUsers = readUserNames(true); 0425 0426 // Replace the old profile name with the new one. 0427 for (int i = 0; i < allUsers.size(); ++i) 0428 { 0429 if (QString::compare(allUsers.at(i)->profile(), from, Qt::CaseSensitive) == 0) 0430 { 0431 allUsers[i]->setProfile(to); 0432 } 0433 } 0434 0435 // Write the new list to the file. 0436 writeUserNames(allUsers, true); 0437 0438 // Profile settings changed, so invoke the slot. 0439 slotActiveProfileChanged(Smb4KProfileManager::self()->activeProfile()); 0440 0441 // Clear the temporary lists of bookmarks and groups. 0442 while (!allUsers.isEmpty()) 0443 { 0444 delete allUsers.takeFirst(); 0445 } 0446 } 0447 0448 0449 void Smb4KHomesSharesHandler::removeProfile(const QString& name) 0450 { 0451 // Read all entries for later removal. 0452 QList<Smb4KHomesUsers *> allUsers = readUserNames(true); 0453 QMutableListIterator<Smb4KHomesUsers *> it(allUsers); 0454 0455 while (it.hasNext()) 0456 { 0457 Smb4KHomesUsers *user = it.next(); 0458 0459 if (QString::compare(user->profile(), name, Qt::CaseSensitive) == 0) 0460 { 0461 it.remove(); 0462 } 0463 } 0464 0465 // Write the new list to the file. 0466 writeUserNames(allUsers, true); 0467 0468 // Profile settings changed, so invoke the slot. 0469 slotActiveProfileChanged(Smb4KProfileManager::self()->activeProfile()); 0470 0471 // Clear the temporary list of homes users. 0472 while (!allUsers.isEmpty()) 0473 { 0474 delete allUsers.takeFirst(); 0475 } 0476 } 0477 0478 0479 ///////////////////////////////////////////////////////////////////////////// 0480 // SLOT IMPLEMENTATIONS 0481 ///////////////////////////////////////////////////////////////////////////// 0482 0483 void Smb4KHomesSharesHandler::slotAboutToQuit() 0484 { 0485 writeUserNames(d->homesUsers); 0486 } 0487 0488 0489 void Smb4KHomesSharesHandler::slotActiveProfileChanged(const QString& /*activeProfile*/) 0490 { 0491 // Clear the list of homes users. 0492 while (!d->homesUsers.isEmpty()) 0493 { 0494 delete d->homesUsers.takeFirst(); 0495 } 0496 0497 // Reload the list of homes users. 0498 d->homesUsers = readUserNames(false); 0499 } 0500