File indexing completed on 2024-04-21 15:42:43

0001 /***************************************************************************
0002     This class handles the bookmarks.
0003                              -------------------
0004     begin                : Fr Jan 9 2004
0005     copyright            : (C) 2004-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 "smb4kbookmarkhandler.h"
0032 #include "smb4kbookmarkhandler_p.h"
0033 #include "smb4khomesshareshandler.h"
0034 #include "smb4kglobal.h"
0035 #include "smb4kbookmark.h"
0036 #include "smb4khost.h"
0037 #include "smb4kshare.h"
0038 #include "smb4ksettings.h"
0039 #include "smb4knotification.h"
0040 #include "smb4kprofilemanager.h"
0041 
0042 // Qt includes
0043 #include <QDir>
0044 #include <QFile>
0045 #include <QTextCodec>
0046 #include <QTextStream>
0047 #include <QXmlStreamWriter>
0048 #include <QXmlStreamReader>
0049 #include <QPointer>
0050 #include <QMutableListIterator>
0051 #include <QApplication>
0052 
0053 // KDE includes
0054 #define TRANSLATION_DOMAIN "smb4k-core"
0055 #include <KI18n/KLocalizedString>
0056 
0057 
0058 using namespace Smb4KGlobal;
0059 
0060 
0061 Q_GLOBAL_STATIC(Smb4KBookmarkHandlerStatic, p);
0062 
0063 
0064 
0065 Smb4KBookmarkHandler::Smb4KBookmarkHandler(QObject *parent)
0066 : QObject(parent), d(new Smb4KBookmarkHandlerPrivate)
0067 {
0068   // 
0069   // First we need the directory.
0070   // 
0071   QString path = dataLocation();
0072   
0073   QDir dir;
0074   
0075   if (!dir.exists(path))
0076   {
0077     dir.mkpath(path);
0078   }
0079 
0080   //
0081   // Read the list of bookmarks
0082   // 
0083   readBookmarkList();
0084   
0085   //
0086   // Init the bookmark editor
0087   // 
0088   d->editor = 0;
0089 }
0090 
0091 
0092 Smb4KBookmarkHandler::~Smb4KBookmarkHandler()
0093 {
0094   while (!d->bookmarks.isEmpty())
0095   {
0096     d->bookmarks.takeFirst().clear();
0097   }
0098 }
0099 
0100 
0101 Smb4KBookmarkHandler *Smb4KBookmarkHandler::self()
0102 {
0103   return &p->instance;
0104 }
0105 
0106 
0107 void Smb4KBookmarkHandler::addBookmark(const SharePtr &share)
0108 {
0109   if (share)
0110   {
0111     QList<SharePtr> shares;
0112     shares << share;
0113     addBookmarks(shares);
0114   }
0115 }
0116 
0117 
0118 void Smb4KBookmarkHandler::addBookmarks(const QList<SharePtr> &list)
0119 {
0120   //
0121   // Prepare the list of bookmarks that should be added
0122   //
0123   QList<BookmarkPtr> newBookmarks;
0124   
0125   for (const SharePtr &share : list)
0126   {
0127     //
0128     // Printer shares cannot be bookmarked
0129     //
0130     if (share->isPrinter())
0131     {
0132       Smb4KNotification::cannotBookmarkPrinter(share);
0133       continue;
0134     }
0135     
0136     //
0137     // Process homes shares
0138     //
0139     if (share->isHomesShare() && !Smb4KHomesSharesHandler::self()->specifyUser(share, true))
0140     {
0141       continue;
0142     }
0143     
0144     //
0145     // Check if the share has already been bookmarked and skip it if it
0146     // already exists
0147     //
0148     BookmarkPtr knownBookmark = findBookmarkByUrl(share->isHomesShare() ? share->homeUrl() : share->url());
0149     
0150     if (knownBookmark)
0151     {
0152       Smb4KNotification::bookmarkExists(knownBookmark.data());
0153       continue;
0154     }
0155     
0156     BookmarkPtr bookmark = BookmarkPtr(new Smb4KBookmark(share.data()));
0157     bookmark->setProfile(Smb4KProfileManager::self()->activeProfile());
0158     newBookmarks << bookmark;
0159   }
0160   
0161   //
0162   // Show the bookmark dialog, if necessary
0163   //
0164   if (!newBookmarks.isEmpty())
0165   {
0166     QPointer<Smb4KBookmarkDialog> dlg = new Smb4KBookmarkDialog(newBookmarks, groupsList(), QApplication::activeWindow());
0167     
0168     if (dlg->exec() == QDialog::Accepted)
0169     {
0170       // The bookmark dialog uses an internal list of bookmarks, 
0171       // so use that one instead of the temporary list created 
0172       // above.
0173       addBookmarks(dlg->bookmarks(), false);
0174     }
0175     
0176     delete dlg;
0177   }
0178   
0179   //
0180   // Clear the temporary list of bookmarks
0181   //
0182   while (!newBookmarks.isEmpty())
0183   {
0184     newBookmarks.takeFirst().clear();
0185   }
0186 }
0187 
0188 
0189 void Smb4KBookmarkHandler::addBookmarks(const QList<BookmarkPtr> &list, bool replace)
0190 {
0191   //
0192   // Process the incoming list.
0193   // In case the internal list should be replaced, clear the internal 
0194   // list first.
0195   // 
0196   if (replace)
0197   {
0198     QMutableListIterator<BookmarkPtr> it(d->bookmarks);
0199     
0200     while (it.hasNext())
0201     {
0202       BookmarkPtr bookmark = it.next();
0203       
0204       if (Smb4KSettings::useProfiles() && bookmark->profile() != Smb4KProfileManager::self()->activeProfile())
0205       {
0206         continue;
0207       }
0208       
0209       it.remove();
0210     }
0211   }
0212   
0213   //
0214   // Copy all bookmarks that are not in the list
0215   // 
0216   for (const BookmarkPtr &bookmark : list)
0217   {
0218     //
0219     // Check if the bookmark label is already in use
0220     // 
0221     if (!bookmark->label().isEmpty() && findBookmarkByLabel(bookmark->label()))
0222     {
0223       Smb4KNotification::bookmarkLabelInUse(bookmark.data());
0224       bookmark->setLabel(QString("%1 (1)").arg(bookmark->label()));
0225     }
0226       
0227     //
0228     // Check if we have to add the bookmark
0229     // 
0230     BookmarkPtr existingBookmark = findBookmarkByUrl(bookmark->url());
0231       
0232     if (!existingBookmark)
0233     {
0234       d->bookmarks << bookmark;
0235     }
0236     else
0237     {
0238       // We do not need to update the bookmark, because we are
0239       // operating on a shared pointer.
0240     }
0241   }
0242   
0243   //
0244   // Save the bookmark list and emit the updated() signal
0245   //
0246   writeBookmarkList();
0247   emit updated();
0248 }
0249 
0250 
0251 void Smb4KBookmarkHandler::removeBookmark(const BookmarkPtr &bookmark)
0252 {
0253   if (bookmark)
0254   {
0255     for (int i = 0; i < d->bookmarks.size(); ++i)
0256     {
0257       if ((!Smb4KSettings::useProfiles() || Smb4KSettings::activeProfile() == d->bookmarks.at(i)->profile()) &&
0258           QString::compare(d->bookmarks.at(i)->url().toString(QUrl::RemoveUserInfo|QUrl::RemovePort),
0259                            bookmark->url().toString(QUrl::RemoveUserInfo|QUrl::RemovePort),
0260                            Qt::CaseInsensitive) == 0 &&
0261           QString::compare(bookmark->groupName(), d->bookmarks.at(i)->groupName(), Qt::CaseInsensitive) == 0)
0262       {
0263         d->bookmarks.takeAt(i).clear();
0264         break;
0265       }
0266     }
0267     
0268     // Write the list to the bookmarks file.
0269     writeBookmarkList();
0270     emit updated();
0271   }
0272 }
0273 
0274 
0275 void Smb4KBookmarkHandler::removeGroup(const QString& name)
0276 {
0277   QMutableListIterator<BookmarkPtr> it(d->bookmarks);
0278   
0279   while (it.hasNext())
0280   {
0281     const BookmarkPtr &b = it.next();
0282     
0283     if ((!Smb4KSettings::useProfiles() || Smb4KSettings::activeProfile() == b->profile()) ||
0284         QString::compare(b->groupName(), name, Qt::CaseInsensitive) == 0)
0285     {
0286       it.remove();
0287     }
0288   }
0289   
0290   // Write the list to the bookmarks file.
0291   writeBookmarkList();
0292   emit updated();
0293 }
0294 
0295 
0296 void Smb4KBookmarkHandler::writeBookmarkList()
0297 {
0298   QFile xmlFile(dataLocation()+QDir::separator()+"bookmarks.xml");
0299 
0300   if (!d->bookmarks.isEmpty())
0301   {
0302     if (xmlFile.open(QIODevice::WriteOnly|QIODevice::Text))
0303     {
0304       QXmlStreamWriter xmlWriter(&xmlFile);
0305       xmlWriter.setAutoFormatting(true);
0306       xmlWriter.writeStartDocument();
0307       xmlWriter.writeStartElement("bookmarks");
0308       xmlWriter.writeAttribute("version", "2.0");
0309 
0310       for (const BookmarkPtr &bookmark : d->bookmarks)
0311       {
0312         if (!bookmark->url().isValid())
0313         {
0314           Smb4KNotification::invalidURLPassed();
0315           continue;
0316         }
0317         
0318         xmlWriter.writeStartElement("bookmark");
0319         xmlWriter.writeAttribute("profile", bookmark->profile());
0320         xmlWriter.writeAttribute("group", bookmark->groupName());
0321 
0322         xmlWriter.writeTextElement("workgroup", bookmark->workgroupName());
0323         xmlWriter.writeTextElement("url", bookmark->url().toString(QUrl::RemoveUserInfo|QUrl::RemovePort));
0324         xmlWriter.writeTextElement("login", bookmark->login());
0325         xmlWriter.writeTextElement("ip", bookmark->hostIpAddress());
0326         xmlWriter.writeTextElement("label", bookmark->label());
0327 
0328         xmlWriter.writeEndElement();
0329       }
0330 
0331       xmlWriter.writeEndDocument();
0332 
0333       xmlFile.close();
0334     }
0335     else
0336     {
0337       Smb4KNotification::openingFileFailed(xmlFile);
0338     }
0339   }
0340   else
0341   {
0342     xmlFile.remove();
0343   }
0344 }
0345 
0346 
0347 void Smb4KBookmarkHandler::readBookmarkList()
0348 {
0349   //
0350   // Clear the list of bookmarks
0351   //
0352   while (!d->bookmarks.isEmpty())
0353   {
0354     d->bookmarks.takeFirst().clear();
0355   }
0356   
0357   // 
0358   // Locate the XML file and read the bookmarks
0359   // 
0360   QFile xmlFile(dataLocation()+QDir::separator()+"bookmarks.xml");
0361 
0362   if (xmlFile.open(QIODevice::ReadOnly | QIODevice::Text))
0363   {
0364     QXmlStreamReader xmlReader(&xmlFile);
0365 
0366     while (!xmlReader.atEnd())
0367     {
0368       xmlReader.readNext();
0369 
0370       if (xmlReader.isStartElement())
0371       {
0372         if (xmlReader.name() == "bookmarks" && 
0373             (xmlReader.attributes().value("version") != "1.1" && xmlReader.attributes().value("version") != "2.0"))
0374         {
0375           xmlReader.raiseError(i18n("The format of %1 is not supported.", xmlFile.fileName()));
0376           break;
0377         }
0378         else
0379         {
0380           if (xmlReader.name() == "bookmark")
0381           {
0382             QString profile = xmlReader.attributes().value("profile").toString();
0383             
0384             BookmarkPtr bookmark = BookmarkPtr(new Smb4KBookmark());
0385             bookmark->setProfile(profile);
0386             bookmark->setGroupName(xmlReader.attributes().value("group").toString());
0387               
0388             while (!(xmlReader.isEndElement() && xmlReader.name() == "bookmark"))
0389             {
0390               xmlReader.readNext();
0391 
0392               if (xmlReader.isStartElement())
0393               {
0394                 if (xmlReader.name() == "workgroup")
0395                 {
0396                   bookmark->setWorkgroupName(xmlReader.readElementText());
0397                 }
0398                 else if (xmlReader.name() == "unc")
0399                 {
0400                   bookmark->setUrl(xmlReader.readElementText());
0401                 }
0402                 else if (xmlReader.name() == "url")
0403                 {
0404                   bookmark->setUrl(QUrl(xmlReader.readElementText()));
0405                 }
0406                 else if (xmlReader.name() == "login")
0407                 {
0408                   bookmark->setLogin(xmlReader.readElementText());
0409                 }
0410                 else if (xmlReader.name() == "ip")
0411                 {
0412                   bookmark->setHostIpAddress(xmlReader.readElementText());
0413                 }
0414                 else if (xmlReader.name() == "label")
0415                 {
0416                   bookmark->setLabel(xmlReader.readElementText());
0417                 }
0418 
0419                 continue;
0420               }
0421               else
0422               {
0423                 continue;
0424               }
0425             }
0426               
0427             d->bookmarks << bookmark;
0428           }
0429           else
0430           {
0431             continue;
0432           }
0433         }
0434       }
0435       else
0436       {
0437         continue;
0438       }
0439     }
0440 
0441     xmlFile.close();
0442 
0443     if (xmlReader.hasError())
0444     {
0445       Smb4KNotification::readingFileFailed(xmlFile, xmlReader.errorString());
0446     }
0447   }
0448   else
0449   {
0450     if (xmlFile.exists())
0451     {
0452       Smb4KNotification::openingFileFailed(xmlFile);
0453     }
0454   }
0455   
0456   emit updated();
0457 }
0458 
0459 
0460 BookmarkPtr Smb4KBookmarkHandler::findBookmarkByUrl(const QUrl &url)
0461 {
0462   // Update the bookmarks:
0463   update();
0464 
0465   // Find the bookmark:
0466   BookmarkPtr bookmark;
0467 
0468   if (!url.isEmpty() && url.isValid() && !bookmarksList().isEmpty())
0469   {
0470     for (const BookmarkPtr &b : bookmarksList())
0471     {
0472       if (QString::compare(b->url().toString(QUrl::RemoveUserInfo|QUrl::RemovePort),
0473                            url.toString(QUrl::RemoveUserInfo|QUrl::RemovePort),
0474                            Qt::CaseInsensitive) == 0)
0475       {
0476         bookmark = b;
0477         break;
0478       }
0479     }
0480   }
0481 
0482   return bookmark;
0483 }
0484 
0485 
0486 BookmarkPtr Smb4KBookmarkHandler::findBookmarkByLabel(const QString &label)
0487 {
0488   // Update the bookmarks:
0489   update();
0490 
0491   // Find the bookmark:
0492   BookmarkPtr bookmark;
0493 
0494   for (const BookmarkPtr &b : bookmarksList())
0495   {
0496     if (QString::compare(b->label().toUpper(), label.toUpper()) == 0)
0497     {
0498       bookmark = b;
0499       break;
0500     }
0501     else
0502     {
0503       continue;
0504     }
0505   }
0506 
0507   return bookmark;
0508 }
0509 
0510 
0511 QList<BookmarkPtr> Smb4KBookmarkHandler::bookmarksList() const
0512 {
0513   // Update the bookmarks:
0514   update();
0515 
0516   // Get this list of the bookmarks
0517   if (Smb4KSettings::useProfiles())
0518   {
0519     QList<BookmarkPtr> bookmarks;
0520     
0521     for (const BookmarkPtr &b : d->bookmarks)
0522     {
0523       if (b->profile() == Smb4KSettings::activeProfile())
0524       {
0525         bookmarks << b;
0526       }
0527     }
0528     
0529     return bookmarks;
0530   }
0531   
0532   // Return the list of bookmarks:
0533   return d->bookmarks;
0534 }
0535 
0536 
0537 QList<BookmarkPtr> Smb4KBookmarkHandler::bookmarksList(const QString &group) const
0538 {
0539   // Update bookmarks
0540   update();
0541 
0542   // Get the list of bookmarks organized in the given group
0543   QList<BookmarkPtr> bookmarks;
0544 
0545   for (const BookmarkPtr &bookmark : bookmarksList())
0546   {
0547     if (QString::compare(group, bookmark->groupName(), Qt::CaseInsensitive) == 0)
0548     {
0549       bookmarks << bookmark;
0550     }
0551   }
0552 
0553   return bookmarks;
0554 }
0555 
0556 
0557 QStringList Smb4KBookmarkHandler::groupsList() const
0558 {
0559   QStringList groups;
0560   
0561   for (const BookmarkPtr &b : bookmarksList())
0562   {
0563     if (!groups.contains(b->groupName()))
0564     {
0565       groups << b->groupName();
0566     }
0567   }
0568   
0569   return groups;
0570 }
0571 
0572 
0573 void Smb4KBookmarkHandler::resetBookmarks()
0574 {
0575   readBookmarkList();
0576 }
0577 
0578 
0579 bool Smb4KBookmarkHandler::isBookmarked(const SharePtr& share)
0580 {
0581   if (findBookmarkByUrl(share->url()))
0582   {
0583     return true;
0584   }
0585   
0586   return false;
0587 }
0588 
0589 
0590 void Smb4KBookmarkHandler::editBookmarks()
0591 {
0592   //
0593   // Only allow one instance of the bookmark editor
0594   // 
0595   if (!d->editor)
0596   {
0597     d->editor = new Smb4KBookmarkEditor(bookmarksList(), QApplication::activeWindow());
0598   }
0599   else
0600   {
0601     d->editor->raise();
0602   }
0603   
0604   if (d->editor->exec() == QDialog::Accepted)
0605   {
0606     addBookmarks(d->editor->editedBookmarks(), true);
0607   }
0608   else
0609   {
0610     resetBookmarks();
0611   }
0612   
0613   //
0614   // Delete the editor after use
0615   // 
0616   delete d->editor;
0617   d->editor = 0;
0618 }
0619 
0620 
0621 void Smb4KBookmarkHandler::update() const
0622 {
0623   // Get new IP addresses.
0624   for (const BookmarkPtr &bookmark : d->bookmarks)
0625   {
0626     HostPtr host = findHost(bookmark->hostName(), bookmark->workgroupName());
0627     
0628     if (host)
0629     {
0630       if (host->hasIpAddress() && bookmark->hostIpAddress() != host->ipAddress())
0631       {
0632         bookmark->setHostIpAddress(host->ipAddress());
0633       }
0634     }
0635   }
0636 }
0637 
0638 
0639 void Smb4KBookmarkHandler::migrateProfile(const QString& from, const QString& to)
0640 {
0641   // Replace the old profile name with the new one.
0642   for (const BookmarkPtr &bookmark : d->bookmarks)
0643   {
0644     if (QString::compare(bookmark->profile(), from, Qt::CaseSensitive) == 0)
0645     {
0646       bookmark->setProfile(to);
0647     }
0648   }
0649   
0650   // Write the new list to the file.
0651   writeBookmarkList();
0652 }
0653 
0654 
0655 void Smb4KBookmarkHandler::removeProfile(const QString& name)
0656 {
0657   QMutableListIterator<BookmarkPtr> it(d->bookmarks);
0658   
0659   while (it.hasNext())
0660   {
0661     const BookmarkPtr &bookmark = it.next();
0662     
0663     if (QString::compare(bookmark->profile(), name, Qt::CaseSensitive) == 0)
0664     {
0665       it.remove();
0666     }
0667   }
0668   
0669   // Write the new list to the file.
0670   writeBookmarkList();
0671 }
0672