Rex Dieter d7d5b6
diff --git a/plugins/cliunarchiverplugin/kerfuffle_cliunarchiver.desktop b/plugins/cliunarchiverplugin/kerfuffle_cliunarchiver.desktop
Rex Dieter d7d5b6
new file mode 100644
Rex Dieter d7d5b6
index 0000000..2b5bd9e
Rex Dieter d7d5b6
--- /dev/null
Rex Dieter d7d5b6
+++ b/plugins/cliunarchiverplugin/kerfuffle_cliunarchiver.desktop
Rex Dieter d7d5b6
@@ -0,0 +1,15 @@
Rex Dieter d7d5b6
+[Desktop Entry]
Rex Dieter d7d5b6
+Type=Service
Rex Dieter d7d5b6
+X-KDE-ServiceTypes=Kerfuffle/Plugin
Rex Dieter d7d5b6
+X-KDE-Library=kerfuffle_cliunarchiver
Rex Dieter d7d5b6
+X-KDE-PluginInfo-Author=Luke Shumaker
Rex Dieter d7d5b6
+X-KDE-PluginInfo-Email=lukeshu@sbcglobal.net
Rex Dieter d7d5b6
+X-KDE-PluginInfo-Name= kerfuffle_cliunarchiver
Rex Dieter d7d5b6
+X-KDE-PluginInfo-Version=0.0.1
Rex Dieter d7d5b6
+X-KDE-PluginInfo-Website=http://www.kde.org
Rex Dieter d7d5b6
+X-KDE-PluginInfo-License=GPLv2+
Rex Dieter d7d5b6
+X-KDE-Priority=150
Rex Dieter d7d5b6
+X-KDE-Kerfuffle-APIRevision=1
Rex Dieter d7d5b6
+X-KDE-Kerfuffle-ReadWrite=false
Rex Dieter d7d5b6
+Name=The Unarchiver plugin
Rex Dieter d7d5b6
+MimeType=application/x-rar;
Rex Dieter d7d5b6
diff --git a/plugins/cliunarchiverplugin/cliplugin.cpp b/plugins/cliunarchiverplugin/cliplugin.cpp
Rex Dieter d7d5b6
new file mode 100644
Rex Dieter d7d5b6
index 0000000..e0adcf7
Rex Dieter d7d5b6
--- /dev/null
Rex Dieter d7d5b6
+++ b/plugins/cliunarchiverplugin/cliplugin.cpp
Rex Dieter d7d5b6
@@ -0,0 +1,170 @@
Rex Dieter d7d5b6
+ /*
Rex Dieter d7d5b6
+ * ark -- archiver for the KDE project
Rex Dieter d7d5b6
+ *
Rex Dieter d7d5b6
+ * Copyright (C) 2011 Luke Shumaker <lukeshu@sbcglobal.net>
Rex Dieter d7d5b6
+ *
Rex Dieter d7d5b6
+ * This program is free software; you can redistribute it and/or
Rex Dieter d7d5b6
+ * modify it under the terms of the GNU General Public License
Rex Dieter d7d5b6
+ * as published by the Free Software Foundation; either version 2
Rex Dieter d7d5b6
+ * of the License, or (at your option) any later version.
Rex Dieter d7d5b6
+ *
Rex Dieter d7d5b6
+ * This program is distributed in the hope that it will be useful,
Rex Dieter d7d5b6
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
Rex Dieter d7d5b6
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
Rex Dieter d7d5b6
+ * GNU General Public License for more details.
Rex Dieter d7d5b6
+ *
Rex Dieter d7d5b6
+ * You should have received a copy of the GNU General Public License
Rex Dieter d7d5b6
+ * along with this program; if not, write to the Free Software
Rex Dieter d7d5b6
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
Rex Dieter d7d5b6
+ *
Rex Dieter d7d5b6
+ */
Rex Dieter d7d5b6
+
Rex Dieter d7d5b6
+#include "kerfuffle/cliinterface.h"
Rex Dieter d7d5b6
+#include "kerfuffle/kerfuffle_export.h"
Rex Dieter d7d5b6
+
Rex Dieter d7d5b6
+#include <KDebug>
Rex Dieter d7d5b6
+
Rex Dieter d7d5b6
+#include <QDateTime>
Rex Dieter d7d5b6
+#include <QDir>
Rex Dieter d7d5b6
+#include <QRegExp>
Rex Dieter d7d5b6
+#include <QString>
Rex Dieter d7d5b6
+#include <QStringList>
Rex Dieter d7d5b6
+
Rex Dieter d7d5b6
+using namespace Kerfuffle;
Rex Dieter d7d5b6
+
Rex Dieter d7d5b6
+class CliPlugin: public CliInterface
Rex Dieter d7d5b6
+{
Rex Dieter d7d5b6
+public:
Rex Dieter d7d5b6
+    explicit CliPlugin(QObject *parent, const QVariantList & args)
Rex Dieter d7d5b6
+        : CliInterface(parent, args) {
Rex Dieter d7d5b6
+        m_indentLevel = 0;
Rex Dieter d7d5b6
+    }
Rex Dieter d7d5b6
+
Rex Dieter d7d5b6
+    virtual ~CliPlugin() {
Rex Dieter d7d5b6
+    }
Rex Dieter d7d5b6
+
Rex Dieter d7d5b6
+    virtual ParameterList parameterList() const {
Rex Dieter d7d5b6
+        static ParameterList p;
Rex Dieter d7d5b6
+        if (p.isEmpty()) {
Rex Dieter d7d5b6
+            /* Limitations:
Rex Dieter d7d5b6
+             *  01 - creates an empty file upon entering wrong password
Rex Dieter d7d5b6
+             *  02 - unar detects if output is being redirected and then does not accept any input
Rex Dieter d7d5b6
+             */
Rex Dieter d7d5b6
+
Rex Dieter d7d5b6
+            ///////////////[ COMMON ]/////////////
Rex Dieter d7d5b6
+
Rex Dieter d7d5b6
+            p[CaptureProgress] = false;
Rex Dieter d7d5b6
+            p[PasswordPromptPattern] = QLatin1String("Password (will not be shown): ");
Rex Dieter d7d5b6
+
Rex Dieter d7d5b6
+            ///////////////[ LIST ]/////////////
Rex Dieter d7d5b6
+
Rex Dieter d7d5b6
+            p[ListProgram] = QLatin1String("lsar");
Rex Dieter d7d5b6
+            p[ListArgs] = QStringList() << QLatin1String("-json") << QLatin1String("$Archive");
Rex Dieter d7d5b6
+
Rex Dieter d7d5b6
+            ///////////////[ EXTRACT ]/////////////
Rex Dieter d7d5b6
+
Rex Dieter d7d5b6
+            p[ExtractProgram] = QLatin1String("unar");
Rex Dieter d7d5b6
+            p[ExtractArgs] = QStringList() << QLatin1String("$Archive") << QLatin1String("$Files") << QLatin1String("$PasswordSwitch") << QLatin1String("$RootNodeSwitch");
Rex Dieter d7d5b6
+            p[NoTrailingSlashes]  = true;
Rex Dieter d7d5b6
+            p[PasswordSwitch] = QStringList() << QLatin1String("-password") << QLatin1String("$Password");
Rex Dieter d7d5b6
+	    p[RootNodeSwitch] = QStringList() << QLatin1String("-output-directory") << QLatin1String("$Path");
Rex Dieter d7d5b6
+            p[FileExistsExpression] = QLatin1String("^\\\"(.+)\\\" already exists.");
Rex Dieter d7d5b6
+            p[FileExistsInput] = QStringList()
Rex Dieter d7d5b6
+                     << QLatin1String("o") //overwrite
Rex Dieter d7d5b6
+                     << QLatin1String("s") //skip
Rex Dieter d7d5b6
+                     << QLatin1String("O") //overwrite all
Rex Dieter d7d5b6
+                     << QLatin1String("S") //autoskip
Rex Dieter d7d5b6
+                     << QLatin1String("q") //cancel
Rex Dieter d7d5b6
+                     ;
Rex Dieter d7d5b6
+
Rex Dieter d7d5b6
+            ///////////////[ DELETE ]/////////////
Rex Dieter d7d5b6
+
Rex Dieter d7d5b6
+            p[DeleteProgram] = QLatin1String("x-fakeprogram");
Rex Dieter d7d5b6
+            //p[DeleteArgs]    =
Rex Dieter d7d5b6
+
Rex Dieter d7d5b6
+            ///////////////[ ADD ]/////////////
Rex Dieter d7d5b6
+
Rex Dieter d7d5b6
+            p[AddProgram] = QLatin1String("x-fakeprogram");
Rex Dieter d7d5b6
+            //p[AddArgs]    =
Rex Dieter d7d5b6
+
Rex Dieter d7d5b6
+            ///////////////[ ERRORS ]/////////////
Rex Dieter d7d5b6
+
Rex Dieter d7d5b6
+            p[ExtractionFailedPatterns] = QStringList()
Rex Dieter d7d5b6
+                << QLatin1String("Failed! \\((.+)\\)$")
Rex Dieter d7d5b6
+                << QLatin1String("Segmentation fault$");
Rex Dieter d7d5b6
+
Rex Dieter d7d5b6
+            p[WrongPasswordPatterns] = QStringList()
Rex Dieter d7d5b6
+                << QLatin1String("Failed! \\((.+)\\)$");
Rex Dieter d7d5b6
+        }
Rex Dieter d7d5b6
+        return p;
Rex Dieter d7d5b6
+    }
Rex Dieter d7d5b6
+
Rex Dieter d7d5b6
+    QString m_entryFilename, m_internalId;
Rex Dieter d7d5b6
+    ArchiveEntry m_currentEntry;
Rex Dieter d7d5b6
+    int m_indentLevel;
Rex Dieter d7d5b6
+
Rex Dieter d7d5b6
+    bool readListLine(const QString &line) {
Rex Dieter d7d5b6
+        /* lsar will give us JSON output.  However, we actually parse based on
Rex Dieter d7d5b6
+         * the indentation.  Ugly, I know, but
Rex Dieter d7d5b6
+         *  1. It's easier
Rex Dieter d7d5b6
+         *  2. lsar's JSON is invalid JSON, so actual parsers bork.
Rex Dieter d7d5b6
+         */
Rex Dieter d7d5b6
+
Rex Dieter d7d5b6
+        int spaces;
Rex Dieter d7d5b6
+        for(spaces=0;(spaces
Rex Dieter d7d5b6
+        // Since this is so ugly anyway, I'm not even going to check to
Rex Dieter d7d5b6
+        // make sure that spaces is even.  I mean, what would I do about it?
Rex Dieter d7d5b6
+        int m_newIndentLevel = spaces/2;
Rex Dieter d7d5b6
+
Rex Dieter d7d5b6
+        if (m_newIndentLevel>m_indentLevel) {
Rex Dieter d7d5b6
+            if (m_newIndentLevel==3) {
Rex Dieter d7d5b6
+                m_currentEntry.clear();
Rex Dieter d7d5b6
+                m_currentEntry[IsDirectory] = false;
Rex Dieter d7d5b6
+            }
Rex Dieter d7d5b6
+        } else if (m_newIndentLevel
Rex Dieter d7d5b6
+            if ( (m_newIndentLevel<3) && (m_indentLevel>=3) ) {
Rex Dieter d7d5b6
+                EntryMetaDataType index = IsDirectory;
Rex Dieter d7d5b6
+                if (m_currentEntry[index].toBool()) {
Rex Dieter d7d5b6
+                    m_currentEntry[FileName].toString().append(QLatin1String("/"));
Rex Dieter d7d5b6
+                }
Rex Dieter d7d5b6
+                kDebug() << "Added entry:" << m_currentEntry;
Rex Dieter d7d5b6
+                entry(m_currentEntry);
Rex Dieter d7d5b6
+            }
Rex Dieter d7d5b6
+        }
Rex Dieter d7d5b6
+        m_indentLevel = m_newIndentLevel;
Rex Dieter d7d5b6
+
Rex Dieter d7d5b6
+        QRegExp rx(QLatin1String("^\\s*\"([^\"]*)\": (.*),$"));
Rex Dieter d7d5b6
+        if (rx.indexIn(line) >= 0) {
Rex Dieter d7d5b6
+            QRegExp rx_unquote(QLatin1String("^\"(.*)\"$"));
Rex Dieter d7d5b6
+            QString key = rx.cap(1);
Rex Dieter d7d5b6
+            QString value = rx.cap(2);
Rex Dieter d7d5b6
+
Rex Dieter d7d5b6
+            if (false) {
Rex Dieter d7d5b6
+            } else if (key==QLatin1String("XADFileName")) {
Rex Dieter d7d5b6
+                rx_unquote.indexIn(value);
Rex Dieter d7d5b6
+                m_currentEntry[FileName] = m_currentEntry[InternalID] = rx_unquote.cap(1);
Rex Dieter d7d5b6
+            } else if (key==QLatin1String("XADFileSize")) {
Rex Dieter d7d5b6
+                m_currentEntry[Size] = value.toInt();
Rex Dieter d7d5b6
+            } else if (key==QLatin1String("XADCompressedSize")) {
Rex Dieter d7d5b6
+                m_currentEntry[CompressedSize] = value.toInt();
Rex Dieter d7d5b6
+            } else if (key==QLatin1String("XADLastModificationDate")) {
Rex Dieter d7d5b6
+                QDateTime ts(QDate::fromString(value, QLatin1String("\"YYYY-MM-DD hh:mm:ss")));
Rex Dieter d7d5b6
+                m_currentEntry[Timestamp] = ts;
Rex Dieter d7d5b6
+            } else if (key==QLatin1String("XADIsDirectory")) {
Rex Dieter d7d5b6
+                m_currentEntry[IsDirectory] = (value==QLatin1String("1"));
Rex Dieter d7d5b6
+            } else if (key==QLatin1String("RARCRC32")) {
Rex Dieter d7d5b6
+                m_currentEntry[CRC] = value.toInt();
Rex Dieter d7d5b6
+            } else if (key==QLatin1String("RARCompressionMethod")) {
Rex Dieter d7d5b6
+                m_currentEntry[Method] = value.toInt();
Rex Dieter d7d5b6
+            } else if (key==QLatin1String("Encrypted")) {
Rex Dieter d7d5b6
+                m_currentEntry[IsPasswordProtected] = (value.toInt() != 0);
Rex Dieter d7d5b6
+            }
Rex Dieter d7d5b6
+            // TODO: add RAR version. ([Version])
Rex Dieter d7d5b6
+        }
Rex Dieter d7d5b6
+
Rex Dieter d7d5b6
+        return true;
Rex Dieter d7d5b6
+    }
Rex Dieter d7d5b6
+};
Rex Dieter d7d5b6
+
Rex Dieter d7d5b6
+KERFUFFLE_EXPORT_PLUGIN(CliPlugin)
Rex Dieter d7d5b6
+
Rex Dieter d7d5b6
diff --git a/plugins/CMakeLists.txt b/plugins/CMakeLists.txt
Rex Dieter d7d5b6
index 3619412..6368839 100644
Rex Dieter d7d5b6
--- a/plugins/CMakeLists.txt
Rex Dieter d7d5b6
+++ b/plugins/CMakeLists.txt
Rex Dieter d7d5b6
@@ -20,6 +20,7 @@ if (LIBARCHIVE_FOUND)
Rex Dieter d7d5b6
 endif (LIBARCHIVE_FOUND)
Rex Dieter d7d5b6
 
Rex Dieter d7d5b6
 add_subdirectory( clirarplugin )
Rex Dieter d7d5b6
+add_subdirectory( cliunarchiverplugin )
Rex Dieter d7d5b6
 add_subdirectory( cli7zplugin )
Rex Dieter d7d5b6
 add_subdirectory( clizipplugin )
Rex Dieter d7d5b6
 add_subdirectory( libsinglefileplugin )
Rex Dieter d7d5b6
diff --git a/plugins/cliunarchiverplugin/CMakeLists.txt b/plugins/cliunarchiverplugin/CMakeLists.txt
Rex Dieter d7d5b6
new file mode 100644
Rex Dieter d7d5b6
index 0000000..ccd52e7
Rex Dieter d7d5b6
--- /dev/null
Rex Dieter d7d5b6
+++ b/plugins/cliunarchiverplugin/CMakeLists.txt
Rex Dieter d7d5b6
@@ -0,0 +1,21 @@
Rex Dieter d7d5b6
+
Rex Dieter d7d5b6
+include_directories(
Rex Dieter d7d5b6
+                     ${CMAKE_CURRENT_SOURCE_DIR}/../..
Rex Dieter d7d5b6
+                     ${CMAKE_CURRENT_BINARY_DIR}/../..
Rex Dieter d7d5b6
+                   )
Rex Dieter d7d5b6
+
Rex Dieter d7d5b6
+########### next target ###############
Rex Dieter d7d5b6
+
Rex Dieter d7d5b6
+set(kerfuffle_cliunarchiver_SRCS cliplugin.cpp)
Rex Dieter d7d5b6
+
Rex Dieter d7d5b6
+kde4_add_plugin(kerfuffle_cliunarchiver ${kerfuffle_cliunarchiver_SRCS})
Rex Dieter d7d5b6
+
Rex Dieter d7d5b6
+target_link_libraries(kerfuffle_cliunarchiver  ${KDE4_KDECORE_LIBS} ${KDE4_KIO_LIBS} kerfuffle )
Rex Dieter d7d5b6
+
Rex Dieter d7d5b6
+
Rex Dieter d7d5b6
+
Rex Dieter d7d5b6
+########### install files ###############
Rex Dieter d7d5b6
+
Rex Dieter d7d5b6
+install(TARGETS kerfuffle_cliunarchiver  DESTINATION ${PLUGIN_INSTALL_DIR} )
Rex Dieter d7d5b6
+install( FILES kerfuffle_cliunarchiver.desktop  DESTINATION  ${SERVICES_INSTALL_DIR} )
Rex Dieter d7d5b6
+