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