1 //  -*- c-basic-offset:4; indent-tabs-mode:nil -*-
2 /*
3     This file is part of the KDE libraries
4     SPDX-FileCopyrightText: 2002-2003 Alexander Kellett <lypanov@kde.org>
5 
6     SPDX-License-Identifier: LGPL-2.0-only
7 */
8 
9 #include "kbookmarkimporter_ie.h"
10 #include "kbookmarkimporter.h"
11 #include "kbookmarks_debug.h"
12 
13 #include <QFileDialog>
14 
15 #include <QApplication>
16 #include <QRegularExpression>
17 
18 #include <qplatformdefs.h>
19 
20 
21 /**
22  * A class for importing IE bookmarks
23  * @deprecated
24  */
25 class KIEBookmarkImporter : public QObject
26 {
27     Q_OBJECT
28 public:
KIEBookmarkImporter(const QString & fileName)29     KIEBookmarkImporter(const QString &fileName)
30         : m_fileName(fileName)
31     {
32     }
~KIEBookmarkImporter()33     ~KIEBookmarkImporter() override
34     {
35     }
36 
37     void parseIEBookmarks();
38 
39     // Usual place for IE bookmarks
40     static QString IEBookmarksDir();
41 
42 Q_SIGNALS:
43     void newBookmark(const QString &text, const QString &url, const QString &additionalInfo);
44     void newFolder(const QString &text, bool open, const QString &additionalInfo);
45     void newSeparator();
46     void endFolder();
47 
48 protected:
49     void parseIEBookmarks_dir(const QString &dirname, const QString &name = QString());
50     void parseIEBookmarks_url_file(const QString &filename, const QString &name);
51 
52     const QString m_fileName;
53 };
54 
parseIEBookmarks_url_file(const QString & filename,const QString & name)55 void KIEBookmarkImporter::parseIEBookmarks_url_file(const QString &filename, const QString &name)
56 {
57     static const int g_lineLimit = 16 * 1024;
58 
59     QFile f(filename);
60 
61     if (f.open(QIODevice::ReadOnly)) {
62         QByteArray s(g_lineLimit, 0);
63 
64         while (f.readLine(s.data(), g_lineLimit) >= 0) {
65             if (s[s.length() - 1] != '\n') { // Gosh, this line is longer than g_lineLimit. Skipping.
66                 qCWarning(KBOOKMARKS_LOG) << "IE bookmarks contain a line longer than " << g_lineLimit << ". Skipping.";
67                 continue;
68             }
69             const QString t = QString::fromUtf8(s.trimmed());
70             QRegularExpression rx(QStringLiteral("URL=(.*)"));
71             auto match = rx.match(t);
72             if (match.hasMatch()) {
73                 Q_EMIT newBookmark(name, match.captured(1), QLatin1String(""));
74             }
75         }
76 
77         f.close();
78     }
79 }
80 
parseIEBookmarks_dir(const QString & dirname,const QString & foldername)81 void KIEBookmarkImporter::parseIEBookmarks_dir(const QString &dirname, const QString &foldername)
82 {
83     QDir dir(dirname);
84     dir.setFilter(QDir::Files | QDir::Dirs | QDir::AllDirs);
85     dir.setSorting(QFlags<QDir::SortFlag>(QDir::Name | QDir::DirsFirst));
86     dir.setNameFilters(QStringList(QStringLiteral("*.url"))); // AK - possibly add ";index.ini" ?
87 
88     const QFileInfoList list = dir.entryInfoList();
89     if (list.isEmpty()) {
90         return;
91     }
92 
93     if (dirname != m_fileName) {
94         Q_EMIT newFolder(foldername, false, QLatin1String(""));
95     }
96 
97     for (const QFileInfo &fi : list) {
98         if (fi.fileName() == QLatin1String(".") || fi.fileName() == QLatin1String("..")) {
99             continue;
100         }
101 
102         if (fi.isDir()) {
103             parseIEBookmarks_dir(fi.absoluteFilePath(), fi.fileName());
104 
105         } else if (fi.isFile()) {
106             if (fi.fileName().endsWith(QLatin1String(".url"))) {
107                 QString name = fi.fileName();
108                 name.truncate(name.length() - 4); // .url
109                 parseIEBookmarks_url_file(fi.absoluteFilePath(), name);
110             }
111             // AK - add index.ini
112         }
113     }
114 
115     if (dirname != m_fileName) {
116         Q_EMIT endFolder();
117     }
118 }
119 
parseIEBookmarks()120 void KIEBookmarkImporter::parseIEBookmarks()
121 {
122     parseIEBookmarks_dir(m_fileName);
123 }
124 
IEBookmarksDir()125 QString KIEBookmarkImporter::IEBookmarksDir()
126 {
127     static KIEBookmarkImporterImpl *p = nullptr;
128     if (!p) {
129         p = new KIEBookmarkImporterImpl;
130     }
131     return p->findDefaultLocation();
132 }
133 
parse()134 void KIEBookmarkImporterImpl::parse()
135 {
136     KIEBookmarkImporter importer(m_fileName);
137     setupSignalForwards(&importer, this);
138     importer.parseIEBookmarks();
139 }
140 
findDefaultLocation(bool) const141 QString KIEBookmarkImporterImpl::findDefaultLocation(bool) const
142 {
143     // notify user that they must give a new dir such
144     // as "Favourites" as otherwise it'll just place
145     // lots of .url files in the given dir and gui
146     // stuff in the exporter is ugly so that exclues
147     // the possibility of just writing to Favourites
148     // and checking if overwriting...
149     return QFileDialog::getExistingDirectory(QApplication::activeWindow());
150 }
151 
152 /////////////////////////////////////////////////
153 
154 class IEExporter : private KBookmarkGroupTraverser
155 {
156 public:
157     IEExporter(const QString &);
write(const KBookmarkGroup & grp)158     void write(const KBookmarkGroup &grp)
159     {
160         traverse(grp);
161     }
162 
163 private:
164     void visit(const KBookmark &) override;
165     void visitEnter(const KBookmarkGroup &) override;
166     void visitLeave(const KBookmarkGroup &) override;
167 
168 private:
169     QDir m_currentDir;
170 };
171 
ieStyleQuote(const QString & str)172 static QString ieStyleQuote(const QString &str)
173 {
174     QString s(str);
175     s.replace(QRegularExpression(QStringLiteral("[/\\:*?\"<>|]")), QStringLiteral("_"));
176     return s;
177 }
178 
IEExporter(const QString & dname)179 IEExporter::IEExporter(const QString &dname)
180 {
181     m_currentDir.setPath(dname);
182 }
183 
visit(const KBookmark & bk)184 void IEExporter::visit(const KBookmark &bk)
185 {
186     const QString fname = m_currentDir.path() + QLatin1Char('/') + ieStyleQuote(bk.fullText()) + QLatin1String(".url");
187     // qCDebug(KBOOKMARKS_LOG) << "visit(" << bk.text() << "), fname == " << fname;
188     QFile file(fname);
189     if (file.open(QIODevice::WriteOnly)) {
190         QTextStream ts(&file);
191         ts << "[InternetShortcut]\r\n";
192         ts << "URL=" << bk.url().toString().toUtf8() << "\r\n";
193     }
194 }
195 
visitEnter(const KBookmarkGroup & grp)196 void IEExporter::visitEnter(const KBookmarkGroup &grp)
197 {
198     const QString dname = m_currentDir.path() + QLatin1Char('/') + ieStyleQuote(grp.fullText());
199     // qCDebug(KBOOKMARKS_LOG) << "visitEnter(" << grp.text() << "), dname == " << dname;
200     m_currentDir.mkdir(dname);
201     m_currentDir.cd(dname);
202 }
203 
visitLeave(const KBookmarkGroup &)204 void IEExporter::visitLeave(const KBookmarkGroup &)
205 {
206     // qCDebug(KBOOKMARKS_LOG) << "visitLeave()";
207     m_currentDir.cdUp();
208 }
209 
write(const KBookmarkGroup & parent)210 void KIEBookmarkExporterImpl::write(const KBookmarkGroup &parent)
211 {
212     IEExporter exporter(m_fileName);
213     exporter.write(parent);
214 }
215 
216 #include "kbookmarkimporter_ie.moc"
217