diff --git a/plugins/latex/latexplugin.cpp b/plugins/latex/latexplugin.cpp index f3aa8dfe9..3a9989ccb 100644 --- a/plugins/latex/latexplugin.cpp +++ b/plugins/latex/latexplugin.cpp @@ -1,264 +1,265 @@ /* Kopete Latex Plugin Copyright (c) 2004 by Duncan Mac-Vicar Prett Copyright (c) 2004-2005 by Olivier Goffart Kopete (c) 2001-2004 by the Kopete developers ************************************************************************* * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ************************************************************************* */ #include "latexplugin.h" #include #include #include #include #include #include #include #include #include #include #include #include #include "kopetechatsessionmanager.h" #include "kopeteuiglobal.h" #include "latexconfig.h" #include "latexguiclient.h" #define ENCODED_IMAGE_MODE 0 K_PLUGIN_FACTORY(LatexPluginFactory, registerPlugin(); ) LatexPlugin::LatexPlugin(QObject *parent, const QVariantList & /*args*/) : Kopete::Plugin(parent) { // kDebug(14317) ; if (!s_pluginStatic) { s_pluginStatic = this; } mMagickNotFoundShown = false; connect(Kopete::ChatSessionManager::self(), SIGNAL(aboutToDisplay(Kopete::Message&)), SLOT(slotMessageAboutToShow(Kopete::Message&))); connect(Kopete::ChatSessionManager::self(), SIGNAL(aboutToSend(Kopete::Message&)), this, SLOT(slotMessageAboutToSend(Kopete::Message&))); connect(Kopete::ChatSessionManager::self(), SIGNAL(chatSessionCreated(Kopete::ChatSession *)), this, SLOT(slotNewChatSession(Kopete::ChatSession *))); m_convScript = QStandardPaths::findExecutable(QStringLiteral("kopete_latexconvert.sh")); //Add GUI action to all already existing kmm (if the plugin is launched when kopete already rining) const QList sessions = Kopete::ChatSessionManager::self()->sessions(); foreach (Kopete::ChatSession *cs, sessions) { slotNewChatSession(cs); } } LatexPlugin::~LatexPlugin() { qDeleteAll(m_tempFiles); s_pluginStatic = nullptr; } LatexPlugin *LatexPlugin::plugin() { return s_pluginStatic; } LatexPlugin *LatexPlugin::s_pluginStatic = nullptr; void LatexPlugin::slotNewChatSession(Kopete::ChatSession *KMM) { new LatexGUIClient(KMM); } void LatexPlugin::slotMessageAboutToShow(Kopete::Message &msg) { QString mMagick = QStandardPaths::findExecutable(QStringLiteral("convert")); if (mMagick.isEmpty()) { // show just once if (!mMagickNotFoundShown) { KMessageBox::queuedMessageBox( Kopete::UI::Global::mainWidget(), KMessageBox::Error, i18n( "Cannot find the Magick 'convert' program.\nconvert is required to render the LaTeX formulae.\nPlease get the software from www.imagemagick.org or from your distribution's package manager.") ); mMagickNotFoundShown = true; } // don't try to parse if convert is not installed return; } QString messageText = msg.plainBody(); if (!messageText.contains(QLatin1String("$$"))) { + // return when no latex strings found return; } //kDebug(14317) << " Using converter: " << m_convScript; // /\[([^]]).*?\[/$1\]/ // \$\$.+?\$\$ // this searches for $$formula$$ QRegExp rg("\\$\\$.+\\$\\$"); rg.setMinimal(true); // this searches for [latex]formula[/latex] //QRegExp rg("\\[([^]\]).*?\\[/$1\\]"); int pos = 0; QMap replaceMap; while (pos >= 0 && pos < messageText.length()) { // kDebug(14317) << " searching pos: " << pos; pos = rg.indexIn(messageText, pos); if (pos >= 0) { const QString match = rg.cap(0); pos += rg.matchedLength(); QString formul = match; // first remove the $$ delimiters on start and end formul.remove(QStringLiteral("$$")); // then trim the result, so we can skip totally empty/whitespace-only formulas formul = formul.trimmed(); if (formul.isEmpty() || !securityCheck(formul)) { continue; } const QString fileName = handleLatex(formul); // get the image and encode it with base64 #if ENCODED_IMAGE_MODE QImage renderedImage(fileName); imagePxWidth = renderedImage.width(); imagePxHeight = renderedImage.height(); if (!renderedImage.isNull()) { QByteArray ba; QBuffer buffer(ba); buffer.open(QIODevice::WriteOnly); renderedImage.save(&buffer, "PNG"); QString imageURL = QString::fromLatin1("data:image/png;base64,%1").arg(KCodecs::base64Encode(ba)); replaceMap[match] = imageURL; } #else replaceMap[match] = fileName; #endif } } if (replaceMap.isEmpty()) { //we haven't found any LaTeX strings return; } messageText = msg.escapedBody(); int imagePxWidth, imagePxHeight; for (QMap::ConstIterator it = replaceMap.constBegin(); it != replaceMap.constEnd(); ++it) { QImage theImage(*it); if (theImage.isNull()) { continue; } imagePxWidth = theImage.width(); imagePxHeight = theImage.height(); QString escapedLATEX = it.key().toHtmlEscaped().replace('\"', QLatin1String(""")); //we need the escape quotes because that string will be in a title="" argument, but not the \n messageText.replace(Kopete::Message::escape(it.key()), " \"" "); } msg.setForcedHtmlBody(messageText); } void LatexPlugin::slotMessageAboutToSend(Kopete::Message &msg) { Q_UNUSED(msg) //disabled because to work correctly, we need to find what special has the gif we can send over MSN #if 0 KSharedConfig::Ptr config = KSharedConfig::openConfig(); config->setGroup("Latex Plugin"); if (!config->readEntry("ParseOutgoing", false)) { return; } QString messageText = msg.plainBody(); if (!messageText.contains("$$")) { return; } /* if( msg.from()->protocol()->pluginId()!="MSNProtocol" ) return;*/ // this searches for $$formula$$ QRegExp rg("^\\s*\\$\\$([^$]+)\\$\\$\\s*$"); if (rg.search(messageText) != -1) { QString latexFormula = rg.cap(1); if (!securityCheck(latexFormula)) { return; } QString url = handleLatex(latexFormula); if (!url.isNull()) { QString escapedLATEX = messageText.toHtmlEscaped().replace('\"', """); QString messageText = "\"""; msg.setBody(messageText, Kopete::Message::RichText); } } #endif } QString LatexPlugin::handleLatex(const QString &latexFormula) { KTemporaryFile *tempFile = new KTemporaryFile(); tempFile->setPrefix(QStringLiteral("kopetelatex-")); tempFile->setSuffix(QStringLiteral(".png")); tempFile->open(); m_tempFiles.append(tempFile); QString fileName = tempFile->fileName(); KProcess p; QString argumentRes = QStringLiteral("-r %1x%2").arg(LatexConfig::horizontalDPI()).arg(LatexConfig::verticalDPI()); QString argumentOut = QStringLiteral("-o %1").arg(fileName); QString argumentInclude(QStringLiteral("-x %1")); //QString argumentFormat = "-fgif"; //we uses gif format because MSN only handle gif LatexConfig::self()->load(); QString includePath = LatexConfig::latexIncludeFile(); if (!includePath.isNull()) { p << m_convScript << argumentRes << argumentOut /*<< argumentFormat*/ << argumentInclude.arg(includePath) << latexFormula; } else { p << m_convScript << argumentRes << argumentOut /*<< argumentFormat*/ << latexFormula; } kDebug(14317) << "Rendering" << m_convScript << argumentRes << argumentOut << argumentInclude << latexFormula; // FIXME our sucky sync filter API limitations :-) p.execute(); return fileName; } bool LatexPlugin::securityCheck(const QString &latexFormula) { return !latexFormula.contains(QRegExp("\\\\(def|let|futurelet|newcommand|renewcomment|else|fi|write|input|include" "|chardef|catcode|makeatletter|noexpand|toksdef|every|errhelp|errorstopmode|scrollmode|nonstopmode|batchmode" "|read|csname|newhelp|relax|afterground|afterassignment|expandafter|noexpand|special|command|loop|repeat|toks" "|output|line|mathcode|name|item|section|mbox|DeclareRobustCommand)[^a-zA-Z]")); } #include "latexplugin.moc" // vim: set noet ts=4 sts=4 sw=4: diff --git a/tests/libkopete/CMakeLists.txt b/tests/libkopete/CMakeLists.txt index 7fe11a3f5..236284b8c 100755 --- a/tests/libkopete/CMakeLists.txt +++ b/tests/libkopete/CMakeLists.txt @@ -1,9 +1,11 @@ include_directories( ${KOPETE_INCLUDES} ) set( KOPETE_TEST_LIBRARIES Qt5::Test KF5::KIOCore kopete ) +ecm_add_test(kopetetasktest.cpp LINK_LIBRARIES ${KOPETE_TEST_LIBRARIES}) +ecm_add_test(kopetestatusmessagetest.cpp LINK_LIBRARIES ${KOPETE_TEST_LIBRARIES}) diff --git a/tests/libkopete/kopetestatusmessagetest.cpp b/tests/libkopete/kopetestatusmessagetest.cpp new file mode 100644 index 000000000..ea25894ba --- /dev/null +++ b/tests/libkopete/kopetestatusmessagetest.cpp @@ -0,0 +1,98 @@ +/* + Tests for Kopete::StatusMessage + + Copyright (c) 2017 by Vijay Krishnavanshi + + Kopete (c) 2002-2017 by the Kopete developers + + ************************************************************************* + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + ************************************************************************* +*/ + + +#include "kopetestatusmessage.h" +#include +#include +class StatusMessageTest : public QObject +{ + Q_OBJECT +private slots: + void testStatus(); + void testConstructors(); + void testStatusMetaData(); + void testStatusHash(); + void testEmptyStatus(); +}; + +void StatusMessageTest::testStatus() +{ + const QString str = QStringLiteral("given we are here this should work"); + Kopete::StatusMessage status(str); + status.setMessage(str); + QCOMPARE(status.message(), str); +} + +void StatusMessageTest::testConstructors() +{ + const QString str = QStringLiteral("Hello"); + Kopete::StatusMessage statusD(str); + Kopete::StatusMessage statusP; + statusP.setMessage(str); + QCOMPARE(statusD.message(), statusP.message()); +} + +void StatusMessageTest::testStatusMetaData() +{ + const QString sname = QStringLiteral("Coldplay - Paradise"); + const QString smplayer = QStringLiteral("VLC"); + const QString sartist = QStringLiteral("ColdPlay"); + const QString stitle = QStringLiteral("Paradise"); + Kopete::StatusMessage status(sname); + status.addMetaData(QStringLiteral("MusicPlayer"), smplayer); + status.addMetaData(QStringLiteral("artist"), sartist); + status.addMetaData(QStringLiteral("title"), stitle); + QVERIFY(status.hasMetaData("sadhgsadf") == false); + QCOMPARE(status.hasMetaData("artist") , true); + QCOMPARE(status.metaData("MusicPlayer").toString(), smplayer); + QCOMPARE(status.metaData("artist").toString(), sartist); + QCOMPARE(status.metaData("title").toString(), stitle); + QCOMPARE(status.message(), sname); +} + +void StatusMessageTest::testStatusHash() +{ + const QString sname = QStringLiteral("Coldplay - Paradise"); + const QString smplayer = QStringLiteral("VLC"); + const QString sartist = QStringLiteral("ColdPlay"); + const QString stitle = QStringLiteral("Paradise"); + const QString salbum = QStringLiteral("Unknown"); + Kopete::StatusMessage status(sname); + status.addMetaData(QStringLiteral("MusicPlayer"), smplayer); + status.addMetaData(QStringLiteral("artist"), sartist); + status.addMetaData(QStringLiteral("title"), stitle); + status.addMetaData(QStringLiteral("album"), salbum); + QCOMPARE(status.metaData("artist").toString(), sartist); + QCOMPARE(status.metaData("title").toString(), stitle); + QHash metaDataHash; + metaDataHash.insert(QStringLiteral("artist"), QStringLiteral("Chris Martin")); + metaDataHash.insert(QStringLiteral("title"), QStringLiteral("Undefined")); + status.addMetaData(metaDataHash); + QCOMPARE(status.metaData("artist").toString(), QStringLiteral("Chris Martin")); + QCOMPARE(status.metaData("title").toString(), QStringLiteral("Undefined")); + QCOMPARE(status.metaData("album").toString(), salbum); +} + +void StatusMessageTest::testEmptyStatus() +{ + Kopete::StatusMessage status; + QCOMPARE(status.isEmpty(), true); +} + +QTEST_MAIN(StatusMessageTest) +#include "kopetestatusmessagetest.moc" diff --git a/tests/libkopete/kopetetasktest.cpp b/tests/libkopete/kopetetasktest.cpp new file mode 100644 index 000000000..cc356166e --- /dev/null +++ b/tests/libkopete/kopetetasktest.cpp @@ -0,0 +1,94 @@ +/* + Tests for Kopete::Task + + Copyright (c) 2017 by Vijay Krishnavanshi + + Kopete (c) 2002-2017 by the Kopete developers + + ************************************************************************* + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + ************************************************************************* +*/ + +#include +#include +#include +#include + +#include +#include + + +class ParseEmoticonTask : public Kopete::Task +{ + Q_OBJECT + +public: + ParseEmoticonTask(const QString &sourceString); + + QString parseResult() const + { + return m_parsed; + } + +private slots: + void start(); + +private: + void parseEmoticon(const QString &value); + + QString m_source; + QString m_parsed; +}; + +class KopeteTaskTest : public QObject +{ + Q_OBJECT +private slots: + void testEmoticonTask(); +}; + + +const QString sampleString = QString("Sample string :) :D ;)"); + +ParseEmoticonTask::ParseEmoticonTask(const QString &sourceString) + : Kopete::Task(), m_source(sourceString) +{ + QTimer::singleShot(0, this, &ParseEmoticonTask::start); +} + +void ParseEmoticonTask::start() +{ + parseEmoticon(m_source); +} + +void ParseEmoticonTask::parseEmoticon(const QString &value) +{ + m_parsed = Kopete::Emoticons::parseEmoticons(value, KEmoticonsTheme::RelaxedParse | KEmoticonsTheme::SkipHTML); + + if (m_parsed.isEmpty()) { + setError(100); + } + + emitResult(); +} + +void KopeteTaskTest::testEmoticonTask() +{ + ParseEmoticonTask *task = new ParseEmoticonTask(sampleString); + QSignalSpy spy(task, SIGNAL(result(KJob*))); + + // For the task to execute, we must manually call the event loop. + qApp->processEvents(); + + QCOMPARE(spy.count(), 1); + QCOMPARE(task->error(), 0); +} + +QTEST_MAIN(KopeteTaskTest) +#include "kopetetasktest.moc"