File indexing completed on 2024-04-21 14:53:27

0001 //  -*- c-basic-offset:4; indent-tabs-mode:nil -*-
0002 /*
0003     This file is part of the KDE libraries
0004     SPDX-FileCopyrightText: 1996-1998 Martin R. Jones <mjones@kde.org>
0005     SPDX-FileCopyrightText: 2000 David Faure <faure@kde.org>
0006     SPDX-FileCopyrightText: 2003 Alexander Kellett <lypanov@kde.org>
0007 
0008     SPDX-License-Identifier: LGPL-2.0-only
0009 */
0010 
0011 #include "kbookmarkimporter_ns.h"
0012 #include "kbookmarkmanager.h"
0013 #include "kbookmarks_debug.h"
0014 
0015 #include <KCharsets>
0016 
0017 #include <QFileDialog>
0018 #include <QMessageBox>
0019 #include <QApplication>
0020 #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
0021 #include <QTextCodec>
0022 #else
0023 #include <QStringConverter>
0024 #endif
0025 
0026 QString KNSBookmarkImporterImpl::toUnicode(const QByteArray &data) const
0027 {
0028 #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
0029     QTextCodec *codec = m_utf8 ? QTextCodec::codecForName("UTF-8") : QTextCodec::codecForLocale();
0030     Q_ASSERT(codec);
0031     if (!codec) {
0032         return {};
0033     }
0034     return codec->toUnicode(data);
0035 #else
0036     auto codec = QStringDecoder(m_utf8 ? QStringDecoder::Utf8 : QStringDecoder::System);
0037     return codec.decode(data);
0038 #endif
0039 }
0040 
0041 void KNSBookmarkImporterImpl::parse()
0042 {
0043     QFile f(m_fileName);
0044 
0045     if (f.open(QIODevice::ReadOnly)) {
0046         static const int g_lineLimit = 16 * 1024;
0047         QByteArray s(g_lineLimit, 0);
0048         // skip header
0049         while (f.readLine(s.data(), g_lineLimit) >= 1 && !s.contains("<DL>")) {
0050             ;
0051         }
0052 
0053         while (int size = f.readLine(s.data(), g_lineLimit) >= 1) {
0054             if (size == g_lineLimit) { // Gosh, this line is longer than g_lineLimit. Skipping.
0055                 qCWarning(KBOOKMARKS_LOG) << "Netscape bookmarks contain a line longer than " << g_lineLimit << ". Skipping.";
0056                 continue;
0057             }
0058             QByteArray t = s.trimmed();
0059 
0060             if (t.left(4).toUpper() == "<HR>") {
0061                 Q_EMIT newSeparator();
0062                 t = t.mid(4).trimmed();
0063                 if (t.isEmpty()) {
0064                     continue;
0065                 }
0066             }
0067 
0068             if (t.left(12).toUpper() == "<DT><A HREF=" || t.left(16).toUpper() == "<DT><H3><A HREF=") {
0069                 int firstQuotes = t.indexOf('"') + 1;
0070                 int secondQuotes = t.indexOf('"', firstQuotes);
0071                 if (firstQuotes != -1 && secondQuotes != -1) {
0072                     QByteArray link = t.mid(firstQuotes, secondQuotes - firstQuotes);
0073                     int endTag = t.indexOf('>', secondQuotes + 1);
0074 
0075                     int closeTag = t.indexOf('<', endTag + 1);
0076 
0077                     QByteArray name = t.mid(endTag + 1, closeTag - endTag - 1);
0078                     QString qname = KCharsets::resolveEntities(toUnicode(name));
0079 
0080                     Q_EMIT newBookmark(qname, toUnicode(link), QString());
0081                 }
0082             } else if (t.left(7).toUpper() == "<DT><H3") {
0083                 int endTag = t.indexOf('>', 7);
0084                 QByteArray name = t.mid(endTag + 1);
0085                 name = name.left(name.indexOf('<'));
0086                 QString qname = KCharsets::resolveEntities(toUnicode(name));
0087                 QByteArray additionalInfo = t.mid(8, endTag - 8);
0088                 bool folded = (additionalInfo.left(6) == "FOLDED");
0089                 if (folded) {
0090                     additionalInfo.remove(0, 7);
0091                 }
0092 
0093                 Q_EMIT newFolder(qname, !folded, QString());
0094             } else if (t.left(8).toUpper() == "</DL><P>") {
0095                 Q_EMIT endFolder();
0096             }
0097         }
0098 
0099         f.close();
0100     }
0101 }
0102 
0103 QString KNSBookmarkImporterImpl::findDefaultLocation(bool forSaving) const
0104 {
0105     if (m_utf8) {
0106         const QString mozillaHomePath = QDir::homePath() + QLatin1String("/.mozilla");
0107         if (forSaving) {
0108             return QFileDialog::getSaveFileName(QApplication::activeWindow(), QString(), mozillaHomePath, tr("HTML Files (*.html)"));
0109         } else {
0110             return QFileDialog::getOpenFileName(QApplication::activeWindow(), QString(), mozillaHomePath, tr("*.html|HTML Files (*.html)"));
0111         }
0112     } else {
0113         return QDir::homePath() + QLatin1String("/.netscape/bookmarks.html");
0114     }
0115 }
0116 
0117 ////////////////////////////////////////////////////////////////
0118 
0119 void KNSBookmarkExporterImpl::setUtf8(bool utf8)
0120 {
0121     m_utf8 = utf8;
0122 }
0123 
0124 void KNSBookmarkExporterImpl::write(const KBookmarkGroup &parent)
0125 {
0126     if (!QFile::exists(m_fileName)) {
0127         QString errorMsg = KNSBookmarkImporterImpl::tr(
0128                                "Could not find %1. Netscape is probably not installed. "
0129                                "Aborting the export.")
0130                                .arg(m_fileName);
0131         QMessageBox::critical(nullptr, KNSBookmarkImporterImpl::tr("Netscape not found"), errorMsg);
0132         return;
0133     }
0134     if (QFile::exists(m_fileName)) {
0135         (void)QFile::rename(m_fileName, m_fileName + QLatin1String(".beforekde"));
0136     }
0137 
0138     QFile file(m_fileName);
0139 
0140     if (!file.open(QIODevice::WriteOnly)) {
0141         qCCritical(KBOOKMARKS_LOG) << "Can't write to file " << m_fileName;
0142         return;
0143     }
0144 
0145     QTextStream fstream(&file);
0146 #if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
0147     // NOTE: QStringConverter::System assumes the encoding is UTF-8 for Unix based systems
0148     fstream.setEncoding(m_utf8 ? QStringConverter::Utf8 : QStringConverter::System);
0149     QString charset = QString::fromUtf8(QStringConverter::nameForEncoding(m_utf8 ? QStringConverter::Utf8 : QStringConverter::System));
0150 #else
0151     fstream.setCodec(m_utf8 ? QTextCodec::codecForName("UTF-8") : QTextCodec::codecForLocale());
0152     QString charset = m_utf8 ? QStringLiteral("UTF-8") : QString::fromLatin1(QTextCodec::codecForLocale()->name()).toUpper();
0153 #endif
0154 
0155     fstream << "<!DOCTYPE NETSCAPE-Bookmark-file-1>\n"
0156             << KNSBookmarkImporterImpl::tr("<!-- This file was generated by Konqueror -->") << "\n"
0157             << "<META HTTP-EQUIV=\"Content-Type\" CONTENT=\"text/html; charset=" << charset << "\">\n"
0158             << "<TITLE>" << KNSBookmarkImporterImpl::tr("Bookmarks") << "</TITLE>\n"
0159             << "<H1>" << KNSBookmarkImporterImpl::tr("Bookmarks") << "</H1>\n"
0160             << "<DL><p>\n"
0161             << folderAsString(parent) << "</DL><P>\n";
0162 }
0163 
0164 QString KNSBookmarkExporterImpl::folderAsString(const KBookmarkGroup &parent) const
0165 {
0166     QString str;
0167     QTextStream fstream(&str, QIODevice::WriteOnly);
0168 
0169     for (KBookmark bk = parent.first(); !bk.isNull(); bk = parent.next(bk)) {
0170         if (bk.isSeparator()) {
0171             fstream << "<HR>\n";
0172             fstream.flush();
0173             continue;
0174         }
0175 
0176         QString text = bk.fullText().toHtmlEscaped();
0177 
0178         if (bk.isGroup()) {
0179             fstream << "<DT><H3 " << (!bk.toGroup().isOpen() ? "FOLDED " : "") << bk.internalElement().attribute(QStringLiteral("netscapeinfo")) << ">" << text
0180                     << "</H3>\n"
0181                     << "<DL><P>\n"
0182                     << folderAsString(bk.toGroup()) << "</DL><P>\n";
0183             fstream.flush();
0184             continue;
0185 
0186         } else {
0187             // note - netscape seems to use local8bit for url...
0188             fstream << "<DT><A HREF=\"" << bk.url().toString() << "\"" << bk.internalElement().attribute(QStringLiteral("netscapeinfo")) << ">" << text
0189                     << "</A>\n";
0190             fstream.flush();
0191             continue;
0192         }
0193     }
0194 
0195     return str;
0196 }
0197 
0198 ////
0199 
0200 #include "moc_kbookmarkimporter_ns.cpp"