summaryrefslogtreecommitdiffstats
path: root/kftpgrabber/src/misc
diff options
context:
space:
mode:
Diffstat (limited to 'kftpgrabber/src/misc')
-rw-r--r--kftpgrabber/src/misc/Makefile.am23
-rw-r--r--kftpgrabber/src/misc/config.kcfgc7
-rw-r--r--kftpgrabber/src/misc/configbase.cpp141
-rw-r--r--kftpgrabber/src/misc/configbase.h137
-rw-r--r--kftpgrabber/src/misc/customcommands/Makefile.am16
-rw-r--r--kftpgrabber/src/misc/customcommands/commands.xml113
-rw-r--r--kftpgrabber/src/misc/customcommands/entry.cpp155
-rw-r--r--kftpgrabber/src/misc/customcommands/entry.h236
-rw-r--r--kftpgrabber/src/misc/customcommands/handlers.cpp97
-rw-r--r--kftpgrabber/src/misc/customcommands/handlers.h147
-rw-r--r--kftpgrabber/src/misc/customcommands/manager.cpp211
-rw-r--r--kftpgrabber/src/misc/customcommands/manager.h118
-rw-r--r--kftpgrabber/src/misc/customcommands/parameterentrydialog.cpp131
-rw-r--r--kftpgrabber/src/misc/customcommands/parameterentrydialog.h79
-rw-r--r--kftpgrabber/src/misc/customcommands/responsedialog.cpp60
-rw-r--r--kftpgrabber/src/misc/customcommands/responsedialog.h65
-rw-r--r--kftpgrabber/src/misc/desencryptor.cpp119
-rw-r--r--kftpgrabber/src/misc/desencryptor.h71
-rw-r--r--kftpgrabber/src/misc/filter.cpp421
-rw-r--r--kftpgrabber/src/misc/filter.h506
-rw-r--r--kftpgrabber/src/misc/filterwidgethandler.cpp539
-rw-r--r--kftpgrabber/src/misc/filterwidgethandler.h279
-rw-r--r--kftpgrabber/src/misc/interfaces/Makefile.am15
-rw-r--r--kftpgrabber/src/misc/interfaces/kftpbookmarkimportplugin.cpp55
-rw-r--r--kftpgrabber/src/misc/interfaces/kftpbookmarkimportplugin.desktop29
-rw-r--r--kftpgrabber/src/misc/interfaces/kftpbookmarkimportplugin.h83
-rw-r--r--kftpgrabber/src/misc/kftpapi.cpp81
-rw-r--r--kftpgrabber/src/misc/kftpapi.h73
-rw-r--r--kftpgrabber/src/misc/kftpgrabber.kcfg319
-rw-r--r--kftpgrabber/src/misc/kftpotpgenerator.cpp470
-rw-r--r--kftpgrabber/src/misc/kftpotpgenerator.h75
-rw-r--r--kftpgrabber/src/misc/kftppluginmanager.cpp76
-rw-r--r--kftpgrabber/src/misc/kftppluginmanager.h82
-rw-r--r--kftpgrabber/src/misc/kftpwalletconnection.cpp166
-rw-r--r--kftpgrabber/src/misc/kftpwalletconnection.h68
-rw-r--r--kftpgrabber/src/misc/kftpzeroconf.cpp67
-rw-r--r--kftpgrabber/src/misc/kftpzeroconf.h70
-rw-r--r--kftpgrabber/src/misc/libs/Makefile.am3
-rw-r--r--kftpgrabber/src/misc/libs/ssh/Makefile.am8
-rw-r--r--kftpgrabber/src/misc/libs/ssh/auth.c597
-rw-r--r--kftpgrabber/src/misc/libs/ssh/base64.c210
-rw-r--r--kftpgrabber/src/misc/libs/ssh/buffer.c161
-rw-r--r--kftpgrabber/src/misc/libs/ssh/channels.c691
-rw-r--r--kftpgrabber/src/misc/libs/ssh/client.c261
-rw-r--r--kftpgrabber/src/misc/libs/ssh/connect.c295
-rw-r--r--kftpgrabber/src/misc/libs/ssh/crypt.c100
-rw-r--r--kftpgrabber/src/misc/libs/ssh/crypto.h47
-rw-r--r--kftpgrabber/src/misc/libs/ssh/dh.c411
-rw-r--r--kftpgrabber/src/misc/libs/ssh/error.c67
-rw-r--r--kftpgrabber/src/misc/libs/ssh/gzip.c140
-rw-r--r--kftpgrabber/src/misc/libs/ssh/kex.c264
-rw-r--r--kftpgrabber/src/misc/libs/ssh/keyfiles.c341
-rw-r--r--kftpgrabber/src/misc/libs/ssh/keys.c353
-rw-r--r--kftpgrabber/src/misc/libs/ssh/libssh.h218
-rw-r--r--kftpgrabber/src/misc/libs/ssh/misc.c98
-rw-r--r--kftpgrabber/src/misc/libs/ssh/options.c341
-rw-r--r--kftpgrabber/src/misc/libs/ssh/packet.c303
-rw-r--r--kftpgrabber/src/misc/libs/ssh/priv.h384
-rw-r--r--kftpgrabber/src/misc/libs/ssh/sftp.c1289
-rw-r--r--kftpgrabber/src/misc/libs/ssh/sftp.h225
-rw-r--r--kftpgrabber/src/misc/libs/ssh/ssh2.h69
-rw-r--r--kftpgrabber/src/misc/libs/ssh/string.c65
-rw-r--r--kftpgrabber/src/misc/libs/ssh/wrapper.c241
-rw-r--r--kftpgrabber/src/misc/misc.cpp193
-rw-r--r--kftpgrabber/src/misc/misc.h74
-rw-r--r--kftpgrabber/src/misc/plugins/Makefile.am3
-rw-r--r--kftpgrabber/src/misc/plugins/bookmarkimport/Makefile.am3
-rw-r--r--kftpgrabber/src/misc/plugins/bookmarkimport/filezilla3/Makefile.am14
-rw-r--r--kftpgrabber/src/misc/plugins/bookmarkimport/filezilla3/kftpimportfz3plugin.cpp166
-rw-r--r--kftpgrabber/src/misc/plugins/bookmarkimport/filezilla3/kftpimportfz3plugin.h82
-rw-r--r--kftpgrabber/src/misc/plugins/bookmarkimport/filezilla3/kftpimportplugin_filezilla3.desktop38
-rw-r--r--kftpgrabber/src/misc/plugins/bookmarkimport/gftp/Makefile.am14
-rw-r--r--kftpgrabber/src/misc/plugins/bookmarkimport/gftp/kftpimportgftpplugin.cpp236
-rw-r--r--kftpgrabber/src/misc/plugins/bookmarkimport/gftp/kftpimportgftpplugin.h83
-rw-r--r--kftpgrabber/src/misc/plugins/bookmarkimport/gftp/kftpimportplugin_gftp.desktop61
-rw-r--r--kftpgrabber/src/misc/plugins/bookmarkimport/kftp/Makefile.am14
-rw-r--r--kftpgrabber/src/misc/plugins/bookmarkimport/kftp/kftpimportkftpplugin.cpp118
-rw-r--r--kftpgrabber/src/misc/plugins/bookmarkimport/kftp/kftpimportkftpplugin.h83
-rw-r--r--kftpgrabber/src/misc/plugins/bookmarkimport/kftp/kftpimportplugin_kftp.desktop57
-rw-r--r--kftpgrabber/src/misc/plugins/bookmarkimport/ncftp/Makefile.am14
-rw-r--r--kftpgrabber/src/misc/plugins/bookmarkimport/ncftp/kftpimportncftpplugin.cpp165
-rw-r--r--kftpgrabber/src/misc/plugins/bookmarkimport/ncftp/kftpimportncftpplugin.h80
-rw-r--r--kftpgrabber/src/misc/plugins/bookmarkimport/ncftp/kftpimportplugin_ncftp.desktop62
83 files changed, 14142 insertions, 0 deletions
diff --git a/kftpgrabber/src/misc/Makefile.am b/kftpgrabber/src/misc/Makefile.am
new file mode 100644
index 0000000..8250ffc
--- /dev/null
+++ b/kftpgrabber/src/misc/Makefile.am
@@ -0,0 +1,23 @@
+INCLUDES = -I$(srcdir)/.. \
+ -I$(srcdir)/../engine \
+ -I$(srcdir)/../misc/interfaces \
+ $(all_includes)
+
+METASOURCES = AUTO
+noinst_LIBRARIES = libkftpgrabbercore.a
+libkftpgrabbercore_a_SOURCES = misc.cpp kftpotpgenerator.cpp \
+ kftpapi.cpp desencryptor.cpp kftpwalletconnection.cpp \
+ kftppluginmanager.cpp \
+ kftpzeroconf.cpp config.kcfgc configbase.cpp filter.cpp \
+ filterwidgethandler.cpp
+
+libkftpgrabbercore_a_LIBADD = interfaces/libkftpinterfaces.la customcommands/libcustomcommands.a
+
+kde_kcfg_DATA = kftpgrabber.kcfg
+
+noinst_HEADERS = misc.h kftpotpgenerator.h kftpapi.h desencryptor.h \
+ kftpwalletconnection.h kftppluginmanager.h kftpzeroconf.h \
+ configbase.h filter.h filterwidgethandler.h
+
+SUBDIRS = interfaces plugins libs customcommands
+
diff --git a/kftpgrabber/src/misc/config.kcfgc b/kftpgrabber/src/misc/config.kcfgc
new file mode 100644
index 0000000..d8ca269
--- /dev/null
+++ b/kftpgrabber/src/misc/config.kcfgc
@@ -0,0 +1,7 @@
+File=kftpgrabber.kcfg
+ClassName=Config
+Inherits=ConfigBase
+NameSpace=KFTPCore
+Singleton=true
+Mutators=true
+IncludeFiles=configbase.h
diff --git a/kftpgrabber/src/misc/configbase.cpp b/kftpgrabber/src/misc/configbase.cpp
new file mode 100644
index 0000000..39d58e4
--- /dev/null
+++ b/kftpgrabber/src/misc/configbase.cpp
@@ -0,0 +1,141 @@
+/*
+ * This file is part of the KFTPGrabber project
+ *
+ * Copyright (C) 2003-2005 by the KFTPGrabber developers
+ * Copyright (C) 2003-2005 Jernej Kos <kostko@jweb-network.net>
+ *
+ * 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
+ * is provided AS IS, WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, and
+ * NON-INFRINGEMENT. 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 Steet, Fifth Floor, Boston,
+ * MA 02110-1301, USA.
+ *
+ * In addition, as a special exception, the copyright holders give
+ * permission to link the code of portions of this program with the
+ * OpenSSL library under certain conditions as described in each
+ * individual source file, and distribute linked combinations
+ * including the two.
+ *
+ * You must obey the GNU General Public License in all respects
+ * for all of the code used other than OpenSSL. If you modify
+ * file(s) with this exception, you may extend this exception to your
+ * version of the file(s), but you are not obligated to do so. If you
+ * do not wish to do so, delete this exception statement from your
+ * version. If you delete this exception statement from all source
+ * files in the program, then also delete it here.
+ */
+
+#include "configbase.h"
+#include "config.h"
+#include "kftpapi.h"
+#include "filter.h"
+
+#include <qregexp.h>
+
+#include <kapplication.h>
+#include <kconfig.h>
+#include <kemailsettings.h>
+#include <klocale.h>
+
+namespace KFTPCore {
+
+ConfigBase::ConfigBase(const QString &fileName)
+ : QObject(),
+ KConfigSkeleton(fileName)
+{
+ m_fileExistsDownActions.setTypeText(i18n("Download"));
+ m_fileExistsUpActions.setTypeText(i18n("Upload"));
+ m_fileExistsFxpActions.setTypeText(i18n("FXP"));
+
+ m_transMode = 'I';
+}
+
+void ConfigBase::postInit()
+{
+ // Restore the actions
+ QString tmp = Config::downloadActions();
+ tmp >> m_fileExistsDownActions;
+
+ tmp = Config::uploadActions();
+ tmp >> m_fileExistsUpActions;
+
+ tmp = Config::fxpActions();
+ tmp >> m_fileExistsFxpActions;
+}
+
+void ConfigBase::saveConfig()
+{
+ // Save actions before writing
+ QString tmp;
+ tmp << m_fileExistsDownActions;
+ Config::setDownloadActions(tmp);
+
+ tmp << m_fileExistsUpActions;
+ Config::setUploadActions(tmp);
+
+ tmp << m_fileExistsFxpActions;
+ Config::setFxpActions(tmp);
+
+ // Save the window's position
+ Config::setSize(KFTPAPI::getInstance()->mainWindow()->size());
+ Config::setPosition(KFTPAPI::getInstance()->mainWindow()->pos());
+
+ // Save filters
+ Filter::Filters::self()->save();
+
+ // Write the config
+ writeConfig();
+}
+
+void ConfigBase::emitChange()
+{
+ emit configChanged();
+}
+
+char ConfigBase::ftpMode(const QString &filename)
+{
+ // Get FTP mode (binary/ascii)
+ switch (m_transMode) {
+ case 'A': return 'A'; break;
+ case 'I': return 'I'; break;
+ case 'X':
+ default: {
+ char mode = 'I';
+ QRegExp e;
+ e.setWildcard(true);
+
+ QStringList list = Config::asciiList();
+ QStringList::iterator end(list.end());
+ for (QStringList::iterator i(list.begin()); i != end; ++i) {
+ e.setPattern((*i));
+
+ if (e.exactMatch(filename)) {
+ mode = 'A';
+ break;
+ }
+ }
+
+ return mode;
+ }
+ }
+}
+
+QString ConfigBase::getGlobalMail()
+{
+ KEMailSettings kes;
+ kes.setProfile(kes.defaultProfileName());
+ return kes.getSetting(KEMailSettings::EmailAddress);
+}
+
+}
+
+#include "configbase.moc"
diff --git a/kftpgrabber/src/misc/configbase.h b/kftpgrabber/src/misc/configbase.h
new file mode 100644
index 0000000..50e1d7a
--- /dev/null
+++ b/kftpgrabber/src/misc/configbase.h
@@ -0,0 +1,137 @@
+/*
+ * This file is part of the KFTPGrabber project
+ *
+ * Copyright (C) 2003-2005 by the KFTPGrabber developers
+ * Copyright (C) 2003-2005 Jernej Kos <kostko@jweb-network.net>
+ *
+ * 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
+ * is provided AS IS, WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, and
+ * NON-INFRINGEMENT. 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 Steet, Fifth Floor, Boston,
+ * MA 02110-1301, USA.
+ *
+ * In addition, as a special exception, the copyright holders give
+ * permission to link the code of portions of this program with the
+ * OpenSSL library under certain conditions as described in each
+ * individual source file, and distribute linked combinations
+ * including the two.
+ *
+ * You must obey the GNU General Public License in all respects
+ * for all of the code used other than OpenSSL. If you modify
+ * file(s) with this exception, you may extend this exception to your
+ * version of the file(s), but you are not obligated to do so. If you
+ * do not wish to do so, delete this exception statement from your
+ * version. If you delete this exception statement from all source
+ * files in the program, then also delete it here.
+ */
+
+#ifndef KFTPCORECONFIGBASE_H
+#define KFTPCORECONFIGBASE_H
+
+#include <qobject.h>
+
+#include <kconfigskeleton.h>
+
+#include "kftpfileexistsactions.h"
+
+#define PRIO_SKIP 0
+#define PRIO_NOT_FOUND -999
+
+namespace KFTPCore {
+
+/**
+ * This is a base class for KFTPGrabber's configuration. It is inherited by
+ * auto-generated KConfigXT class KFTPCore::Config that adds all the configuration
+ * options.
+ *
+ * @author Jernej Kos
+ */
+class ConfigBase : public QObject, public KConfigSkeleton
+{
+Q_OBJECT
+public:
+ ConfigBase(const QString &fileName);
+
+ /**
+ * Does some post initialization stuff that couldn't be done in the constructor due
+ * to use of Config singleton.
+ */
+ void postInit();
+
+ /**
+ * Does some pre write stuff (eg. exporting the actions).
+ */
+ void saveConfig();
+
+ /**
+ * Returns a proper mode for the requested file. If the current mode is set to AUTO
+ * the list of ascii file patterns is consulted.
+ *
+ * @param filename The filename for which the mode should be returned
+ * @return A valid FTP transfer mode
+ */
+ char ftpMode(const QString &filename);
+
+ /**
+ * Set the global transfer mode.
+ *
+ * @param mode Transfer mode
+ */
+ void setGlobalMode(char mode) { m_transMode = mode; }
+
+ /**
+ * Get the global transfer mode.
+ *
+ * @return The transfer mode currently in use
+ */
+ char getGlobalMode() { return m_transMode; }
+
+ /**
+ * Get the download actions object.
+ *
+ * @return The FileExistsActions object for download actions
+ */
+ KFTPQueue::FileExistsActions *dActions() { return &m_fileExistsDownActions; }
+
+ /**
+ * Get the upload actions object.
+ *
+ * @return The FileExistsActions object for upload actions
+ */
+ KFTPQueue::FileExistsActions *uActions() { return &m_fileExistsUpActions; }
+
+ /**
+ * Get the fxp actions object.
+ *
+ * @return The FileExistsActions object for fxp actions
+ */
+ KFTPQueue::FileExistsActions *fActions() { return &m_fileExistsFxpActions; }
+public slots:
+ /**
+ * Emits the configChanged() signal.
+ */
+ void emitChange();
+protected:
+ QString getGlobalMail();
+private:
+ KFTPQueue::FileExistsActions m_fileExistsDownActions;
+ KFTPQueue::FileExistsActions m_fileExistsUpActions;
+ KFTPQueue::FileExistsActions m_fileExistsFxpActions;
+
+ char m_transMode;
+signals:
+ void configChanged();
+};
+
+}
+
+#endif
diff --git a/kftpgrabber/src/misc/customcommands/Makefile.am b/kftpgrabber/src/misc/customcommands/Makefile.am
new file mode 100644
index 0000000..8436cf4
--- /dev/null
+++ b/kftpgrabber/src/misc/customcommands/Makefile.am
@@ -0,0 +1,16 @@
+INCLUDES = -I$(srcdir)/../.. \
+ -I$(srcdir)/.. \
+ -I$(srcdir)/../../engine \
+ -I$(srcdir)/../../misc/interfaces \
+ -I$(srcdir)/../../widgets \
+ $(all_includes)
+METASOURCES = AUTO
+noinst_LIBRARIES = libcustomcommands.a
+noinst_HEADERS = handlers.h entry.h manager.h parameterentrydialog.h \
+ responsedialog.h
+libcustomcommands_a_SOURCES = handlers.cpp entry.cpp manager.cpp \
+ parameterentrydialog.cpp responsedialog.cpp
+
+shellrcdir = $(kde_datadir)/kftpgrabber
+shellrc_DATA = commands.xml
+
diff --git a/kftpgrabber/src/misc/customcommands/commands.xml b/kftpgrabber/src/misc/customcommands/commands.xml
new file mode 100644
index 0000000..82bde8e
--- /dev/null
+++ b/kftpgrabber/src/misc/customcommands/commands.xml
@@ -0,0 +1,113 @@
+<commands>
+ <category name="GlFTPd">
+ <category name="Information">
+ <entry name="Show current aliases">
+ <description>Shows current user aliases.</description>
+ <command>SITE ALIAS</command>
+ <response handler="Raw" display="Window">
+ <expected code="2" />
+ </response>
+ </entry>
+
+ <entry name="Show group info" icon="info">
+ <description>Shows group information.</description>
+ <command>SITE GRP %1</command>
+ <params>
+ <param type="String">Group name</param>
+ </params>
+ <response handler="Raw" display="Window">
+ <expected code="2" />
+ </response>
+ </entry>
+
+ <entry name="Show your idle time">
+ <description>Shows your current idle time.</description>
+ <command>SITE IDLE</command>
+ <response handler="Raw" display="Window">
+ <expected code="2" />
+ </response>
+ </entry>
+
+ <entry name="Show online users">
+ <description>Shows the users that are currently online.</description>
+ <command>SITE WHO</command>
+ <response handler="Raw" display="Window">
+ <expected code="2" />
+ </response>
+ </entry>
+
+ <entry name="Show welcome screen">
+ <description>Shows the welcome screen.</description>
+ <command>SITE WELCOME</command>
+ <response handler="Raw" display="Window">
+ <expected code="2" />
+ </response>
+ </entry>
+
+ <separator />
+
+ <entry name="Set your idle time">
+ <description>Sets your maximum idle time (in seconds).</description>
+ <command>SITE IDLE %1</command>
+ <params>
+ <param type="Integer">Idle time</param>
+ </params>
+ <response handler="Substitute" display="MessageBox">
+ <expected code="2" />
+ <text>Idle time successfully changed.</text>
+ </response>
+ </entry>
+
+ <entry name="Change your password" icon="password">
+ <description>Changes your account password.</description>
+ <command>SITE PASSWD %1</command>
+ <params>
+ <param type="Password">Password</param>
+ </params>
+ <response handler="Substitute" display="MessageBox">
+ <expected code="2" />
+ <text>Password successfully changed.</text>
+ </response>
+ </entry>
+ </category>
+
+ <category name="User Management">
+ <entry name="Delete a user" icon="editdelete">
+ <description>Removes a user from the server's user database.</description>
+ <command>SITE DELUSER %1</command>
+ <params>
+ <param type="String">Username</param>
+ </params>
+ <response handler="Substitute" display="MessageBox">
+ <expected code="2" />
+ <text>User successfully removed.</text>
+ </response>
+ </entry>
+
+ <entry name="Change user's password" icon="password">
+ <description>Changes a user's password.</description>
+ <command>SITE CHPASS %1 %2</command>
+ <params>
+ <param type="String">Username</param>
+ <param type="Password">New password</param>
+ </params>
+ <response handler="Substitute" display="MessageBox">
+ <expected code="2" />
+ <text>Password successfully changed.</text>
+ </response>
+ </entry>
+
+ <entry name="Kick a user from this server">
+ <description>Terminates all connections for the specified user.</description>
+ <command>SITE KICK %1</command>
+ <params>
+ <param type="String">Username</param>
+ </params>
+ <response handler="Substitute" display="MessageBox">
+ <expected code="2" />
+ <text>User has been kicked.</text>
+ </response>
+ </entry>
+ </category>
+ </category>
+</commands> \ No newline at end of file
diff --git a/kftpgrabber/src/misc/customcommands/entry.cpp b/kftpgrabber/src/misc/customcommands/entry.cpp
new file mode 100644
index 0000000..346f3cf
--- /dev/null
+++ b/kftpgrabber/src/misc/customcommands/entry.cpp
@@ -0,0 +1,155 @@
+/*
+ * This file is part of the KFTPGrabber project
+ *
+ * Copyright (C) 2003-2006 by the KFTPGrabber developers
+ * Copyright (C) 2003-2006 Jernej Kos <kostko@jweb-network.net>
+ *
+ * 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
+ * is provided AS IS, WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, and
+ * NON-INFRINGEMENT. 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 Steet, Fifth Floor, Boston,
+ * MA 02110-1301, USA.
+ *
+ * In addition, as a special exception, the copyright holders give
+ * permission to link the code of portions of this program with the
+ * OpenSSL library under certain conditions as described in each
+ * individual source file, and distribute linked combinations
+ * including the two.
+ *
+ * You must obey the GNU General Public License in all respects
+ * for all of the code used other than OpenSSL. If you modify
+ * file(s) with this exception, you may extend this exception to your
+ * version of the file(s), but you are not obligated to do so. If you
+ * do not wish to do so, delete this exception statement from your
+ * version. If you delete this exception statement from all source
+ * files in the program, then also delete it here.
+ */
+#include "entry.h"
+#include "kftpsession.h"
+#include "manager.h"
+
+#include "parameterentrydialog.h"
+#include "responsedialog.h"
+
+#include <klocale.h>
+#include <kmessagebox.h>
+
+namespace KFTPCore {
+
+namespace CustomCommands {
+
+Entry::Entry(QObject *parent, const QString &name)
+ : QObject(parent),
+ m_name(name)
+{
+}
+
+void Entry::appendParameter(ParameterType type, const QString &name)
+{
+ m_params.append(Parameter(type, name));
+}
+
+void Entry::setResponseHandler(const QString &handler, QDomNode args)
+{
+ m_handler = handler;
+ m_handlerArguments = args;
+}
+
+void Entry::execute(KFTPSession::Session *session)
+{
+ // Create a dialog for parameter input
+ QString command = m_command;
+
+ if (m_params.count() > 0) {
+ ParameterEntryDialog *dialog = new ParameterEntryDialog(this, m_params);
+ if (dialog->exec() != QDialog::Accepted) {
+ delete dialog;
+ return;
+ }
+
+ command = dialog->formatCommand(command);
+ delete dialog;
+ }
+
+ // Execute the command with proper parameters
+ m_lastSession = session;
+
+ connect(session->getClient()->eventHandler(), SIGNAL(gotRawResponse(const QString&)), this, SLOT(handleResponse(const QString&)));
+ session->getClient()->raw(command);
+}
+
+void Entry::handleResponse(const QString &response)
+{
+ if (!m_lastSession)
+ return;
+
+ m_lastSession->getClient()->eventHandler()->QObject::disconnect(this);
+ m_lastSession = 0;
+
+ // Invoke the proper handler
+ QString expectedReturn = m_handlerArguments.namedItem("expected").toElement().attribute("code");
+
+ if (!response.startsWith(expectedReturn)) {
+ KMessageBox::error(0, i18n("<qt>Requested operation has failed! Response from server is:<br/><br /><b>%1</b></qt>").arg(response));
+ return;
+ }
+
+ Handlers::Handler *handler = Manager::self()->handler(m_handler);
+
+ if (!handler) {
+ KMessageBox::error(0, i18n("<qt>Handler named <b>%1</b> can't be found for response parsing!</qt>").arg(m_handler));
+ return;
+ }
+
+ QString parsed = handler->handleResponse(response, m_handlerArguments);
+
+ // Find the proper way to display the parsed response
+ switch (m_displayType) {
+ case None: return;
+ case Window: {
+ ResponseDialog *dialog = new ResponseDialog(m_name, parsed);
+ dialog->exec();
+ delete dialog;
+ break;
+ }
+ case MessageBox: {
+ KMessageBox::information(0, parsed);
+ break;
+ }
+ }
+}
+
+Entry::Parameter::Parameter()
+ : m_type(String),
+ m_name("<invalid>")
+{
+}
+
+Entry::Parameter::Parameter(ParameterType type, const QString &name)
+ : m_type(type),
+ m_name(name)
+{
+}
+
+EntryAction::EntryAction(Entry *entry, KFTPSession::Session *session)
+ : KAction(entry->name(), entry->icon()),
+ m_entryInfo(entry),
+ m_session(session)
+{
+}
+
+}
+
+}
+
+#include "entry.moc"
+
diff --git a/kftpgrabber/src/misc/customcommands/entry.h b/kftpgrabber/src/misc/customcommands/entry.h
new file mode 100644
index 0000000..e7c82c4
--- /dev/null
+++ b/kftpgrabber/src/misc/customcommands/entry.h
@@ -0,0 +1,236 @@
+/*
+ * This file is part of the KFTPGrabber project
+ *
+ * Copyright (C) 2003-2006 by the KFTPGrabber developers
+ * Copyright (C) 2003-2006 Jernej Kos <kostko@jweb-network.net>
+ *
+ * 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
+ * is provided AS IS, WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, and
+ * NON-INFRINGEMENT. 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 Steet, Fifth Floor, Boston,
+ * MA 02110-1301, USA.
+ *
+ * In addition, as a special exception, the copyright holders give
+ * permission to link the code of portions of this program with the
+ * OpenSSL library under certain conditions as described in each
+ * individual source file, and distribute linked combinations
+ * including the two.
+ *
+ * You must obey the GNU General Public License in all respects
+ * for all of the code used other than OpenSSL. If you modify
+ * file(s) with this exception, you may extend this exception to your
+ * version of the file(s), but you are not obligated to do so. If you
+ * do not wish to do so, delete this exception statement from your
+ * version. If you delete this exception statement from all source
+ * files in the program, then also delete it here.
+ */
+#ifndef KFTPCORE_CUSTOMCOMMANDSENTRY_H
+#define KFTPCORE_CUSTOMCOMMANDSENTRY_H
+
+#include <qdom.h>
+#include <qvaluelist.h>
+
+#include <kaction.h>
+
+namespace KFTPSession {
+ class Session;
+}
+
+namespace KFTPCore {
+
+namespace CustomCommands {
+
+/**
+ * This class represents a single custom command entry. A tree of
+ * such objects is constructed from an XML file.
+ *
+ * @author Jernej Kos
+ */
+class Entry : public QObject {
+Q_OBJECT
+public:
+ /**
+ * Possible parameter types.
+ */
+ enum ParameterType {
+ String,
+ Password,
+ Integer
+ };
+
+ /**
+ * Possible display types.
+ */
+ enum DisplayType {
+ None,
+ Window,
+ MessageBox
+ };
+
+ /**
+ * A single command parameter.
+ */
+ class Parameter {
+ public:
+ /**
+ * Class constructor.
+ */
+ Parameter();
+
+ /**
+ * Class constructor.
+ *
+ * @param type Parameter type
+ * @param name Parameter name
+ */
+ Parameter(ParameterType type, const QString &name);
+
+ /**
+ * Returns the parameter type.
+ */
+ ParameterType type() const { return m_type; }
+
+ /**
+ * Returns the parameter name.
+ */
+ QString name() const { return m_name; }
+ private:
+ ParameterType m_type;
+ QString m_name;
+ };
+
+ /**
+ * Class constructor.
+ *
+ * @param name Short entry name
+ */
+ Entry(QObject *parent, const QString &name);
+
+ /**
+ * Returns entry's name.
+ */
+ QString name() const { return m_name; }
+
+ /**
+ * Returns entry's description.
+ */
+ QString description() const { return m_description; }
+
+ /**
+ * Returns entry's icon name.
+ */
+ QString icon() const { return m_icon; }
+
+ /**
+ * Sets entry's description.
+ *
+ * @param description A longer entry description; can be rich text
+ */
+ void setDescription(const QString &description) { m_description = description; }
+
+ /**
+ * Set entry's icon.
+ *
+ * @param icon An icon name
+ */
+ void setIcon(const QString &icon) { m_icon = icon; }
+
+ /**
+ * Sets the raw command to be sent.
+ *
+ * @param command A valid FTP command with optional parameter placeholders
+ */
+ void setCommand(const QString &command) { m_command = command; }
+
+ /**
+ * Appends a command parameter.
+ *
+ * @param type Parameter type
+ * @param name Human readable parameter name
+ */
+ void appendParameter(ParameterType type, const QString &name);
+
+ /**
+ * Sets response display type.
+ *
+ * @param type Display type
+ */
+ void setDisplayType(DisplayType type) { m_displayType = type; }
+
+ /**
+ * Sets the response handler to use.
+ *
+ * @param handler Handler name
+ * @param args Optional argument node
+ */
+ void setResponseHandler(const QString &handler, QDomNode args);
+
+ /**
+ * Executes this entry. This will actually generate and show a proper
+ * user input dialog, execute the command with the provided parameters,
+ * pass the raw response to a selected handler and properly display
+ * the result.
+ *
+ * @param session A remote session where command should be executed
+ */
+ void execute(KFTPSession::Session *session);
+private slots:
+ void handleResponse(const QString &response);
+private:
+ QString m_name;
+ QString m_description;
+ QString m_icon;
+ QString m_command;
+ QString m_handler;
+ DisplayType m_displayType;
+
+ QValueList<Parameter> m_params;
+ QDomNode m_handlerArguments;
+
+ KFTPSession::Session *m_lastSession;
+};
+
+/**
+ * This class is a wrapper action, so a proper entry gets pulled and
+ * executed.
+ *
+ * @author Jernej Kos
+ */
+class EntryAction : public KAction {
+public:
+ /**
+ * Class constructor.
+ *
+ * @param entry Associated entry
+ * @param session Associated session
+ */
+ EntryAction(Entry *entry, KFTPSession::Session *session);
+
+ /**
+ * Returns the associated entry instance.
+ */
+ Entry *entryInfo() const { return m_entryInfo; }
+
+ /**
+ * Returns the associated session instance.
+ */
+ KFTPSession::Session *session() const { return m_session; }
+private:
+ Entry *m_entryInfo;
+ KFTPSession::Session *m_session;
+};
+
+}
+
+}
+
+#endif
diff --git a/kftpgrabber/src/misc/customcommands/handlers.cpp b/kftpgrabber/src/misc/customcommands/handlers.cpp
new file mode 100644
index 0000000..8cf5349
--- /dev/null
+++ b/kftpgrabber/src/misc/customcommands/handlers.cpp
@@ -0,0 +1,97 @@
+/*
+ * This file is part of the KFTPGrabber project
+ *
+ * Copyright (C) 2003-2006 by the KFTPGrabber developers
+ * Copyright (C) 2003-2006 Jernej Kos <kostko@jweb-network.net>
+ *
+ * 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
+ * is provided AS IS, WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, and
+ * NON-INFRINGEMENT. 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 Steet, Fifth Floor, Boston,
+ * MA 02110-1301, USA.
+ *
+ * In addition, as a special exception, the copyright holders give
+ * permission to link the code of portions of this program with the
+ * OpenSSL library under certain conditions as described in each
+ * individual source file, and distribute linked combinations
+ * including the two.
+ *
+ * You must obey the GNU General Public License in all respects
+ * for all of the code used other than OpenSSL. If you modify
+ * file(s) with this exception, you may extend this exception to your
+ * version of the file(s), but you are not obligated to do so. If you
+ * do not wish to do so, delete this exception statement from your
+ * version. If you delete this exception statement from all source
+ * files in the program, then also delete it here.
+ */
+#include "handlers.h"
+
+#include <qdom.h>
+#include <qregexp.h>
+
+namespace KFTPCore {
+
+namespace CustomCommands {
+
+namespace Handlers {
+
+Handler::Handler(const QString &name)
+ : m_name(name)
+{
+}
+
+RawHandler::RawHandler()
+ : Handler("Raw")
+{
+}
+
+SubstituteHandler::SubstituteHandler()
+ : Handler("Substitue")
+{
+}
+
+QString SubstituteHandler::handleResponse(const QString &raw, QDomNode arguments) const
+{
+ QString text = arguments.namedItem("text").toElement().text();
+
+ if (text.contains("%1"))
+ return text.arg(raw);
+
+ return text;
+}
+
+RegexpHandler::RegexpHandler()
+ : Handler("Regexp")
+{
+}
+
+QString RegexpHandler::handleResponse(const QString &raw, QDomNode arguments) const
+{
+ QString result;
+ QRegExp e(arguments.namedItem("match").toElement().text());
+
+ if (e.exactMatch(raw.stripWhiteSpace())) {
+ result = arguments.namedItem("display").toElement().text();
+
+ for (int i = 1; i <= e.numCaptures(); i++) {
+ result.replace(QString("\\%1").arg(i), e.cap(i));
+ }
+ }
+
+ return result;
+}
+
+}
+
+}
+
+}
diff --git a/kftpgrabber/src/misc/customcommands/handlers.h b/kftpgrabber/src/misc/customcommands/handlers.h
new file mode 100644
index 0000000..f41a3de
--- /dev/null
+++ b/kftpgrabber/src/misc/customcommands/handlers.h
@@ -0,0 +1,147 @@
+/*
+ * This file is part of the KFTPGrabber project
+ *
+ * Copyright (C) 2003-2006 by the KFTPGrabber developers
+ * Copyright (C) 2003-2006 Jernej Kos <kostko@jweb-network.net>
+ *
+ * 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
+ * is provided AS IS, WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, and
+ * NON-INFRINGEMENT. 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 Steet, Fifth Floor, Boston,
+ * MA 02110-1301, USA.
+ *
+ * In addition, as a special exception, the copyright holders give
+ * permission to link the code of portions of this program with the
+ * OpenSSL library under certain conditions as described in each
+ * individual source file, and distribute linked combinations
+ * including the two.
+ *
+ * You must obey the GNU General Public License in all respects
+ * for all of the code used other than OpenSSL. If you modify
+ * file(s) with this exception, you may extend this exception to your
+ * version of the file(s), but you are not obligated to do so. If you
+ * do not wish to do so, delete this exception statement from your
+ * version. If you delete this exception statement from all source
+ * files in the program, then also delete it here.
+ */
+#ifndef KFTPCORE_CUSTOMCOMMANDS_HANDLERSHANDLERS_H
+#define KFTPCORE_CUSTOMCOMMANDS_HANDLERSHANDLERS_H
+
+#include <qstring.h>
+#include <qdom.h>
+
+namespace KFTPCore {
+
+namespace CustomCommands {
+
+namespace Handlers {
+
+/**
+ * The handler class is an abstract class which every actual handler
+ * must implement.
+ *
+ * @author Jernej Kos
+ */
+class Handler {
+public:
+ /**
+ * Class constructor.
+ *
+ * @param name Handler name
+ */
+ Handler(const QString &name);
+
+ /**
+ * Returns the handler's name.
+ */
+ QString name() const { return m_name; }
+
+ /**
+ * This method should be implemented by actual handlers to handler the
+ * server response.
+ *
+ * @param raw Raw FTP response
+ * @param arguments Any argument nodes supplied in the XML file
+ * @return This method should return a formatted string
+ */
+ virtual QString handleResponse(const QString &raw, QDomNode arguments) const = 0;
+private:
+ QString m_name;
+};
+
+/**
+ * The Raw handler accepts no arguments and simply passes on raw data.
+ *
+ * @author Jernej Kos
+ */
+class RawHandler : public Handler {
+public:
+ /**
+ * Class constructor.
+ */
+ RawHandler();
+
+ /**
+ * @overload
+ * Reimplemented from Handler.
+ */
+ QString handleResponse(const QString &raw, QDomNode) const { return raw; }
+};
+
+/**
+ * The Substitue handler always returns a predefined value when the
+ * operation is completed successfully. %1 can be used in place of the
+ * raw data received from the server.
+ *
+ * @author Jernej Kos
+ */
+class SubstituteHandler : public Handler {
+public:
+ /**
+ * Class constructor.
+ */
+ SubstituteHandler();
+
+ /**
+ * @overload
+ * Reimplemented from Handler.
+ */
+ QString handleResponse(const QString &raw, QDomNode arguments) const;
+};
+
+/**
+ * The Regexp handler enables custom response parsing using regular
+ * expressions.
+ *
+ * @author Jernej Kos
+ */
+class RegexpHandler : public Handler {
+public:
+ /**
+ * Class constructor.
+ */
+ RegexpHandler();
+
+ /**
+ * @overload
+ * Reimplemented from Handler.
+ */
+ QString handleResponse(const QString &raw, QDomNode arguments) const;
+};
+
+}
+
+}
+
+}
+
+#endif
diff --git a/kftpgrabber/src/misc/customcommands/manager.cpp b/kftpgrabber/src/misc/customcommands/manager.cpp
new file mode 100644
index 0000000..1cda06a
--- /dev/null
+++ b/kftpgrabber/src/misc/customcommands/manager.cpp
@@ -0,0 +1,211 @@
+/*
+ * This file is part of the KFTPGrabber project
+ *
+ * Copyright (C) 2003-2006 by the KFTPGrabber developers
+ * Copyright (C) 2003-2006 Jernej Kos <kostko@jweb-network.net>
+ *
+ * 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
+ * is provided AS IS, WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, and
+ * NON-INFRINGEMENT. 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 Steet, Fifth Floor, Boston,
+ * MA 02110-1301, USA.
+ *
+ * In addition, as a special exception, the copyright holders give
+ * permission to link the code of portions of this program with the
+ * OpenSSL library under certain conditions as described in each
+ * individual source file, and distribute linked combinations
+ * including the two.
+ *
+ * You must obey the GNU General Public License in all respects
+ * for all of the code used other than OpenSSL. If you modify
+ * file(s) with this exception, you may extend this exception to your
+ * version of the file(s), but you are not obligated to do so. If you
+ * do not wish to do so, delete this exception statement from your
+ * version. If you delete this exception statement from all source
+ * files in the program, then also delete it here.
+ */
+#include "manager.h"
+#include "entry.h"
+
+#include <qfile.h>
+
+#include <kstandarddirs.h>
+#include <kstaticdeleter.h>
+#include <kpopupmenu.h>
+#include <kmessagebox.h>
+#include <klocale.h>
+
+namespace KFTPCore {
+
+namespace CustomCommands {
+
+Manager *Manager::m_self = 0;
+static KStaticDeleter<Manager> staticManagerDeleter;
+
+Manager *Manager::self()
+{
+ if (!m_self) {
+ staticManagerDeleter.setObject(m_self, new Manager());
+ }
+
+ return m_self;
+}
+
+Manager::Manager()
+ : QObject()
+{
+ // Populate the handlers list
+ m_handlers["Raw"] = new Handlers::RawHandler();
+ m_handlers["Substitute"] = new Handlers::SubstituteHandler();
+ m_handlers["Regexp"] = new Handlers::RegexpHandler();
+}
+
+Manager::~Manager()
+{
+ if (m_self == this)
+ staticManagerDeleter.setObject(m_self, 0, false);
+
+ // Destroy the handlers
+ delete static_cast<Handlers::RawHandler*>(m_handlers["Raw"]);
+ delete static_cast<Handlers::SubstituteHandler*>(m_handlers["Substitute"]);
+ delete static_cast<Handlers::RegexpHandler*>(m_handlers["Regexp"]);
+
+ m_handlers.clear();
+}
+
+void Manager::load()
+{
+ QString filename = locateLocal("appdata", "commands.xml");
+
+ if (!QFile::exists(filename)) {
+ // Copy the default command set over
+ QFile source(locate("appdata", "commands.xml"));
+ QFile destination(filename);
+
+ source.open(IO_ReadOnly);
+ destination.open(IO_WriteOnly | IO_Truncate);
+
+ destination.writeBlock(source.readAll());
+ source.close();
+ destination.close();
+ }
+
+ QFile file(filename);
+ if (!file.open(IO_ReadOnly))
+ return;
+
+ m_document.setContent(&file);
+ file.close();
+}
+
+void Manager::parseEntries(KActionMenu *parentMenu, const QDomNode &parentNode, KFTPSession::Session *session) const
+{
+ QDomNode n = parentNode.firstChild();
+
+ while (!n.isNull()) {
+ if (n.isElement()) {
+ QDomElement e = n.toElement();
+ QString tagName = e.tagName();
+ QString name = e.attribute("name");
+
+ if (tagName == "category") {
+ KActionMenu *menu = new KActionMenu(name, "folder", parentMenu);
+ parentMenu->insert(menu);
+
+ // Recurse into this category
+ parseEntries(menu, n, session);
+ } else if (tagName == "entry") {
+ Entry *entry = new Entry((Manager*) this, name);
+ entry->setDescription(n.namedItem("description").toElement().text());
+ entry->setIcon(e.attribute("icon"));
+ entry->setCommand(n.namedItem("command").toElement().text());
+
+ QDomNode p = n.namedItem("params").firstChild();
+ while (!p.isNull()) {
+ QDomElement pElement = p.toElement();
+
+ if (pElement.tagName() == "param") {
+ QString typeString = pElement.attribute("type");
+ Entry::ParameterType type = Entry::String;
+
+ if (typeString == "String")
+ type = Entry::String;
+ else if (typeString == "Password")
+ type = Entry::Password;
+ else if (typeString == "Integer")
+ type = Entry::Integer;
+
+ entry->appendParameter(type, pElement.text());
+ }
+
+ p = p.nextSibling();
+ }
+
+ QDomElement rElement = n.namedItem("response").toElement();
+ entry->setResponseHandler(rElement.attribute("handler"), rElement);
+
+ QString displayString = rElement.attribute("display");
+ Entry::DisplayType displayType = Entry::None;
+
+ if (displayString == "None")
+ displayType = Entry::None;
+ else if (displayString == "Window")
+ displayType = Entry::Window;
+ else if (displayString == "MessageBox")
+ displayType = Entry::MessageBox;
+
+ entry->setDisplayType(displayType);
+
+ // Create a new action
+ EntryAction *action = new EntryAction(entry, session);
+ connect(action, SIGNAL(activated()), this, SLOT(slotActionActivated()));
+
+ parentMenu->insert(action);
+ } else if (tagName == "separator") {
+ parentMenu->popupMenu()->insertSeparator();
+ } else {
+ KMessageBox::error(0, i18n("Unknown tag while parsing custom site commands!"));
+ }
+ }
+
+ n = n.nextSibling();
+ }
+}
+
+Handlers::Handler *Manager::handler(const QString &name) const
+{
+ if (m_handlers.contains(name))
+ return m_handlers[name];
+
+ return 0;
+}
+
+KActionMenu *Manager::categories(const QString &name, KFTPSession::Session *session) const
+{
+ KActionMenu *actionMenu = new KActionMenu(name);
+ parseEntries(actionMenu, m_document.documentElement(), session);
+
+ return actionMenu;
+}
+
+void Manager::slotActionActivated()
+{
+ EntryAction *action = (EntryAction*) QObject::sender();
+ action->entryInfo()->execute(action->session());
+}
+
+}
+
+}
+
+#include "manager.moc"
+
diff --git a/kftpgrabber/src/misc/customcommands/manager.h b/kftpgrabber/src/misc/customcommands/manager.h
new file mode 100644
index 0000000..db5dd6d
--- /dev/null
+++ b/kftpgrabber/src/misc/customcommands/manager.h
@@ -0,0 +1,118 @@
+/*
+ * This file is part of the KFTPGrabber project
+ *
+ * Copyright (C) 2003-2006 by the KFTPGrabber developers
+ * Copyright (C) 2003-2006 Jernej Kos <kostko@jweb-network.net>
+ *
+ * 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
+ * is provided AS IS, WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, and
+ * NON-INFRINGEMENT. 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 Steet, Fifth Floor, Boston,
+ * MA 02110-1301, USA.
+ *
+ * In addition, as a special exception, the copyright holders give
+ * permission to link the code of portions of this program with the
+ * OpenSSL library under certain conditions as described in each
+ * individual source file, and distribute linked combinations
+ * including the two.
+ *
+ * You must obey the GNU General Public License in all respects
+ * for all of the code used other than OpenSSL. If you modify
+ * file(s) with this exception, you may extend this exception to your
+ * version of the file(s), but you are not obligated to do so. If you
+ * do not wish to do so, delete this exception statement from your
+ * version. If you delete this exception statement from all source
+ * files in the program, then also delete it here.
+ */
+#ifndef KFTPCORE_CUSTOMCOMMANDSMANAGER_H
+#define KFTPCORE_CUSTOMCOMMANDSMANAGER_H
+
+#include <qobject.h>
+#include <qdom.h>
+#include <qmap.h>
+
+#include <kaction.h>
+
+#include "handlers.h"
+
+namespace KFTPSession {
+ class Session;
+}
+
+namespace KFTPCore {
+
+namespace CustomCommands {
+
+/**
+ * This class represents the entry manager. It parses the XML file and
+ * creates the necessary entries. This class is a singleton.
+ *
+ * @author Jernej Kos
+ */
+class Manager : public QObject {
+Q_OBJECT
+public:
+ /**
+ * Class destructor.
+ */
+ ~Manager();
+
+ /**
+ * Returns a Manager instance.
+ */
+ static Manager *self();
+
+ /**
+ * Returns an appropriate handler.
+ *
+ * @param name Handler string identifier
+ */
+ Handlers::Handler *handler(const QString &name) const;
+
+ /**
+ * Returns a KActionMenu that can be used for displaying categories of
+ * entries to the user.
+ */
+ KActionMenu *categories(const QString &name, KFTPSession::Session *session) const;
+public slots:
+ /**
+ * Loads a valid commands XML file.
+ */
+ void load();
+protected:
+ static Manager *m_self;
+
+ /**
+ * Class constructor.
+ */
+ Manager();
+
+ /**
+ * Recursive entry parser.
+ */
+ void parseEntries(KActionMenu *parentMenu, const QDomNode &parentNode, KFTPSession::Session *session) const;
+protected slots:
+ /**
+ * This slot gets called when an EntryAction is activated.
+ */
+ void slotActionActivated();
+private:
+ KActionMenu *m_categories;
+ QDomDocument m_document;
+ QMap<QString, Handlers::Handler*> m_handlers;
+};
+
+}
+
+}
+
+#endif
diff --git a/kftpgrabber/src/misc/customcommands/parameterentrydialog.cpp b/kftpgrabber/src/misc/customcommands/parameterentrydialog.cpp
new file mode 100644
index 0000000..808b400
--- /dev/null
+++ b/kftpgrabber/src/misc/customcommands/parameterentrydialog.cpp
@@ -0,0 +1,131 @@
+/*
+ * This file is part of the KFTPGrabber project
+ *
+ * Copyright (C) 2003-2006 by the KFTPGrabber developers
+ * Copyright (C) 2003-2006 Jernej Kos <kostko@jweb-network.net>
+ *
+ * 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
+ * is provided AS IS, WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, and
+ * NON-INFRINGEMENT. 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 Steet, Fifth Floor, Boston,
+ * MA 02110-1301, USA.
+ *
+ * In addition, as a special exception, the copyright holders give
+ * permission to link the code of portions of this program with the
+ * OpenSSL library under certain conditions as described in each
+ * individual source file, and distribute linked combinations
+ * including the two.
+ *
+ * You must obey the GNU General Public License in all respects
+ * for all of the code used other than OpenSSL. If you modify
+ * file(s) with this exception, you may extend this exception to your
+ * version of the file(s), but you are not obligated to do so. If you
+ * do not wish to do so, delete this exception statement from your
+ * version. If you delete this exception statement from all source
+ * files in the program, then also delete it here.
+ */
+#include "parameterentrydialog.h"
+#include "entry.h"
+
+#include <qvbox.h>
+#include <qlayout.h>
+#include <qlabel.h>
+
+#include <kiconloader.h>
+#include <klineedit.h>
+#include <kpassdlg.h>
+#include <knuminput.h>
+
+namespace KFTPCore {
+
+namespace CustomCommands {
+
+ParameterEntryDialog::ParameterEntryDialog(Entry *entry, QValueList<Entry::Parameter> params)
+ : KDialogBase(0, "", true, entry->name(), Ok|Cancel, Ok),
+ m_params(params)
+{
+ QFrame *mainWidget = makeMainWidget();
+ QVBoxLayout *mainLayout = new QVBoxLayout(mainWidget);
+
+ QHBoxLayout *headerLayout = new QHBoxLayout(mainWidget);
+ QLabel *icon = new QLabel(mainWidget);
+ icon->setPixmap(DesktopIcon(entry->icon(), 32));
+ headerLayout->addWidget(icon);
+
+ QVBoxLayout *headerTextLayout = new QVBoxLayout(mainWidget);
+ headerTextLayout->addWidget(new QLabel(QString("<b>%1</b>").arg(entry->name()), mainWidget));
+ headerTextLayout->addWidget(new QLabel(entry->description(), mainWidget));
+ headerLayout->addLayout(headerTextLayout, 1);
+
+ mainLayout->addLayout(headerLayout);
+ mainLayout->addSpacing(5);
+
+ QFrame *frame = new QFrame(mainWidget);
+ frame->setFrameStyle(QFrame::StyledPanel | QFrame::Raised);
+
+ QVBoxLayout *frameLayout = new QVBoxLayout(frame);
+ frameLayout->setMargin(10);
+ mainLayout->addWidget(frame);
+
+ int num = 0;
+ QValueList<Entry::Parameter>::ConstIterator lend = params.end();
+ for (QValueList<Entry::Parameter>::ConstIterator i = params.begin(); i != lend; ++i) {
+ QHBoxLayout *layout = new QHBoxLayout(frame);
+ QWidget *entryWidget = 0;
+ QString name = QString("param_%1").arg(num++);
+
+ switch ((*i).type()) {
+ case Entry::String: entryWidget = new KLineEdit(frame, name.ascii()); break;
+ case Entry::Password: entryWidget = new KPasswordEdit(frame, name.ascii()); break;
+ case Entry::Integer: entryWidget = new KIntNumInput(frame, name.ascii()); break;
+ }
+
+ // The first widget should have focus
+ if (num == 1)
+ entryWidget->setFocus();
+
+ layout->addWidget(new QLabel((*i).name() + ":", frame));
+ layout->addStretch(1);
+ layout->addWidget(entryWidget);
+ frameLayout->addLayout(layout);
+ frameLayout->addSpacing(5);
+ }
+
+ setMaximumWidth(350);
+ resize(350, minimumHeight());
+}
+
+QString ParameterEntryDialog::formatCommand(const QString &command)
+{
+ QString tmp = command;
+
+ int num = 0;
+ QValueList<Entry::Parameter>::ConstIterator lend = m_params.end();
+ for (QValueList<Entry::Parameter>::ConstIterator i = m_params.begin(); i != lend; ++i) {
+ QObject *entryWidget = child(QString("param_%1").arg(num++).ascii());
+
+ switch ((*i).type()) {
+ case Entry::String: tmp = tmp.arg(static_cast<KLineEdit*>(entryWidget)->text()); break;
+ case Entry::Password: tmp = tmp.arg(static_cast<KPasswordEdit*>(entryWidget)->password()); break;
+ case Entry::Integer: tmp = tmp.arg(static_cast<KIntNumInput*>(entryWidget)->value()); break;
+ }
+ }
+
+ return tmp;
+}
+
+}
+
+}
+
+#include "parameterentrydialog.moc"
+
diff --git a/kftpgrabber/src/misc/customcommands/parameterentrydialog.h b/kftpgrabber/src/misc/customcommands/parameterentrydialog.h
new file mode 100644
index 0000000..3a7d242
--- /dev/null
+++ b/kftpgrabber/src/misc/customcommands/parameterentrydialog.h
@@ -0,0 +1,79 @@
+/*
+ * This file is part of the KFTPGrabber project
+ *
+ * Copyright (C) 2003-2006 by the KFTPGrabber developers
+ * Copyright (C) 2003-2006 Jernej Kos <kostko@jweb-network.net>
+ *
+ * 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
+ * is provided AS IS, WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, and
+ * NON-INFRINGEMENT. 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 Steet, Fifth Floor, Boston,
+ * MA 02110-1301, USA.
+ *
+ * In addition, as a special exception, the copyright holders give
+ * permission to link the code of portions of this program with the
+ * OpenSSL library under certain conditions as described in each
+ * individual source file, and distribute linked combinations
+ * including the two.
+ *
+ * You must obey the GNU General Public License in all respects
+ * for all of the code used other than OpenSSL. If you modify
+ * file(s) with this exception, you may extend this exception to your
+ * version of the file(s), but you are not obligated to do so. If you
+ * do not wish to do so, delete this exception statement from your
+ * version. If you delete this exception statement from all source
+ * files in the program, then also delete it here.
+ */
+#ifndef KFTPCORE_CUSTOMCOMMANDSPARAMETERENTRYDIALOG_H
+#define KFTPCORE_CUSTOMCOMMANDSPARAMETERENTRYDIALOG_H
+
+#include <kdialogbase.h>
+#include <qvaluelist.h>
+
+#include "entry.h"
+
+namespace KFTPCore {
+
+namespace CustomCommands {
+
+/**
+ * A dialog for parameter entry.
+ *
+ * @author Jernej Kos <kostko@jweb-network.net>
+ */
+class ParameterEntryDialog : public KDialogBase {
+Q_OBJECT
+public:
+ /**
+ * Class constructor.
+ *
+ * @param entry An entry instance
+ * @param params Parameter list
+ */
+ ParameterEntryDialog(Entry *entry, QValueList<Entry::Parameter> params);
+
+ /**
+ * Properly replaces the parameter placeholders with actual user
+ * entered values.
+ *
+ * @param command A command string with placeholders
+ */
+ QString formatCommand(const QString &command);
+private:
+ QValueList<Entry::Parameter> m_params;
+};
+
+}
+
+}
+
+#endif
diff --git a/kftpgrabber/src/misc/customcommands/responsedialog.cpp b/kftpgrabber/src/misc/customcommands/responsedialog.cpp
new file mode 100644
index 0000000..11970f9
--- /dev/null
+++ b/kftpgrabber/src/misc/customcommands/responsedialog.cpp
@@ -0,0 +1,60 @@
+/*
+ * This file is part of the KFTPGrabber project
+ *
+ * Copyright (C) 2003-2006 by the KFTPGrabber developers
+ * Copyright (C) 2003-2006 Jernej Kos <kostko@jweb-network.net>
+ *
+ * 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
+ * is provided AS IS, WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, and
+ * NON-INFRINGEMENT. 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 Steet, Fifth Floor, Boston,
+ * MA 02110-1301, USA.
+ *
+ * In addition, as a special exception, the copyright holders give
+ * permission to link the code of portions of this program with the
+ * OpenSSL library under certain conditions as described in each
+ * individual source file, and distribute linked combinations
+ * including the two.
+ *
+ * You must obey the GNU General Public License in all respects
+ * for all of the code used other than OpenSSL. If you modify
+ * file(s) with this exception, you may extend this exception to your
+ * version of the file(s), but you are not obligated to do so. If you
+ * do not wish to do so, delete this exception statement from your
+ * version. If you delete this exception statement from all source
+ * files in the program, then also delete it here.
+ */
+#include "responsedialog.h"
+
+#include <ktextedit.h>
+
+namespace KFTPCore {
+
+namespace CustomCommands {
+
+ResponseDialog::ResponseDialog(const QString &caption, const QString &response)
+ : KDialogBase(0, "", true, caption, Ok)
+{
+ KTextEdit *contents = new KTextEdit(this);
+ setMainWidget(contents);
+
+ contents->setTextFormat(Qt::LogText);
+ contents->unsetPalette();
+ contents->append(response);
+
+ setMinimumSize(500, 300);
+}
+
+}
+
+}
+
diff --git a/kftpgrabber/src/misc/customcommands/responsedialog.h b/kftpgrabber/src/misc/customcommands/responsedialog.h
new file mode 100644
index 0000000..ab370ee
--- /dev/null
+++ b/kftpgrabber/src/misc/customcommands/responsedialog.h
@@ -0,0 +1,65 @@
+/*
+ * This file is part of the KFTPGrabber project
+ *
+ * Copyright (C) 2003-2006 by the KFTPGrabber developers
+ * Copyright (C) 2003-2006 Jernej Kos <kostko@jweb-network.net>
+ *
+ * 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
+ * is provided AS IS, WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, and
+ * NON-INFRINGEMENT. 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 Steet, Fifth Floor, Boston,
+ * MA 02110-1301, USA.
+ *
+ * In addition, as a special exception, the copyright holders give
+ * permission to link the code of portions of this program with the
+ * OpenSSL library under certain conditions as described in each
+ * individual source file, and distribute linked combinations
+ * including the two.
+ *
+ * You must obey the GNU General Public License in all respects
+ * for all of the code used other than OpenSSL. If you modify
+ * file(s) with this exception, you may extend this exception to your
+ * version of the file(s), but you are not obligated to do so. If you
+ * do not wish to do so, delete this exception statement from your
+ * version. If you delete this exception statement from all source
+ * files in the program, then also delete it here.
+ */
+#ifndef KFTPCORE_CUSTOMCOMMANDSRESPONSEDIALOG_H
+#define KFTPCORE_CUSTOMCOMMANDSRESPONSEDIALOG_H
+
+#include <kdialogbase.h>
+
+namespace KFTPCore {
+
+namespace CustomCommands {
+
+/**
+ * A dialog for displaying operation results.
+ *
+ * @author Jernej Kos <kostko@jweb-network.net>
+ */
+class ResponseDialog : public KDialogBase {
+public:
+ /**
+ * Class constructor.
+ *
+ * @param caption Dialog caption
+ * @param response Response text (can be rich-text)
+ */
+ ResponseDialog(const QString &caption, const QString &response);
+};
+
+}
+
+}
+
+#endif
diff --git a/kftpgrabber/src/misc/desencryptor.cpp b/kftpgrabber/src/misc/desencryptor.cpp
new file mode 100644
index 0000000..d53fd5e
--- /dev/null
+++ b/kftpgrabber/src/misc/desencryptor.cpp
@@ -0,0 +1,119 @@
+/*
+ * This file is part of the KFTPGrabber project
+ *
+ * Copyright (C) 2004 by the KFTPGrabber developers
+ * Copyright (C) 2004 Jernej Kos <kostko@jweb-network.net>
+ *
+ * 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
+ * is provided AS IS, WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, and
+ * NON-INFRINGEMENT. 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 Steet, Fifth Floor, Boston,
+ * MA 02110-1301, USA.
+ *
+ * In addition, as a special exception, the copyright holders give
+ * permission to link the code of portions of this program with the
+ * OpenSSL library under certain conditions as described in each
+ * individual source file, and distribute linked combinations
+ * including the two.
+ * You must obey the GNU General Public License in all respects
+ * for all of the code used other than OpenSSL. If you modify
+ * file(s) with this exception, you may extend this exception to your
+ * version of the file(s), but you are not obligated to do so. If you
+ * do not wish to do so, delete this exception statement from your
+ * version. If you delete this exception statement from all source
+ * files in the program, then also delete it here.
+ */
+
+#include "desencryptor.h"
+
+#include <kmdcodec.h>
+#include <qfile.h>
+
+namespace KFTPGrabberBase {
+
+DESEncryptor::DESEncryptor()
+{
+}
+
+void DESEncryptor::DESExec(const QString &str, int mode)
+{
+ QCString string(str.ascii());
+ m_output = "";
+
+ QByteArray in;
+ QByteArray out;
+
+ if (mode == DES_DECRYPT) {
+ // Base64 decode the output
+ KCodecs::base64Decode(string, in);
+ } else {
+ in.resize(string.size());
+ memcpy(in.data(), string.data(), in.size());
+ }
+
+ // Read 8 chars at a time and encrypt/decrypt them
+ unsigned int i = 0;
+ char *o_message = (char*) malloc(8);
+ char *o_output = (char*) malloc(8);
+
+ memset(o_message, 0, 9);
+ memset(o_output, 0, 9);
+ //out.resize(in.size() * 2);
+
+ while (i < in.size()) {
+ out.resize(out.size() + 8);
+ memcpy(o_message, in.data() + i, 8);
+ DES_ecb_encrypt((DES_cblock *) o_message, (DES_cblock*) o_output, &m_schedule, mode);
+ memcpy(out.data() + i, o_output, 8);
+
+ // Next 8 bytes
+ i += 8;
+
+ // Clear everything
+ memset(o_message, 0, 9);
+ memset(o_output, 0, 9);
+ }
+
+ free(o_message);
+ free(o_output);
+
+ if (mode == DES_ENCRYPT) {
+ // Base64 encode the output
+ m_output = KCodecs::base64Encode(out).data();
+ } else {
+ m_output = QCString(out).data();
+ }
+}
+
+void DESEncryptor::setKey(const QString &key)
+{
+ // Setup our DES key
+ DES_string_to_key(key.ascii(), &m_key);
+ DES_set_key_checked(&m_key, &m_schedule);
+}
+
+void DESEncryptor::encrypt(const QString &string)
+{
+ DESExec(string, DES_ENCRYPT);
+}
+
+void DESEncryptor::decrypt(const QString &string)
+{
+ DESExec(string, DES_DECRYPT);
+}
+
+QString DESEncryptor::output()
+{
+ return m_output;
+}
+
+}
diff --git a/kftpgrabber/src/misc/desencryptor.h b/kftpgrabber/src/misc/desencryptor.h
new file mode 100644
index 0000000..bf9ab68
--- /dev/null
+++ b/kftpgrabber/src/misc/desencryptor.h
@@ -0,0 +1,71 @@
+/*
+ * This file is part of the KFTPGrabber project
+ *
+ * Copyright (C) 2004 by the KFTPGrabber developers
+ * Copyright (C) 2004 Jernej Kos <kostko@jweb-network.net>
+ *
+ * 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
+ * is provided AS IS, WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, and
+ * NON-INFRINGEMENT. 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 Steet, Fifth Floor, Boston,
+ * MA 02110-1301, USA.
+ *
+ * In addition, as a special exception, the copyright holders give
+ * permission to link the code of portions of this program with the
+ * OpenSSL library under certain conditions as described in each
+ * individual source file, and distribute linked combinations
+ * including the two.
+ * You must obey the GNU General Public License in all respects
+ * for all of the code used other than OpenSSL. If you modify
+ * file(s) with this exception, you may extend this exception to your
+ * version of the file(s), but you are not obligated to do so. If you
+ * do not wish to do so, delete this exception statement from your
+ * version. If you delete this exception statement from all source
+ * files in the program, then also delete it here.
+ */
+
+#ifndef KFTPGRABBERBASEDESENCRYPTOR_H
+#define KFTPGRABBERBASEDESENCRYPTOR_H
+
+/* OpenSSL includes */
+#include <openssl/des.h>
+
+#include <qstring.h>
+
+namespace KFTPGrabberBase {
+
+/**
+Class for encrypting text and files using OpenSSL's DES encryption.
+
+@author Jernej Kos
+*/
+class DESEncryptor{
+public:
+ DESEncryptor();
+
+ void setKey(const QString &key);
+ void encrypt(const QString &string);
+ void decrypt(const QString &string);
+
+ QString output();
+private:
+ DES_cblock m_key;
+ DES_key_schedule m_schedule;
+
+ QString m_output;
+
+ void DESExec(const QString &str, int mode);
+};
+
+}
+
+#endif
diff --git a/kftpgrabber/src/misc/filter.cpp b/kftpgrabber/src/misc/filter.cpp
new file mode 100644
index 0000000..605eba7
--- /dev/null
+++ b/kftpgrabber/src/misc/filter.cpp
@@ -0,0 +1,421 @@
+/*
+ * This file is part of the KFTPGrabber project
+ *
+ * Copyright (C) 2003-2006 by the KFTPGrabber developers
+ * Copyright (C) 2003-2006 Jernej Kos <kostko@jweb-network.net>
+ *
+ * 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
+ * is provided AS IS, WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, and
+ * NON-INFRINGEMENT. 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 Steet, Fifth Floor, Boston,
+ * MA 02110-1301, USA.
+ *
+ * In addition, as a special exception, the copyright holders give
+ * permission to link the code of portions of this program with the
+ * OpenSSL library under certain conditions as described in each
+ * individual source file, and distribute linked combinations
+ * including the two.
+ *
+ * You must obey the GNU General Public License in all respects
+ * for all of the code used other than OpenSSL. If you modify
+ * file(s) with this exception, you may extend this exception to your
+ * version of the file(s), but you are not obligated to do so. If you
+ * do not wish to do so, delete this exception statement from your
+ * version. If you delete this exception statement from all source
+ * files in the program, then also delete it here.
+ */
+#include "filter.h"
+
+#include <qregexp.h>
+
+#include <kapplication.h>
+#include <klocale.h>
+#include <kstaticdeleter.h>
+#include <kconfig.h>
+
+namespace KFTPCore {
+
+namespace Filter {
+
+Condition::Condition(Field field, Type type, const QVariant &value)
+ : m_field(field),
+ m_type(type),
+ m_value(value)
+{
+}
+
+bool Condition::matches(const KFTPEngine::DirectoryEntry &entry) const
+{
+ bool result = false;
+ QString check;
+
+ switch (m_field) {
+ default:
+ case Filename: check = entry.filename(); break;
+ case EntryType: check = entry.type(); break;
+ case Size: check = QString::number(entry.size()); break;
+ }
+
+ switch (m_type) {
+ case None: result = false; break;
+
+ case Contains: result = (check.contains(m_value.toString()) > 0); break;
+ case ContainsNot: result = (check.contains(m_value.toString()) == 0); break;
+
+ case Is: result = (check == m_value.toString()); break;
+ case IsNot: result = (check != m_value.toString()); break;
+
+ case Matches: {
+ QRegExp r(m_value.toString());
+ result = (r.search(check) > -1);
+ break;
+ }
+ case MatchesNot: {
+ QRegExp r(m_value.toString());
+ result = (r.search(check) == -1);
+ break;
+ }
+
+ case Greater: result = (check.toULongLong() > m_value.toULongLong()); break;
+ case Smaller: result = (check.toULongLong() < m_value.toULongLong()); break;
+ }
+
+ return result;
+}
+
+ConditionChain::ConditionChain()
+ : QPtrList<Condition>(),
+ m_type(All)
+{
+ setAutoDelete(true);
+}
+
+ConditionChain::ConditionChain(Type type)
+ : QPtrList<Condition>(),
+ m_type(type)
+{
+ setAutoDelete(true);
+}
+
+bool ConditionChain::matches(const KFTPEngine::DirectoryEntry &entry) const
+{
+ if (isEmpty())
+ return false;
+
+ QPtrList<Condition>::ConstIterator le = end();
+ for (QPtrList<Condition>::ConstIterator i = begin(); i != le; ++i) {
+ bool match = (*i)->matches(entry);
+
+ if (match && m_type == Any)
+ return true;
+ else if (!match && m_type == All)
+ return false;
+ }
+
+ if (m_type == Any)
+ return false;
+
+ return true;
+}
+
+Action::Action()
+ : m_valid(false)
+{
+}
+
+Action::Action(Type type, const QVariant &value)
+ : m_valid(true),
+ m_type(type),
+ m_value(value)
+{
+}
+
+ActionChain::ActionChain()
+ : QPtrList<Action>()
+{
+ setAutoDelete(true);
+}
+
+const Action *ActionChain::getAction(Action::Type type) const
+{
+ ActionChain::ConstIterator le = end();
+ for (ActionChain::ConstIterator i = begin(); i != le; ++i)
+ if ((*i)->type() == type)
+ return (*i);
+
+ return 0;
+}
+
+Rule::Rule()
+ : m_name(QString::null),
+ m_enabled(false)
+{
+}
+
+Rule::Rule(const Rule *rule)
+ : m_name(rule->name()),
+ m_enabled(rule->isEnabled())
+{
+ // Copy conditions
+ const ConditionChain *conditionList = rule->conditions();
+ m_conditionChain.setType(conditionList->type());
+
+ ConditionChain::ConstIterator cle = conditionList->end();
+ for (ConditionChain::ConstIterator i = conditionList->begin(); i != cle; ++i) {
+ const Condition *c = (*i);
+
+ m_conditionChain.append(new Condition(c->field(), c->type(), c->value()));
+ }
+
+ // Copy actions
+ const ActionChain *actionList = rule->actions();
+
+ ActionChain::ConstIterator ale = actionList->end();
+ for (ActionChain::ConstIterator i = actionList->begin(); i != ale; ++i) {
+ const Action *a = (*i);
+
+ m_actionChain.append(new Action(a->type(), a->value()));
+ }
+}
+
+Rule::Rule(const QString &name)
+ : m_name(name),
+ m_enabled(true)
+{
+ // Add a simple condition and a simple action
+ m_conditionChain.append(new Condition(Filename, Condition::Contains, QVariant("")));
+ m_actionChain.append(new Action(Action::None, QVariant()));
+}
+
+Filters *Filters::m_self = 0;
+static KStaticDeleter<Filters> staticFiltersDeleter;
+
+Filters *Filters::self()
+{
+ if (!m_self) {
+ staticFiltersDeleter.setObject(m_self, new Filters());
+ }
+
+ return m_self;
+}
+
+Filters::Filters()
+ : QPtrList<Rule>(),
+ m_enabled(true)
+{
+ setAutoDelete(true);
+
+ // Generate human readable strings
+ m_fieldNames << i18n("Filename");
+ m_fieldNames << i18n("Entry Type");
+ m_fieldNames << i18n("Size");
+
+ m_actionNames << " ";
+ m_actionNames << i18n("Change priority");
+ m_actionNames << i18n("Skip when queuing");
+ m_actionNames << i18n("Colorize in list view");
+ m_actionNames << i18n("Hide from list view");
+ m_actionNames << i18n("Lowercase destination");
+
+ // Load the filters
+ load();
+}
+
+Filters::~Filters()
+{
+ if (m_self == this)
+ staticFiltersDeleter.setObject(m_self, 0, false);
+}
+
+void Filters::save()
+{
+ int num = 0;
+ KConfig *config = kapp->config();
+
+ config->setGroup("Filters");
+ config->writeEntry("count", count());
+
+ // Remove any existing sections
+ for (int i = 0; ; i++) {
+ QString groupName = QString("Filter #%1").arg(i);
+
+ if (config->hasGroup(groupName))
+ config->deleteGroup(groupName);
+ else
+ break;
+ }
+
+ Filters::ConstIterator le = end();
+ for (Filters::ConstIterator i = begin(); i != le; ++i, num++) {
+ const Rule *rule = (*i);
+
+ config->setGroup(QString("Filter #%1").arg(num));
+ config->writeEntry("name", rule->name());
+ config->writeEntry("enabled", rule->isEnabled());
+
+ // Write conditions
+ int cnum = 0;
+ const ConditionChain *conditions = rule->conditions();
+ config->writeEntry("conditions", conditions->count());
+ config->writeEntry("conditions-type", (int) conditions->type());
+
+ ConditionChain::ConstIterator cle = conditions->end();
+ for (ConditionChain::ConstIterator j = conditions->begin(); j != cle; ++j, cnum++) {
+ const Condition *c = (*j);
+ QString prefix = QString("condition%1-").arg(cnum);
+
+ config->writeEntry(prefix + "field", (int) c->field());
+ config->writeEntry(prefix + "type", (int) c->type());
+ config->writeEntry(prefix + "value", c->value());
+ config->writeEntry(prefix + "valueType", (int) c->value().type());
+ }
+
+ // Write actions
+ int anum = 0;
+ const ActionChain *actions = rule->actions();
+ config->writeEntry("actions", actions->count());
+
+ ActionChain::ConstIterator ale = actions->end();
+ for (ActionChain::ConstIterator j = actions->begin(); j != ale; ++j, anum++) {
+ const Action *a = (*j);
+ QString prefix = QString("action%1-").arg(anum);
+
+ config->writeEntry(prefix + "type", (int) a->type());
+ config->writeEntry(prefix + "value", a->value());
+ config->writeEntry(prefix + "valueType", (int) a->value().type());
+ }
+ }
+}
+
+void Filters::load()
+{
+ int num = 0;
+ KConfig *config = kapp->config();
+
+ config->setGroup("Filters");
+ num = config->readNumEntry("count");
+
+ for (int i = 0; i < num; i++) {
+ Rule *rule = new Rule();
+
+ config->setGroup(QString("Filter #%1").arg(i));
+ rule->setName(config->readEntry("name", i18n("Unnamed Rule")));
+ rule->setEnabled(config->readBoolEntry("enabled", true));
+
+ // Read conditions
+ ConditionChain *conditions = const_cast<ConditionChain*>(rule->conditions());
+ int cnum = config->readNumEntry("conditions");
+ conditions->setType((ConditionChain::Type) config->readNumEntry("conditions-type"));
+
+ for (int j = 0; j < cnum; j++) {
+ QString prefix = QString("condition%1-").arg(j);
+
+ conditions->append(new Condition((Field) config->readNumEntry(prefix + "field"),
+ (Condition::Type) config->readNumEntry(prefix + "type"),
+ config->readPropertyEntry(prefix + "value",
+ (QVariant::Type) config->readNumEntry(prefix + "valueType"))));
+ }
+
+ // Read actions
+ ActionChain *actions = const_cast<ActionChain*>(rule->actions());
+ int anum = config->readNumEntry("actions");
+
+ for (int j = 0; j < anum; j++) {
+ QString prefix = QString("action%1-").arg(j);
+
+ actions->append(new Action((Action::Type) config->readNumEntry(prefix + "type"),
+ config->readPropertyEntry(prefix + "value",
+ (QVariant::Type) config->readNumEntry(prefix + "valueType"))));
+ }
+
+ append(rule);
+ }
+}
+
+const ActionChain *Filters::process(const KFTPEngine::DirectoryEntry &entry) const
+{
+ if (m_enabled) {
+ QPtrList<Rule>::ConstIterator le = end();
+ for (QPtrList<Rule>::ConstIterator i = begin(); i != le; ++i) {
+ const Rule *rule = (*i);
+
+ if (rule->isEnabled() && rule->conditions()->matches(entry))
+ return rule->actions();
+ }
+ }
+
+ // Nothing has matched
+ return 0;
+}
+
+const Action *Filters::process(const KFTPEngine::DirectoryEntry &entry, QValueList<Action::Type> types) const
+{
+ const ActionChain *chain = process(entry);
+
+ if (!chain || chain->isEmpty())
+ return 0;
+
+ // Find an action that matches the filter
+ ActionChain::ConstIterator le = chain->end();
+ for (ActionChain::ConstIterator i = chain->begin(); i != le; ++i) {
+ if (types.contains((*i)->type()))
+ return (*i);
+ }
+
+ return 0;
+}
+
+const Action *Filters::process(const KFTPEngine::DirectoryEntry &entry, Action::Type filter) const
+{
+ const ActionChain *chain = process(entry);
+
+ if (!chain || chain->isEmpty())
+ return 0;
+
+ // Find an action that matches the filter
+ ActionChain::ConstIterator le = chain->end();
+ for (ActionChain::ConstIterator i = chain->begin(); i != le; ++i) {
+ if ((*i)->type() == filter)
+ return (*i);
+ }
+
+ return 0;
+}
+
+const Action *Filters::process(const KURL &url, filesize_t size, bool directory, Action::Type filter) const
+{
+ KFTPEngine::DirectoryEntry entry;
+ entry.setFilename(url.filename());
+ entry.setSize(size);
+ entry.setType(directory ? 'd' : 'f');
+
+ return process(entry, filter);
+}
+
+const ActionChain *Filters::process(const KURL &url, filesize_t size, bool directory) const
+{
+ KFTPEngine::DirectoryEntry entry;
+ entry.setFilename(url.filename());
+ entry.setSize(size);
+ entry.setType(directory ? 'd' : 'f');
+
+ return process(entry);
+}
+
+const Action *Filters::process(const KURL &url, Action::Type filter) const
+{
+ return process(url, 0, false, filter);
+}
+
+}
+
+}
diff --git a/kftpgrabber/src/misc/filter.h b/kftpgrabber/src/misc/filter.h
new file mode 100644
index 0000000..8c7ac36
--- /dev/null
+++ b/kftpgrabber/src/misc/filter.h
@@ -0,0 +1,506 @@
+/*
+ * This file is part of the KFTPGrabber project
+ *
+ * Copyright (C) 2003-2006 by the KFTPGrabber developers
+ * Copyright (C) 2003-2006 Jernej Kos <kostko@jweb-network.net>
+ *
+ * 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
+ * is provided AS IS, WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, and
+ * NON-INFRINGEMENT. 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 Steet, Fifth Floor, Boston,
+ * MA 02110-1301, USA.
+ *
+ * In addition, as a special exception, the copyright holders give
+ * permission to link the code of portions of this program with the
+ * OpenSSL library under certain conditions as described in each
+ * individual source file, and distribute linked combinations
+ * including the two.
+ *
+ * You must obey the GNU General Public License in all respects
+ * for all of the code used other than OpenSSL. If you modify
+ * file(s) with this exception, you may extend this exception to your
+ * version of the file(s), but you are not obligated to do so. If you
+ * do not wish to do so, delete this exception statement from your
+ * version. If you delete this exception statement from all source
+ * files in the program, then also delete it here.
+ */
+#ifndef KFTPCORE_FILTERFILTERS_H
+#define KFTPCORE_FILTERFILTERS_H
+
+#include <qvariant.h>
+#include <qvaluelist.h>
+
+#include "engine/directorylisting.h"
+
+namespace KFTPCore {
+
+namespace Filter {
+
+/**
+ * Possible filter fields.
+ */
+enum Field {
+ Filename = 0,
+ EntryType = 1,
+ Size = 2
+};
+
+/**
+ * A filter condition class of different types.
+ *
+ * @author Jernej Kos
+ */
+class Condition {
+public:
+ /**
+ * Condition type.
+ *
+ * The following types are valid:
+ * - None: this rule never validates
+ * - Contains: field contains a given substring
+ * - ContainsNot: field does not contain a given substring
+ * - Is: field is equal to the given value
+ * - IsNot: field is not equal to the given value
+ * - Matches: field matches a given regular expression
+ * - MatchesNot: field doesn't match a given regular expression
+ * - Greater: field's integer value is greater than the given value
+ * - Smaller: field's integer value is smaller than the given value
+ */
+ enum Type {
+ None = -1,
+ Contains = 0,
+ ContainsNot = 1,
+ Is = 2,
+ IsNot = 3,
+ Matches = 4,
+ MatchesNot = 5,
+ Greater = 6,
+ Smaller = 7
+ };
+
+ /**
+ * Class constructor. The constructed condition is invalid.
+ */
+ Condition() {}
+
+ /**
+ * Class constructor.
+ *
+ * @param field Field to check
+ * @param type Condition type
+ * @param value Value to check against
+ */
+ Condition(Field field, Type type, const QVariant &value);
+
+ /**
+ * Returns the field this condition operates on.
+ */
+ Field field() const { return m_field; }
+
+ /**
+ * Set condition field.
+ *
+ * @param field A valid condition field
+ */
+ void setField(Field field) { m_field = field; }
+
+ /**
+ * Returns the type of this condition.
+ */
+ Type type() const { return m_type; }
+
+ /**
+ * Set condition type.
+ *
+ * @param type A valid condition type
+ */
+ void setType(Type type) { m_type = type; }
+
+ /**
+ * Returns the value this condition validates the field with.
+ */
+ QVariant value() const { return m_value; }
+
+ /**
+ * Set condition validation value.
+ *
+ * @param value A valid validation value
+ */
+ void setValue(const QVariant &value) { m_value = value; }
+
+ /**
+ * Does the specified entry match this condition ?
+ *
+ * @param entry Directory entry to compare
+ * @return True if the entry matches this condition, false otherwise
+ */
+ bool matches(const KFTPEngine::DirectoryEntry &entry) const;
+private:
+ Field m_field;
+ Type m_type;
+ QVariant m_value;
+};
+
+/**
+ * This class represents a chain of filter conditions.
+ *
+ * @author Jernej Kos
+ */
+class ConditionChain : public QPtrList<Condition> {
+public:
+ /**
+ * Chain type.
+ *
+ * The following types are valid:
+ * - All: all conditions must match
+ * - Any: any condition can match
+ */
+ enum Type {
+ All = 0,
+ Any = 1
+ };
+
+ /**
+ * Class constructor.
+ */
+ ConditionChain();
+
+ /**
+ * Class constructor.
+ */
+ ConditionChain(Type type);
+
+ /**
+ * Returns condition chain match type.
+ */
+ Type type() const { return m_type; }
+
+ /**
+ * Set condition chain match type.
+ *
+ * @param type A valid type
+ */
+ void setType(Type type) { m_type = type; }
+
+ /**
+ * Does the specified entry match this condition chain ? The actual
+ * matching depends on chain type.
+ *
+ * @param entry Directory entry to compare
+ * @return True if the entry matches this chain, false otherwise
+ */
+ bool matches(const KFTPEngine::DirectoryEntry &entry) const;
+private:
+ Type m_type;
+};
+
+/**
+ * This class represents a single action to take.
+ */
+class Action {
+public:
+ /**
+ * Action type.
+ *
+ * These are the valid types:
+ * - Priority: when queuing files, their priority should be changed
+ * - Skip: do not queue such files
+ * - Colorize: change font color in the list view
+ * - Hide: do not display such files in the list view
+ * - Lowercase: lowercase the destination filename when queuing
+ */
+ enum Type {
+ None = 0,
+ Priority = 1,
+ Skip = 2,
+ Colorize = 3,
+ Hide = 4,
+ Lowercase = 5
+ };
+
+ /**
+ * Class constructor. The resulting action is invalid.
+ */
+ Action();
+
+ /**
+ * Class constructor.
+ *
+ * @param type Action type
+ * @param value Action parameters
+ */
+ Action(Type type, const QVariant &value);
+
+ /**
+ * Returns true if the action is valid.
+ */
+ bool isValid() const { return m_valid; }
+
+ /**
+ * Get action's type.
+ */
+ Type type() const { return m_type; }
+
+ /**
+ * Set the action type.
+ *
+ * @param type A valid action type
+ */
+ void setType(Type type) { m_type = type; }
+
+ /**
+ * Get action's parameters.
+ */
+ QVariant value() const { return m_value; }
+
+ /**
+ * Set action parameter.
+ *
+ * @param value Parameter value
+ */
+ void setValue(const QVariant &value) { m_value = value; }
+private:
+ bool m_valid;
+ Type m_type;
+ QVariant m_value;
+};
+
+/**
+ * This class represents a chain of filter actions.
+ *
+ * @author Jernej Kos
+ */
+class ActionChain : public QPtrList<Action> {
+public:
+ /**
+ * Class constructor.
+ */
+ ActionChain();
+
+ /**
+ * Get an action of the specified type.
+ *
+ * @param type Action type to search for
+ * @return A valid Action or null if there is none
+ */
+ const Action *getAction(Action::Type type) const;
+};
+
+/**
+ * This class represents a single filter rule consiting of a condition chain
+ * and an action chain.
+ *
+ * @author Jernej Kos
+ */
+class Rule {
+public:
+ /**
+ * Class constructor.
+ */
+ Rule();
+
+ /**
+ * Class copy constructor. Creates a duplicate deep copy of the provided
+ * rule.
+ *
+ * @param rule The rule to copy
+ */
+ Rule(const Rule *rule);
+
+ /**
+ * Class constructor.
+ *
+ * @param name Human readable rule name
+ */
+ Rule(const QString &name);
+
+ /**
+ * Get rule's name.
+ */
+ QString name() const { return m_name; }
+
+ /**
+ * Set rule's name.
+ */
+ void setName(const QString &name) { m_name = name; }
+
+ /**
+ * Is this rule enabled or not ?
+ *
+ * @return True if the rule is enabled, false otherwise
+ */
+ bool isEnabled() const { return m_enabled; }
+
+ /**
+ * Enable or disable this rule.
+ *
+ * @param value True if the rule is enabled, false otherwise
+ */
+ void setEnabled(bool value) { m_enabled = value; }
+
+ /**
+ * Get the condition chain reference.
+ */
+ const ConditionChain *conditions() const { return &m_conditionChain; }
+
+ /**
+ * Get the action chain reference.
+ */
+ const ActionChain *actions() const { return &m_actionChain; }
+private:
+ QString m_name;
+ bool m_enabled;
+ ConditionChain m_conditionChain;
+ ActionChain m_actionChain;
+};
+
+/**
+ * This class contains all the currently loaded rules.
+ *
+ * @author Jernej Kos
+ */
+class Filters : public QPtrList<Rule> {
+public:
+ /**
+ * Get the global rule chain.
+ */
+ static Filters *self();
+
+ /**
+ * Class destructor.
+ */
+ ~Filters();
+
+ /**
+ * Load the rules from a file.
+ */
+ void load();
+
+ /**
+ * Serialize the rules and save them to a file.
+ */
+ void save();
+
+ /**
+ * Is filtering enabled or not ?
+ *
+ * @return True if filtering is enabled, false otherwise
+ */
+ bool isEnabled() const { return m_enabled; }
+
+ /**
+ * Enable or disable filtering.
+ *
+ * @param value True if filtering is enabled, false otherwise
+ */
+ void setEnabled(bool value) { m_enabled = value; }
+
+ /**
+ * Process the specified entry and return an action chain that matched
+ * first.
+ *
+ * @param entry The entry to process
+ * @return An ActionChain reference (might be empty if nothing matched)
+ */
+ const ActionChain *process(const KFTPEngine::DirectoryEntry &entry) const;
+
+ /**
+ * Process the specified entry and return an action to use. This will
+ * go trough all loaded rules and attempt to process each one by one.
+ * The first one that succeeds is returned.
+ *
+ * @param entry The entry to process
+ * @param types Only return the action of this type
+ * @return An Action reference (might be invalid if nothing matched)
+ */
+ const Action *process(const KFTPEngine::DirectoryEntry &entry, QValueList<Action::Type> types) const;
+
+ /**
+ * Process the specified entry and return an action to use. This will
+ * go trough all loaded rules and attempt to process each one by one.
+ * The first one that succeeds is returned.
+ *
+ * @param entry The entry to process
+ * @param filter Only return the action of this type
+ * @return An Action reference (might be invalid if nothing matched)
+ */
+ const Action *process(const KFTPEngine::DirectoryEntry &entry, Action::Type filter) const;
+
+ /**
+ * This method is provided for convienience. It behaves just like the
+ * above method.
+ *
+ * @param url File's URL
+ * @param size File's size
+ * @param directory True if the entry is a directory
+ * @param filter Only return the action of this type
+ * @return An Action reference (might be invalid if nothing matched)
+ */
+ const Action *process(const KURL &url, filesize_t size, bool directory, Action::Type filter) const;
+
+ /**
+ * Process the specified entry and return an action chain that matched
+ * first.
+ *
+ * @param url File's URL
+ * @param size File's size
+ * @param directory True if the entry is a directory
+ * @return An ActionChain reference (might be invalid if nothing matched)
+ */
+ const ActionChain *process(const KURL &url, filesize_t size, bool directory) const;
+
+ /**
+ * This method is provided for convienience. It behaves just like the
+ * above method.
+ *
+ * Note that 0 will be used for filesize and this may affect the filter
+ * process!
+ *
+ * @param url File's URL
+ * @param filter Only return the action of this type
+ * @return An Action reference (might be invalid if nothing matched)
+ */
+ const Action *process(const KURL &url, Action::Type filter) const;
+
+ /**
+ * Get a human readable list of possible field names.
+ *
+ * @return A QStringList representing the field names
+ */
+ const QStringList &getFieldNames() { return m_fieldNames; }
+
+ /**
+ * Get a human readable list of possible action names
+ *
+ * @return A QStringList representing the action names
+ */
+ const QStringList &getActionNames() { return m_actionNames; }
+protected:
+ /**
+ * Class constructor.
+ */
+ Filters();
+private:
+ static Filters *m_self;
+
+ bool m_enabled;
+ ActionChain m_emptyActionChain;
+
+ QStringList m_fieldNames;
+ QStringList m_actionNames;
+};
+
+}
+
+}
+
+#endif
diff --git a/kftpgrabber/src/misc/filterwidgethandler.cpp b/kftpgrabber/src/misc/filterwidgethandler.cpp
new file mode 100644
index 0000000..6fa368d
--- /dev/null
+++ b/kftpgrabber/src/misc/filterwidgethandler.cpp
@@ -0,0 +1,539 @@
+/*
+ * This file is part of the KFTPGrabber project
+ *
+ * Copyright (C) 2003-2006 by the KFTPGrabber developers
+ * Copyright (C) 2003-2006 Jernej Kos <kostko@jweb-network.net>
+ *
+ * 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
+ * is provided AS IS, WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, and
+ * NON-INFRINGEMENT. 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 Steet, Fifth Floor, Boston,
+ * MA 02110-1301, USA.
+ *
+ * In addition, as a special exception, the copyright holders give
+ * permission to link the code of portions of this program with the
+ * OpenSSL library under certain conditions as described in each
+ * individual source file, and distribute linked combinations
+ * including the two.
+ *
+ * You must obey the GNU General Public License in all respects
+ * for all of the code used other than OpenSSL. If you modify
+ * file(s) with this exception, you may extend this exception to your
+ * version of the file(s), but you are not obligated to do so. If you
+ * do not wish to do so, delete this exception statement from your
+ * version. If you delete this exception statement from all source
+ * files in the program, then also delete it here.
+ */
+#include "filterwidgethandler.h"
+
+#include <qcombobox.h>
+#include <qlabel.h>
+
+#include <klocale.h>
+#include <kstaticdeleter.h>
+#include <klineedit.h>
+#include <knuminput.h>
+#include <kcolorbutton.h>
+
+namespace KFTPCore {
+
+namespace Filter {
+
+namespace {
+
+static const struct {
+ const Condition::Type type;
+ const char *name;
+} TextTypes[] = {
+ { Condition::Contains, I18N_NOOP("contains") },
+ { Condition::ContainsNot, I18N_NOOP("does not contain") },
+ { Condition::Is, I18N_NOOP("equals") },
+ { Condition::IsNot, I18N_NOOP("does not equal") },
+ { Condition::Matches, I18N_NOOP("matches regexp") },
+ { Condition::MatchesNot, I18N_NOOP("does not match regexp") }
+};
+
+static const int TextTypeCount = sizeof(TextTypes) / sizeof(*TextTypes);
+
+class TextWidgetHandler : public ConditionWidgetHandler
+{
+public:
+ TextWidgetHandler()
+ : ConditionWidgetHandler()
+ {
+ }
+
+ QWidget *createTypeWidget(QWidget *parent, const QObject *receiver) const
+ {
+ QComboBox *combo = new QComboBox(parent);
+
+ for (int i = 0; i < TextTypeCount; i++) {
+ combo->insertItem(i18n(TextTypes[i].name));
+ }
+
+ combo->adjustSize();
+
+ // Connect the signal
+ QObject::connect(combo, SIGNAL(activated(int)), receiver, SLOT(slotTypeChanged()));
+
+ return combo;
+ }
+
+ Condition::Type getConditionType(QWidget *widget) const
+ {
+ QComboBox *combo = static_cast<QComboBox*>(widget);
+ return TextTypes[combo->currentItem()].type;
+ }
+
+ void createValueWidgets(QWidgetStack *stack, const QObject *receiver) const
+ {
+ KLineEdit *lineEdit = new KLineEdit(stack, "textWidgetHandler_LineEdit");
+ QObject::connect(lineEdit, SIGNAL(textChanged(const QString&)), receiver, SLOT(slotValueChanged()));
+ stack->addWidget(lineEdit);
+ }
+
+ QVariant getConditionValue(QWidgetStack *values) const
+ {
+ KLineEdit *lineEdit = static_cast<KLineEdit*>(values->child("textWidgetHandler_LineEdit"));
+ return QVariant(lineEdit->text());
+ }
+
+ void update(int field, QWidgetStack *types, QWidgetStack *values) const
+ {
+ types->raiseWidget(field);
+ values->raiseWidget((QWidget*) values->child("textWidgetHandler_LineEdit"));
+ }
+
+ void setCondition(QWidgetStack *types, QWidgetStack *values, const Condition *condition)
+ {
+ // Set condition type
+ const Condition::Type type = condition->type();
+ int typeIndex = 0;
+
+ for (; typeIndex < TextTypeCount; typeIndex++)
+ if (type == TextTypes[typeIndex].type)
+ break;
+
+ QComboBox *combo = static_cast<QComboBox*>(types->widget(((int) condition->field())));
+ combo->blockSignals(true);
+ combo->setCurrentItem(typeIndex);
+ combo->blockSignals(false);
+ types->raiseWidget(combo);
+
+ // Set condition value
+ KLineEdit *lineEdit = static_cast<KLineEdit*>(values->child("textWidgetHandler_LineEdit"));
+ lineEdit->blockSignals(true);
+ lineEdit->setText(condition->value().toString());
+ lineEdit->blockSignals(false);
+ values->raiseWidget(lineEdit);
+ }
+};
+
+}
+
+namespace {
+
+static const struct {
+ const Condition::Type type;
+ const char *name;
+} EntryTypes[] = {
+ { Condition::Is, I18N_NOOP("is") },
+ { Condition::IsNot, I18N_NOOP("is not") }
+};
+
+static const int EntryTypeCount = sizeof(EntryTypes) / sizeof(*EntryTypes);
+
+class EntryWidgetHandler : public ConditionWidgetHandler
+{
+public:
+ EntryWidgetHandler()
+ : ConditionWidgetHandler()
+ {
+ }
+
+ QWidget *createTypeWidget(QWidget *parent, const QObject *receiver) const
+ {
+ QComboBox *combo = new QComboBox(parent);
+
+ for (int i = 0; i < EntryTypeCount; i++) {
+ combo->insertItem(i18n(EntryTypes[i].name));
+ }
+
+ combo->adjustSize();
+
+ // Connect the signal
+ QObject::connect(combo, SIGNAL(activated(int)), receiver, SLOT(slotTypeChanged()));
+
+ return combo;
+ }
+
+ Condition::Type getConditionType(QWidget *widget) const
+ {
+ QComboBox *combo = static_cast<QComboBox*>(widget);
+ return EntryTypes[combo->currentItem()].type;
+ }
+
+ void createValueWidgets(QWidgetStack *stack, const QObject *receiver) const
+ {
+ QComboBox *combo = new QComboBox(stack, "entryWidgetHandler_Combo");
+ combo->insertItem(i18n("File"), 0);
+ combo->insertItem(i18n("Directory"), 1);
+
+ QObject::connect(combo, SIGNAL(activated(int)), receiver, SLOT(slotValueChanged()));
+ stack->addWidget(combo);
+ }
+
+ QVariant getConditionValue(QWidgetStack *values) const
+ {
+ QComboBox *combo = static_cast<QComboBox*>(values->child("entryWidgetHandler_Combo"));
+ QVariant value;
+
+ if (combo->currentItem() == 0)
+ value = QVariant(QString("f"));
+ else
+ value = QVariant(QString("d"));
+
+ return value;
+ }
+
+ void update(int field, QWidgetStack *types, QWidgetStack *values) const
+ {
+ types->raiseWidget(field);
+ values->raiseWidget((QWidget*) values->child("entryWidgetHandler_Combo"));
+ }
+
+ void setCondition(QWidgetStack *types, QWidgetStack *values, const Condition *condition)
+ {
+ // Set condition type
+ const Condition::Type type = condition->type();
+ int typeIndex = 0;
+
+ for (; typeIndex < EntryTypeCount; typeIndex++)
+ if (type == EntryTypes[typeIndex].type)
+ break;
+
+ QComboBox *combo = static_cast<QComboBox*>(types->widget(((int) condition->field())));
+ combo->blockSignals(true);
+ combo->setCurrentItem(typeIndex);
+ combo->blockSignals(false);
+ types->raiseWidget(combo);
+
+ // Set condition value
+ combo = static_cast<QComboBox*>(values->child("entryWidgetHandler_Combo"));
+ combo->blockSignals(true);
+ combo->setCurrentItem(condition->value().toString() == "f" ? 0 : 1);
+ combo->blockSignals(false);
+ values->raiseWidget(combo);
+ }
+};
+
+}
+
+namespace {
+
+static const struct {
+ const Condition::Type type;
+ const char *name;
+} SizeTypes[] = {
+ { Condition::Is, I18N_NOOP("equals") },
+ { Condition::IsNot, I18N_NOOP("does not equal") },
+ { Condition::Greater, I18N_NOOP("is greater than") },
+ { Condition::Smaller, I18N_NOOP("is smaller than") }
+};
+
+static const int SizeTypeCount = sizeof(SizeTypes) / sizeof(*SizeTypes);
+
+class SizeWidgetHandler : public ConditionWidgetHandler
+{
+public:
+ SizeWidgetHandler()
+ : ConditionWidgetHandler()
+ {
+ }
+
+ QWidget *createTypeWidget(QWidget *parent, const QObject *receiver) const
+ {
+ QComboBox *combo = new QComboBox(parent);
+
+ for (int i = 0; i < SizeTypeCount; i++) {
+ combo->insertItem(i18n(SizeTypes[i].name));
+ }
+
+ combo->adjustSize();
+
+ // Connect the signal
+ QObject::connect(combo, SIGNAL(activated(int)), receiver, SLOT(slotTypeChanged()));
+
+ return combo;
+ }
+
+ Condition::Type getConditionType(QWidget *widget) const
+ {
+ QComboBox *combo = static_cast<QComboBox*>(widget);
+ return SizeTypes[combo->currentItem()].type;
+ }
+
+ void createValueWidgets(QWidgetStack *stack, const QObject *receiver) const
+ {
+ KIntNumInput *numInput = new KIntNumInput(stack, "sizeWidgetHandler_NumInput");
+ numInput->setMinValue(0);
+ numInput->setSuffix(" " + i18n("bytes"));
+
+ QObject::connect(numInput, SIGNAL(valueChanged(int)), receiver, SLOT(slotValueChanged()));
+ stack->addWidget(numInput);
+ }
+
+ QVariant getConditionValue(QWidgetStack *values) const
+ {
+ KIntNumInput *numInput = static_cast<KIntNumInput*>(values->child("sizeWidgetHandler_NumInput"));
+ return QVariant(numInput->value());
+ }
+
+ void update(int field, QWidgetStack *types, QWidgetStack *values) const
+ {
+ types->raiseWidget(field);
+ values->raiseWidget((QWidget*) values->child("sizeWidgetHandler_NumInput"));
+ }
+
+ void setCondition(QWidgetStack *types, QWidgetStack *values, const Condition *condition)
+ {
+ // Set condition type
+ const Condition::Type type = condition->type();
+ int typeIndex = 0;
+
+ for (; typeIndex < SizeTypeCount; typeIndex++)
+ if (type == SizeTypes[typeIndex].type)
+ break;
+
+ QComboBox *combo = static_cast<QComboBox*>(types->widget(((int) condition->field())));
+ combo->blockSignals(true);
+ combo->setCurrentItem(typeIndex);
+ combo->blockSignals(false);
+ types->raiseWidget(combo);
+
+ // Set condition value
+ KIntNumInput *numInput = static_cast<KIntNumInput*>(values->child("sizeWidgetHandler_NumInput"));
+ numInput->blockSignals(true);
+ numInput->setValue(condition->value().toInt());
+ numInput->blockSignals(false);
+ values->raiseWidget(numInput);
+ }
+};
+
+}
+
+class EmptyActionWidgetHandler : public ActionWidgetHandler
+{
+public:
+ EmptyActionWidgetHandler()
+ : ActionWidgetHandler()
+ {
+ }
+
+ virtual QWidget *createWidget(QWidget *parent, const QObject *receiver) const
+ {
+ Q_UNUSED(receiver);
+
+ return new QWidget(parent);
+ }
+
+ QVariant getActionValue(QWidget *widget) const
+ {
+ Q_UNUSED(widget);
+
+ return QVariant(QString());
+ }
+
+ void setAction(QWidgetStack *stack, const Action *action) const
+ {
+ stack->raiseWidget((int) action->type());
+ }
+};
+
+class NoneActionWidgetHandler : public EmptyActionWidgetHandler
+{
+public:
+ NoneActionWidgetHandler()
+ : EmptyActionWidgetHandler()
+ {
+ }
+
+ QWidget *createWidget(QWidget *parent, const QObject *receiver) const
+ {
+ Q_UNUSED(receiver);
+
+ return new QLabel(i18n("Please select an action."), parent);
+ }
+};
+
+class PriorityActionWidgetHandler : public ActionWidgetHandler
+{
+public:
+ PriorityActionWidgetHandler()
+ : ActionWidgetHandler()
+ {
+ }
+
+ QWidget *createWidget(QWidget *parent, const QObject *receiver) const
+ {
+ KIntNumInput *numInput = new KIntNumInput(parent);
+ numInput->setPrefix(i18n("Priority:") + " ");
+
+ QObject::connect(numInput, SIGNAL(valueChanged(int)), receiver, SLOT(slotValueChanged()));
+ return numInput;
+ }
+
+ QVariant getActionValue(QWidget *widget) const
+ {
+ KIntNumInput *numInput = static_cast<KIntNumInput*>(widget);
+ return QVariant(numInput->value());
+ }
+
+ void setAction(QWidgetStack *stack, const Action *action) const
+ {
+ stack->raiseWidget((int) action->type());
+ KIntNumInput *numInput = static_cast<KIntNumInput*>(stack->visibleWidget());
+ numInput->setValue(action->value().toInt());
+ }
+};
+
+class ColorizeActionWidgetHandler : public ActionWidgetHandler
+{
+public:
+ ColorizeActionWidgetHandler()
+ : ActionWidgetHandler()
+ {
+ }
+
+ QWidget *createWidget(QWidget *parent, const QObject *receiver) const
+ {
+ KColorButton *colorButton = new KColorButton(parent);
+
+ QObject::connect(colorButton, SIGNAL(changed(const QColor&)), receiver, SLOT(slotValueChanged()));
+ return colorButton;
+ }
+
+ QVariant getActionValue(QWidget *widget) const
+ {
+ KColorButton *colorButton = static_cast<KColorButton*>(widget);
+ return QVariant(colorButton->color());
+ }
+
+ void setAction(QWidgetStack *stack, const Action *action) const
+ {
+ stack->raiseWidget((int) action->type());
+ KColorButton *colorButton = static_cast<KColorButton*>(stack->visibleWidget());
+ colorButton->setColor(action->value().toColor());
+ }
+};
+
+WidgetHandlerManager *WidgetHandlerManager::m_self = 0;
+static KStaticDeleter<WidgetHandlerManager> staticHandlerManagerDeleter;
+
+WidgetHandlerManager *WidgetHandlerManager::self()
+{
+ if (!m_self) {
+ staticHandlerManagerDeleter.setObject(m_self, new WidgetHandlerManager());
+ }
+
+ return m_self;
+}
+
+WidgetHandlerManager::WidgetHandlerManager()
+{
+ // Register condition handlers
+ registerConditionHandler(Filename, new TextWidgetHandler());
+ registerConditionHandler(EntryType, new EntryWidgetHandler());
+ registerConditionHandler(Size, new SizeWidgetHandler());
+
+ // Register action handlers
+ registerActionHandler(Action::None, new NoneActionWidgetHandler());
+ registerActionHandler(Action::Priority, new PriorityActionWidgetHandler());
+ registerActionHandler(Action::Skip, new EmptyActionWidgetHandler());
+ registerActionHandler(Action::Colorize, new ColorizeActionWidgetHandler());
+ registerActionHandler(Action::Hide, new EmptyActionWidgetHandler());
+ registerActionHandler(Action::Lowercase, new EmptyActionWidgetHandler());
+}
+
+WidgetHandlerManager::~WidgetHandlerManager()
+{
+ if (m_self == this)
+ staticHandlerManagerDeleter.setObject(m_self, 0, false);
+}
+
+void WidgetHandlerManager::registerConditionHandler(Field field, ConditionWidgetHandler *handler)
+{
+ m_conditionHandlers[field] = handler;
+}
+
+void WidgetHandlerManager::registerActionHandler(Action::Type type, ActionWidgetHandler *handler)
+{
+ m_actionHandlers[type] = handler;
+}
+
+void WidgetHandlerManager::createConditionWidgets(QWidgetStack *types, QWidgetStack *values, const QObject *receiver)
+{
+ ConditionHandlerMap::ConstIterator le = m_conditionHandlers.end();
+ for (ConditionHandlerMap::ConstIterator i = m_conditionHandlers.begin(); i != le; ++i) {
+ Field field = i.key();
+ const ConditionWidgetHandler *handler = i.data();
+
+ types->addWidget(handler->createTypeWidget(types, receiver), (int) field);
+ handler->createValueWidgets(values, receiver);
+ }
+}
+
+void WidgetHandlerManager::createActionWidgets(QWidgetStack *stack, const QObject *receiver)
+{
+ ActionHandlerMap::ConstIterator le = m_actionHandlers.end();
+ for (ActionHandlerMap::ConstIterator i = m_actionHandlers.begin(); i != le; ++i) {
+ Action::Type type = i.key();
+ const ActionWidgetHandler *handler = i.data();
+
+ stack->addWidget(handler->createWidget(stack, receiver), (int) type);
+ }
+}
+
+void WidgetHandlerManager::update(Field field, QWidgetStack *types, QWidgetStack *values)
+{
+ m_conditionHandlers[field]->update((int) field, types, values);
+}
+
+void WidgetHandlerManager::setCondition(QWidgetStack *types, QWidgetStack *values, const Condition *condition)
+{
+ m_conditionHandlers[condition->field()]->setCondition(types, values, condition);
+}
+
+Condition::Type WidgetHandlerManager::getConditionType(Field field, QWidgetStack *types)
+{
+ return m_conditionHandlers[field]->getConditionType(types->widget((int) field));
+}
+
+QVariant WidgetHandlerManager::getConditionValue(Field field, QWidgetStack *values)
+{
+ return m_conditionHandlers[field]->getConditionValue(values);
+}
+
+void WidgetHandlerManager::setAction(QWidgetStack *stack, const Action *action)
+{
+ m_actionHandlers[action->type()]->setAction(stack, action);
+}
+
+QVariant WidgetHandlerManager::getActionValue(QWidgetStack *stack)
+{
+ QWidget *widget = stack->visibleWidget();
+ return m_actionHandlers[(Action::Type) stack->id(widget)]->getActionValue(widget);
+}
+
+}
+
+}
diff --git a/kftpgrabber/src/misc/filterwidgethandler.h b/kftpgrabber/src/misc/filterwidgethandler.h
new file mode 100644
index 0000000..5ea6376
--- /dev/null
+++ b/kftpgrabber/src/misc/filterwidgethandler.h
@@ -0,0 +1,279 @@
+/*
+ * This file is part of the KFTPGrabber project
+ *
+ * Copyright (C) 2003-2006 by the KFTPGrabber developers
+ * Copyright (C) 2003-2006 Jernej Kos <kostko@jweb-network.net>
+ *
+ * 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
+ * is provided AS IS, WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, and
+ * NON-INFRINGEMENT. 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 Steet, Fifth Floor, Boston,
+ * MA 02110-1301, USA.
+ *
+ * In addition, as a special exception, the copyright holders give
+ * permission to link the code of portions of this program with the
+ * OpenSSL library under certain conditions as described in each
+ * individual source file, and distribute linked combinations
+ * including the two.
+ *
+ * You must obey the GNU General Public License in all respects
+ * for all of the code used other than OpenSSL. If you modify
+ * file(s) with this exception, you may extend this exception to your
+ * version of the file(s), but you are not obligated to do so. If you
+ * do not wish to do so, delete this exception statement from your
+ * version. If you delete this exception statement from all source
+ * files in the program, then also delete it here.
+ */
+#ifndef KFTPCORE_FILTERFILTERWIDGETHANDLER_H
+#define KFTPCORE_FILTERFILTERWIDGETHANDLER_H
+
+#include "filter.h"
+
+#include <qmap.h>
+#include <qwidget.h>
+#include <qwidgetstack.h>
+
+namespace KFTPCore {
+
+namespace Filter {
+
+/**
+ * This is an interface that any condition widget handlers must implement
+ * in order to be registred with the manager. The handler handles several
+ * widgets at once so it should not keep any member variables.
+ *
+ * @author Jernej Kos
+ */
+class ConditionWidgetHandler {
+public:
+ /**
+ * This method has to return a new widget used for displaying condition
+ * types. It is usually a combobox with several options. The returned
+ * widget is added to the value widget stack.
+ *
+ * @param parent Widget to be used as parent for the newly created widget
+ * @param receiver Object that receives type change notifications
+ * @return A valid QWidget instance
+ */
+ virtual QWidget *createTypeWidget(QWidget *parent, const QObject *receiver) const = 0;
+
+ /**
+ * This method has to create one or several input widgets for different
+ * condition types. Each widget has to be added to the widget stack. An
+ * identifying widget name is recommended for each widget, so you can easily
+ * access it from other methods which get the value stack widget passed as
+ * an argument.
+ *
+ * @param stack Value widget stack
+ * @param receiver Object that receives value change notifications
+ */
+ virtual void createValueWidgets(QWidgetStack *stack, const QObject *receiver) const = 0;
+
+ /**
+ * Update the status of all widgets.
+ *
+ * @param field The field to display
+ * @param types Type widget stack to use
+ * @param values Value widget stack to use
+ */
+ virtual void update(int field, QWidgetStack *types, QWidgetStack *values) const = 0;
+
+ /**
+ * Extract data from internal condition representation and show it to the
+ * user using the created widgets.
+ *
+ * @param types Type widget stack to use
+ * @param values Value widget stack to use
+ * @param condition The condition representation
+ */
+ virtual void setCondition(QWidgetStack *types, QWidgetStack *values, const Condition *condition) = 0;
+
+ /**
+ * This method should return the currently selected condition type.
+ *
+ * @param widget The type widget previously created
+ * @return A valid Condition::Type
+ */
+ virtual Condition::Type getConditionType(QWidget *widget) const = 0;
+
+ /**
+ * This method should return the current condition value.
+ *
+ * @param values Value widget stack to use
+ * @return A valid condition value
+ */
+ virtual QVariant getConditionValue(QWidgetStack *values) const = 0;
+};
+
+/**
+ * This is an interface that any action widget handlers must implement
+ * in order to be registred with the manager. The handler handles several
+ * widgets at once so it should not keep any member variables.
+ *
+ * @author Jernej Kos
+ */
+class ActionWidgetHandler {
+public:
+ /**
+ * This method has to return a new widget used for displaying the action
+ * value. It is usually a line edit or a similar input widget. The returned
+ * widget is added to the value widget stack.
+ *
+ * @param parent Widget to be used as parent for the newly created widget
+ * @param receiver Object that receives type change notifications
+ * @return A valid QWidget instance
+ */
+ virtual QWidget *createWidget(QWidget *parent, const QObject *receiver) const = 0;
+
+ /**
+ * Extract data from internal action representation and show it to the
+ * user using the created widgets.
+ *
+ * @param stack Value widget stack to use
+ * @param action The action representation
+ */
+ virtual void setAction(QWidgetStack *stack, const Action *action) const = 0;
+
+ /**
+ * This method should return the current action value.
+ *
+ * @param values Value widget stack to use
+ * @return A valid action value
+ */
+ virtual QVariant getActionValue(QWidget *widget) const = 0;
+};
+
+/**
+ * This class keeps a list of all registred condition and action widget
+ * handlers. It is a singleton.
+ *
+ * @author Jernej Kos
+ */
+class WidgetHandlerManager
+{
+public:
+ /**
+ * Get the global class instance.
+ */
+ static WidgetHandlerManager *self();
+
+ /**
+ * Class destructor.
+ */
+ ~WidgetHandlerManager();
+
+ /**
+ * Create widgets for all currently registred condition handlers.
+ *
+ * @param types Type widget stack to use
+ * @param value Value widget stack to use
+ * @param receiver Object that receives change notifications
+ */
+ void createConditionWidgets(QWidgetStack *types, QWidgetStack *values, const QObject *receiver);
+
+ /**
+ * Create widgets for all currently registred action handlers.
+ *
+ * @param stack Value widget stack to use
+ * @param receiver Object that receives change notifications
+ */
+ void createActionWidgets(QWidgetStack *stack, const QObject *receiver);
+
+ /**
+ * Update the specified condition widget handler.
+ *
+ * @param field New condition field
+ * @param types Type widget stack to use
+ * @param values Value widget stack to use
+ */
+ void update(Field field, QWidgetStack *types, QWidgetStack *values);
+
+ /**
+ * Extract data from internal condition representation and show it to the
+ * user using the created widgets.
+ *
+ * @param types Type widget stack to use
+ * @param values Value widget stack to use
+ * @param condition The condition representation
+ */
+ void setCondition(QWidgetStack *types, QWidgetStack *values, const Condition *condition);
+
+ /**
+ * Get the currently selected condition type.
+ *
+ * @param field Condition field
+ * @param types Type widget stack to use
+ * @return A valid Condition::Type
+ */
+ Condition::Type getConditionType(Field field, QWidgetStack *types);
+
+ /**
+ * Get the current condition value.
+ *
+ * @param field Condition field
+ * @param values Value widget stack to use
+ * @return A valid condition value
+ */
+ QVariant getConditionValue(Field field, QWidgetStack *values);
+
+ /**
+ * Extract data from internal action representation and show it to the
+ * user using the created widgets.
+ *
+ * @param stack Value widget stack to use
+ * @param action The action representation
+ */
+ void setAction(QWidgetStack *stack, const Action *action);
+
+ /**
+ * Get the current action value.
+ *
+ * @param stack Value widget stack to use
+ * @return A valid action value
+ */
+ QVariant getActionValue(QWidgetStack *stack);
+
+ /**
+ * Register a new condition handler with the manager.
+ *
+ * @param field Field that this handler handles
+ * @param handler The actual handler instance
+ */
+ void registerConditionHandler(Field field, ConditionWidgetHandler *handler);
+
+ /**
+ * Register a new action handler with the manager.
+ *
+ * @param type Action type that this handler handles
+ * @param handler The actual handler instance
+ */
+ void registerActionHandler(Action::Type type, ActionWidgetHandler *handler);
+protected:
+ /**
+ * Class constructor.
+ */
+ WidgetHandlerManager();
+private:
+ static WidgetHandlerManager *m_self;
+
+ typedef QMap<Field, ConditionWidgetHandler*> ConditionHandlerMap;
+ ConditionHandlerMap m_conditionHandlers;
+
+ typedef QMap<Action::Type, ActionWidgetHandler*> ActionHandlerMap;
+ ActionHandlerMap m_actionHandlers;
+};
+
+}
+
+}
+
+#endif
diff --git a/kftpgrabber/src/misc/interfaces/Makefile.am b/kftpgrabber/src/misc/interfaces/Makefile.am
new file mode 100644
index 0000000..8d88141
--- /dev/null
+++ b/kftpgrabber/src/misc/interfaces/Makefile.am
@@ -0,0 +1,15 @@
+INCLUDES = -I$(top_srcdir)/kftpgrabber/src/ftp \
+ -I$(top_srcdir)/kftpgrabber/src/qsa \
+ $(all_includes)
+
+METASOURCES = AUTO
+
+lib_LTLIBRARIES = libkftpinterfaces.la
+libkftpinterfaces_la_SOURCES = kftpbookmarkimportplugin.cpp
+libkftpinterfaces_la_LDFLAGS = $(all_libraries) -version-info 0:0:0 -no-undefined
+libkftpinterfaces_la_LIBADD = $(LIB_QT) $(LIB_KDECORE) $(LIB_KDEUI) $(LIB_KPARTS)
+
+kftpgrabberincludedir = $(includedir)/kftpgrabber
+kftpgrabberinclude_HEADERS = kftpbookmarkimportplugin.h
+
+kde_servicetypes_DATA = kftpbookmarkimportplugin.desktop
diff --git a/kftpgrabber/src/misc/interfaces/kftpbookmarkimportplugin.cpp b/kftpgrabber/src/misc/interfaces/kftpbookmarkimportplugin.cpp
new file mode 100644
index 0000000..49a7322
--- /dev/null
+++ b/kftpgrabber/src/misc/interfaces/kftpbookmarkimportplugin.cpp
@@ -0,0 +1,55 @@
+/*
+ * This file is part of the KFTPGrabber project
+ *
+ * Copyright (C) 2004 by the KFTPGrabber developers
+ * Copyright (C) 2004 Jernej Kos <kostko@jweb-network.net>
+ *
+ * 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
+ * is provided AS IS, WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, and
+ * NON-INFRINGEMENT. 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 Steet, Fifth Floor, Boston,
+ * MA 02110-1301, USA.
+ *
+ * In addition, as a special exception, the copyright holders give
+ * permission to link the code of portions of this program with the
+ * OpenSSL library under certain conditions as described in each
+ * individual source file, and distribute linked combinations
+ * including the two.
+ * You must obey the GNU General Public License in all respects
+ * for all of the code used other than OpenSSL. If you modify
+ * file(s) with this exception, you may extend this exception to your
+ * version of the file(s), but you are not obligated to do so. If you
+ * do not wish to do so, delete this exception statement from your
+ * version. If you delete this exception statement from all source
+ * files in the program, then also delete it here.
+ */
+
+#include "kftpbookmarkimportplugin.h"
+
+#include <qdir.h>
+
+KFTPBookmarkImportPlugin::KFTPBookmarkImportPlugin(QObject *parent, const char *name)
+ : KParts::Plugin(parent, name)
+{
+}
+
+
+KFTPBookmarkImportPlugin::~KFTPBookmarkImportPlugin()
+{
+}
+
+QString KFTPBookmarkImportPlugin::userPath(const QString &path)
+{
+ return QDir::homeDirPath() + "/" + path;
+}
+
+#include "kftpbookmarkimportplugin.moc"
diff --git a/kftpgrabber/src/misc/interfaces/kftpbookmarkimportplugin.desktop b/kftpgrabber/src/misc/interfaces/kftpbookmarkimportplugin.desktop
new file mode 100644
index 0000000..48d124e
--- /dev/null
+++ b/kftpgrabber/src/misc/interfaces/kftpbookmarkimportplugin.desktop
@@ -0,0 +1,29 @@
+[Desktop Entry]
+Type=ServiceType
+X-KDE-ServiceType=KFTPGrabber/BookmarkImportPlugin
+Comment=A KFTPGrabber plugin for importing bookmarks
+Comment[ar]=قابس KFTPGrabber لإستيراد علامات المواقع
+Comment[bg]=Приставка за импортиране на отметки в KFTPGrabber
+Comment[cs]=Modul KFTPGrabbera pro import záložek
+Comment[da]=Et KFTPGrabber plugin til at importere bogmærker
+Comment[de]=KFTPGrabber-Modul zum Lesezeichenimport
+Comment[el]=Ένα πρόσθετο του KFTPGrabber για την εισαγωγή σελιδοδεικτών
+Comment[es]=Un complemento de KFTPGrabber para importar marcadores
+Comment[et]=KFTPGrabberi järjehoidjate importimise plugin
+Comment[fr]=Un module KFTPGrabber pour l'importation de signets
+Comment[ga]=Breiseán KFTPGrabber le haghaidh iompórtála leabharmharcanna
+Comment[gl]=Un plugin de KFTPGrabber para importar marcadores
+Comment[it]=Un plugin per KFTPGrabber per importare i segnalibri
+Comment[ja]=KFTPGrabber ブックマークをインポートするプラグイン
+Comment[ka]=სანიშნეების იმპორტის მოდული KFTPGrabber-თვის
+Comment[lt]=KFTPGrabber įskiepis žymelių importavimui
+Comment[nl]=een KFTPGrabber-plugin voor het importeren van bladwijzers
+Comment[pt]=Um 'plugin' do KFTPGrabber para importar listas de favoritos
+Comment[pt_BR]=Um plug-in do KFTPGrabber para a importar favoritos
+Comment[sr]=Прикључак KFTPGrabber-а за увоз маркера
+Comment[sr@Latn]=Priključak KFTPGrabber-a za uvoz markera
+Comment[sv]=Ett insticksprogram för bokmärkesimport till KFTPgrabber
+Comment[tr]=Yer imlerini almak için KFTPGrabber eklentisi
+Comment[uk]=Втулок KFTPGrabber для імпортування закладок
+Comment[xx]=xxA KFTPGrabber plugin for importing bookmarksxx
+Comment[zh_CN]=导入书签的 KFTPGrabber 插件
diff --git a/kftpgrabber/src/misc/interfaces/kftpbookmarkimportplugin.h b/kftpgrabber/src/misc/interfaces/kftpbookmarkimportplugin.h
new file mode 100644
index 0000000..e82a718
--- /dev/null
+++ b/kftpgrabber/src/misc/interfaces/kftpbookmarkimportplugin.h
@@ -0,0 +1,83 @@
+/*
+ * This file is part of the KFTPGrabber project
+ *
+ * Copyright (C) 2004 by the KFTPGrabber developers
+ * Copyright (C) 2004 Jernej Kos <kostko@jweb-network.net>
+ *
+ * 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
+ * is provided AS IS, WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, and
+ * NON-INFRINGEMENT. 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 Steet, Fifth Floor, Boston,
+ * MA 02110-1301, USA.
+ *
+ * In addition, as a special exception, the copyright holders give
+ * permission to link the code of portions of this program with the
+ * OpenSSL library under certain conditions as described in each
+ * individual source file, and distribute linked combinations
+ * including the two.
+ * You must obey the GNU General Public License in all respects
+ * for all of the code used other than OpenSSL. If you modify
+ * file(s) with this exception, you may extend this exception to your
+ * version of the file(s), but you are not obligated to do so. If you
+ * do not wish to do so, delete this exception statement from your
+ * version. If you delete this exception statement from all source
+ * files in the program, then also delete it here.
+ */
+
+#ifndef KFTPBOOKMARKIMPORTPLUGIN_H
+#define KFTPBOOKMARKIMPORTPLUGIN_H
+
+#include <kparts/plugin.h>
+
+/**
+ * This class is the base class for all bookmark import plugins.
+ *
+ * @author Jernej Kos
+ */
+class KFTPBookmarkImportPlugin : public KParts::Plugin {
+Q_OBJECT
+public:
+ KFTPBookmarkImportPlugin(QObject *parent, const char *name = 0);
+ virtual ~KFTPBookmarkImportPlugin();
+
+ /**
+ * This method should return the properly formated XML for KFTPGrabber
+ * bookmarks that is generated from the import.
+ *
+ * @return The @ref QDomDocument representation of XML
+ */
+ virtual QDomDocument getImportedXml() = 0;
+
+ /**
+ * This method should start the import procedure.
+ *
+ * @param fileName is the path to the file that will be imported
+ */
+ virtual void import(const QString &fileName) = 0;
+
+ /**
+ * This method should return the default path where the bookmarks could
+ * be located. The path must be relative to the user's home directory.
+ *
+ * @return The default path where bookmarks are located
+ */
+ virtual QString getDefaultPath() = 0;
+protected:
+ QString userPath(const QString &path);
+signals:
+ /**
+ * Progress of bookmark importing (in percent).
+ */
+ void progress(int percent);
+};
+
+#endif
diff --git a/kftpgrabber/src/misc/kftpapi.cpp b/kftpgrabber/src/misc/kftpapi.cpp
new file mode 100644
index 0000000..e6498a2
--- /dev/null
+++ b/kftpgrabber/src/misc/kftpapi.cpp
@@ -0,0 +1,81 @@
+/*
+ * This file is part of the KFTPGrabber project
+ *
+ * Copyright (C) 2003-2004 by the KFTPGrabber developers
+ * Copyright (C) 2003-2004 Jernej Kos <kostko@jweb-network.net>
+ *
+ * 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
+ * is provided AS IS, WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, and
+ * NON-INFRINGEMENT. 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 Steet, Fifth Floor, Boston,
+ * MA 02110-1301, USA.
+ *
+ * In addition, as a special exception, the copyright holders give
+ * permission to link the code of portions of this program with the
+ * OpenSSL library under certain conditions as described in each
+ * individual source file, and distribute linked combinations
+ * including the two.
+ * You must obey the GNU General Public License in all respects
+ * for all of the code used other than OpenSSL. If you modify
+ * file(s) with this exception, you may extend this exception to your
+ * version of the file(s), but you are not obligated to do so. If you
+ * do not wish to do so, delete this exception statement from your
+ * version. If you delete this exception statement from all source
+ * files in the program, then also delete it here.
+ */
+
+#include "kftpapi.h"
+#include "kftpwalletconnection.h"
+#include "kftppluginmanager.h"
+#include "kftpzeroconf.h"
+
+KFTPAPI *KFTPAPI::m_instance = 0L;
+
+KFTPAPI *KFTPAPI::getInstance()
+{
+ if (!m_instance)
+ m_instance = new KFTPAPI();
+
+ return m_instance;
+}
+
+KFTPAPI::KFTPAPI()
+{
+ m_zeroconfInterface = new KFTPZeroConf(this);
+}
+
+KFTPAPI::~KFTPAPI()
+{
+ m_instance = 0L;
+}
+
+KFTPPluginManager *KFTPAPI::pluginManager()
+{
+ return KFTPPluginManager::getInstance();
+}
+
+KFTPWalletConnection *KFTPAPI::walletConnection()
+{
+ return KFTPWalletConnection::getInstance();
+}
+
+MainWindow *KFTPAPI::mainWindow()
+{
+ return m_mainWindow;
+}
+
+KFTPZeroConf *KFTPAPI::zeroConfInterface()
+{
+ return m_zeroconfInterface;
+}
+
+#include "kftpapi.moc"
diff --git a/kftpgrabber/src/misc/kftpapi.h b/kftpgrabber/src/misc/kftpapi.h
new file mode 100644
index 0000000..3a77ab4
--- /dev/null
+++ b/kftpgrabber/src/misc/kftpapi.h
@@ -0,0 +1,73 @@
+/*
+ * This file is part of the KFTPGrabber project
+ *
+ * Copyright (C) 2003-2004 by the KFTPGrabber developers
+ * Copyright (C) 2003-2004 Jernej Kos <kostko@jweb-network.net>
+ *
+ * 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
+ * is provided AS IS, WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, and
+ * NON-INFRINGEMENT. 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 Steet, Fifth Floor, Boston,
+ * MA 02110-1301, USA.
+ *
+ * In addition, as a special exception, the copyright holders give
+ * permission to link the code of portions of this program with the
+ * OpenSSL library under certain conditions as described in each
+ * individual source file, and distribute linked combinations
+ * including the two.
+ * You must obey the GNU General Public License in all respects
+ * for all of the code used other than OpenSSL. If you modify
+ * file(s) with this exception, you may extend this exception to your
+ * version of the file(s), but you are not obligated to do so. If you
+ * do not wish to do so, delete this exception statement from your
+ * version. If you delete this exception statement from all source
+ * files in the program, then also delete it here.
+ */
+
+#ifndef KFTPAPI_H
+#define KFTPAPI_H
+
+#include <config.h>
+#include <qobject.h>
+
+#include "mainwindow.h"
+
+class KFTPPluginManager;
+class KFTPWalletConnection;
+class KFTPZeroConf;
+
+/**
+@author Jernej Kos
+*/
+class KFTPAPI : public QObject
+{
+Q_OBJECT
+friend class MainWindow;
+public:
+ KFTPAPI();
+ ~KFTPAPI();
+
+ static KFTPAPI *getInstance();
+
+ KFTPPluginManager *pluginManager();
+ KFTPWalletConnection *walletConnection();
+ MainWindow *mainWindow();
+
+ KFTPZeroConf *zeroConfInterface();
+private:
+ static KFTPAPI *m_instance;
+
+ MainWindow *m_mainWindow;
+ KFTPZeroConf *m_zeroconfInterface;
+};
+
+#endif
diff --git a/kftpgrabber/src/misc/kftpgrabber.kcfg b/kftpgrabber/src/misc/kftpgrabber.kcfg
new file mode 100644
index 0000000..80cc583
--- /dev/null
+++ b/kftpgrabber/src/misc/kftpgrabber.kcfg
@@ -0,0 +1,319 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE kcfg SYSTEM "http://www.kde.org/standards/kcfg/1.0/kcfg.dtd">
+<kcfg>
+ <kcfgfile name="kftpgrabberrc"/>
+
+ <!-- Includes -->
+ <include>qsize.h</include>
+ <include>qpoint.h</include>
+ <include>qdir.h</include>
+ <include>configbase.h</include>
+
+ <!-- Config groups -->
+ <group name="MainWindow">
+ <entry name="size" type="Size">
+ <default code="true">QSize(800, 500)</default>
+ <label>The size of the main window.</label>
+ </entry>
+ <entry name="position" type="Point">
+ <default code="true">QPoint(0, 0)</default>
+ <label>The position of the main window on the screen.</label>
+ </entry>
+ </group>
+
+ <group name="General">
+ <entry name="retryCount" type="Int">
+ <default>10</default>
+ <min>0</min>
+ <label>The default retry count for new sites.</label>
+ </entry>
+
+ <entry name="retryTime" type="Int">
+ <default>60</default>
+ <min>0</min>
+ <label>The default retry delay for new sites.</label>
+ </entry>
+
+ <entry name="showBalloons" type="Bool">
+ <default>true</default>
+ <label>Should a balloon be displayed when some actions complete.</label>
+ </entry>
+
+ <entry name="showBalloonWhenQueueEmpty" type="Bool">
+ <default>false</default>
+ <label>Should a balloon be displayed when all queued transfers are completed.</label>
+ </entry>
+
+ <entry name="showRetrySuccessBalloon" type="Bool">
+ <default>true</default>
+ <label>Should a balloon be displayed when a connection to the server is successfully established after retrying.</label>
+ </entry>
+
+ <entry name="confirmExit" type="Bool">
+ <default>true</default>
+ <label>Should the user confirm exit if there are transfers running.</label>
+ </entry>
+
+ <entry name="encryptBookmarks" type="Bool">
+ <default>false</default>
+ <label>Encryption status of the bookmarks file.</label>
+ </entry>
+
+ <entry name="defLocalDir" type="Path">
+ <default code="true">QDir::homeDirPath()</default>
+ <label>Default local directory.</label>
+ </entry>
+
+ <entry name="exitOnClose" type="Bool">
+ <default>false</default>
+ <label>Should the application exit when users clicks the X button.</label>
+ </entry>
+
+ <entry name="startMinimized" type="Bool">
+ <default>false</default>
+ <label>Should the application be started minimized.</label>
+ </entry>
+
+ <entry name="showSplash" type="Bool">
+ <default>true</default>
+ <label>Should the splash screen be displayed when starting the application.</label>
+ </entry>
+
+ <entry name="showSystrayIcon" type="Bool">
+ <default>true</default>
+ <label>Should the systray icon be displayed.</label>
+ </entry>
+
+ <entry name="showWalletSites" type="Bool">
+ <default>false</default>
+ <label>Should the sites from KWallet be shown among the bookmarks.</label>
+ </entry>
+
+ <entry name="confirmDisconnects" type="Bool">
+ <default>true</default>
+ <label>Should a "confirm disconnect" dialog be displayed each time a disconnect is requested.</label>
+ </entry>
+
+ <entry name="defEncoding" type="String">
+ <default>iso 8859-1</default>
+ <label>The default site encoding.</label>
+ </entry>
+
+ <entry name="recentSites" type="StringList">
+ <label>Recent sites accessed via quick connect.</label>
+ </entry>
+ </group>
+
+ <group name="Actions">
+ <entry name="downloadActions" type="String">
+ <default>4;4;4;4;4;4;4;4;4;</default>
+ </entry>
+
+ <entry name="uploadActions" type="String">
+ <default>4;4;4;4;4;4;4;4;4;</default>
+ </entry>
+
+ <entry name="fxpActions" type="String">
+ <default>4;4;4;4;4;4;4;4;4;</default>
+ </entry>
+ </group>
+
+ <group name="Filters">
+ <entry name="asciiList" type="StringList">
+ <default>.txt,.bat,.php,.asp,.htm,.html,.css,.cpp,.h,.hpp,.js,.inc,.nfo,.pl,.sh,.xml,.sql</default>
+ <label>A list of file patters where ASCII mode should be used for transfer.</label>
+ </entry>
+
+ <entry name="skipEmptyDirs" type="Bool">
+ <default>false</default>
+ <label>Should empty directories be skipped.</label>
+ </entry>
+ </group>
+
+ <group name="Log">
+ <entry name="logFont" type="Font">
+ <label>The font that should be used for the log widget.</label>
+ <default code="true">KGlobalSettings::generalFont()</default>
+ </entry>
+
+ <entry name="logCommandsColor" type="Color">
+ <default code="true">QColor(67, 170, 23)</default>
+ <label>The color of the commands sent to the server.</label>
+ </entry>
+
+ <entry name="logResponsesColor" type="Color">
+ <default code="true">QColor(0, 0, 255)</default>
+ <label>The color of the responses from the server.</label>
+ </entry>
+
+ <entry name="logMultilineColor" type="Color">
+ <default code="true">QColor(148, 188, 22)</default>
+ <label>The color of the multiline responses from the server.</label>
+ </entry>
+
+ <entry name="logErrorColor" type="Color">
+ <default code="true">QColor(255, 0, 0)</default>
+ <label>The color of the error messages.</label>
+ </entry>
+
+ <entry name="logStatusColor" type="Color">
+ <default code="true">QColor(0, 0, 0)</default>
+ <label>The color of the status messages.</label>
+ </entry>
+
+ <entry name="saveToFile" type="Bool">
+ <default>false</default>
+ <label>Should the log be written to a file as well.</label>
+ </entry>
+
+ <entry name="outputFilename" type="Path">
+ <label>The file to which the log should be written.</label>
+ </entry>
+ </group>
+
+ <group name="Transfers">
+ <entry name="activeForcePort" type="Bool">
+ <default>false</default>
+ <label>Should a port from a specified portrange be selected on active transfers.</label>
+ </entry>
+
+ <entry name="activeMinPort" type="Int">
+ <default>0</default>
+ <min>0</min>
+ <max>65536</max>
+ <label>The start of the portrange.</label>
+ </entry>
+
+ <entry name="activeMaxPort" type="Int">
+ <default>65536</default>
+ <min>0</min>
+ <max>65536</max>
+ <label>The end of the portrange.</label>
+ </entry>
+
+ <entry name="portForceIp" type="Bool">
+ <default>false</default>
+ <label>Should an IP be overriden when doing active transfers.</label>
+ </entry>
+
+ <entry name="portIp" type="String">
+ <label>The IP to be sent when overriding the PORT command.</label>
+ </entry>
+
+ <entry name="ignoreExternalIpForLan" type="Bool">
+ <default>true</default>
+ <label>Should the external IP be ignored for LAN connections.</label>
+ </entry>
+
+ <entry name="queueOnDND" type="Bool">
+ <default>false</default>
+ <label>Should the transfers be queued insted of started when using drag and drop.</label>
+ </entry>
+
+ <entry name="diskCheckSpace" type="Bool">
+ <default>false</default>
+ <label>Should kftpgrabber check for free space and abort the transfer when there is not enough free.</label>
+ </entry>
+
+ <entry name="diskCheckInterval" type="Int">
+ <default>60</default>
+ <min>30</min>
+ <label>Interval for disk checking.</label>
+ </entry>
+
+ <entry name="diskMinFreeSpace" type="Int">
+ <default>500</default>
+ <min>0</min>
+ <label>Minimum free space (in MiB) that must be available.</label>
+ </entry>
+
+ <entry name="globalMail" type="Bool">
+ <default>true</default>
+ <label>Use global KDE e-mail address for anonymous passwords.</label>
+ </entry>
+
+ <entry name="anonMail" type="String">
+ <default code="true">getGlobalMail()</default>
+ <label>The e-mail address that should be used for anonymous passwords.</label>
+ </entry>
+
+ <entry name="threadCount" type="Int">
+ <default>1</default>
+ <min>1</min>
+ <max>10</max>
+ <label>Number of threads to use when transfering.</label>
+ </entry>
+
+ <entry name="threadUsePrimary" type="Bool">
+ <default>true</default>
+ <label>Should the primary connection be used for transfers.</label>
+ </entry>
+
+ <entry name="controlTimeout" type="Int">
+ <default>60</default>
+ <min>10</min>
+ <label>Timeout (in seconds) for the control connection.</label>
+ </entry>
+
+ <entry name="dataTimeout" type="Int">
+ <default>60</default>
+ <min>10</min>
+ <max>300</max>
+ <label>Timeout (in seconds) for data transfers.</label>
+ </entry>
+
+ <entry name="downloadSpeedLimit" type="Int">
+ <default>0</default>
+ <label>Global download speed limit (kbytes/s).</label>
+ </entry>
+
+ <entry name="uploadSpeedLimit" type="Int">
+ <default>0</default>
+ <label>Global upload speed limit (kbytes/s).</label>
+ </entry>
+
+ <entry name="failedAutoRetry" type="Bool">
+ <default>false</default>
+ <label>Should failed transfers be automaticly retried.</label>
+ </entry>
+
+ <entry name="failedAutoRetryCount" type="Int">
+ <default>1</default>
+ <min>1</min>
+ <max>20</max>
+ <label>Maximum number of retries before marking transfer as failed.</label>
+ </entry>
+ </group>
+
+ <group name="Display">
+ <entry name="showTree" type="Bool">
+ <default>true</default>
+ <label>Should the directory tree be shown by default.</label>
+ </entry>
+
+ <entry name="showHiddenFiles" type="Bool">
+ <default>true</default>
+ <label>Should hidden files be shown when browsing.</label>
+ </entry>
+
+ <entry name="showSizeInBytes" type="Bool">
+ <default>false</default>
+ <label>Should the filesize be shown in bytes rather than in "human readable" form.</label>
+ </entry>
+
+ <entry name="showOwnerGroup" type="Bool">
+ <default>false</default>
+ <label>Should the owner and group be shown for each file.</label>
+ </entry>
+
+ <entry name="showDirectorySize" type="Bool">
+ <default>false</default>
+ <label>Show directory size.</label>
+ </entry>
+
+ <entry name="showLeftSidebar" type="Bool">
+ <default>false</default>
+ <label>Show left sidebar.</label>
+ </entry>
+ </group>
+</kcfg>
diff --git a/kftpgrabber/src/misc/kftpotpgenerator.cpp b/kftpgrabber/src/misc/kftpotpgenerator.cpp
new file mode 100644
index 0000000..ea6bb73
--- /dev/null
+++ b/kftpgrabber/src/misc/kftpotpgenerator.cpp
@@ -0,0 +1,470 @@
+/*
+ * This file is part of the KFTPGrabber project
+ *
+ * Copyright (C) 2003-2004 by the KFTPGrabber developers
+ * Copyright (C) 2003-2004 Jernej Kos <kostko@jweb-network.net>
+ *
+ * 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
+ * is provided AS IS, WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, and
+ * NON-INFRINGEMENT. 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 Steet, Fifth Floor, Boston,
+ * MA 02110-1301, USA.
+ *
+ * In addition, as a special exception, the copyright holders give
+ * permission to link the code of portions of this program with the
+ * OpenSSL library under certain conditions as described in each
+ * individual source file, and distribute linked combinations
+ * including the two.
+ * You must obey the GNU General Public License in all respects
+ * for all of the code used other than OpenSSL. If you modify
+ * file(s) with this exception, you may extend this exception to your
+ * version of the file(s), but you are not obligated to do so. If you
+ * do not wish to do so, delete this exception statement from your
+ * version. If you delete this exception statement from all source
+ * files in the program, then also delete it here.
+ */
+
+#include "kftpotpgenerator.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+
+/* OpenSSL includes */
+#include <openssl/md4.h>
+#include <openssl/md5.h>
+#include <openssl/ripemd.h>
+#include <openssl/sha.h>
+
+KFTPOTPGenerator::KFTPOTPGenerator(const QString &challenge, const QString &password)
+{
+ m_password = password;
+
+ /* Parse the string and set the alg */
+ //otp-md5 498 gr4542
+ QString alg = challenge.section(' ', 0, 0);
+ if (alg == "otp-md4" || alg == "s/key")
+ m_alg = ALG_MD4;
+ else if (alg == "otp-md5")
+ m_alg = ALG_MD5;
+ else if (alg == "otp-rmd160")
+ m_alg = ALG_RMD160;
+ else if (alg == "otp-sha1")
+ m_alg = ALG_SHA1;
+ else
+ m_alg = ALG_NONE;
+
+ // Extract the actual challenge
+ m_seq = challenge.section(' ', 1, 1).toInt();
+ m_seed = challenge.section(' ', 2, 2).stripWhiteSpace().lower();
+}
+
+void KFTPOTPGenerator::genDigest(char *msg, unsigned int len)
+{
+ switch (m_alg) {
+ case ALG_MD4: genDigestMD(4, msg, len); break;
+ case ALG_MD5: genDigestMD(5, msg, len); break;
+ case ALG_RMD160: genDigestRS(0, msg, len); break;
+ case ALG_SHA1: genDigestRS(1, msg, len); break;
+ default: {
+ qDebug("[OTP] Unknown algorythm!");
+ }
+ }
+}
+
+QString KFTPOTPGenerator::generateOTP()
+{
+ if (m_alg == ALG_NONE)
+ return QString::null;
+
+ unsigned char results[9];
+ char *tmp = (char*) malloc(m_seed.length() + m_password.length());
+ strcpy(tmp, QString(m_seed + m_password).ascii());
+ genDigest(tmp, strlen(tmp));
+
+ memcpy(results, tmp, 8);
+ free(tmp);
+
+ for (unsigned short i = 0; i < m_seq; i++) {
+ genDigest((char*) results, 8);
+ }
+
+ results[8] = parity(results);
+ char *response = (char*) malloc(31);
+ sixWords(results, response);
+
+ return QString(response);
+}
+
+void KFTPOTPGenerator::genDigestMD(int type, char *msg, unsigned int len)
+{
+ unsigned char digest[16];
+ unsigned short i;
+
+ if (type == 4)
+ MD4((const unsigned char*)msg, len, digest);
+ else if (type == 5)
+ MD5((const unsigned char*)msg, len, digest);
+
+ for(i = 0; i < 8; i++)
+ digest[i] ^= digest[i+8];
+
+ memcpy(msg, digest, 8);
+}
+
+void KFTPOTPGenerator::genDigestRS(int type, char *msg, unsigned int len)
+{
+ unsigned char digest[20];
+ unsigned short i;
+
+ if (type == 0)
+ RIPEMD160((const unsigned char*)msg, len, digest);
+ else if (type == 1)
+ SHA1((const unsigned char*)msg, len, digest);
+
+ for(i = 0; i < 8; i++)
+ digest[i] ^= digest[i+8];
+
+ for(i = 0; i < 4; i++)
+ digest[i] ^= digest[i+16];
+
+ memcpy(msg, digest, 8);
+}
+
+unsigned short KFTPOTPGenerator::extract(char *s, int start, int len)
+{
+ unsigned char cl;
+ unsigned char cc;
+ unsigned char cr;
+ unsigned int x;
+
+
+ cl = s[start / 8];
+ cc = s[start / 8 + 1];
+ cr = s[start / 8 + 2];
+ x = ((int) (cl << 8 | cc) << 8 | cr);
+ x = x >> (24 - (len + (start % 8)));
+ x = (x & (0xffff >> (16 - len)));
+
+ return (unsigned short)x;
+}
+
+unsigned char KFTPOTPGenerator::parity(unsigned char *msg)
+{
+
+ unsigned short parity, i;
+ parity = 0;
+
+ for (i = 0; i < 64; i += 2) {
+ parity += extract((char*)msg, i, 2);
+ }
+
+ return (unsigned char)parity << 6;
+}
+
+unsigned char *KFTPOTPGenerator::sixWords(unsigned char *msg, char *response)
+{
+ static const char *words[2048] = {
+ "A", "ABE", "ACE", "ACT", "AD", "ADA", "ADD", "AGO",
+ "AID", "AIM", "AIR", "ALL", "ALP", "AM", "AMY", "AN",
+ "ANA", "AND", "ANN", "ANT", "ANY", "APE", "APS", "APT",
+ "ARC", "ARE", "ARK", "ARM", "ART", "AS", "ASH", "ASK",
+ "AT", "ATE", "AUG", "AUK", "AVE", "AWE", "AWK", "AWL",
+ "AWN", "AX", "AYE", "BAD", "BAG", "BAH", "BAM", "BAN",
+ "BAR", "BAT", "BAY", "BE", "BED", "BEE", "BEG", "BEN",
+ "BET", "BEY", "BIB", "BID", "BIG", "BIN", "BIT", "BOB",
+ "BOG", "BON", "BOO", "BOP", "BOW", "BOY", "BUB", "BUD",
+ "BUG", "BUM", "BUN", "BUS", "BUT", "BUY", "BY", "BYE",
+ "CAB", "CAL", "CAM", "CAN", "CAP", "CAR", "CAT", "CAW",
+ "COD", "COG", "COL", "CON", "COO", "COP", "COT", "COW",
+ "COY", "CRY", "CUB", "CUE", "CUP", "CUR", "CUT", "DAB",
+ "DAD", "DAM", "DAN", "DAR", "DAY", "DEE", "DEL", "DEN",
+ "DES", "DEW", "DID", "DIE", "DIG", "DIN", "DIP", "DO",
+ "DOE", "DOG", "DON", "DOT", "DOW", "DRY", "DUB", "DUD",
+ "DUE", "DUG", "DUN", "EAR", "EAT", "ED", "EEL", "EGG",
+ "EGO", "ELI", "ELK", "ELM", "ELY", "EM", "END", "EST",
+ "ETC", "EVA", "EVE", "EWE", "EYE", "FAD", "FAN", "FAR",
+ "FAT", "FAY", "FED", "FEE", "FEW", "FIB", "FIG", "FIN",
+ "FIR", "FIT", "FLO", "FLY", "FOE", "FOG", "FOR", "FRY",
+ "FUM", "FUN", "FUR", "GAB", "GAD", "GAG", "GAL", "GAM",
+ "GAP", "GAS", "GAY", "GEE", "GEL", "GEM", "GET", "GIG",
+ "GIL", "GIN", "GO", "GOT", "GUM", "GUN", "GUS", "GUT",
+ "GUY", "GYM", "GYP", "HA", "HAD", "HAL", "HAM", "HAN",
+ "HAP", "HAS", "HAT", "HAW", "HAY", "HE", "HEM", "HEN",
+ "HER", "HEW", "HEY", "HI", "HID", "HIM", "HIP", "HIS",
+ "HIT", "HO", "HOB", "HOC", "HOE", "HOG", "HOP", "HOT",
+ "HOW", "HUB", "HUE", "HUG", "HUH", "HUM", "HUT", "I",
+ "ICY", "IDA", "IF", "IKE", "ILL", "INK", "INN", "IO",
+ "ION", "IQ", "IRA", "IRE", "IRK", "IS", "IT", "ITS",
+ "IVY", "JAB", "JAG", "JAM", "JAN", "JAR", "JAW", "JAY",
+ "JET", "JIG", "JIM", "JO", "JOB", "JOE", "JOG", "JOT",
+ "JOY", "JUG", "JUT", "KAY", "KEG", "KEN", "KEY", "KID",
+ "KIM", "KIN", "KIT", "LA", "LAB", "LAC", "LAD", "LAG",
+ "LAM", "LAP", "LAW", "LAY", "LEA", "LED", "LEE", "LEG",
+ "LEN", "LEO", "LET", "LEW", "LID", "LIE", "LIN", "LIP",
+ "LIT", "LO", "LOB", "LOG", "LOP", "LOS", "LOT", "LOU",
+ "LOW", "LOY", "LUG", "LYE", "MA", "MAC", "MAD", "MAE",
+ "MAN", "MAO", "MAP", "MAT", "MAW", "MAY", "ME", "MEG",
+ "MEL", "MEN", "MET", "MEW", "MID", "MIN", "MIT", "MOB",
+ "MOD", "MOE", "MOO", "MOP", "MOS", "MOT", "MOW", "MUD",
+ "MUG", "MUM", "MY", "NAB", "NAG", "NAN", "NAP", "NAT",
+ "NAY", "NE", "NED", "NEE", "NET", "NEW", "NIB", "NIL",
+ "NIP", "NIT", "NO", "NOB", "NOD", "NON", "NOR", "NOT",
+ "NOV", "NOW", "NU", "NUN", "NUT", "O", "OAF", "OAK",
+ "OAR", "OAT", "ODD", "ODE", "OF", "OFF", "OFT", "OH",
+ "OIL", "OK", "OLD", "ON", "ONE", "OR", "ORB", "ORE",
+ "ORR", "OS", "OTT", "OUR", "OUT", "OVA", "OW", "OWE",
+ "OWL", "OWN", "OX", "PA", "PAD", "PAL", "PAM", "PAN",
+ "PAP", "PAR", "PAT", "PAW", "PAY", "PEA", "PEG", "PEN",
+ "PEP", "PER", "PET", "PEW", "PHI", "PI", "PIE", "PIN",
+ "PIT", "PLY", "PO", "POD", "POE", "POP", "POT", "POW",
+ "PRO", "PRY", "PUB", "PUG", "PUN", "PUP", "PUT", "QUO",
+ "RAG", "RAM", "RAN", "RAP", "RAT", "RAW", "RAY", "REB",
+ "RED", "REP", "RET", "RIB", "RID", "RIG", "RIM", "RIO",
+ "RIP", "ROB", "ROD", "ROE", "RON", "ROT", "ROW", "ROY",
+ "RUB", "RUE", "RUG", "RUM", "RUN", "RYE", "SAC", "SAD",
+ "SAG", "SAL", "SAM", "SAN", "SAP", "SAT", "SAW", "SAY",
+ "SEA", "SEC", "SEE", "SEN", "SET", "SEW", "SHE", "SHY",
+ "SIN", "SIP", "SIR", "SIS", "SIT", "SKI", "SKY", "SLY",
+ "SO", "SOB", "SOD", "SON", "SOP", "SOW", "SOY", "SPA",
+ "SPY", "SUB", "SUD", "SUE", "SUM", "SUN", "SUP", "TAB",
+ "TAD", "TAG", "TAN", "TAP", "TAR", "TEA", "TED", "TEE",
+ "TEN", "THE", "THY", "TIC", "TIE", "TIM", "TIN", "TIP",
+ "TO", "TOE", "TOG", "TOM", "TON", "TOO", "TOP", "TOW",
+ "TOY", "TRY", "TUB", "TUG", "TUM", "TUN", "TWO", "UN",
+ "UP", "US", "USE", "VAN", "VAT", "VET", "VIE", "WAD",
+ "WAG", "WAR", "WAS", "WAY", "WE", "WEB", "WED", "WEE",
+ "WET", "WHO", "WHY", "WIN", "WIT", "WOK", "WON", "WOO",
+ "WOW", "WRY", "WU", "YAM", "YAP", "YAW", "YE", "YEA",
+ "YES", "YET", "YOU", "ABED", "ABEL", "ABET", "ABLE",
+ "ABUT", "ACHE", "ACID", "ACME", "ACRE", "ACTA", "ACTS",
+ "ADAM", "ADDS", "ADEN", "AFAR", "AFRO", "AGEE", "AHEM",
+ "AHOY", "AIDA", "AIDE", "AIDS", "AIRY", "AJAR", "AKIN",
+ "ALAN", "ALEC", "ALGA", "ALIA", "ALLY", "ALMA", "ALOE",
+ "ALSO", "ALTO", "ALUM", "ALVA", "AMEN", "AMES", "AMID",
+ "AMMO", "AMOK", "AMOS", "AMRA", "ANDY", "ANEW", "ANNA",
+ "ANNE", "ANTE", "ANTI", "AQUA", "ARAB", "ARCH", "AREA",
+ "ARGO", "ARID", "ARMY", "ARTS", "ARTY", "ASIA", "ASKS",
+ "ATOM", "AUNT", "AURA", "AUTO", "AVER", "AVID", "AVIS",
+ "AVON", "AVOW", "AWAY", "AWRY", "BABE", "BABY", "BACH",
+ "BACK", "BADE", "BAIL", "BAIT", "BAKE", "BALD", "BALE",
+ "BALI", "BALK", "BALL", "BALM", "BAND", "BANE", "BANG",
+ "BANK", "BARB", "BARD", "BARE", "BARK", "BARN", "BARR",
+ "BASE", "BASH", "BASK", "BASS", "BATE", "BATH", "BAWD",
+ "BAWL", "BEAD", "BEAK", "BEAM", "BEAN", "BEAR", "BEAT",
+ "BEAU", "BECK", "BEEF", "BEEN", "BEER", "BEET", "BELA",
+ "BELL", "BELT", "BEND", "BENT", "BERG", "BERN", "BERT",
+ "BESS", "BEST", "BETA", "BETH", "BHOY", "BIAS", "BIDE",
+ "BIEN", "BILE", "BILK", "BILL", "BIND", "BING", "BIRD",
+ "BITE", "BITS", "BLAB", "BLAT", "BLED", "BLEW", "BLOB",
+ "BLOC", "BLOT", "BLOW", "BLUE", "BLUM", "BLUR", "BOAR",
+ "BOAT", "BOCA", "BOCK", "BODE", "BODY", "BOGY", "BOHR",
+ "BOIL", "BOLD", "BOLO", "BOLT", "BOMB", "BONA", "BOND",
+ "BONE", "BONG", "BONN", "BONY", "BOOK", "BOOM", "BOON",
+ "BOOT", "BORE", "BORG", "BORN", "BOSE", "BOSS", "BOTH",
+ "BOUT", "BOWL", "BOYD", "BRAD", "BRAE", "BRAG", "BRAN",
+ "BRAY", "BRED", "BREW", "BRIG", "BRIM", "BROW", "BUCK",
+ "BUDD", "BUFF", "BULB", "BULK", "BULL", "BUNK", "BUNT",
+ "BUOY", "BURG", "BURL", "BURN", "BURR", "BURT", "BURY",
+ "BUSH", "BUSS", "BUST", "BUSY", "BYTE", "CADY", "CAFE",
+ "CAGE", "CAIN", "CAKE", "CALF", "CALL", "CALM", "CAME",
+ "CANE", "CANT", "CARD", "CARE", "CARL", "CARR", "CART",
+ "CASE", "CASH", "CASK", "CAST", "CAVE", "CEIL", "CELL",
+ "CENT", "CERN", "CHAD", "CHAR", "CHAT", "CHAW", "CHEF",
+ "CHEN", "CHEW", "CHIC", "CHIN", "CHOU", "CHOW", "CHUB",
+ "CHUG", "CHUM", "CITE", "CITY", "CLAD", "CLAM", "CLAN",
+ "CLAW", "CLAY", "CLOD", "CLOG", "CLOT", "CLUB", "CLUE",
+ "COAL", "COAT", "COCA", "COCK", "COCO", "CODA", "CODE",
+ "CODY", "COED", "COIL", "COIN", "COKE", "COLA", "COLD",
+ "COLT", "COMA", "COMB", "COME", "COOK", "COOL", "COON",
+ "COOT", "CORD", "CORE", "CORK", "CORN", "COST", "COVE",
+ "COWL", "CRAB", "CRAG", "CRAM", "CRAY", "CREW", "CRIB",
+ "CROW", "CRUD", "CUBA", "CUBE", "CUFF", "CULL", "CULT",
+ "CUNY", "CURB", "CURD", "CURE", "CURL", "CURT", "CUTS",
+ "DADE", "DALE", "DAME", "DANA", "DANE", "DANG", "DANK",
+ "DARE", "DARK", "DARN", "DART", "DASH", "DATA", "DATE",
+ "DAVE", "DAVY", "DAWN", "DAYS", "DEAD", "DEAF", "DEAL",
+ "DEAN", "DEAR", "DEBT", "DECK", "DEED", "DEEM", "DEER",
+ "DEFT", "DEFY", "DELL", "DENT", "DENY", "DESK", "DIAL",
+ "DICE", "DIED", "DIET", "DIME", "DINE", "DING", "DINT",
+ "DIRE", "DIRT", "DISC", "DISH", "DISK", "DIVE", "DOCK",
+ "DOES", "DOLE", "DOLL", "DOLT", "DOME", "DONE", "DOOM",
+ "DOOR", "DORA", "DOSE", "DOTE", "DOUG", "DOUR", "DOVE",
+ "DOWN", "DRAB", "DRAG", "DRAM", "DRAW", "DREW", "DRUB",
+ "DRUG", "DRUM", "DUAL", "DUCK", "DUCT", "DUEL", "DUET",
+ "DUKE", "DULL", "DUMB", "DUNE", "DUNK", "DUSK", "DUST",
+ "DUTY", "EACH", "EARL", "EARN", "EASE", "EAST", "EASY",
+ "EBEN", "ECHO", "EDDY", "EDEN", "EDGE", "EDGY", "EDIT",
+ "EDNA", "EGAN", "ELAN", "ELBA", "ELLA", "ELSE", "EMIL",
+ "EMIT", "EMMA", "ENDS", "ERIC", "EROS", "EVEN", "EVER",
+ "EVIL", "EYED", "FACE", "FACT", "FADE", "FAIL", "FAIN",
+ "FAIR", "FAKE", "FALL", "FAME", "FANG", "FARM", "FAST",
+ "FATE", "FAWN", "FEAR", "FEAT", "FEED", "FEEL", "FEET",
+ "FELL", "FELT", "FEND", "FERN", "FEST", "FEUD", "FIEF",
+ "FIGS", "FILE", "FILL", "FILM", "FIND", "FINE", "FINK",
+ "FIRE", "FIRM", "FISH", "FISK", "FIST", "FITS", "FIVE",
+ "FLAG", "FLAK", "FLAM", "FLAT", "FLAW", "FLEA", "FLED",
+ "FLEW", "FLIT", "FLOC", "FLOG", "FLOW", "FLUB", "FLUE",
+ "FOAL", "FOAM", "FOGY", "FOIL", "FOLD", "FOLK", "FOND",
+ "FONT", "FOOD", "FOOL", "FOOT", "FORD", "FORE", "FORK",
+ "FORM", "FORT", "FOSS", "FOUL", "FOUR", "FOWL", "FRAU",
+ "FRAY", "FRED", "FREE", "FRET", "FREY", "FROG", "FROM",
+ "FUEL", "FULL", "FUME", "FUND", "FUNK", "FURY", "FUSE",
+ "FUSS", "GAFF", "GAGE", "GAIL", "GAIN", "GAIT", "GALA",
+ "GALE", "GALL", "GALT", "GAME", "GANG", "GARB", "GARY",
+ "GASH", "GATE", "GAUL", "GAUR", "GAVE", "GAWK", "GEAR",
+ "GELD", "GENE", "GENT", "GERM", "GETS", "GIBE", "GIFT",
+ "GILD", "GILL", "GILT", "GINA", "GIRD", "GIRL", "GIST",
+ "GIVE", "GLAD", "GLEE", "GLEN", "GLIB", "GLOB", "GLOM",
+ "GLOW", "GLUE", "GLUM", "GLUT", "GOAD", "GOAL", "GOAT",
+ "GOER", "GOES", "GOLD", "GOLF", "GONE", "GONG", "GOOD",
+ "GOOF", "GORE", "GORY", "GOSH", "GOUT", "GOWN", "GRAB",
+ "GRAD", "GRAY", "GREG", "GREW", "GREY", "GRID", "GRIM",
+ "GRIN", "GRIT", "GROW", "GRUB", "GULF", "GULL", "GUNK",
+ "GURU", "GUSH", "GUST", "GWEN", "GWYN", "HAAG", "HAAS",
+ "HACK", "HAIL", "HAIR", "HALE", "HALF", "HALL", "HALO",
+ "HALT", "HAND", "HANG", "HANK", "HANS", "HARD", "HARK",
+ "HARM", "HART", "HASH", "HAST", "HATE", "HATH", "HAUL",
+ "HAVE", "HAWK", "HAYS", "HEAD", "HEAL", "HEAR", "HEAT",
+ "HEBE", "HECK", "HEED", "HEEL", "HEFT", "HELD", "HELL",
+ "HELM", "HERB", "HERD", "HERE", "HERO", "HERS", "HESS",
+ "HEWN", "HICK", "HIDE", "HIGH", "HIKE", "HILL", "HILT",
+ "HIND", "HINT", "HIRE", "HISS", "HIVE", "HOBO", "HOCK",
+ "HOFF", "HOLD", "HOLE", "HOLM", "HOLT", "HOME", "HONE",
+ "HONK", "HOOD", "HOOF", "HOOK", "HOOT", "HORN", "HOSE",
+ "HOST", "HOUR", "HOVE", "HOWE", "HOWL", "HOYT", "HUCK",
+ "HUED", "HUFF", "HUGE", "HUGH", "HUGO", "HULK", "HULL",
+ "HUNK", "HUNT", "HURD", "HURL", "HURT", "HUSH", "HYDE",
+ "HYMN", "IBIS", "ICON", "IDEA", "IDLE", "IFFY", "INCA",
+ "INCH", "INTO", "IONS", "IOTA", "IOWA", "IRIS", "IRMA",
+ "IRON", "ISLE", "ITCH", "ITEM", "IVAN", "JACK", "JADE",
+ "JAIL", "JAKE", "JANE", "JAVA", "JEAN", "JEFF", "JERK",
+ "JESS", "JEST", "JIBE", "JILL", "JILT", "JIVE", "JOAN",
+ "JOBS", "JOCK", "JOEL", "JOEY", "JOHN", "JOIN", "JOKE",
+ "JOLT", "JOVE", "JUDD", "JUDE", "JUDO", "JUDY", "JUJU",
+ "JUKE", "JULY", "JUNE", "JUNK", "JUNO", "JURY", "JUST",
+ "JUTE", "KAHN", "KALE", "KANE", "KANT", "KARL", "KATE",
+ "KEEL", "KEEN", "KENO", "KENT", "KERN", "KERR", "KEYS",
+ "KICK", "KILL", "KIND", "KING", "KIRK", "KISS", "KITE",
+ "KLAN", "KNEE", "KNEW", "KNIT", "KNOB", "KNOT", "KNOW",
+ "KOCH", "KONG", "KUDO", "KURD", "KURT", "KYLE", "LACE",
+ "LACK", "LACY", "LADY", "LAID", "LAIN", "LAIR", "LAKE",
+ "LAMB", "LAME", "LAND", "LANE", "LANG", "LARD", "LARK",
+ "LASS", "LAST", "LATE", "LAUD", "LAVA", "LAWN", "LAWS",
+ "LAYS", "LEAD", "LEAF", "LEAK", "LEAN", "LEAR", "LEEK",
+ "LEER", "LEFT", "LEND", "LENS", "LENT", "LEON", "LESK",
+ "LESS", "LEST", "LETS", "LIAR", "LICE", "LICK", "LIED",
+ "LIEN", "LIES", "LIEU", "LIFE", "LIFT", "LIKE", "LILA",
+ "LILT", "LILY", "LIMA", "LIMB", "LIME", "LIND", "LINE",
+ "LINK", "LINT", "LION", "LISA", "LIST", "LIVE", "LOAD",
+ "LOAF", "LOAM", "LOAN", "LOCK", "LOFT", "LOGE", "LOIS",
+ "LOLA", "LONE", "LONG", "LOOK", "LOON", "LOOT", "LORD",
+ "LORE", "LOSE", "LOSS", "LOST", "LOUD", "LOVE", "LOWE",
+ "LUCK", "LUCY", "LUGE", "LUKE", "LULU", "LUND", "LUNG",
+ "LURA", "LURE", "LURK", "LUSH", "LUST", "LYLE", "LYNN",
+ "LYON", "LYRA", "MACE", "MADE", "MAGI", "MAID", "MAIL",
+ "MAIN", "MAKE", "MALE", "MALI", "MALL", "MALT", "MANA",
+ "MANN", "MANY", "MARC", "MARE", "MARK", "MARS", "MART",
+ "MARY", "MASH", "MASK", "MASS", "MAST", "MATE", "MATH",
+ "MAUL", "MAYO", "MEAD", "MEAL", "MEAN", "MEAT", "MEEK",
+ "MEET", "MELD", "MELT", "MEMO", "MEND", "MENU", "MERT",
+ "MESH", "MESS", "MICE", "MIKE", "MILD", "MILE", "MILK",
+ "MILL", "MILT", "MIMI", "MIND", "MINE", "MINI", "MINK",
+ "MINT", "MIRE", "MISS", "MIST", "MITE", "MITT", "MOAN",
+ "MOAT", "MOCK", "MODE", "MOLD", "MOLE", "MOLL", "MOLT",
+ "MONA", "MONK", "MONT", "MOOD", "MOON", "MOOR", "MOOT",
+ "MORE", "MORN", "MORT", "MOSS", "MOST", "MOTH", "MOVE",
+ "MUCH", "MUCK", "MUDD", "MUFF", "MULE", "MULL", "MURK",
+ "MUSH", "MUST", "MUTE", "MUTT", "MYRA", "MYTH", "NAGY",
+ "NAIL", "NAIR", "NAME", "NARY", "NASH", "NAVE", "NAVY",
+ "NEAL", "NEAR", "NEAT", "NECK", "NEED", "NEIL", "NELL",
+ "NEON", "NERO", "NESS", "NEST", "NEWS", "NEWT", "NIBS",
+ "NICE", "NICK", "NILE", "NINA", "NINE", "NOAH", "NODE",
+ "NOEL", "NOLL", "NONE", "NOOK", "NOON", "NORM", "NOSE",
+ "NOTE", "NOUN", "NOVA", "NUDE", "NULL", "NUMB", "OATH",
+ "OBEY", "OBOE", "ODIN", "OHIO", "OILY", "OINT", "OKAY",
+ "OLAF", "OLDY", "OLGA", "OLIN", "OMAN", "OMEN", "OMIT",
+ "ONCE", "ONES", "ONLY", "ONTO", "ONUS", "ORAL", "ORGY",
+ "OSLO", "OTIS", "OTTO", "OUCH", "OUST", "OUTS", "OVAL",
+ "OVEN", "OVER", "OWLY", "OWNS", "QUAD", "QUIT", "QUOD",
+ "RACE", "RACK", "RACY", "RAFT", "RAGE", "RAID", "RAIL",
+ "RAIN", "RAKE", "RANK", "RANT", "RARE", "RASH", "RATE",
+ "RAVE", "RAYS", "READ", "REAL", "REAM", "REAR", "RECK",
+ "REED", "REEF", "REEK", "REEL", "REID", "REIN", "RENA",
+ "REND", "RENT", "REST", "RICE", "RICH", "RICK", "RIDE",
+ "RIFT", "RILL", "RIME", "RING", "RINK", "RISE", "RISK",
+ "RITE", "ROAD", "ROAM", "ROAR", "ROBE", "ROCK", "RODE",
+ "ROIL", "ROLL", "ROME", "ROOD", "ROOF", "ROOK", "ROOM",
+ "ROOT", "ROSA", "ROSE", "ROSS", "ROSY", "ROTH", "ROUT",
+ "ROVE", "ROWE", "ROWS", "RUBE", "RUBY", "RUDE", "RUDY",
+ "RUIN", "RULE", "RUNG", "RUNS", "RUNT", "RUSE", "RUSH",
+ "RUSK", "RUSS", "RUST", "RUTH", "SACK", "SAFE", "SAGE",
+ "SAID", "SAIL", "SALE", "SALK", "SALT", "SAME", "SAND",
+ "SANE", "SANG", "SANK", "SARA", "SAUL", "SAVE", "SAYS",
+ "SCAN", "SCAR", "SCAT", "SCOT", "SEAL", "SEAM", "SEAR",
+ "SEAT", "SEED", "SEEK", "SEEM", "SEEN", "SEES", "SELF",
+ "SELL", "SEND", "SENT", "SETS", "SEWN", "SHAG", "SHAM",
+ "SHAW", "SHAY", "SHED", "SHIM", "SHIN", "SHOD", "SHOE",
+ "SHOT", "SHOW", "SHUN", "SHUT", "SICK", "SIDE", "SIFT",
+ "SIGH", "SIGN", "SILK", "SILL", "SILO", "SILT", "SINE",
+ "SING", "SINK", "SIRE", "SITE", "SITS", "SITU", "SKAT",
+ "SKEW", "SKID", "SKIM", "SKIN", "SKIT", "SLAB", "SLAM",
+ "SLAT", "SLAY", "SLED", "SLEW", "SLID", "SLIM", "SLIT",
+ "SLOB", "SLOG", "SLOT", "SLOW", "SLUG", "SLUM", "SLUR",
+ "SMOG", "SMUG", "SNAG", "SNOB", "SNOW", "SNUB", "SNUG",
+ "SOAK", "SOAR", "SOCK", "SODA", "SOFA", "SOFT", "SOIL",
+ "SOLD", "SOME", "SONG", "SOON", "SOOT", "SORE", "SORT",
+ "SOUL", "SOUR", "SOWN", "STAB", "STAG", "STAN", "STAR",
+ "STAY", "STEM", "STEW", "STIR", "STOW", "STUB", "STUN",
+ "SUCH", "SUDS", "SUIT", "SULK", "SUMS", "SUNG", "SUNK",
+ "SURE", "SURF", "SWAB", "SWAG", "SWAM", "SWAN", "SWAT",
+ "SWAY", "SWIM", "SWUM", "TACK", "TACT", "TAIL", "TAKE",
+ "TALE", "TALK", "TALL", "TANK", "TASK", "TATE", "TAUT",
+ "TEAL", "TEAM", "TEAR", "TECH", "TEEM", "TEEN", "TEET",
+ "TELL", "TEND", "TENT", "TERM", "TERN", "TESS", "TEST",
+ "THAN", "THAT", "THEE", "THEM", "THEN", "THEY", "THIN",
+ "THIS", "THUD", "THUG", "TICK", "TIDE", "TIDY", "TIED",
+ "TIER", "TILE", "TILL", "TILT", "TIME", "TINA", "TINE",
+ "TINT", "TINY", "TIRE", "TOAD", "TOGO", "TOIL", "TOLD",
+ "TOLL", "TONE", "TONG", "TONY", "TOOK", "TOOL", "TOOT",
+ "TORE", "TORN", "TOTE", "TOUR", "TOUT", "TOWN", "TRAG",
+ "TRAM", "TRAY", "TREE", "TREK", "TRIG", "TRIM", "TRIO",
+ "TROD", "TROT", "TROY", "TRUE", "TUBA", "TUBE", "TUCK",
+ "TUFT", "TUNA", "TUNE", "TUNG", "TURF", "TURN", "TUSK",
+ "TWIG", "TWIN", "TWIT", "ULAN", "UNIT", "URGE", "USED",
+ "USER", "USES", "UTAH", "VAIL", "VAIN", "VALE", "VARY",
+ "VASE", "VAST", "VEAL", "VEDA", "VEIL", "VEIN", "VEND",
+ "VENT", "VERB", "VERY", "VETO", "VICE", "VIEW", "VINE",
+ "VISE", "VOID", "VOLT", "VOTE", "WACK", "WADE", "WAGE",
+ "WAIL", "WAIT", "WAKE", "WALE", "WALK", "WALL", "WALT",
+ "WAND", "WANE", "WANG", "WANT", "WARD", "WARM", "WARN",
+ "WART", "WASH", "WAST", "WATS", "WATT", "WAVE", "WAVY",
+ "WAYS", "WEAK", "WEAL", "WEAN", "WEAR", "WEED", "WEEK",
+ "WEIR", "WELD", "WELL", "WELT", "WENT", "WERE", "WERT",
+ "WEST", "WHAM", "WHAT", "WHEE", "WHEN", "WHET", "WHOA",
+ "WHOM", "WICK", "WIFE", "WILD", "WILL", "WIND", "WINE",
+ "WING", "WINK", "WINO", "WIRE", "WISE", "WISH", "WITH",
+ "WOLF", "WONT", "WOOD", "WOOL", "WORD", "WORE", "WORK",
+ "WORM", "WORN", "WOVE", "WRIT", "WYNN", "YALE", "YANG",
+ "YANK", "YARD", "YARN", "YAWL", "YAWN", "YEAH", "YEAR",
+ "YELL", "YOGA", "YOKE"
+ };
+
+ snprintf(response, 31, "%s %s %s %s %s %s",
+ words[extract((char*)msg, 0, 11)],
+ words[extract((char*)msg, 11, 11)],
+ words[extract((char*)msg, 22, 11)],
+ words[extract((char*)msg, 33, 11)],
+ words[extract((char*)msg, 44, 11)],
+ words[extract((char*)msg, 55, 11)]);
+
+ return (unsigned char*)response;
+}
diff --git a/kftpgrabber/src/misc/kftpotpgenerator.h b/kftpgrabber/src/misc/kftpotpgenerator.h
new file mode 100644
index 0000000..5292ead
--- /dev/null
+++ b/kftpgrabber/src/misc/kftpotpgenerator.h
@@ -0,0 +1,75 @@
+/*
+ * This file is part of the KFTPGrabber project
+ *
+ * Copyright (C) 2003-2004 by the KFTPGrabber developers
+ * Copyright (C) 2003-2004 Jernej Kos <kostko@jweb-network.net>
+ *
+ * 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
+ * is provided AS IS, WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, and
+ * NON-INFRINGEMENT. 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 Steet, Fifth Floor, Boston,
+ * MA 02110-1301, USA.
+ *
+ * In addition, as a special exception, the copyright holders give
+ * permission to link the code of portions of this program with the
+ * OpenSSL library under certain conditions as described in each
+ * individual source file, and distribute linked combinations
+ * including the two.
+ * You must obey the GNU General Public License in all respects
+ * for all of the code used other than OpenSSL. If you modify
+ * file(s) with this exception, you may extend this exception to your
+ * version of the file(s), but you are not obligated to do so. If you
+ * do not wish to do so, delete this exception statement from your
+ * version. If you delete this exception statement from all source
+ * files in the program, then also delete it here.
+ */
+
+#ifndef KFTPOTPGENERATOR_H
+#define KFTPOTPGENERATOR_H
+
+#include <qstring.h>
+
+enum AlgType {
+ ALG_MD4,
+ ALG_MD5,
+ ALG_RMD160,
+ ALG_SHA1,
+ ALG_NONE
+};
+
+/*
+ KFTPOTPGenerator - OTP generator for purpuse of FTP auth, based on code from
+ otpCalc copyright (C) 2001 by Anthony D. Urso
+*/
+
+/**
+@author Jernej Kos
+*/
+class KFTPOTPGenerator{
+public:
+ KFTPOTPGenerator(const QString &challenge, const QString &password);
+ QString generateOTP();
+private:
+ QString m_seed;
+ QString m_password;
+ AlgType m_alg;
+ int m_seq;
+
+ void genDigest(char *msg, unsigned int len);
+ void genDigestMD(int type, char *msg, unsigned int len);
+ void genDigestRS(int type, char *msg, unsigned int len);
+ static unsigned short extract(char *s, int start, int len);
+ unsigned char parity(unsigned char *msg);
+ unsigned char *sixWords(unsigned char *msg, char *response);
+};
+
+#endif
diff --git a/kftpgrabber/src/misc/kftppluginmanager.cpp b/kftpgrabber/src/misc/kftppluginmanager.cpp
new file mode 100644
index 0000000..fc9dbb0
--- /dev/null
+++ b/kftpgrabber/src/misc/kftppluginmanager.cpp
@@ -0,0 +1,76 @@
+/*
+ * This file is part of the KFTPGrabber project
+ *
+ * Copyright (C) 2003-2004 by the KFTPGrabber developers
+ * Copyright (C) 2003-2004 Jernej Kos <kostko@jweb-network.net>
+ *
+ * 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
+ * is provided AS IS, WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, and
+ * NON-INFRINGEMENT. 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 Steet, Fifth Floor, Boston,
+ * MA 02110-1301, USA.
+ *
+ * In addition, as a special exception, the copyright holders give
+ * permission to link the code of portions of this program with the
+ * OpenSSL library under certain conditions as described in each
+ * individual source file, and distribute linked combinations
+ * including the two.
+ * You must obey the GNU General Public License in all respects
+ * for all of the code used other than OpenSSL. If you modify
+ * file(s) with this exception, you may extend this exception to your
+ * version of the file(s), but you are not obligated to do so. If you
+ * do not wish to do so, delete this exception statement from your
+ * version. If you delete this exception statement from all source
+ * files in the program, then also delete it here.
+ */
+
+#include "kftppluginmanager.h"
+#include "kftpbookmarkimportplugin.h"
+
+KFTPPluginManager *KFTPPluginManager::m_instance = 0L;
+
+KFTPPluginManager *KFTPPluginManager::getInstance()
+{
+ if (!m_instance)
+ m_instance = new KFTPPluginManager();
+
+ return m_instance;
+}
+
+KFTPPluginManager::KFTPPluginManager(QObject *parent, const char *name)
+ : QObject(parent, name)
+{
+}
+
+void KFTPPluginManager::loadPlugins()
+{
+}
+
+KTrader::OfferList KFTPPluginManager::getImportPlugins()
+{
+ return KTrader::self()->query("KFTPGrabber/BookmarkImportPlugin");
+}
+
+KFTPBookmarkImportPlugin *KFTPPluginManager::loadImportPlugin(KService::Ptr service)
+{
+ int errCode = 0;
+
+ KFTPBookmarkImportPlugin *plugin = KParts::ComponentFactory::createInstanceFromService<KFTPBookmarkImportPlugin>(service, this, 0, QStringList(), &errCode);
+
+ if (plugin) {
+ qDebug("[PLUGIN MANAGER] Loaded '%s' plugin for bookmark import.", service->name().ascii());
+ }
+
+ return plugin;
+}
+
+#include "kftppluginmanager.moc"
diff --git a/kftpgrabber/src/misc/kftppluginmanager.h b/kftpgrabber/src/misc/kftppluginmanager.h
new file mode 100644
index 0000000..b377a62
--- /dev/null
+++ b/kftpgrabber/src/misc/kftppluginmanager.h
@@ -0,0 +1,82 @@
+/*
+ * This file is part of the KFTPGrabber project
+ *
+ * Copyright (C) 2003-2004 by the KFTPGrabber developers
+ * Copyright (C) 2003-2004 Jernej Kos <kostko@jweb-network.net>
+ *
+ * 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
+ * is provided AS IS, WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, and
+ * NON-INFRINGEMENT. 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 Steet, Fifth Floor, Boston,
+ * MA 02110-1301, USA.
+ *
+ * In addition, as a special exception, the copyright holders give
+ * permission to link the code of portions of this program with the
+ * OpenSSL library under certain conditions as described in each
+ * individual source file, and distribute linked combinations
+ * including the two.
+ * You must obey the GNU General Public License in all respects
+ * for all of the code used other than OpenSSL. If you modify
+ * file(s) with this exception, you may extend this exception to your
+ * version of the file(s), but you are not obligated to do so. If you
+ * do not wish to do so, delete this exception statement from your
+ * version. If you delete this exception statement from all source
+ * files in the program, then also delete it here.
+ */
+
+#ifndef KFTPPLUGINMANAGER_H
+#define KFTPPLUGINMANAGER_H
+
+#include <kparts/componentfactory.h>
+
+#include <qobject.h>
+#include <qptrlist.h>
+
+class KFTPBookmarkImportPlugin;
+
+/**
+ * This class is responsible for loading all the KFTPGrabber plugins and
+ * their communication with the rest of the application.
+ *
+ * @author Jernej Kos
+ */
+class KFTPPluginManager : public QObject
+{
+Q_OBJECT
+public:
+ KFTPPluginManager(QObject *parent = 0, const char *name = 0);
+ static KFTPPluginManager *getInstance();
+
+ /**
+ * This method will load all the plugins.
+ */
+ void loadPlugins();
+
+ /**
+ * Load bookmark import plugin.
+ *
+ * @param service The plugin KService::Ptr
+ * @return The loaded plugin or NULL if plugin can't be loaded
+ */
+ KFTPBookmarkImportPlugin *loadImportPlugin(KService::Ptr service);
+
+ /**
+ * Returns the list of all currently loaded import plugins.
+ *
+ * @return List of all laoded import plugins
+ */
+ KTrader::OfferList getImportPlugins();
+private:
+ static KFTPPluginManager *m_instance;
+};
+
+#endif
diff --git a/kftpgrabber/src/misc/kftpwalletconnection.cpp b/kftpgrabber/src/misc/kftpwalletconnection.cpp
new file mode 100644
index 0000000..242b00d
--- /dev/null
+++ b/kftpgrabber/src/misc/kftpwalletconnection.cpp
@@ -0,0 +1,166 @@
+/*
+ * This file is part of the KFTPGrabber project
+ *
+ * Copyright (C) 2004 by the KFTPGrabber developers
+ * Copyright (C) 2004 Jernej Kos <kostko@jweb-network.net>
+ *
+ * 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
+ * is provided AS IS, WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, and
+ * NON-INFRINGEMENT. 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 Steet, Fifth Floor, Boston,
+ * MA 02110-1301, USA.
+ *
+ * In addition, as a special exception, the copyright holders give
+ * permission to link the code of portions of this program with the
+ * OpenSSL library under certain conditions as described in each
+ * individual source file, and distribute linked combinations
+ * including the two.
+ * You must obey the GNU General Public License in all respects
+ * for all of the code used other than OpenSSL. If you modify
+ * file(s) with this exception, you may extend this exception to your
+ * version of the file(s), but you are not obligated to do so. If you
+ * do not wish to do so, delete this exception statement from your
+ * version. If you delete this exception statement from all source
+ * files in the program, then also delete it here.
+ */
+
+#include <kurl.h>
+
+#include "kftpwalletconnection.h"
+
+KFTPWalletConnection *KFTPWalletConnection::m_instance = 0L;
+
+KFTPWalletConnection *KFTPWalletConnection::getInstance()
+{
+ if (!m_instance)
+ m_instance = new KFTPWalletConnection();
+
+ return m_instance;
+}
+
+KFTPWalletConnection::KFTPWalletConnection()
+ : QObject()
+{
+ m_wallet = 0L;
+ m_walletRefCount = 0;
+}
+
+
+KFTPWalletConnection::~KFTPWalletConnection()
+{
+ m_instance = 0L;
+ slotWalletClosed();
+}
+
+void KFTPWalletConnection::slotWalletClosed()
+{
+ m_walletRefCount--;
+ if (m_walletRefCount == 0) {
+ delete m_wallet;
+ m_wallet = 0L;
+ }
+}
+
+QValueList<KURL> KFTPWalletConnection::getSiteList()
+{
+ QValueList<KURL> sites;
+
+ if (!KWallet::Wallet::folderDoesNotExist(KWallet::Wallet::NetworkWallet(), KWallet::Wallet::PasswordFolder())) {
+ if (!m_wallet) {
+ m_wallet = KWallet::Wallet::openWallet(KWallet::Wallet::NetworkWallet(), 0, KWallet::Wallet::Synchronous);
+
+ if (m_wallet) {
+ m_walletRefCount++;
+ connect(m_wallet, SIGNAL(walletClosed()), this, SLOT(slotWalletClosed()));
+ }
+ }
+
+ if (!m_wallet)
+ return QValueList<KURL>();
+
+ // Get the site list from our wallet
+ m_wallet->setFolder(KWallet::Wallet::PasswordFolder());
+
+ QStringList list = m_wallet->entryList();
+ QStringList::iterator i;
+
+ for (i = list.begin(); i != list.end(); ++i) {
+ QMap<QString, QString> map;
+
+ if ((*i).startsWith("ftp-") && m_wallet->readMap(*i, map) == 0) {
+ QString name = *i;
+ name.replace("ftp-", "ftp://");
+
+ KURL siteUrl(name);
+ siteUrl.setUser(map["login"]);
+ siteUrl.setPass(map["password"]);
+
+ if (siteUrl.port() == 0)
+ siteUrl.setPort(21);
+
+ if (sites.contains(siteUrl) == 0)
+ sites.append(siteUrl);
+ }
+ }
+ }
+
+ return sites;
+}
+
+QString KFTPWalletConnection::getPassword(const QString &whatFor)
+{
+ if (!KWallet::Wallet::folderDoesNotExist(KWallet::Wallet::NetworkWallet(), QString::fromLatin1("KFTPGrabber"))) {
+ // We have our own folder
+ if (!m_wallet) {
+ m_wallet = KWallet::Wallet::openWallet(KWallet::Wallet::NetworkWallet(), 0, KWallet::Wallet::Synchronous);
+
+ if (m_wallet) {
+ m_walletRefCount++;
+ connect(m_wallet, SIGNAL(walletClosed()), this, SLOT(slotWalletClosed()));
+ }
+ }
+
+ // Try to read the password from the wallet
+ QString pass;
+ if (m_wallet && m_wallet->setFolder(QString::fromLatin1("KFTPGrabber")) && m_wallet->readPassword(whatFor, pass) == 0) {
+ return pass;
+ }
+ }
+
+ return QString::null;
+}
+
+void KFTPWalletConnection::setPassword(const QString &whatFor, const QString &password)
+{
+ if (KWallet::Wallet::isEnabled()) {
+ if (!m_wallet) {
+ m_wallet = KWallet::Wallet::openWallet(KWallet::Wallet::NetworkWallet(), 0, KWallet::Wallet::Synchronous);
+
+ if (m_wallet) {
+ m_walletRefCount++;
+ connect(m_wallet, SIGNAL(walletClosed()), this, SLOT(slotWalletClosed()));
+ }
+ }
+
+ if (m_wallet) {
+ // Create our folder
+ if (!m_wallet->hasFolder(QString::fromLatin1("KFTPGrabber"))) {
+ m_wallet->createFolder(QString::fromLatin1("KFTPGrabber"));
+ }
+
+ m_wallet->setFolder(QString::fromLatin1("KFTPGrabber"));
+ m_wallet->writePassword(whatFor, password);
+ }
+ }
+}
+
+#include "kftpwalletconnection.moc"
diff --git a/kftpgrabber/src/misc/kftpwalletconnection.h b/kftpgrabber/src/misc/kftpwalletconnection.h
new file mode 100644
index 0000000..782d0d3
--- /dev/null
+++ b/kftpgrabber/src/misc/kftpwalletconnection.h
@@ -0,0 +1,68 @@
+/*
+ * This file is part of the KFTPGrabber project
+ *
+ * Copyright (C) 2003-2004 by the KFTPGrabber developers
+ * Copyright (C) 2003-2004 Jernej Kos <kostko@jweb-network.net>
+ *
+ * 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
+ * is provided AS IS, WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, and
+ * NON-INFRINGEMENT. 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 Steet, Fifth Floor, Boston,
+ * MA 02110-1301, USA.
+ *
+ * In addition, as a special exception, the copyright holders give
+ * permission to link the code of portions of this program with the
+ * OpenSSL library under certain conditions as described in each
+ * individual source file, and distribute linked combinations
+ * including the two.
+ * You must obey the GNU General Public License in all respects
+ * for all of the code used other than OpenSSL. If you modify
+ * file(s) with this exception, you may extend this exception to your
+ * version of the file(s), but you are not obligated to do so. If you
+ * do not wish to do so, delete this exception statement from your
+ * version. If you delete this exception statement from all source
+ * files in the program, then also delete it here.
+ */
+
+#ifndef KFTPWALLETCONNECTION_H
+#define KFTPWALLETCONNECTION_H
+
+#include <kwallet.h>
+#include <qobject.h>
+
+/**
+Enables communication of KFTPGrabber with KDE's wallet system (KWallet)
+
+@author Jernej Kos
+*/
+class KFTPWalletConnection : public QObject
+{
+Q_OBJECT
+public:
+ KFTPWalletConnection();
+ ~KFTPWalletConnection();
+
+ QValueList<KURL> getSiteList();
+
+ QString getPassword(const QString &whatFor);
+ void setPassword(const QString &whatFor, const QString &password);
+
+ static KFTPWalletConnection *getInstance();
+private:
+ static KFTPWalletConnection *m_instance;
+ KWallet::Wallet *m_wallet;
+ uint m_walletRefCount;
+private slots:
+ void slotWalletClosed();
+};
+
+#endif
diff --git a/kftpgrabber/src/misc/kftpzeroconf.cpp b/kftpgrabber/src/misc/kftpzeroconf.cpp
new file mode 100644
index 0000000..39d1f63
--- /dev/null
+++ b/kftpgrabber/src/misc/kftpzeroconf.cpp
@@ -0,0 +1,67 @@
+/*
+ * This file is part of the KFTPGrabber project
+ *
+ * Copyright (C) 2003-2005 by the KFTPGrabber developers
+ * Copyright (C) 2003-2005 Jernej Kos <kostko@jweb-network.net>
+ *
+ * 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
+ * is provided AS IS, WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, and
+ * NON-INFRINGEMENT. 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 Steet, Fifth Floor, Boston,
+ * MA 02110-1301, USA.
+ *
+ * In addition, as a special exception, the copyright holders give
+ * permission to link the code of portions of this program with the
+ * OpenSSL library under certain conditions as described in each
+ * individual source file, and distribute linked combinations
+ * including the two.
+ *
+ * You must obey the GNU General Public License in all respects
+ * for all of the code used other than OpenSSL. If you modify
+ * file(s) with this exception, you may extend this exception to your
+ * version of the file(s), but you are not obligated to do so. If you
+ * do not wish to do so, delete this exception statement from your
+ * version. If you delete this exception statement from all source
+ * files in the program, then also delete it here.
+ */
+#include "kftpzeroconf.h"
+
+KFTPZeroConf::KFTPZeroConf(QObject *parent, const char *name)
+ : QObject(parent, name)
+{
+#if KDE_IS_VERSION(3,4,0)
+ m_browser = new DNSSD::ServiceBrowser("_ftp._tcp", 0, true);
+
+ connect(m_browser, SIGNAL(finished()), this, SLOT(slotServiceChanged()));
+
+ m_browser->startBrowse();
+#endif
+}
+
+
+KFTPZeroConf::~KFTPZeroConf()
+{
+}
+
+#if KDE_IS_VERSION(3,4,0)
+const QValueList<DNSSD::RemoteService::Ptr> &KFTPZeroConf::getServiceList() const
+{
+ return m_browser->services();
+}
+#endif
+
+void KFTPZeroConf::slotServiceChanged()
+{
+ emit servicesUpdated();
+}
+
+#include "kftpzeroconf.moc"
diff --git a/kftpgrabber/src/misc/kftpzeroconf.h b/kftpgrabber/src/misc/kftpzeroconf.h
new file mode 100644
index 0000000..68c9ca2
--- /dev/null
+++ b/kftpgrabber/src/misc/kftpzeroconf.h
@@ -0,0 +1,70 @@
+/*
+ * This file is part of the KFTPGrabber project
+ *
+ * Copyright (C) 2003-2005 by the KFTPGrabber developers
+ * Copyright (C) 2003-2005 Jernej Kos <kostko@jweb-network.net>
+ *
+ * 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
+ * is provided AS IS, WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, and
+ * NON-INFRINGEMENT. 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 Steet, Fifth Floor, Boston,
+ * MA 02110-1301, USA.
+ *
+ * In addition, as a special exception, the copyright holders give
+ * permission to link the code of portions of this program with the
+ * OpenSSL library under certain conditions as described in each
+ * individual source file, and distribute linked combinations
+ * including the two.
+ *
+ * You must obey the GNU General Public License in all respects
+ * for all of the code used other than OpenSSL. If you modify
+ * file(s) with this exception, you may extend this exception to your
+ * version of the file(s), but you are not obligated to do so. If you
+ * do not wish to do so, delete this exception statement from your
+ * version. If you delete this exception statement from all source
+ * files in the program, then also delete it here.
+ */
+#ifndef KFTPZEROCONF_H
+#define KFTPZEROCONF_H
+
+#include <qobject.h>
+
+#include <kdeversion.h>
+
+#if KDE_IS_VERSION(3,4,0)
+#include <dnssd/servicebrowser.h>
+#endif
+
+/**
+ * This class provides an interface to KDNSSD (that is available from KDE 3.4).
+ *
+ * @author Jernej Kos
+ */
+class KFTPZeroConf : public QObject
+{
+Q_OBJECT
+public:
+ KFTPZeroConf(QObject *parent = 0, const char *name = 0);
+ ~KFTPZeroConf();
+
+#if KDE_IS_VERSION(3,4,0)
+ const QValueList<DNSSD::RemoteService::Ptr> &getServiceList() const;
+private:
+ DNSSD::ServiceBrowser *m_browser;
+#endif
+private slots:
+ void slotServiceChanged();
+signals:
+ void servicesUpdated();
+};
+
+#endif
diff --git a/kftpgrabber/src/misc/libs/Makefile.am b/kftpgrabber/src/misc/libs/Makefile.am
new file mode 100644
index 0000000..b4be6a2
--- /dev/null
+++ b/kftpgrabber/src/misc/libs/Makefile.am
@@ -0,0 +1,3 @@
+INCLUDES = $(all_includes)
+METASOURCES = AUTO
+SUBDIRS = ssh
diff --git a/kftpgrabber/src/misc/libs/ssh/Makefile.am b/kftpgrabber/src/misc/libs/ssh/Makefile.am
new file mode 100644
index 0000000..91a0031
--- /dev/null
+++ b/kftpgrabber/src/misc/libs/ssh/Makefile.am
@@ -0,0 +1,8 @@
+INCLUDES = $(all_includes)
+METASOURCES = AUTO
+noinst_LIBRARIES = libssh.a
+libssh_a_SOURCES = auth.c base64.c buffer.c channels.c client.c connect.c\
+ crypt.c dh.c error.c gzip.c kex.c keyfiles.c keys.c misc.c options.c\
+ packet.c sftp.c string.c wrapper.c
+noinst_HEADERS = crypto.h libssh.h sftp.h ssh2.h
+AM_CFLAGS = -w
diff --git a/kftpgrabber/src/misc/libs/ssh/auth.c b/kftpgrabber/src/misc/libs/ssh/auth.c
new file mode 100644
index 0000000..88ac7ec
--- /dev/null
+++ b/kftpgrabber/src/misc/libs/ssh/auth.c
@@ -0,0 +1,597 @@
+/* auth.c deals with authentication methods */
+/*
+Copyright 2003 Aris Adamantiadis
+
+This file is part of the SSH Library
+
+The SSH Library is free software; you can redistribute it and/or modify
+it under the terms of the GNU Lesser General Public License as published by
+the Free Software Foundation; either version 2.1 of the License, or (at your
+option) any later version.
+
+The SSH Library 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 Lesser General Public
+License for more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with the SSH Library; see the file COPYING. If not, write to
+the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor, Boston,
+MA 02110-1301, USA. */
+
+#include "priv.h"
+#include "ssh2.h"
+#include <string.h>
+#include <netdb.h>
+
+static int ask_userauth(SSH_SESSION *session){
+ if(session->auth_service_asked)
+ return 0;
+ else {
+ if(ssh_service_request(session,"ssh-userauth"))
+ return -1;
+ else
+ session->auth_service_asked++;
+ }
+ return 0;
+
+}
+
+static void burn(char *ptr){
+ if(ptr)
+ memset(ptr,'X',strlen(ptr));
+}
+
+static void string_burn(STRING *s){
+ memset(s->string,'X',string_len(s));
+}
+
+static int wait_auth_status(SSH_SESSION *session,int kbdint){
+ int err=SSH_AUTH_ERROR;
+ int cont=1;
+ STRING *can_continue;
+ u8 partial=0;
+ char *c_cont;
+ while(cont){
+ if(packet_read(session))
+ break;
+ if(packet_translate(session))
+ break;
+ switch(session->in_packet.type){
+ case SSH2_MSG_USERAUTH_FAILURE:
+ can_continue=buffer_get_ssh_string(session->in_buffer);
+ if(!can_continue || buffer_get_u8(session->in_buffer,&partial)!=1 ){
+ ssh_set_error(session,SSH_INVALID_DATA,"invalid SSH_MSG_USERAUTH_FAILURE message");
+ return SSH_AUTH_ERROR;
+ }
+ c_cont=string_to_char(can_continue);
+ if(partial){
+ err=SSH_AUTH_PARTIAL;
+ ssh_set_error(session,SSH_NO_ERROR,"partial success, authentications that can continue : %s",c_cont);
+ }
+ else {
+ err=SSH_AUTH_DENIED;
+ ssh_set_error(session,SSH_REQUEST_DENIED,"Access denied. authentications that can continue : %s",c_cont);
+ }
+ free(can_continue);
+ free(c_cont);
+ cont=0;
+ break;
+ case SSH2_MSG_USERAUTH_PK_OK:
+ /* SSH monkeys have defined the same number for both */
+ /* SSH_MSG_USERAUTH_PK_OK and SSH_MSG_USERAUTH_INFO_REQUEST */
+ /* which is not really smart; */
+ /*case SSH2_MSG_USERAUTH_INFO_REQUEST: */
+ if(kbdint){
+ err=SSH_AUTH_INFO;
+ cont=0;
+ break;
+ }
+ /* continue through success */
+ case SSH2_MSG_USERAUTH_SUCCESS:
+ err=SSH_AUTH_SUCCESS;
+ cont=0;
+ break;
+ case SSH2_MSG_USERAUTH_BANNER:
+ {
+ STRING *banner=buffer_get_ssh_string(session->in_buffer);
+ if(!banner){
+ ssh_say(1,"The banner message was invalid. continuing though\n");
+ break;
+ }
+ ssh_say(2,"Received a message banner\n");
+ if(session->banner)
+ free(session->banner); /* erase the older one */
+ session->banner=banner;
+ break;
+ }
+ default:
+ packet_parse(session);
+ break;
+ }
+ }
+ return err;
+}
+
+/* use the "none" authentication question */
+
+int ssh_userauth_none(SSH_SESSION *session,char *username){
+ STRING *user;
+ STRING *service;
+ STRING *method;
+ if(!username)
+ if(!(username=session->options->username)){
+ if(options_default_username(session->options))
+ return SSH_AUTH_ERROR;
+ else
+ username=session->options->username;
+ }
+ if(ask_userauth(session))
+ return SSH_AUTH_ERROR;
+ user=string_from_char(username);
+ method=string_from_char("none");
+ service=string_from_char("ssh-connection");
+ packet_clear_out(session);
+ buffer_add_u8(session->out_buffer,SSH2_MSG_USERAUTH_REQUEST);
+ buffer_add_ssh_string(session->out_buffer,user);
+ buffer_add_ssh_string(session->out_buffer,service);
+ buffer_add_ssh_string(session->out_buffer,method);
+ free(service);
+ free(method);
+ free(user);
+ packet_send(session);
+ return wait_auth_status(session,0);
+}
+
+int ssh_userauth_offer_pubkey(SSH_SESSION *session, char *username,int type, STRING *publickey){
+ STRING *user;
+ STRING *service;
+ STRING *method;
+ STRING *algo;
+ int err=SSH_AUTH_ERROR;
+ if(!username)
+ if(!(username=session->options->username)){
+ if(options_default_username(session->options))
+ return SSH_AUTH_ERROR;
+ else
+ username=session->options->username;
+ }
+ if(ask_userauth(session))
+ return SSH_AUTH_ERROR;
+ user=string_from_char(username);
+ service=string_from_char("ssh-connection");
+ method=string_from_char("publickey");
+ algo=string_from_char(ssh_type_to_char(type));
+
+ packet_clear_out(session);
+ buffer_add_u8(session->out_buffer,SSH2_MSG_USERAUTH_REQUEST);
+ buffer_add_ssh_string(session->out_buffer,user);
+ buffer_add_ssh_string(session->out_buffer,service);
+ buffer_add_ssh_string(session->out_buffer,method);
+ buffer_add_u8(session->out_buffer,0);
+ buffer_add_ssh_string(session->out_buffer,algo);
+ buffer_add_ssh_string(session->out_buffer,publickey);
+ packet_send(session);
+ err=wait_auth_status(session,0);
+ free(user);
+ free(method);
+ free(service);
+ free(algo);
+ return err;
+}
+
+int ssh_userauth_pubkey(SSH_SESSION *session, char *username, STRING *publickey, PRIVATE_KEY *privatekey){
+ STRING *user;
+ STRING *service;
+ STRING *method;
+ STRING *algo;
+ STRING *sign;
+ int err=SSH_AUTH_ERROR;
+ if(!username)
+ if(!(username=session->options->username)){
+ if(options_default_username(session->options))
+ return err;
+ else
+ username=session->options->username;
+ }
+ if(ask_userauth(session))
+ return err;
+ user=string_from_char(username);
+ service=string_from_char("ssh-connection");
+ method=string_from_char("publickey");
+ algo=string_from_char(ssh_type_to_char(privatekey->type));
+
+
+ /* we said previously the public key was accepted */
+ packet_clear_out(session);
+ buffer_add_u8(session->out_buffer,SSH2_MSG_USERAUTH_REQUEST);
+ buffer_add_ssh_string(session->out_buffer,user);
+ buffer_add_ssh_string(session->out_buffer,service);
+ buffer_add_ssh_string(session->out_buffer,method);
+ buffer_add_u8(session->out_buffer,1);
+ buffer_add_ssh_string(session->out_buffer,algo);
+ buffer_add_ssh_string(session->out_buffer,publickey);
+ sign=ssh_do_sign(session,session->out_buffer,privatekey);
+ if(sign){
+ buffer_add_ssh_string(session->out_buffer,sign);
+ free(sign);
+ packet_send(session);
+ err=wait_auth_status(session,0);
+ }
+ free(user);
+ free(service);
+ free(method);
+ free(algo);
+ return err;
+}
+
+int ssh_userauth_password(SSH_SESSION *session,char *username,char *password){
+ STRING *user;
+ STRING *service;
+ STRING *method;
+ STRING *password_s;
+ int err;
+ if(!username)
+ if(!(username=session->options->username)){
+ if(options_default_username(session->options))
+ return SSH_AUTH_ERROR;
+ else
+ username=session->options->username;
+ }
+ if(ask_userauth(session))
+ return SSH_AUTH_ERROR;
+ user=string_from_char(username);
+ service=string_from_char("ssh-connection");
+ method=string_from_char("password");
+ password_s=string_from_char(password);
+
+ packet_clear_out(session);
+ buffer_add_u8(session->out_buffer,SSH2_MSG_USERAUTH_REQUEST);
+ buffer_add_ssh_string(session->out_buffer,user);
+ buffer_add_ssh_string(session->out_buffer,service);
+ buffer_add_ssh_string(session->out_buffer,method);
+ buffer_add_u8(session->out_buffer,0);
+ buffer_add_ssh_string(session->out_buffer,password_s);
+ free(user);
+ free(service);
+ free(method);
+ memset(password_s,0,strlen(password)+4);
+ free(password_s);
+ packet_send(session);
+ err=wait_auth_status(session,0);
+ return err;
+}
+
+static char *keys_path[]={NULL,"%s/.ssh/identity","%s/.ssh/id_dsa","%s/.ssh/id_rsa",NULL};
+static char *pub_keys_path[]={NULL,"%s/.ssh/identity.pub","%s/.ssh/id_dsa.pub","%s/.ssh/id_rsa.pub",NULL};
+
+/* this function initialy was in the client */
+/* but the fools are the ones who never change mind */
+int ssh_userauth_autopubkey(SSH_SESSION *session, const char *passphrase){
+ int count=1; /* bypass identity */
+ int type=0;
+ int err;
+ STRING *pubkey;
+ char *privkeyfile=NULL;
+ PRIVATE_KEY *privkey;
+ char *id=NULL;
+ /* always testing none */
+ err=ssh_userauth_none(session,NULL);
+ if(err==SSH_AUTH_ERROR || err==SSH_AUTH_SUCCESS){
+ return err;
+ }
+ if(session->options->identity){
+ ssh_say(2,"Trying identity file %s\n",session->options->identity);
+ keys_path[0]=session->options->identity;
+ /* let's hope alloca exists */
+ id=malloc(strlen(session->options->identity)+1 + 4);
+ sprintf(id,"%s.pub",session->options->identity);
+ pub_keys_path[0]=id;
+ count =0;
+ }
+ while((pubkey=publickey_from_next_file(session,pub_keys_path,keys_path, &privkeyfile,&type,&count))){
+ err=ssh_userauth_offer_pubkey(session,NULL,type,pubkey);
+ if(err==SSH_AUTH_ERROR){
+ if(id){
+ pub_keys_path[0]=NULL;
+ keys_path[0]=NULL;
+ free(id);
+ }
+ free(pubkey);
+ return err;
+ } else
+ if(err != SSH_AUTH_SUCCESS){
+ ssh_say(2,"Public key refused by server\n");
+ free(pubkey);
+ continue;
+ }
+ /* pubkey accepted by server ! */
+ privkey=privatekey_from_file(session,privkeyfile,type,passphrase);
+ if (!privkey) {
+ free(pubkey);
+
+ if (passphrase == NULL) {
+ return -666;
+ }
+
+ ssh_say(0, "Private key decryption failed with the provided password (%s).\n", ssh_get_error(session));
+ continue;
+ }
+ err=ssh_userauth_pubkey(session,NULL,pubkey,privkey);
+ if(err==SSH_AUTH_ERROR){
+ if(id){
+ pub_keys_path[0]=NULL;
+ keys_path[0]=NULL;
+ free(id);
+ }
+ free(pubkey);
+ private_key_free(privkey);
+ return err;
+ } else
+ if(err != SSH_AUTH_SUCCESS){
+ ssh_say(0,"Weird : server accepted our public key but refused the signature\nit might be a bug of libssh\n");
+ free(pubkey);
+ private_key_free(privkey);
+ continue;
+ }
+ /* auth success */
+ ssh_say(1,"Authentication using %s success\n",privkeyfile);
+ free(pubkey);
+ private_key_free(privkey);
+ free(privkeyfile);
+ if(id){
+ pub_keys_path[0]=NULL;
+ keys_path[0]=NULL;
+ free(id);
+ }
+ return SSH_AUTH_SUCCESS;
+ }
+ ssh_say(1,"Tried every public key, none matched\n");
+ ssh_set_error(session,SSH_NO_ERROR,"no public key matched");
+ if(id){
+ pub_keys_path[0]=NULL;
+ keys_path[0]=NULL;
+ free(id);
+ }
+
+ return SSH_AUTH_DENIED;
+}
+
+static struct ssh_kbdint *kbdint_new(){
+ struct ssh_kbdint *kbd=malloc(sizeof (struct ssh_kbdint));
+ memset(kbd,0,sizeof(*kbd));
+ return kbd;
+}
+
+
+static void kbdint_free(struct ssh_kbdint *kbd){
+ int i,n=kbd->nprompts;
+ if(kbd->name)
+ free(kbd->name);
+ if(kbd->instruction)
+ free(kbd->instruction);
+ if(kbd->prompts){
+ for(i=0;i<n;++i){
+ burn(kbd->prompts[i]);
+ free(kbd->prompts[i]);
+ }
+ free(kbd->prompts);
+ }
+ if(kbd->answers){
+ for(i=0;i<n;++i){
+ burn(kbd->answers[i]);
+ free(kbd->answers[i]);
+ }
+ free(kbd->answers);
+ }
+ if(kbd->echo){
+ free(kbd->echo);
+ }
+ free(kbd);
+}
+
+static void kbdint_clean(struct ssh_kbdint *kbd){
+ int i,n=kbd->nprompts;
+ if(kbd->name){
+ free(kbd->name);
+ kbd->name=NULL;
+ }
+ if(kbd->instruction){
+ free(kbd->instruction);
+ kbd->instruction=NULL;
+ }
+ if(kbd->prompts){
+ for(i=0;i<n;++i){
+ burn(kbd->prompts[i]);
+ free(kbd->prompts[i]);
+ }
+ free(kbd->prompts);
+ kbd->prompts=NULL;
+ }
+ if(kbd->answers){
+ for(i=0;i<n;++i){
+ burn(kbd->answers[i]);
+ free(kbd->answers[i]);
+ }
+ free(kbd->answers);
+ kbd->answers=NULL;
+ }
+ if(kbd->echo){
+ free(kbd->echo);
+ kbd->echo=NULL;
+ }
+ kbd->nprompts=0;
+}
+
+/* this function sends the first packet as explained in section 3.1
+ * of the draft */
+static int kbdauth_init(SSH_SESSION *session,
+ char *user, char *submethods){
+ STRING *user_s=string_from_char(user);
+ STRING *submethods_s=(submethods ? string_from_char(submethods): string_from_char(""));
+ STRING *service=string_from_char("ssh-connection");
+ STRING *method=string_from_char("keyboard-interactive");
+ packet_clear_out(session);
+ buffer_add_u8(session->out_buffer,SSH2_MSG_USERAUTH_REQUEST);
+ buffer_add_ssh_string(session->out_buffer,user_s);
+ buffer_add_ssh_string(session->out_buffer,service);
+ buffer_add_ssh_string(session->out_buffer,method);
+ buffer_add_u32(session->out_buffer,0); /* language tag */
+ buffer_add_ssh_string(session->out_buffer,submethods_s);
+ free(user_s);
+ free(service);
+ free(method);
+ free(submethods_s);
+ if(packet_send(session))
+ return SSH_AUTH_ERROR;
+ return wait_auth_status(session,1);
+}
+
+static int kbdauth_info_get(SSH_SESSION *session){
+ STRING *name; /* name of the "asking" window showed to client */
+ STRING *instruction;
+ STRING *tmp;
+ u32 nprompts;
+ int i;
+ name=buffer_get_ssh_string(session->in_buffer);
+ instruction=buffer_get_ssh_string(session->in_buffer);
+ tmp=buffer_get_ssh_string(session->in_buffer);
+ buffer_get_u32(session->in_buffer,&nprompts);
+ if(!name || !instruction || !tmp){
+ if(name)
+ free(name);
+ if(instruction)
+ free(instruction);
+ /* tmp must be empty if we got here */
+ ssh_set_error(session,SSH_FATAL,"Invalid USERAUTH_INFO_REQUEST msg");
+ return SSH_AUTH_ERROR;
+ }
+ if(tmp)
+ free(tmp); /* no use */
+ if(!session->kbdint)
+ session->kbdint=kbdint_new();
+ else
+ kbdint_clean(session->kbdint);
+ session->kbdint->name=string_to_char(name);
+ free(name);
+ session->kbdint->instruction=string_to_char(instruction);
+ free(instruction);
+ nprompts=ntohl(nprompts);
+ if(nprompts>KBDINT_MAX_PROMPT){
+ ssh_set_error(session,SSH_FATAL,"Too much prompt asked from server: %lu(0x%.8lx)",nprompts,nprompts);
+ return SSH_AUTH_ERROR;
+ }
+ session->kbdint->nprompts=nprompts;
+ session->kbdint->prompts=malloc(nprompts*sizeof(char *));
+ memset(session->kbdint->prompts,0,nprompts*sizeof(char *));
+ session->kbdint->echo=malloc(nprompts);
+ memset(session->kbdint->echo,0,nprompts);
+ for(i=0;i<nprompts;++i){
+ tmp=buffer_get_ssh_string(session->in_buffer);
+ buffer_get_u8(session->in_buffer,&session->kbdint->echo[i]);
+ if(!tmp){
+ ssh_set_error(session,SSH_FATAL,"Short INFO_REQUEST packet");
+ return SSH_AUTH_ERROR;
+ }
+ session->kbdint->prompts[i]=string_to_char(tmp);
+ free(tmp);
+ }
+ return SSH_AUTH_INFO; /* we are not auth. but we parsed the packet */
+}
+
+/* sends challenge back to the server */
+static int kbdauth_send(SSH_SESSION *session) {
+ STRING *answer;
+ int i;
+ packet_clear_out(session);
+ buffer_add_u8(session->out_buffer,SSH2_MSG_USERAUTH_INFO_RESPONSE);
+ buffer_add_u32(session->out_buffer,htonl(session->kbdint->nprompts));
+ for(i=0;i<session->kbdint->nprompts;++i){
+ if(session->kbdint->answers[i])
+ answer=string_from_char(session->kbdint->answers[i]);
+ else
+ answer=string_from_char("");
+ buffer_add_ssh_string(session->out_buffer,answer);
+ string_burn(answer);
+ free(answer);
+ }
+ if(packet_send(session))
+ return SSH_AUTH_ERROR;
+ return wait_auth_status(session,1);
+}
+
+/* the heart of the whole keyboard interactive login */
+int ssh_userauth_kbdint(SSH_SESSION *session,char *user,char *submethods){
+ int err;
+ if( !session->kbdint){
+ /* first time we call. we must ask for a challenge */
+ if(!user)
+ if(!(user=session->options->username)){
+ if(options_default_username(session->options))
+ return SSH_AUTH_ERROR;
+ else
+ user=session->options->username;
+ }
+ if(ask_userauth(session))
+ return SSH_AUTH_ERROR;
+ err=kbdauth_init(session,user,submethods);
+ if(err!=SSH_AUTH_INFO)
+ return err; /* error or first try success */
+ err=kbdauth_info_get(session);
+ if(err==SSH_AUTH_ERROR){
+ kbdint_free(session->kbdint);
+ session->kbdint=NULL;
+ }
+ return err;
+ }
+ /* if we are at this point, it's because session->kbdint exists */
+ /* it means the user has set some informations there we need to send *
+ * the server. and then we need to ack the status (new questions or ok *
+ * pass in */
+ err=kbdauth_send(session);
+ kbdint_free(session->kbdint);
+ session->kbdint=NULL;
+ if(err!=SSH_AUTH_INFO)
+ return err;
+ err=kbdauth_info_get(session);
+ if(err==SSH_AUTH_ERROR){
+ kbdint_free(session->kbdint);
+ session->kbdint=NULL;
+ }
+ return err;
+}
+
+int ssh_userauth_kbdint_getnprompts(SSH_SESSION *session){
+ return session->kbdint->nprompts;
+}
+
+char *ssh_userauth_kbdint_getname(SSH_SESSION *session){
+ return session->kbdint->name;
+}
+
+char *ssh_userauth_kbdint_getinstruction(SSH_SESSION *session){
+ return session->kbdint->instruction;
+}
+
+char *ssh_userauth_kbdint_getprompt(SSH_SESSION *session, int i,
+ char *echo){
+ if(i > session->kbdint->nprompts)
+ return NULL;
+ if(echo)
+ *echo=session->kbdint->echo[i];
+ return session->kbdint->prompts[i];
+}
+
+void ssh_userauth_kbdint_setanswer(SSH_SESSION *session, unsigned int i, char *answer){
+ if (i>session->kbdint->nprompts)
+ return;
+ if(!session->kbdint->answers){
+ session->kbdint->answers=malloc(sizeof(char*)*session->kbdint->nprompts);
+ memset(session->kbdint->answers,0,sizeof(char *) * session->kbdint->nprompts);
+ }
+ if(session->kbdint->answers[i]){
+ burn(session->kbdint->answers[i]);
+ free(session->kbdint->answers[i]);
+ }
+ session->kbdint->answers[i]=strdup(answer);
+}
diff --git a/kftpgrabber/src/misc/libs/ssh/base64.c b/kftpgrabber/src/misc/libs/ssh/base64.c
new file mode 100644
index 0000000..19db420
--- /dev/null
+++ b/kftpgrabber/src/misc/libs/ssh/base64.c
@@ -0,0 +1,210 @@
+/* base64 contains the needed support for base64 alphabet system, */
+/* as described in RFC1521 */
+/*
+Copyright 2003,04 Aris Adamantiadis
+
+This file is part of the SSH Library
+
+The SSH Library is free software; you can redistribute it and/or modify
+it under the terms of the GNU Lesser General Public License as published by
+the Free Software Foundation; either version 2.1 of the License, or (at your
+option) any later version.
+
+The SSH Library 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 Lesser General Public
+License for more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with the SSH Library; see the file COPYING. If not, write to
+the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor, Boston,
+MA 02110-1301, USA. */
+
+/* just the dirtiest part of code i ever made */
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include "priv.h"
+static char alphabet[]="ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+ "abcdefghijklmnopqrstuvwxyz"
+ "0123456789+/" ;
+
+/* transformations */
+#define SET_A(n,i) do { n |= (i&63) <<18; } while (0)
+#define SET_B(n,i) do { n |= (i&63) <<12; } while (0)
+#define SET_C(n,i) do { n |= (i&63) << 6; } while (0)
+#define SET_D(n,i) do { n |= (i&63); } while (0)
+
+#define GET_A(n) ((n & 0xff0000) >> 16)
+#define GET_B(n) ((n & 0xff00) >> 8)
+#define GET_C(n) (n & 0xff)
+
+static int _base64_to_bin(unsigned char dest[3], char *source,int num);
+static int get_equals(char *string);
+
+/* first part : base 64 to binary */
+
+/* base64_to_bin translates a base64 string into a binary one. important, if something went wrong (ie incorrect char)*/
+/* it returns NULL */
+BUFFER *base64_to_bin(char *source){
+ int len;
+ int equals;
+ BUFFER *buffer=buffer_new();
+ unsigned char block[3];
+
+ /* get the number of equals signs, which mirrors the padding */
+ equals=get_equals(source);
+ if(equals>2){
+ buffer_free(buffer);
+ return NULL;
+ }
+
+ len=strlen(source);
+ while(len>4){
+ if(_base64_to_bin(block,source,3)){
+ buffer_free(buffer);
+ return NULL;
+ }
+ buffer_add_data(buffer,block,3);
+ len-=4;
+ source+=4;
+ }
+ /* depending of the number of bytes resting, there are 3 possibilities (from the rfc) */
+ switch(len){
+/* (1) the final quantum of encoding input is an integral
+ multiple of 24 bits; here, the final unit of encoded output will be
+ an integral multiple of 4 characters with no "=" padding */
+ case 4:
+ if(equals!=0){
+ buffer_free(buffer);
+ return NULL;
+ }
+ if(_base64_to_bin(block,source,3)){
+ buffer_free(buffer);
+ return NULL;
+ }
+ buffer_add_data(buffer,block,3);
+ return buffer;
+/*(2) the final quantum of encoding input is exactly 8 bits; here, the final
+ unit of encoded output will be two characters followed by two "="
+ padding characters */
+ case 2:
+ if(equals!=2){
+ buffer_free(buffer);
+ return NULL;
+ }
+ if(_base64_to_bin(block,source,1)){
+ buffer_free(buffer);
+ return NULL;
+ }
+ buffer_add_data(buffer,block,1);
+ return buffer;
+/* the final quantum of encoding input is
+ exactly 16 bits; here, the final unit of encoded output will be three
+ characters followed by one "=" padding character */
+ case 3:
+ if(equals!=1){
+ buffer_free(buffer);
+ return NULL;
+ }
+ if(_base64_to_bin(block,source,2)){
+ buffer_free(buffer);
+ return NULL;
+ }
+ buffer_add_data(buffer,block,2);
+ return buffer;
+ default:
+ /* 4,3,2 are the only padding size allowed */
+ buffer_free(buffer);
+ return NULL;
+ }
+ return NULL;
+}
+
+#define BLOCK(letter,n) do { ptr=strchr(alphabet,source[n]);\
+ if(!ptr) return -1;\
+ i=ptr-alphabet;\
+ SET_##letter(*block,i);\
+ } while(0)
+/* returns 0 if ok, -1 if not (ie invalid char into the stuff) */
+static int to_block4(unsigned long *block, char *source,int num){
+ char *ptr;
+ unsigned int i;
+ *block=0;
+ if(num<1)
+ return 0;
+ BLOCK(A,0); /* 6 bits */
+ BLOCK(B,1); /* 12 */
+ if(num<2)
+ return 0;
+ BLOCK(C,2); /* 18 */
+ if(num < 3)
+ return 0;
+ BLOCK(D,3); /* 24 */
+ return 0;
+}
+
+/* num = numbers of final bytes to be decoded */
+static int _base64_to_bin(unsigned char dest[3], char *source,int num){
+ unsigned long block;
+ if(to_block4(&block,source,num))
+ return -1;
+ dest[0]=GET_A(block);
+ dest[1]=GET_B(block);
+ dest[2]=GET_C(block);
+ return 0;
+}
+
+/* counts the number of "=" signs, and replace them by zeroes */
+static int get_equals(char *string){
+ char *ptr=string;
+ int num=0;
+ while((ptr=strchr(ptr,'='))){
+ num++;
+ *ptr=0;
+ ptr++;
+ }
+
+ return num;
+}
+
+/* thanks sysk for debugging my mess :) */
+#define BITS(n) ((1<<n)-1)
+static void _bin_to_base64(unsigned char *dest, unsigned char source[3], int len){
+ switch (len){
+ case 1:
+ dest[0]=alphabet[(source[0]>>2)];
+ dest[1]=alphabet[((source[0] & BITS(2)) << 4)];
+ dest[2]='=';
+ dest[3]='=';
+ break;
+ case 2:
+ dest[0]=alphabet[source[0]>>2];
+ dest[1]=alphabet[(source[1]>>4) | ((source[0] & BITS(2)) << 4)];
+ dest[2]=alphabet[(source[1]&BITS(4)) << 2];
+ dest[3]='=';
+ break;
+ case 3:
+ dest[0]=alphabet[(source[0]>>2)];
+ dest[1]=alphabet[(source[1]>>4) | ((source[0] & BITS(2)) << 4)];
+ dest[2]=alphabet[ (source[2] >> 6) | (source[1]&BITS(4)) << 2];
+ dest[3]=alphabet[source[2]&BITS(6)];
+ break;
+ }
+}
+
+char *bin_to_base64(unsigned char *source, int len){
+ int flen=len + (3 - (len %3)); /* round to upper 3 multiple */
+ char *buffer;
+ char *ptr;
+ flen=(4 * flen)/3 + 1 ;
+ ptr=buffer=malloc(flen);
+ while(len>0){
+ _bin_to_base64(ptr,source,len>3?3:len);
+ ptr+=4;
+ source +=3;
+ len -=3;
+ }
+ ptr[0]=0;
+ return buffer;
+}
diff --git a/kftpgrabber/src/misc/libs/ssh/buffer.c b/kftpgrabber/src/misc/libs/ssh/buffer.c
new file mode 100644
index 0000000..8d54e3c
--- /dev/null
+++ b/kftpgrabber/src/misc/libs/ssh/buffer.c
@@ -0,0 +1,161 @@
+/* buffer.c */
+/* Well, buffers */
+/*
+Copyright 2003 Aris Adamantiadis
+
+This file is part of the SSH Library
+
+The SSH Library is free software; you can redistribute it and/or modify
+it under the terms of the GNU Lesser General Public License as published by
+the Free Software Foundation; either version 2.1 of the License, or (at your
+option) any later version.
+
+The SSH Library 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 Lesser General Public
+License for more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with the SSH Library; see the file COPYING. If not, write to
+the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor, Boston,
+MA 02110-1301, USA. */
+
+#include <stdlib.h>
+#include <string.h>
+#include <netdb.h>
+#include "priv.h"
+BUFFER *buffer_new(){
+ BUFFER *buffer=malloc(sizeof(BUFFER));
+ memset(buffer,0,sizeof(BUFFER));
+ return buffer;
+ }
+
+void buffer_free(BUFFER *buffer){
+ if(buffer->data){
+ memset(buffer->data,0,buffer->allocated); /* burn the data */
+ free(buffer->data);
+ }
+ free(buffer);
+ }
+
+void buffer_reinit(BUFFER *buffer){
+ memset(buffer->data,0,buffer->used);
+ buffer->used=0;
+ buffer->pos=0;
+}
+
+static void realloc_buffer(BUFFER *buffer,int needed){
+ needed=(needed+0x7f) & ~0x7f;
+ buffer->data=realloc(buffer->data,needed);
+ buffer->allocated=needed;
+}
+
+void buffer_add_data(BUFFER *buffer,void *data,int len){
+ if(buffer->allocated < buffer->used+len)
+ realloc_buffer(buffer,buffer->used+len);
+ memcpy(buffer->data+buffer->used,data,len);
+ buffer->used+=len;
+ }
+
+void buffer_add_ssh_string(BUFFER *buffer,STRING *string){
+ u32 len=ntohl(string->size);
+ buffer_add_data(buffer,string,len+sizeof(u32));
+ }
+
+void buffer_add_u32(BUFFER *buffer,u32 data){
+ buffer_add_data(buffer,&data,sizeof(data));
+}
+
+void buffer_add_u64(BUFFER *buffer,u64 data){
+ buffer_add_data(buffer,&data,sizeof(data));
+}
+
+void buffer_add_u8(BUFFER *buffer,u8 data){
+ buffer_add_data(buffer,&data,sizeof(u8));
+}
+
+void buffer_add_data_begin(BUFFER *buffer, void *data, int len){
+ if(buffer->allocated < buffer->used + len)
+ realloc_buffer(buffer,buffer->used+len);
+ memmove(buffer->data+len,buffer->data,buffer->used);
+ memcpy(buffer->data,data,len);
+ buffer->used+=len;
+}
+
+void buffer_add_buffer(BUFFER *buffer, BUFFER *source){
+ buffer_add_data(buffer,buffer_get(source),buffer_get_len(source));
+}
+
+void *buffer_get(BUFFER *buffer){
+ return buffer->data;
+}
+
+void *buffer_get_rest(BUFFER *buffer){
+ return buffer->data+buffer->pos;
+}
+
+int buffer_get_len(BUFFER *buffer){
+ return buffer->used;
+}
+
+int buffer_get_rest_len(BUFFER *buffer){
+ return buffer->used - buffer->pos;
+}
+
+int buffer_pass_bytes(BUFFER *buffer,int len){
+ if(buffer->used < buffer->pos+len)
+ return 0;
+ buffer->pos+=len;
+ /* if the buffer is empty after having passed the whole bytes into it, we can clean it */
+ if(buffer->pos==buffer->used){
+ buffer->pos=0;
+ buffer->used=0;
+ }
+ return len;
+}
+
+int buffer_pass_bytes_end(BUFFER *buffer,int len){
+ if(buffer->used < buffer->pos + len)
+ return 0;
+ buffer->used-=len;
+ return len;
+}
+
+int buffer_get_data(BUFFER *buffer, void *data, int len){
+ if(buffer->pos+len>buffer->used)
+ return 0; /*no enough data in buffer */
+ memcpy(data,buffer->data+buffer->pos,len);
+ buffer->pos+=len;
+ return len; /* no yet support for partial reads (is it really needed ?? ) */
+}
+
+int buffer_get_u8(BUFFER *buffer, u8 *data){
+ return buffer_get_data(buffer,data,sizeof(u8));
+}
+
+int buffer_get_u32(BUFFER *buffer, u32 *data){
+ return buffer_get_data(buffer,data,sizeof(u32));
+}
+
+int buffer_get_u64(BUFFER *buffer, u64 *data){
+ return buffer_get_data(buffer,data,sizeof(u64));
+}
+
+STRING *buffer_get_ssh_string(BUFFER *buffer){
+ u32 stringlen;
+ u32 hostlen;
+ STRING *str;
+ if(buffer_get_u32(buffer,&stringlen)==0)
+ return NULL;
+ hostlen=ntohl(stringlen);
+ /* verify if there is enough space in buffer to get it */
+ if(buffer->pos+hostlen>buffer->used)
+ return 0; /* it is indeed */
+ str=string_new(hostlen);
+ if(buffer_get_data(buffer,str->string,hostlen)!=hostlen){
+ ssh_say(0,"buffer_get_ssh_string: oddish : second test failed when first was successful. len=%d",hostlen);
+ free(str);
+ return NULL;
+ }
+ return str;
+}
diff --git a/kftpgrabber/src/misc/libs/ssh/channels.c b/kftpgrabber/src/misc/libs/ssh/channels.c
new file mode 100644
index 0000000..9dd94d4
--- /dev/null
+++ b/kftpgrabber/src/misc/libs/ssh/channels.c
@@ -0,0 +1,691 @@
+/* channels.c */
+/* It has support for ... ssh channels */
+/*
+Copyright 2003 Aris Adamantiadis
+
+This file is part of the SSH Library
+
+The SSH Library is free software; you can redistribute it and/or modify
+it under the terms of the GNU Lesser General Public License as published by
+the Free Software Foundation; either version 2.1 of the License, or (at your
+option) any later version.
+
+The SSH Library 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 Lesser General Public
+License for more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with the SSH Library; see the file COPYING. If not, write to
+the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor, Boston,
+MA 02110-1301, USA. */
+
+#include <string.h>
+#include <stdlib.h>
+#include <netdb.h>
+#include <unistd.h>
+#include <stdio.h>
+
+#include "priv.h"
+#include "ssh2.h"
+#define WINDOWLIMIT 1024
+#define WINDOWBASE 32000
+static void channel_default_bufferize(CHANNEL *channel, void *data, int len, int is_stderr);
+static CHANNEL *new_channel(SSH_SESSION *session){
+ CHANNEL *channel=malloc(sizeof(CHANNEL));
+ memset(channel,0,sizeof(CHANNEL));
+ channel->session=session;
+ if(!session->channels){
+ session->channels=channel;
+ channel->next=channel->prev=channel;
+ return channel;
+ }
+ channel->next=session->channels;
+ channel->prev=session->channels->prev;
+ channel->next->prev=channel;
+ channel->prev->next=channel;
+ return channel;
+}
+
+static u32 channel_new_id(SSH_SESSION *session){
+ u32 ret=session->maxchannel;
+ session->maxchannel++;
+ return ret;
+}
+
+static CHANNEL *channel_open(SSH_SESSION *session,char *type_c,int window,
+int maxpacket,BUFFER *payload){
+ CHANNEL *channel=new_channel(session);
+ STRING *type=string_from_char(type_c);
+ u32 foo;
+ int err;
+ packet_clear_out(session);
+ buffer_add_u8(session->out_buffer,SSH2_MSG_CHANNEL_OPEN);
+ channel->local_channel=channel_new_id(session);
+ channel->local_maxpacket=maxpacket;
+ channel->local_window=window;
+ ssh_say(2,"creating a channel %d with %d window and %d max packet\n",channel->local_channel,
+ window,maxpacket);
+ buffer_add_ssh_string(session->out_buffer,type);
+ buffer_add_u32(session->out_buffer,htonl(channel->local_channel));
+ buffer_add_u32(session->out_buffer,htonl(channel->local_window));
+ buffer_add_u32(session->out_buffer,htonl(channel->local_maxpacket));
+ free(type);
+ if(payload)
+ buffer_add_buffer(session->out_buffer,payload);
+ packet_send(session);
+ ssh_say(2,"Sent a SSH_MSG_CHANNEL_OPEN type %s for channel %d\n",type_c,channel->local_channel);
+ err=packet_wait(session,SSH2_MSG_CHANNEL_OPEN_CONFIRMATION,1);
+ switch(session->in_packet.type){
+ case SSH2_MSG_CHANNEL_OPEN_CONFIRMATION:
+ buffer_get_u32(session->in_buffer,&foo);
+ if(channel->local_channel!=ntohl(foo)){
+ ssh_set_error(session,SSH_INVALID_DATA,"server answered with sender chan num %d instead of given %d",
+ ntohl(foo),channel->local_channel);
+ channel_free(channel);
+ return NULL;
+ }
+ buffer_get_u32(session->in_buffer,&foo);
+ channel->remote_channel=ntohl(foo);
+ buffer_get_u32(session->in_buffer,&foo);
+ channel->remote_window=ntohl(foo);
+ buffer_get_u32(session->in_buffer,&foo);
+ channel->remote_maxpacket=ntohl(foo);
+ ssh_say(3,"Received a CHANNEL_OPEN_CONFIRMATION for channel %d:%d\n",
+ channel->local_channel,channel->remote_channel);
+ ssh_say(3,"Remote window : %ld, maxpacket : %ld\n",
+ channel->remote_window, channel->remote_maxpacket);
+ channel->open=1;
+ return channel;
+ case SSH2_MSG_CHANNEL_OPEN_FAILURE:
+ {
+ u32 code;
+ STRING *error_s;
+ char *error;
+ buffer_get_u32(session->in_buffer,&foo);
+ buffer_get_u32(session->in_buffer,&code);
+ error_s=buffer_get_ssh_string(session->in_buffer);
+ error=string_to_char(error_s);
+ ssh_set_error(session,SSH_REQUEST_DENIED,"Channel opening failure : channel %d error (%d) %s",
+ channel->local_channel,ntohl(code),error);
+ free(error);
+ free(error_s);
+ channel_free(channel);
+ return NULL;
+ }
+ default:
+ ssh_say(0,"Received unknown packet %d\n",session->in_packet.type);
+ channel_free(channel);
+ return NULL;
+ }
+ return NULL;
+}
+
+static CHANNEL *find_local_channel(SSH_SESSION *session,u32 num){
+ /* we assume we are always the local */
+ CHANNEL *initchan,*channel;
+ initchan=session->channels;
+ if(!initchan)
+ return NULL;
+ for(channel=initchan;channel->local_channel!=num;channel=channel->next){
+ if(channel->next==initchan)
+ return NULL;
+ }
+ return channel;
+}
+
+static void grow_window(SSH_SESSION *session, CHANNEL *channel){
+ u32 new_window=WINDOWBASE;
+ packet_clear_out(session);
+ buffer_add_u8(session->out_buffer,SSH2_MSG_CHANNEL_WINDOW_ADJUST);
+ buffer_add_u32(session->out_buffer,htonl(channel->remote_channel));
+ buffer_add_u32(session->out_buffer,htonl(new_window));
+ packet_send(session);
+ ssh_say(3,"growing window (channel %d:%d) to %d bytes\n",
+ channel->local_channel,channel->remote_channel,
+ channel->local_window + new_window);
+ channel->local_window+=new_window;
+}
+
+static CHANNEL *channel_from_msg(SSH_SESSION *session){
+ u32 chan;
+ CHANNEL *channel;
+ if (buffer_get_u32(session->in_buffer,&chan)!=sizeof(u32)){
+ ssh_set_error(session,SSH_FATAL,"Getting channel from message : short read");
+ return NULL;
+ }
+ channel=find_local_channel(session,ntohl(chan));
+ if(!channel)
+ ssh_set_error(session,SSH_FATAL,"Server specified invalid channel %d",ntohl(chan));
+ return channel;
+}
+
+static void channel_rcv_change_window(SSH_SESSION *session){
+ u32 bytes;
+ CHANNEL *channel;
+ int err;
+ channel=channel_from_msg(session);
+ if(!channel)
+ ssh_say(0,"%s\n",ssh_get_error(session));
+ err = buffer_get_u32(session->in_buffer,&bytes);
+ if(!channel || err!= sizeof(u32)){
+ ssh_say(1,"Error getting a window adjust message : invalid packet\n");
+ return;
+ }
+ bytes=ntohl(bytes);
+ ssh_say(3,"Adding %d bytes to channel (%d:%d) (from %d bytes)\n",bytes,
+ channel->local_channel,channel->remote_channel,channel->remote_window);
+ channel->remote_window+=bytes;
+}
+
+/* is_stderr is set to 1 if the data are extended, ie stderr */
+static void channel_rcv_data(SSH_SESSION *session,int is_stderr){
+ STRING *str;
+ CHANNEL *channel;
+ channel=channel_from_msg(session);
+ if(!channel){
+ ssh_say(0,"%s",ssh_get_error(session));
+ return;
+ }
+ if(is_stderr){
+ u32 ignore;
+ /* uint32 data type code. we can ignore it */
+ buffer_get_u32(session->in_buffer,&ignore);
+ }
+ str=buffer_get_ssh_string(session->in_buffer);
+
+ if(!str){
+ ssh_say(0,"Invalid data packet !\n");
+ return;
+ }
+ ssh_say(3,"adding %d bytes data in %d\n",string_len(str),is_stderr);
+ /* what shall we do in this case ? let's accept it anyway */
+ if(string_len(str)>channel->local_window)
+ ssh_say(0,"Data packet too big for our window(%d vs %d)",string_len(str),channel->local_window);
+ if(!is_stderr){
+ /* stdout */
+ if(channel->write_fct){
+ channel->write_fct(channel,str->string,string_len(str),channel->userarg);
+ } else {
+ channel_default_bufferize(channel,str->string,string_len(str),is_stderr);
+ }
+ } else {
+ /* stderr */
+ if(channel->write_err_fct){
+ channel->write_err_fct(channel,str->string,string_len(str),channel->userarg);
+ } else {
+ channel_default_bufferize(channel,str->string,string_len(str),is_stderr);
+ }
+ }
+ if(string_len(str)>=channel->local_window)
+ channel->local_window-=string_len(str);
+ else
+ channel->local_window=0; /* buggy remote */
+ if(channel->local_window < WINDOWLIMIT)
+ grow_window(session,channel); /* i wonder if this is the correct place to do that */
+ free(str);
+}
+
+static void channel_rcv_eof(SSH_SESSION *session){
+ CHANNEL *channel;
+ channel=channel_from_msg(session);
+ if(!channel){
+ ssh_say(0,"%s\n",ssh_get_error(session));
+ return;
+ }
+ ssh_say(2,"Received eof on channel (%d:%d)\n",channel->local_channel,
+ channel->remote_channel);
+/* channel->remote_window=0; */
+ channel->remote_eof=1;
+}
+
+static void channel_rcv_close(SSH_SESSION *session){
+ CHANNEL *channel;
+ channel=channel_from_msg(session);
+ if(!channel){
+ ssh_say(0,"%s\n",ssh_get_error(session));
+ return;
+ }
+ ssh_say(2,"Received close on channel (%d:%d)\n",channel->local_channel,
+ channel->remote_channel);
+ channel->open=0;
+ if(!channel->remote_eof)
+ ssh_say(2,"Remote host not polite enough to send an eof before close\n");
+ channel->remote_eof=1;
+}
+
+static void channel_rcv_request(SSH_SESSION *session){
+ STRING *request_s;
+ char *request;
+ u32 status;
+ CHANNEL *channel=channel_from_msg(session);
+ if(!channel){
+ ssh_say(1,"%s\n",ssh_get_error(session));
+ return;
+ }
+ request_s=buffer_get_ssh_string(session->in_buffer);
+ if(!request_s){
+ ssh_say(0,"Invalid MSG_CHANNEL_REQUEST\n");
+ return;
+ }
+ buffer_get_u8(session->in_buffer,(u8 *)&status);
+ request=string_to_char(request_s);
+ if(!strcmp(request,"exit-status")){
+ buffer_get_u32(session->in_buffer,&status);
+ status=ntohl(status);
+/* XXX do something with status, we might need it */
+ free(request_s);
+ free(request);
+ return ;
+ }
+ if(!strcmp(request,"exit-signal")){
+ STRING *signal_s;
+ char *signal;
+ char *core="(core dumped)";
+ u8 i;
+ signal_s=buffer_get_ssh_string(session->in_buffer);
+ if(!signal_s){
+ ssh_say(0,"Invalid MSG_CHANNEL_REQUEST\n");
+ free(request_s);
+ free(request);
+ return;
+ }
+ signal=string_to_char(signal_s);
+ buffer_get_u8(session->in_buffer,&i);
+ if(!i)
+ core="";
+ ssh_say(0,"Remote connection closed by signal SIG%s %s\n",signal,core);
+ free(signal_s);
+ free(signal);
+ free(request_s);
+ free(request);
+ return;
+ }
+ ssh_say(0,"Unknown request %s\n",request);
+ free(request_s);
+ free(request);
+}
+
+/* channel_handle is called by wait_packet, ie, when there is channel informations to handle . */
+void channel_handle(SSH_SESSION *session, int type){
+ ssh_say(3,"Channel_handle(%d)\n",type);
+ switch(type){
+ case SSH2_MSG_CHANNEL_WINDOW_ADJUST:
+ channel_rcv_change_window(session);
+ break;
+ case SSH2_MSG_CHANNEL_DATA:
+ channel_rcv_data(session,0);
+ break;
+ case SSH2_MSG_CHANNEL_EXTENDED_DATA:
+ channel_rcv_data(session,1);
+ break;
+ case SSH2_MSG_CHANNEL_EOF:
+ channel_rcv_eof(session);
+ break;
+ case SSH2_MSG_CHANNEL_CLOSE:
+ channel_rcv_close(session);
+ break;
+ case SSH2_MSG_CHANNEL_REQUEST:
+ channel_rcv_request(session);
+ break;
+ default:
+ ssh_say(0,"Unexpected message %d\n",type);
+ }
+}
+
+/* when data has been received from the ssh server, it can be applied to the known
+ user function, with help of the callback, or inserted here */
+/* XXX is the window changed ? */
+static void channel_default_bufferize(CHANNEL *channel, void *data, int len, int is_stderr){
+ ssh_say(3,"placing %d bytes into channel buffer (stderr=%d)\n",len,is_stderr);
+ if(!is_stderr){
+ /* stdout */
+ if(!channel->stdout_buffer)
+ channel->stdout_buffer=buffer_new();
+ buffer_add_data(channel->stdout_buffer,data,len);
+ } else {
+ /* stderr */
+ if(!channel->stderr_buffer)
+ channel->stderr_buffer=buffer_new();
+ buffer_add_data(channel->stderr_buffer,data,len);
+ }
+}
+
+
+/* --8<-- PUBLIC INTERFACE BEGINS HERE -8<-----8< --- */
+
+/* deprecated */
+CHANNEL *open_session_channel(SSH_SESSION *session,int window,int maxpacket){
+ CHANNEL *chan=channel_open(session,"session",window,maxpacket,NULL);
+ return chan;
+}
+
+CHANNEL *channel_open_session(SSH_SESSION *session){
+ return open_session_channel(session,64000,32000);
+}
+
+/* tcpip forwarding */
+CHANNEL *channel_open_forward(SSH_SESSION *session,char *remotehost, int remoteport, char *sourcehost, int localport){
+ CHANNEL *chan;
+ BUFFER *payload=buffer_new();
+ STRING *str=string_from_char(remotehost);
+ buffer_add_ssh_string(payload,str);
+ free(str);
+ str=string_from_char(sourcehost);
+ buffer_add_u32(payload,htonl(remoteport));
+ buffer_add_ssh_string(payload,str);
+ free(str);
+ buffer_add_u32(payload,htonl(localport));
+ chan=channel_open(session,"direct-tcpip",64000,32000,payload);
+ buffer_free(payload);
+ return chan;
+}
+
+
+void channel_free(CHANNEL *channel){
+ SSH_SESSION *session=channel->session;
+ if(session->alive && channel->open)
+ channel_close(channel);
+ /* handle the "my channel is first on session list" case */
+ if(session->channels==channel)
+ session->channels=channel->next;
+ /* handle the "my channel is the only on session list" case */
+ if(channel->next == channel){
+ session->channels=NULL;
+ } else {
+ channel->prev->next=channel->next;
+ channel->next->prev=channel->prev;
+ }
+ if(channel->stdout_buffer)
+ buffer_free(channel->stdout_buffer);
+ if(channel->stderr_buffer)
+ buffer_free(channel->stderr_buffer);
+ /* debug trick to catch use after frees */
+ memset(channel,'X',sizeof(CHANNEL));
+ free(channel);
+}
+
+int channel_send_eof(CHANNEL *channel){
+ SSH_SESSION *session=channel->session;
+ int ret;
+ packet_clear_out(session);
+ buffer_add_u8(session->out_buffer,SSH2_MSG_CHANNEL_EOF);
+ buffer_add_u32(session->out_buffer,htonl(channel->remote_channel));
+ ret=packet_send(session);
+ ssh_say(1,"Sent a EOF on client channel (%d:%d)\n",channel->local_channel,
+ channel->remote_channel);
+ channel->local_eof=1;
+ return ret;
+}
+
+int channel_close(CHANNEL *channel){
+ SSH_SESSION *session=channel->session;
+ int ret=0;
+ if(!channel->local_eof)
+ ret=channel_send_eof(channel);
+ if(ret)
+ return ret;
+ packet_clear_out(session);
+ buffer_add_u8(session->out_buffer,SSH2_MSG_CHANNEL_CLOSE);
+ buffer_add_u32(session->out_buffer,htonl(channel->remote_channel));
+ ret=packet_send(session);
+ ssh_say(1,"Sent a close on client channel (%d:%d)\n",channel->local_channel,
+ channel->remote_channel);
+ if(!ret)
+ channel->open =0;
+ return ret;
+}
+
+/* Blocking write */
+/* The exact len is written */
+int channel_write(CHANNEL *channel ,void *data,int len){
+ SSH_SESSION *session=channel->session;
+ int effectivelen;
+ int origlen=len;
+ if(channel->local_eof){
+ ssh_set_error(session,SSH_REQUEST_DENIED,"Can't write to channel %d:%d"
+ " after EOF was sent",channel->local_channel,channel->remote_channel);
+ return -1;
+ }
+ while(len >0){
+ if(channel->remote_window<len){
+ ssh_say(2,"Remote window is %d bytes. going to write %d bytes\n",
+ channel->remote_window,len);
+ ssh_say(2,"Waiting for a growing window message...\n");
+ /* wonder what happens when the channel window is zero */
+ while(channel->remote_window==0){
+ /* parse every incoming packet */
+ packet_wait(channel->session,0,0);
+ }
+ effectivelen=len>channel->remote_window?channel->remote_window:len;
+ } else
+ effectivelen=len;
+ packet_clear_out(session);
+ buffer_add_u8(session->out_buffer,SSH2_MSG_CHANNEL_DATA);
+ buffer_add_u32(session->out_buffer,htonl(channel->remote_channel));
+ buffer_add_u32(session->out_buffer,htonl(effectivelen));
+ buffer_add_data(session->out_buffer,data,effectivelen);
+ packet_send(session);
+ ssh_say(2,"channel_write wrote %d bytes\n",effectivelen);
+ channel->remote_window-=effectivelen;
+ len -= effectivelen;
+ data+=effectivelen;
+ }
+ return origlen;
+}
+
+int channel_is_open(CHANNEL *channel){
+ return (channel->open!=0);
+}
+
+
+static int channel_request(CHANNEL *channel,char *request, BUFFER *buffer,int reply){
+ STRING *request_s=string_from_char(request);
+ SSH_SESSION *session=channel->session;
+ int err;
+ packet_clear_out(session);
+ buffer_add_u8(session->out_buffer,SSH2_MSG_CHANNEL_REQUEST);
+ buffer_add_u32(session->out_buffer,htonl(channel->remote_channel));
+ buffer_add_ssh_string(session->out_buffer,request_s);
+ buffer_add_u8(session->out_buffer,reply?1:0);
+ if(buffer)
+ buffer_add_data(session->out_buffer,buffer_get(buffer),buffer_get_len(buffer));
+ packet_send(session);
+ ssh_say(3,"Sent a SSH_MSG_CHANNEL_REQUEST %s\n",request);
+ free(request_s);
+ if(!reply)
+ return 0;
+ err=packet_wait(session,SSH2_MSG_CHANNEL_SUCCESS,1);
+ if(err)
+ if(session->in_packet.type==SSH2_MSG_CHANNEL_FAILURE){
+ ssh_say(2,"%s channel request failed\n",request);
+ ssh_set_error(session,SSH_REQUEST_DENIED,"Channel request %s failed",request);
+ }
+ else
+ ssh_say(3,"Received an unexpected %d message\n",session->in_packet.type);
+ else
+ ssh_say(3,"Received a SUCCESS\n");
+ return err;
+}
+
+int channel_request_pty_size(CHANNEL *channel, char *terminal, int col, int row){
+ STRING *term=string_from_char(terminal);
+ BUFFER *buffer=buffer_new();
+ int err;
+ buffer_add_ssh_string(buffer,term);
+ buffer_add_u32(buffer,htonl(col));
+ buffer_add_u32(buffer,htonl(row));
+ buffer_add_u32(buffer,0);
+ buffer_add_u32(buffer,0);
+/* a 0byte string */
+ buffer_add_u32(buffer,htonl(1));
+ buffer_add_u8(buffer,0);
+ free(term);
+ err=channel_request(channel,"pty-req",buffer,1);
+ buffer_free(buffer);
+ return err;
+}
+
+int channel_request_pty(CHANNEL *channel){
+ return channel_request_pty_size(channel,"xterm",80,24);
+}
+
+int channel_change_pty_size(CHANNEL *channel,int cols,int rows){
+ BUFFER *buffer=buffer_new();
+ int err;
+ /*buffer_add_u8(buffer,0);*/
+ buffer_add_u32(buffer,htonl(cols));
+ buffer_add_u32(buffer,htonl(rows));
+ buffer_add_u32(buffer,0);
+ buffer_add_u32(buffer,0);
+ err=channel_request(channel,"window-change",buffer,0);
+ buffer_free(buffer);
+ return err;
+}
+
+int channel_request_shell(CHANNEL *channel){
+ int err=channel_request(channel,"shell",NULL,1);
+ return err;
+}
+
+int channel_request_subsystem(CHANNEL *channel, char *system){
+ BUFFER* buffer=buffer_new();
+ int ret;
+ STRING *subsystem=string_from_char(system);
+ buffer_add_ssh_string(buffer,subsystem);
+ free(subsystem);
+ ret=channel_request(channel,"subsystem",buffer,1);
+ buffer_free(buffer);
+ return ret;
+}
+
+int channel_request_sftp( CHANNEL *channel){
+ return channel_request_subsystem(channel, "sftp");
+}
+
+
+int channel_request_env(CHANNEL *channel,char *name, char *value){
+ BUFFER *buffer=buffer_new();
+ int ret;
+ STRING *string=string_from_char(name);
+ buffer_add_ssh_string(buffer,string);
+ free(string);
+ string=string_from_char(value);
+ buffer_add_ssh_string(buffer,string);
+ free(string);
+ ret=channel_request(channel,"env",buffer,1);
+ buffer_free(buffer);
+ return ret;
+}
+
+int channel_request_exec(CHANNEL *channel, char *cmd){
+ BUFFER *buffer=buffer_new();
+ int ret;
+ STRING *command=string_from_char(cmd);
+ buffer_add_ssh_string(buffer,command);
+ free(command);
+ ret=channel_request(channel,"exec",buffer,1);
+ buffer_free(buffer);
+ return ret;
+}
+
+int channel_set_write_handler(CHANNEL *chan,
+ void (*write_fct)(CHANNEL *channel, void *data, int len, void *userdefined),void *user){
+ chan->write_fct=write_fct;
+ chan->userarg=user;
+ return 0;
+}
+
+int channel_set_stderr_write_handler(CHANNEL *chan,
+ void (*write_err_fct)(CHANNEL *channel, void *data, int len, void *userdefined),void *user){
+ chan->write_err_fct=write_err_fct;
+ chan->userarg=user;
+ return 0;
+}
+
+
+/* reads into a channel and put result into buffer */
+/* returns number of bytes read, 0 if eof or such and -1 in case of error */
+/* if bytes != 0, the exact number of bytes are going to be read */
+int channel_read(CHANNEL *channel, BUFFER *buffer,int bytes,int is_stderr){
+ BUFFER *stdbuf=NULL;
+ int len;
+ buffer_reinit(buffer);
+ /* maybe i should always set a buffer to avoid races between channel_default_bufferize and channel_read */
+ if(channel->write_fct){
+ ssh_set_error(channel->session,SSH_INVALID_REQUEST,"Specified channel hasn't got a default buffering system\n");
+ return -1;
+ }
+ if(is_stderr){
+ if(!channel->stderr_buffer)
+ channel->stderr_buffer=buffer_new();
+ stdbuf=channel->stderr_buffer;
+ } else {
+ if(!channel->stdout_buffer)
+ channel->stdout_buffer=buffer_new();
+ stdbuf=channel->stdout_buffer;
+ }
+ /* block reading if asked bytes=0 */
+ while((buffer_get_rest_len(stdbuf)==0) || (buffer_get_rest_len(stdbuf) < bytes)){
+ if(channel->remote_eof && buffer_get_rest_len(stdbuf)==0)
+ return 0;
+ if(channel->remote_eof)
+ break; /* return the resting bytes in buffer */
+ if(packet_read(channel->session)||packet_translate(channel->session))
+ return -1;
+ packet_parse(channel->session);
+ }
+
+ if(bytes==0){
+ /* write the ful buffer informations */
+ buffer_add_data(buffer,buffer_get_rest(stdbuf),buffer_get_rest_len(stdbuf));
+ buffer_reinit(stdbuf);
+ } else {
+ len=buffer_get_rest_len(stdbuf);
+ len= (len>bytes?bytes:len); /* read bytes bytes if len is greater, everything otherwise */
+ buffer_add_data(buffer,buffer_get_rest(stdbuf),len);
+ buffer_pass_bytes(stdbuf,len);
+ }
+ return buffer_get_len(buffer);
+}
+
+/* returns the number of bytes available, 0 if nothing is currently available, -1 if error */
+int channel_poll(CHANNEL *channel, int is_stderr){
+ BUFFER *buffer;
+ if(is_stderr){
+ buffer=channel->stderr_buffer;
+ if(!buffer)
+ buffer=channel->stderr_buffer=buffer_new();
+ } else {
+ buffer=channel->stdout_buffer;
+ if(!buffer)
+ buffer=channel->stdout_buffer=buffer_new();
+ }
+ while(buffer_get_len(buffer)==0){
+ if(ssh_fd_poll(channel->session)){
+ if(packet_read(channel->session)||packet_translate(channel->session))
+ return -1;
+ packet_parse(channel->session);
+ } else
+ return 0; /* nothing is available has said fd_poll */
+ }
+ return buffer_get_len(buffer);
+}
+
+/* nonblocking read on the specified channel. it will return <=len bytes of data read
+ atomicly. */
+int channel_read_nonblocking(CHANNEL *channel, char *dest, int len, int is_stderr){
+ int to_read=channel_poll(channel,is_stderr);
+ int lu;
+ BUFFER *buffer=buffer_new();
+ if(to_read<=0){
+ buffer_free(buffer);
+ return to_read; /* may be an error code */
+ }
+ if(to_read>len)
+ to_read=len;
+ lu=channel_read(channel,buffer,to_read,is_stderr);
+ memcpy(dest,buffer_get(buffer),lu>=0?lu:0);
+ buffer_free(buffer);
+ return lu;
+}
diff --git a/kftpgrabber/src/misc/libs/ssh/client.c b/kftpgrabber/src/misc/libs/ssh/client.c
new file mode 100644
index 0000000..a7a7569
--- /dev/null
+++ b/kftpgrabber/src/misc/libs/ssh/client.c
@@ -0,0 +1,261 @@
+/* client.c file */
+/*
+Copyright 2003 Aris Adamantiadis
+
+This file is part of the SSH Library
+
+The SSH Library is free software; you can redistribute it and/or modify
+it under the terms of the GNU Lesser General Public License as published by
+the Free Software Foundation; either version 2.1 of the License, or (at your
+option) any later version.
+
+The SSH Library 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 Lesser General Public
+License for more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with the SSH Library; see the file COPYING. If not, write to
+the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor, Boston,
+MA 02110-1301, USA. */
+
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <netdb.h>
+#include "priv.h"
+#include "ssh2.h"
+static void ssh_cleanup(SSH_SESSION *session);
+#define set_status(opt,status) do {\
+ if (opt->connect_status_function) \
+ opt->connect_status_function(opt->connect_status_arg, status); \
+ } while (0)
+/* simply gets a banner from a socket */
+char *ssh_get_banner(SSH_SESSION *session){
+ char buffer[128];
+ int i = 0;
+ while (i < 127) {
+ if(read(session->fd, &buffer[i], 1)<=0){
+ ssh_set_error(session,SSH_CONNECTION_LOST,"Remote host closed connection");
+ return NULL;
+ }
+ if (buffer[i] == '\r')
+ buffer[i] = 0;
+ if (buffer[i] == '\n') {
+ buffer[i] = 0;
+ return strdup(buffer);
+ }
+ i++;
+ }
+ ssh_set_error(NULL,SSH_FATAL,"Too large banner");
+ return NULL;
+}
+
+/* ssh_send_banner sends a SSH banner to the server */
+/* TODO select a banner compatible with server version */
+/* switch SSH1/1.5/2 */
+/* and quit when the server is SSH1 only */
+
+void ssh_send_banner(SSH_SESSION *session){
+ char *banner=CLIENTBANNER ;
+ char buffer[128];
+ if(session->options->clientbanner)
+ banner=session->options->clientbanner;
+ session->clientbanner=strdup(banner);
+ snprintf(buffer,128,"%s\r\n",session->clientbanner);
+ write(session->fd,buffer,strlen(buffer));
+}
+
+
+int dh_handshake(SSH_SESSION *session){
+ STRING *e,*f,*pubkey,*signature;
+ packet_clear_out(session);
+ buffer_add_u8(session->out_buffer,SSH2_MSG_KEXDH_INIT);
+ dh_generate_x(session);
+ dh_generate_e(session);
+ e=dh_get_e(session);
+ buffer_add_ssh_string(session->out_buffer,e);
+ packet_send(session);
+ free(e);
+ if(packet_wait(session,SSH2_MSG_KEXDH_REPLY,1))
+ return -1;
+ pubkey=buffer_get_ssh_string(session->in_buffer);
+ if(!pubkey){
+ ssh_set_error(NULL,SSH_FATAL,"No public key in packet");
+ return -1;
+ }
+ dh_import_pubkey(session,pubkey);
+ f=buffer_get_ssh_string(session->in_buffer);
+ if(!f){
+ ssh_set_error(NULL,SSH_FATAL,"No F number in packet");
+ return -1;
+ }
+ dh_import_f(session,f);
+ free(f);
+ if(!(signature=buffer_get_ssh_string(session->in_buffer))){
+ ssh_set_error(NULL,SSH_FATAL,"No signature in packet");
+ return -1;
+ }
+
+ dh_build_k(session);
+ packet_wait(session,SSH2_MSG_NEWKEYS,1);
+ ssh_say(2,"Got SSH_MSG_NEWKEYS\n");
+ packet_clear_out(session);
+ buffer_add_u8(session->out_buffer,SSH2_MSG_NEWKEYS);
+ packet_send(session);
+ ssh_say(2,"SSH_MSG_NEWKEYS sent\n");
+ make_sessionid(session);
+ /* set the cryptographic functions for the next crypto (it is needed for generate_session_keys for key lenghts) */
+ if(crypt_set_algorithms(session))
+ return -1;
+ generate_session_keys(session);
+ /* verify the host's signature. XXX do it sooner */
+ if(signature_verify(session,signature)){
+ free(signature);
+ return -1;
+ }
+ free(signature); /* forget it for now ... */
+ /* once we got SSH2_MSG_NEWKEYS we can switch next_crypto and current_crypto */
+ if(session->current_crypto)
+ crypto_free(session->current_crypto);
+ /* XXX later, include a function to change keys */
+ session->current_crypto=session->next_crypto;
+ session->next_crypto=crypto_new();
+ return 0;
+}
+
+int ssh_service_request(SSH_SESSION *session,char *service){
+ STRING *service_s;
+ packet_clear_out(session);
+ buffer_add_u8(session->out_buffer,SSH2_MSG_SERVICE_REQUEST);
+ service_s=string_from_char(service);
+ buffer_add_ssh_string(session->out_buffer,service_s);
+ free(service_s);
+ packet_send(session);
+ ssh_say(3,"Sent SSH_MSG_SERVICE_REQUEST (service %s)\n",service);
+ if(packet_wait(session,SSH2_MSG_SERVICE_ACCEPT,1)){
+ ssh_set_error(session,SSH_INVALID_DATA,"did not receive SERVICE_ACCEPT");
+ return -1;
+ }
+ ssh_say(3,"Received SSH_MSG_SERVICE_ACCEPT (service %s)\n",service);
+ return 0;
+}
+
+SSH_SESSION *ssh_connect(SSH_OPTIONS *options){
+ SSH_SESSION *session;
+ int fd;
+ if(!options){
+ ssh_set_error(NULL,SSH_FATAL,"Null argument given to ssh_connect !");
+ return NULL;
+ }
+ ssh_crypto_init();
+ if(options->fd==-1 && !options->host){
+ ssh_set_error(NULL,SSH_FATAL,"Hostname required");
+ return NULL;
+ }
+ if(options->fd != -1)
+ fd=options->fd;
+ else
+ fd=ssh_connect_host(options->host,options->bindaddr,options->port,
+ options->timeout,options->timeout_usec);
+ if(fd<0)
+ return NULL;
+ set_status(options,0.2);
+ session=ssh_session_new();
+ session->fd=fd;
+ session->alive=1;
+ session->options=options;
+ if(!(session->serverbanner=ssh_get_banner(session))){
+ ssh_cleanup(session);
+ return NULL;
+ }
+ set_status(options,0.4);
+ ssh_say(2,"banner : %s\n",session->serverbanner);
+ ssh_send_banner(session);
+ set_status(options,0.5);
+ if(ssh_get_kex(session,0)){
+ ssh_disconnect(session);
+ return NULL;
+ }
+ set_status(options,0.6);
+ list_kex(&session->server_kex);
+ if(set_kex(session)){
+ ssh_disconnect(session);
+ return NULL;
+ }
+ send_kex(session,0);
+ set_status(options,0.8);
+ if(dh_handshake(session)){
+ ssh_disconnect(session);
+ return NULL;
+ }
+ set_status(options,1.0);
+ session->connected=1;
+ return session;
+}
+
+static void ssh_cleanup(SSH_SESSION *session){
+ int i;
+ if(session->serverbanner)
+ free(session->serverbanner);
+ if(session->clientbanner)
+ free(session->clientbanner);
+ if(session->in_buffer)
+ buffer_free(session->in_buffer);
+ if(session->out_buffer)
+ buffer_free(session->out_buffer);
+ if(session->banner)
+ free(session->banner);
+ if(session->options)
+ options_free(session->options);
+ if(session->current_crypto)
+ crypto_free(session->current_crypto);
+ if(session->next_crypto)
+ crypto_free(session->next_crypto);
+
+ /* delete all channels */
+ while(session->channels)
+ channel_free(session->channels);
+ if(session->client_kex.methods)
+ for(i=0;i<10;i++)
+ if(session->client_kex.methods[i])
+ free(session->client_kex.methods[i]);
+ if(session->server_kex.methods)
+ for(i=0;i<10;++i)
+ if(session->server_kex.methods[i])
+ free(session->server_kex.methods[i]);
+ free(session->client_kex.methods);
+ free(session->server_kex.methods);
+ memset(session,'X',sizeof(SSH_SESSION)); /* burn connection, it could hangs sensitive datas */
+ free(session);
+}
+
+char *ssh_get_issue_banner(SSH_SESSION *session){
+ if(!session->banner)
+ return NULL;
+ return string_to_char(session->banner);
+}
+
+void ssh_disconnect(SSH_SESSION *session){
+ STRING *str;
+ if(session->fd!= -1) {
+ packet_clear_out(session);
+ buffer_add_u8(session->out_buffer,SSH2_MSG_DISCONNECT);
+ buffer_add_u32(session->out_buffer,htonl(SSH2_DISCONNECT_BY_APPLICATION));
+ str=string_from_char("Bye Bye");
+ buffer_add_ssh_string(session->out_buffer,str);
+ free(str);
+ packet_send(session);
+ close(session->fd);
+ session->fd=-1;
+ }
+ session->alive=0;
+ ssh_cleanup(session);
+}
+
+const char *ssh_copyright(){
+ return LIBSSH_VERSION " (c) 2003-2004 Aris Adamantiadis (aris@0xbadc0de.be)"
+ " Distributed under the LGPL, please refer to COPYING file for informations"
+ " about your rights" ;
+}
diff --git a/kftpgrabber/src/misc/libs/ssh/connect.c b/kftpgrabber/src/misc/libs/ssh/connect.c
new file mode 100644
index 0000000..ba117f2
--- /dev/null
+++ b/kftpgrabber/src/misc/libs/ssh/connect.c
@@ -0,0 +1,295 @@
+/* connect.c */
+/* it handles connections to ssh servers */
+/*
+Copyright 2003 Aris Adamantiadis
+
+This file is part of the SSH Library
+
+The SSH Library is free software; you can redistribute it and/or modify
+it under the terms of the GNU Lesser General Public License as published by
+the Free Software Foundation; either version 2.1 of the License, or (at your
+option) any later version.
+
+The SSH Library 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 Lesser General Public
+License for more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with the SSH Library; see the file COPYING. If not, write to
+the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor, Boston,
+MA 02110-1301, USA. */
+
+#include <netdb.h>
+#include <string.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/select.h>
+#include <sys/time.h>
+#include <netinet/in.h>
+#include <fcntl.h>
+#include "priv.h"
+#ifdef HAVE_SYS_POLL_H
+#include <sys/poll.h>
+#endif
+
+#ifndef HAVE_GETHOSTBYNAME
+#ifndef HAVE_GETHOSTBYADDR
+#error "your system doesn't have gethostbyname nor gethostbyaddr"
+#endif
+#endif
+#define FIRST_CHANNEL 42
+static void sock_set_nonblocking(int sock) {
+ fcntl(sock,F_SETFL,O_NONBLOCK);
+}
+static void sock_set_blocking(int sock){
+ fcntl(sock,F_SETFL,0);
+}
+
+/* connect_host connects to an IPv4 (or IPv6) host */
+/* specified by its IP address or hostname. */
+/* output is the file descriptor, <0 if failed. */
+
+int ssh_connect_host(const char *host, const char *bind_addr, int port,long timeout, long usec){
+ struct sockaddr_in sa;
+ struct sockaddr_in bindsa;
+ struct hostent *hp=NULL;
+ static int count=0; /* for reentrencity */
+ int s;
+ while(++count>1)
+ --count;
+#ifdef HAVE_GETHOSTBYADDR
+ hp=gethostbyaddr(host,4,AF_INET);
+#endif
+#ifdef HAVE_GETHOSTBYNAME
+ if(!hp)
+ hp=gethostbyname(host);
+#endif
+ if(!hp){
+ --count;
+ ssh_set_error(NULL,SSH_FATAL,"Failed to resolve hostname %s (%s)",host,hstrerror(h_errno));
+ return -1;
+ }
+ memset(&sa,0,sizeof(sa));
+ memcpy(&sa.sin_addr,hp->h_addr,hp->h_length);
+ sa.sin_family=hp->h_addrtype;
+ sa.sin_port=htons((unsigned short)port);
+ --count;
+
+ if(bind_addr){
+ ssh_say(2,"resolving %s\n",bind_addr);
+ hp=NULL;
+ while(++count>1)
+ --count;
+#ifdef HAVE_GETHOSTBYADDR
+ hp=gethostbyaddr(bind_addr,4,AF_INET);
+#endif
+#ifdef HAVE_GETHOSTBYNAME
+ if(!hp)
+ hp=gethostbyname(bind_addr);
+#endif
+ if(!hp){
+ --count;
+ ssh_set_error(NULL,SSH_FATAL,"Failed to resolve bind address %s (%s)",bind_addr,hstrerror(h_errno));
+ return -1;
+ }
+ }
+ memset(&bindsa,0,sizeof(bindsa));
+ /* create socket */
+ s=socket(sa.sin_family,SOCK_STREAM,0);
+ if(s<0){
+ if(bind_addr)
+ --count;
+ ssh_set_error(NULL,SSH_FATAL,"socket : %s",strerror(errno));
+ return s;
+ }
+
+ if(bind_addr){
+ memcpy(&bindsa.sin_addr,hp->h_addr,hp->h_length);
+ bindsa.sin_family=hp->h_addrtype;
+ --count;
+ if(bind(s,(struct sockaddr *)&bindsa,sizeof(bindsa))<0){
+ ssh_set_error(NULL,SSH_FATAL,"Binding local address : %s",strerror(errno));
+ close(s);
+ return -1;
+ }
+ }
+ if(timeout){
+ struct timeval to;
+ fd_set set;
+ int ret=0;
+ int len=sizeof(ret);
+ to.tv_sec=timeout;
+ to.tv_usec=usec;
+ sock_set_nonblocking(s);
+ connect(s,(struct sockaddr* )&sa,sizeof(sa));
+ FD_ZERO(&set);
+ FD_SET(s,&set);
+ ret=select(s+1,NULL,&set,NULL,&to);
+ if(ret==0){
+ /* timeout */
+ ssh_set_error(NULL,SSH_FATAL,"Timeout while connecting to %s:%d",host,port);
+ close(s);
+ return -1;
+ }
+ if(ret<0){
+ ssh_set_error(NULL,SSH_FATAL,"Select error : %s",strerror(errno));
+ close(s);
+ return -1;
+ }
+ /* get connect(2) return code. zero means no error */
+ getsockopt(s,SOL_SOCKET,SO_ERROR,&ret,&len);
+ if (ret!=0){
+ ssh_set_error(NULL,SSH_FATAL,"Connecting : %s",strerror(ret));
+ close(s);
+ return -1;
+ }
+ /* s is connected ? */
+ ssh_say(3,"socket connected with timeout\n");
+ sock_set_blocking(s);
+ return s;
+ }
+ if(connect(s,(struct sockaddr *)&sa,sizeof(sa))< 0){
+ close(s);
+ ssh_set_error(NULL,SSH_FATAL,"connect: %s",strerror(errno));
+ return -1;
+ }
+ return s;
+}
+
+/* connection_new() returns a newly allocated SSH_SESSION structure pointer */
+SSH_SESSION *ssh_session_new() {
+ SSH_SESSION *conn=malloc(sizeof (SSH_SESSION));
+ memset(conn,0,sizeof(SSH_SESSION));
+ conn->next_crypto=crypto_new();
+ conn->maxchannel=FIRST_CHANNEL;
+ return conn;
+}
+
+
+/* returns 1 if bytes are available on the stream, 0 instead */
+int ssh_fd_poll(SSH_SESSION *session){
+#ifdef HAVE_POLL
+ struct pollfd fdset;
+#else
+ struct timeval sometime;
+ fd_set descriptor;
+#endif
+ if(session->datatoread)
+ return(session->datatoread);
+#ifdef HAVE_POLL
+ fdset.fd=session->fd;
+ fdset.events=POLLHUP|POLLIN|POLLPRI;
+ fdset.revents=0;
+ if(poll(&fdset,1,0)==0)
+ return 0;
+ if(fdset.revents & (POLLHUP|POLLIN|POLLPRI))
+ return (session->datatoread=1);
+ return 0;
+#elif HAVE_SELECT
+
+ /* Set to return immediately (no blocking) */
+ sometime.tv_sec = 0;
+ sometime.tv_usec = 0;
+
+ /* Set up descriptor */
+ FD_ZERO(&descriptor);
+ FD_SET(session->fd, &descriptor);
+
+ /* Make the call, and listen for errors */
+ if (select(session->fd + 1, &descriptor, NULL, NULL, &sometime) < 0) {
+ ssh_set_error(NULL,SSH_FATAL, "select: %s", strerror(errno));
+ return -1;
+ }
+ session->datatoread=FD_ISSET(session->fd,&descriptor);
+ return session->datatoread;
+#else
+#error This system does not have poll() or select(), so ssh_fd_poll() will not work correctly
+ return 0;
+#endif
+}
+
+/* this function is a complete wrapper for the select syscall. it does more than wrapping ... */
+int ssh_select(CHANNEL **channels,CHANNEL **outchannels, int maxfd, fd_set *readfds, struct timeval *timeout){
+ struct timeval zerotime;
+ fd_set localset,localset2;
+ int rep;
+ int i,j;
+ int set;
+
+ zerotime.tv_sec=0;
+ zerotime.tv_usec=0;
+ /* first, poll the maxfd file descriptors from the user with a zero-second timeout. they have the bigger priority */
+ if(maxfd>0){
+ memcpy(&localset,readfds, sizeof(fd_set));
+ rep=select(maxfd,&localset,NULL,NULL,&zerotime);
+ /* catch the eventual errors */
+ if(rep==-1)
+ return -1;
+ }
+ j=0;
+ /* polls every channel. */
+ for(i=0;channels[i];i++){
+ if(channel_poll(channels[i],0)>0){
+ outchannels[j]=channels[i];
+ j++;
+ } else
+ if(channel_poll(channels[i],1)>0){
+ outchannels[j]=channels[i];
+ j++;
+ }
+ }
+ outchannels[j]=NULL;
+ /* look into the localset for active fd */
+ set=0;
+ for(i=0;(i<maxfd) && !set;i++)
+ if(FD_ISSET(i,&localset))
+ set=1;
+ /* j!=0 means a channel has data */
+ if( (j!=0) || (set!=0)){
+ if(maxfd>0)
+ memcpy(readfds,&localset,sizeof(fd_set));
+ return 0;
+ }
+ /* at this point, not any channel had any data ready for reading, nor any fd had data for reading */
+ memcpy(&localset,readfds,sizeof(fd_set));
+ for(i=0;channels[i];i++){
+ if(channels[i]->session->alive){
+ FD_SET(channels[i]->session->fd,&localset);
+ if(channels[i]->session->fd>maxfd-1)
+ maxfd=channels[i]->session->fd+1;
+ }
+ }
+ do {
+ rep=select(maxfd,&localset,NULL,NULL,timeout);
+ } while (rep==-1 && errno==EINTR);
+ if(rep==-1){
+ /* was the error due to a libssh's Channel or from a closed descriptor from the user ? user closed descriptors have been
+ caught in the first select and not closed since that moment. that case shouldn't occur at all */
+ return -1;
+ }
+ /* set the data_to_read flag on each session */
+ for(i=0;channels[i];i++)
+ if(FD_ISSET(channels[i]->session->fd,&localset))
+ channels[i]->session->datatoread=1;
+
+ /* now, test each channel */
+ j=0;
+ for(i=0;channels[i];i++){
+ if(FD_ISSET(channels[i]->session->fd,&localset))
+ if((channel_poll(channels[i],0)>0) || (channel_poll(channels[i],1)>0)){
+ outchannels[j]=channels[i];
+ j++;
+ }
+ }
+ outchannels[j]=NULL;
+ FD_ZERO(&localset2);
+ for(i=0;i<maxfd;i++)
+ if(FD_ISSET(i,readfds) && FD_ISSET(i,&localset))
+ FD_SET(i,&localset2);
+ memcpy(readfds,&localset2,sizeof(fd_set));
+ return 0;
+}
diff --git a/kftpgrabber/src/misc/libs/ssh/crypt.c b/kftpgrabber/src/misc/libs/ssh/crypt.c
new file mode 100644
index 0000000..312c411
--- /dev/null
+++ b/kftpgrabber/src/misc/libs/ssh/crypt.c
@@ -0,0 +1,100 @@
+/* crypt.c */
+/* it just contains the shit necessary to make blowfish-cbc work ... */
+/*
+Copyright 2003 Aris Adamantiadis
+
+This file is part of the SSH Library
+
+The SSH Library is free software; you can redistribute it and/or modify
+it under the terms of the GNU Lesser General Public License as published by
+the Free Software Foundation; either version 2.1 of the License, or (at your
+option) any later version.
+
+The SSH Library 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 Lesser General Public
+License for more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with the SSH Library; see the file COPYING. If not, write to
+the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor, Boston,
+MA 02110-1301, USA. */
+
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <openssl/blowfish.h>
+#include <openssl/evp.h>
+#include <openssl/hmac.h>
+
+#include <netdb.h>
+#include "priv.h"
+#include "crypto.h"
+
+u32 packet_decrypt_len(SSH_SESSION *session, char *crypted){
+ u32 *decrypted;
+ if(session->current_crypto)
+ packet_decrypt(session,crypted,session->current_crypto->in_cipher->blocksize);
+ decrypted=(u32 *)crypted;
+ ssh_say(3,"size decrypted : %lx\n",ntohl(*decrypted));
+ return ntohl(*decrypted);
+}
+
+int packet_decrypt(SSH_SESSION *session, void *data,u32 len){
+ struct crypto_struct *crypto=session->current_crypto->in_cipher;
+ char *out=malloc(len);
+ ssh_say(3,"Decrypting %d bytes data\n",len);
+ crypto->set_decrypt_key(crypto,session->current_crypto->decryptkey);
+ crypto->cbc_decrypt(crypto,data,out,len,session->current_crypto->decryptIV);
+ memcpy(data,out,len);
+ memset(out,0,len);
+ free(out);
+ return 0;
+}
+
+char * packet_encrypt(SSH_SESSION *session,void *data,u32 len){
+ struct crypto_struct *crypto;
+ HMAC_CTX *ctx;
+ char *out;
+ int finallen;
+ u32 seq=ntohl(session->send_seq);
+ if(!session->current_crypto)
+ return NULL; /* nothing to do here */
+ crypto= session->current_crypto->out_cipher;
+ ssh_say(3,"seq num = %d, len = %d\n",session->send_seq,len);
+ crypto->set_encrypt_key(crypto,session->current_crypto->encryptkey);
+ out=malloc(len);
+ ctx=hmac_init(session->current_crypto->encryptMAC,20,HMAC_SHA1);
+ hmac_update(ctx,(unsigned char *)&seq,sizeof(u32));
+ hmac_update(ctx,data,len);
+ hmac_final(ctx,session->current_crypto->hmacbuf,&finallen);
+#ifdef DEBUG_CRYPTO
+ ssh_print_hexa("mac :",data,len);
+ if(finallen!=20)
+ printf("Final len is %d\n",finallen);
+ ssh_print_hexa("packet hmac",session->current_crypto->hmacbuf,20);
+#endif
+ crypto->cbc_encrypt(crypto,data,out,len,session->current_crypto->encryptIV);
+ memcpy(data,out,len);
+ memset(out,0,len);
+ free(out);
+ return session->current_crypto->hmacbuf;
+}
+
+int packet_hmac_verify(SSH_SESSION *session,BUFFER *buffer,char *mac){
+ HMAC_CTX *ctx;
+ unsigned char hmacbuf[EVP_MAX_MD_SIZE];
+ int len;
+ u32 seq=htonl(session->recv_seq);
+ ctx=hmac_init(session->current_crypto->decryptMAC,20,HMAC_SHA1);
+ hmac_update(ctx,(unsigned char *)&seq,sizeof(u32));
+ hmac_update(ctx,buffer_get(buffer),buffer_get_len(buffer));
+ hmac_final(ctx,hmacbuf,&len);
+#ifdef DEBUG_CRYPTO
+ ssh_print_hexa("received mac",mac,len);
+ ssh_print_hexa("Computed mac",hmacbuf,len);
+ ssh_print_hexa("seq",(unsigned char *)&seq,sizeof(u32));
+#endif
+ return memcmp(mac,hmacbuf,len);
+}
diff --git a/kftpgrabber/src/misc/libs/ssh/crypto.h b/kftpgrabber/src/misc/libs/ssh/crypto.h
new file mode 100644
index 0000000..83061e4
--- /dev/null
+++ b/kftpgrabber/src/misc/libs/ssh/crypto.h
@@ -0,0 +1,47 @@
+/*
+Copyright 2003 Aris Adamantiadis
+
+This file is part of the SSH Library
+
+The SSH Library is free software; you can redistribute it and/or modify
+it under the terms of the GNU Lesser General Public License as published by
+the Free Software Foundation; either version 2.1 of the License, or (at your
+option) any later version.
+
+The SSH Library 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 Lesser General Public
+License for more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with the SSH Library; see the file COPYING. If not, write to
+the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor, Boston,
+MA 02110-1301, USA. */
+
+/* Crypto.h is an include file for internal structures of libssh */
+/* It hasn't to be into the final development set of files (and btw the filename would cause problems on most systems) */
+/* Openssl has (really) stupid defines */
+#ifdef set_key
+#undef set_key
+#endif
+#ifdef cbc_encrypt
+#undef cbc_encrypt
+#endif
+#ifdef cbc_decrypt
+#undef cbc_decrypt
+#endif
+#ifdef des_set_key
+#undef des_set_key
+#endif
+struct crypto_struct {
+ char *name; /* ssh name of the algorithm */
+ unsigned int blocksize; /* blocksize of the algo */
+ unsigned int keylen; /* length of the key structure */
+ void *key; /* a key buffer allocated for the algo */
+ unsigned int keysize; /* bytes of key used. != keylen */
+ void (*set_encrypt_key)(struct crypto_struct *cipher, void *key); /* sets the new key for immediate use */
+ void (*set_decrypt_key)(struct crypto_struct *cipher, void *key);
+ void (*cbc_encrypt)(struct crypto_struct *cipher, void *in, void *out,unsigned long len,void *IV);
+ void (*cbc_decrypt)(struct crypto_struct *cipher, void *in, void *out,unsigned long len,void *IV);
+};
+
diff --git a/kftpgrabber/src/misc/libs/ssh/dh.c b/kftpgrabber/src/misc/libs/ssh/dh.c
new file mode 100644
index 0000000..0a1b557
--- /dev/null
+++ b/kftpgrabber/src/misc/libs/ssh/dh.c
@@ -0,0 +1,411 @@
+/* dh.c */
+/* this file contains usefull stuff for Diffie helman algorithm against SSH 2 */
+/*
+Copyright 2003 Aris Adamantiadis
+
+This file is part of the SSH Library
+
+The SSH Library is free software; you can redistribute it and/or modify
+it under the terms of the GNU Lesser General Public License as published by
+the Free Software Foundation; either version 2.1 of the License, or (at your
+option) any later version.
+
+The SSH Library 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 Lesser General Public
+License for more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with the SSH Library; see the file COPYING. If not, write to
+the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor, Boston,
+MA 02110-1301, USA. */
+
+/* Let us resume the dh protocol. */
+/* Each side computes a private prime number, x at client side, y at server side. */
+/* g and n are two numbers common to every ssh software. */
+/* client's public key (e) is calculated by doing */
+/* e = g^x mod p */
+/* client sents e to the server . */
+/* the server computes his own public key, f */
+/* f = g^y mod p */
+/* it sents it to the client */
+/* the common key K is calculated by the client by doing */
+/* k = f^x mod p */
+/* the server does the same with the client public key e */
+/* k' = e^y mod p */
+/* if everything went correctly, k and k' are equal */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <netdb.h>
+#include "priv.h"
+
+#include <openssl/rand.h>
+#include <openssl/evp.h>
+#include <openssl/err.h>
+#include <string.h>
+#include "crypto.h"
+static unsigned char p_value[] = {
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xC9, 0x0F, 0xDA, 0xA2,
+ 0x21, 0x68, 0xC2, 0x34, 0xC4, 0xC6, 0x62, 0x8B, 0x80, 0xDC, 0x1C, 0xD1,
+ 0x29, 0x02, 0x4E, 0x08, 0x8A, 0x67, 0xCC, 0x74, 0x02, 0x0B, 0xBE, 0xA6,
+ 0x3B, 0x13, 0x9B, 0x22, 0x51, 0x4A, 0x08, 0x79, 0x8E, 0x34, 0x04, 0xDD,
+ 0xEF, 0x95, 0x19, 0xB3, 0xCD, 0x3A, 0x43, 0x1B, 0x30, 0x2B, 0x0A, 0x6D,
+ 0xF2, 0x5F, 0x14, 0x37, 0x4F, 0xE1, 0x35, 0x6D, 0x6D, 0x51, 0xC2, 0x45,
+ 0xE4, 0x85, 0xB5, 0x76, 0x62, 0x5E, 0x7E, 0xC6, 0xF4, 0x4C, 0x42, 0xE9,
+ 0xA6, 0x37, 0xED, 0x6B, 0x0B, 0xFF, 0x5C, 0xB6, 0xF4, 0x06, 0xB7, 0xED,
+ 0xEE, 0x38, 0x6B, 0xFB, 0x5A, 0x89, 0x9F, 0xA5, 0xAE, 0x9F, 0x24, 0x11,
+ 0x7C, 0x4B, 0x1F, 0xE6, 0x49, 0x28, 0x66, 0x51, 0xEC, 0xE6, 0x53, 0x81,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
+#define P_LEN 128 /* Size in bytes of the p number */
+
+static unsigned long g_int = 2 ; /* G is defined as 2 by the ssh2 standards */
+static bignum g;
+static bignum p;
+
+/* maybe it might be enhanced .... */
+/* XXX Do it. */
+void ssh_get_random(void *where, int len){
+ static int rndfd=0;
+ if(!rndfd){
+ rndfd=open("/dev/urandom",O_RDONLY);
+ if(rndfd<0){
+ fprintf(stderr,"Can't open /dev/urandom\n");
+ exit(-1);
+ }
+ }
+ read(rndfd,where,len);
+}
+
+/* it inits the values g and p which are used for DH key agreement */
+void ssh_crypto_init(){
+ static int init=0;
+ if(!init){
+ g=bignum_new();
+ bignum_set_word(g,g_int);
+ p=bignum_new();
+ bignum_bin2bn(p_value,P_LEN,p);
+ init++;
+ }
+}
+
+/* prints the bignum on stderr */
+void ssh_print_bignum(char *which,bignum num){
+ char *hex;
+ fprintf(stderr,"%s value: ",which);
+ hex=bignum_bn2hex(num);
+ fprintf(stderr,"%s\n",hex);
+ free(hex);
+}
+
+void ssh_print_hexa(char *descr,unsigned char *what, int len){
+ int i;
+ printf("%s : ",descr);
+ for(i=0;i<len-1;i++)
+ printf("%.2hhx:",what[i]);
+ printf("%.2hhx\n",what[i]);
+}
+
+void dh_generate_x(SSH_SESSION *session){
+ session->next_crypto->x=bignum_new();
+ bignum_rand(session->next_crypto->x,128,0,-1);
+ /* not harder than this */
+#ifdef DEBUG_CRYPTO
+ ssh_print_bignum("x",session->next_crypto->x);
+#endif
+}
+
+void dh_generate_e(SSH_SESSION *session){
+ bignum_CTX ctx=bignum_ctx_new();
+ session->next_crypto->e=bignum_new();
+ bignum_mod_exp(session->next_crypto->e,g,session->next_crypto->x,p,ctx);
+#ifdef DEBUG_CRYPTO
+ ssh_print_bignum("e",session->next_crypto->e);
+#endif
+ bignum_ctx_free(ctx);
+}
+
+
+STRING *make_bignum_string(bignum num){
+ STRING *ptr;
+ int pad=0;
+ int len=bignum_num_bytes(num);
+ int bits=bignum_num_bits(num);
+ int finallen;
+ /* remember if the fist bit is set, it is considered as a negative number. so 0's must be appended */
+ if(!(bits%8) && bignum_is_bit_set(num,bits-1))
+ pad++;
+ ssh_say(3,"%d bits, %d bytes, %d padding\n",bits,len,pad);
+ ptr=malloc(4 + len + pad);
+ ptr->size=htonl(len+pad);
+ if(pad)
+ ptr->string[0]=0;
+ finallen=bignum_bn2bin(num,ptr->string+pad);
+ return ptr;
+}
+
+bignum make_string_bn(STRING *string){
+ int len=ntohl(string->size);
+ ssh_say(3,"Importing a %d bits,%d bytes object ...\n",len*8,len);
+ return bignum_bin2bn(string->string,len,NULL);
+}
+
+STRING *dh_get_e(SSH_SESSION *session){
+ return make_bignum_string(session->next_crypto->e);
+}
+
+void dh_import_pubkey(SSH_SESSION *session,STRING *pubkey_string){
+ session->next_crypto->server_pubkey=pubkey_string;
+}
+
+void dh_import_f(SSH_SESSION *session,STRING *f_string){
+ session->next_crypto->f=make_string_bn(f_string);
+#ifdef DEBUG_CRYPTO
+ ssh_print_bignum("f",session->next_crypto->f);
+#endif
+}
+
+void dh_build_k(SSH_SESSION *session){
+ bignum_CTX ctx=bignum_ctx_new();
+ session->next_crypto->k=bignum_new();
+ bignum_mod_exp(session->next_crypto->k,session->next_crypto->f,session->next_crypto->x,p,ctx);
+#ifdef DEBUG_CRYPTO
+ ssh_print_bignum("shared secret key",session->next_crypto->k);
+#endif
+ bignum_ctx_free(ctx);
+}
+
+static void sha_add(STRING *str,SHACTX *ctx){
+ sha1_update(ctx,str,string_len(str)+4);
+}
+
+void make_sessionid(SSH_SESSION *session){
+ SHACTX *ctx;
+ STRING *num,*str;
+ int len;
+ ctx=sha1_init();
+
+ str=string_from_char(session->clientbanner);
+ sha_add(str,ctx);
+ free(str);
+
+ str=string_from_char(session->serverbanner);
+ sha_add(str,ctx);
+ free(str);
+
+ buffer_add_u32(session->in_hashbuf,0);
+ buffer_add_u8(session->in_hashbuf,0);
+ buffer_add_u32(session->out_hashbuf,0);
+ buffer_add_u8(session->out_hashbuf,0);
+
+ len=ntohl(buffer_get_len(session->out_hashbuf));
+ sha1_update(ctx,&len,4);
+
+ sha1_update(ctx,buffer_get(session->out_hashbuf),buffer_get_len(session->out_hashbuf));
+ buffer_free(session->out_hashbuf);
+ session->out_hashbuf=NULL;
+
+ len=ntohl(buffer_get_len(session->in_hashbuf));
+ sha1_update(ctx,&len,4);
+
+ sha1_update(ctx,buffer_get(session->in_hashbuf),buffer_get_len(session->in_hashbuf));
+ buffer_free(session->in_hashbuf);
+ session->in_hashbuf=NULL;
+ sha1_update(ctx,session->next_crypto->server_pubkey,len=(string_len(session->next_crypto->server_pubkey)+4));
+ num=make_bignum_string(session->next_crypto->e);
+ sha1_update(ctx,num,len=(string_len(num)+4));
+ free(num);
+ num=make_bignum_string(session->next_crypto->f);
+ sha1_update(ctx,num,len=(string_len(num)+4));
+ free(num);
+ num=make_bignum_string(session->next_crypto->k);
+ sha1_update(ctx,num,len=(string_len(num)+4));
+ free(num);
+ sha1_final(session->next_crypto->session_id,ctx);
+
+#ifdef DEBUG_CRYPTO
+ printf("Session hash : ");
+ ssh_print_hexa("session id",session->next_crypto->session_id,SHA_DIGEST_LENGTH);
+#endif
+}
+
+void hashbufout_add_cookie(SSH_SESSION *session){
+ session->out_hashbuf=buffer_new();
+ buffer_add_u8(session->out_hashbuf,20);
+ buffer_add_data(session->out_hashbuf,session->client_kex.cookie,16);
+}
+
+
+void hashbufin_add_cookie(SSH_SESSION *session,unsigned char *cookie){
+ session->in_hashbuf=buffer_new();
+ buffer_add_u8(session->in_hashbuf,20);
+ buffer_add_data(session->in_hashbuf,cookie,16);
+}
+
+static void generate_one_key(STRING *k,char session_id[SHA_DIGEST_LENGTH],char output[SHA_DIGEST_LENGTH],char letter){
+ SHACTX *ctx=sha1_init();
+ sha1_update(ctx,k,string_len(k)+4);
+ sha1_update(ctx,session_id,SHA_DIGEST_LENGTH);
+ sha1_update(ctx,&letter,1);
+ sha1_update(ctx,session_id,SHA_DIGEST_LENGTH);
+ sha1_final(output,ctx);
+}
+
+void generate_session_keys(SSH_SESSION *session){
+ STRING *k_string;
+ SHACTX *ctx;
+ k_string=make_bignum_string(session->next_crypto->k);
+
+ /* IV */
+ generate_one_key(k_string,session->next_crypto->session_id,session->next_crypto->encryptIV,'A');
+ generate_one_key(k_string,session->next_crypto->session_id,session->next_crypto->decryptIV,'B');
+
+ generate_one_key(k_string,session->next_crypto->session_id,session->next_crypto->encryptkey,'C');
+
+ /* some ciphers need more than 20 bytes of input key */
+ if(session->next_crypto->out_cipher->keylen > SHA_DIGEST_LENGTH*8){
+ ctx=sha1_init();
+ sha1_update(ctx,k_string,string_len(k_string)+4);
+ sha1_update(ctx,session->next_crypto->session_id,SHA_DIGEST_LENGTH);
+ sha1_update(ctx,session->next_crypto->encryptkey,SHA_DIGEST_LENGTH);
+ sha1_final(session->next_crypto->encryptkey+SHA_DIGEST_LEN,ctx);
+ }
+
+ generate_one_key(k_string,session->next_crypto->session_id,session->next_crypto->decryptkey,'D');
+
+ if(session->next_crypto->in_cipher->keylen > SHA_DIGEST_LENGTH*8){
+ ctx=sha1_init();
+ sha1_update(ctx,k_string,string_len(k_string)+4);
+ sha1_update(ctx,session->next_crypto->session_id,SHA_DIGEST_LENGTH);
+ sha1_update(ctx,session->next_crypto->decryptkey,SHA_DIGEST_LENGTH);
+ sha1_final(session->next_crypto->decryptkey+SHA_DIGEST_LEN,ctx);
+ }
+
+ generate_one_key(k_string,session->next_crypto->session_id,session->next_crypto->encryptMAC,'E');
+ generate_one_key(k_string,session->next_crypto->session_id,session->next_crypto->decryptMAC,'F');
+
+#ifdef DEBUG_CRYPTO
+ ssh_print_hexa("client->server IV",session->next_crypto->encryptIV,SHA_DIGEST_LENGTH);
+ ssh_print_hexa("server->client IV",session->next_crypto->decryptIV,SHA_DIGEST_LENGTH);
+ ssh_print_hexa("encryption key",session->next_crypto->encryptkey,16);
+ ssh_print_hexa("decryption key",session->next_crypto->decryptkey,16);
+ ssh_print_hexa("Encryption MAC",session->next_crypto->encryptMAC,SHA_DIGEST_LENGTH);
+ ssh_print_hexa("Decryption MAC",session->next_crypto->decryptMAC,20);
+#endif
+ free(k_string);
+}
+
+int ssh_get_pubkey_hash(SSH_SESSION *session,char hash[MD5_DIGEST_LEN]){
+ STRING *pubkey=session->current_crypto->server_pubkey;
+ MD5CTX *ctx;
+ int len=string_len(pubkey);
+
+ ctx=md5_init();
+ md5_update(ctx,pubkey->string,len);
+ md5_final(hash,ctx);
+ return MD5_DIGEST_LEN;
+}
+
+int pubkey_get_hash(SSH_SESSION *session, char hash[MD5_DIGEST_LEN]){
+ return ssh_get_pubkey_hash(session,hash);
+}
+
+STRING *ssh_get_pubkey(SSH_SESSION *session){
+ return string_copy(session->current_crypto->server_pubkey);
+}
+
+/* XXX i doubt it is still needed, or may need some fix */
+static int match(char *group,char *object){
+ char *ptr,*saved;
+ char *end;
+ ptr=strdup(group);
+ saved=ptr;
+ while(1){
+ end=strchr(ptr,',');
+ if(end)
+ *end=0;
+ if(!strcmp(ptr,object)){
+ free(saved);
+ return 0;
+ }
+ if(end)
+ ptr=end+1;
+ else{
+ free(saved);
+ return -1;
+ }
+ }
+ /* not reached */
+ return 1;
+}
+
+int sig_verify(PUBLIC_KEY *pubkey, SIGNATURE *signature, char *digest){
+ int valid=0;
+ char hash[SHA_DIGEST_LENGTH];
+ sha1(digest,SHA_DIGEST_LENGTH,hash);
+ switch(pubkey->type){
+ case TYPE_DSS:
+ valid=DSA_do_verify(hash,SHA_DIGEST_LENGTH,signature->dsa_sign,
+ pubkey->dsa_pub);
+ if(valid==1)
+ return 0;
+ if(valid==-1){
+ ssh_set_error(NULL,SSH_INVALID_DATA,"DSA error : %s",ERR_error_string(ERR_get_error(),NULL));
+ return -1;
+ }
+ ssh_set_error(NULL,SSH_NO_ERROR,"Invalid DSA signature");
+ return -1;
+ case TYPE_RSA:
+ case TYPE_RSA1:
+ valid=RSA_verify(NID_sha1,hash,SHA_DIGEST_LENGTH,
+ signature->rsa_sign->string,string_len(signature->rsa_sign),pubkey->rsa_pub);
+ if(valid==1)
+ return 0;
+ if(valid==-1){
+ ssh_set_error(NULL,SSH_INVALID_DATA,"RSA error : %s",ERR_error_string(ERR_get_error(),NULL));
+ return -1;
+ }
+ ssh_set_error(NULL,SSH_NO_ERROR,"Invalid RSA signature");
+ return -1;
+ default:
+ ssh_set_error(NULL,SSH_INVALID_DATA,"Unknown public key type");
+ return -1;
+ }
+return -1;
+}
+
+
+int signature_verify(SSH_SESSION *session,STRING *signature){
+ PUBLIC_KEY *pubkey;
+ SIGNATURE *sign;
+ int err;
+ if(session->options->dont_verify_hostkey){
+ ssh_say(1,"Host key wasn't verified\n");
+ return 0;
+ }
+ pubkey=publickey_from_string(session->next_crypto->server_pubkey);
+ if(!pubkey)
+ return -1;
+ if(session->options->wanted_methods[KEX_HOSTKEY]){
+ if(match(session->options->wanted_methods[KEX_HOSTKEY],pubkey->type_c)){
+ ssh_set_error((session->connected?session:NULL),SSH_FATAL,"Public key from server (%s) doesn't match user preference (%s)",
+ pubkey->type,session->options->wanted_methods[KEX_HOSTKEY]);
+ publickey_free(pubkey);
+ return -1;
+ }
+ }
+ sign=signature_from_string(signature,pubkey,pubkey->type);
+ if(!sign){
+ ssh_set_error((session->connected?session:NULL),SSH_INVALID_DATA,"Invalid signature blob");
+ publickey_free(pubkey);
+ return -1;
+ }
+ ssh_say(1,"Going to verify a %s type signature\n",pubkey->type_c);
+ err=sig_verify(pubkey,sign,session->next_crypto->session_id);
+ signature_free(sign);
+ session->next_crypto->server_pubkey_type=pubkey->type_c;
+ publickey_free(pubkey);
+ return err;
+}
diff --git a/kftpgrabber/src/misc/libs/ssh/error.c b/kftpgrabber/src/misc/libs/ssh/error.c
new file mode 100644
index 0000000..bbff5b2
--- /dev/null
+++ b/kftpgrabber/src/misc/libs/ssh/error.c
@@ -0,0 +1,67 @@
+/* error.c */
+/* it does contain error processing functions */
+/*
+Copyright 2003,04 Aris Adamantiadis
+
+This file is part of the SSH Library
+
+The SSH Library is free software; you can redistribute it and/or modify
+it under the terms of the GNU Lesser General Public License as published by
+the Free Software Foundation; either version 2.1 of the License, or (at your
+option) any later version.
+
+The SSH Library 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 Lesser General Public
+License for more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with the SSH Library; see the file COPYING. If not, write to
+the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor, Boston,
+MA 02110-1301, USA. */
+
+#include <stdio.h>
+#include <stdarg.h>
+#include "priv.h"
+
+static char error_buffer[ERROR_BUFFERLEN];
+static int error_code;
+static int verbosity;
+
+/* ssh_set_error registers an error with a description. the error code is the class of error, and description is obvious.*/
+void ssh_set_error(SSH_SESSION *session,enum ssh_error code,char *descr,...){
+ va_list va;
+ va_start(va,descr);
+ vsnprintf(session?session->error_buffer : error_buffer,ERROR_BUFFERLEN,descr,va);
+ va_end(va);
+ if(session)
+ session->error_code=code;
+ else
+ error_code=code;
+}
+
+char *ssh_get_error(SSH_SESSION *session){
+ if(session)
+ return session->error_buffer;
+ else
+ return error_buffer;
+}
+
+enum ssh_error ssh_error_code(SSH_SESSION *session){
+ if(session)
+ return session->error_code;
+ else
+ return error_code;
+}
+
+void ssh_say(int priority, char *format,...){
+ va_list va;
+ va_start(va,format);
+ if(priority <= verbosity)
+ vfprintf(stderr,format,va);
+ va_end(va);
+}
+
+void ssh_set_verbosity(int num){
+ verbosity=num;
+}
diff --git a/kftpgrabber/src/misc/libs/ssh/gzip.c b/kftpgrabber/src/misc/libs/ssh/gzip.c
new file mode 100644
index 0000000..1003b50
--- /dev/null
+++ b/kftpgrabber/src/misc/libs/ssh/gzip.c
@@ -0,0 +1,140 @@
+/* gzip.c */
+/* include hooks for compression of packets */
+/*
+Copyright 2003 Aris Adamantiadis
+
+This file is part of the SSH Library
+
+The SSH Library is free software; you can redistribute it and/or modify
+it under the terms of the GNU Lesser General Public License as published by
+the Free Software Foundation; either version 2.1 of the License, or (at your
+option) any later version.
+
+The SSH Library 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 Lesser General Public
+License for more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with the SSH Library; see the file COPYING. If not, write to
+the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor, Boston,
+MA 02110-1301, USA. */
+#include "priv.h"
+#ifdef HAVE_LIBZ
+#undef NO_GZIP
+#else
+#define NO_GZIP
+#endif
+
+#ifndef NO_GZIP
+#include <zlib.h>
+#include <string.h>
+#define BLOCKSIZE 4092
+
+static z_stream *initcompress(SSH_SESSION *session,int level){
+ z_stream *stream=malloc(sizeof(z_stream));
+ int status;
+ memset(stream,0,sizeof(z_stream));
+ status=deflateInit(stream,level);
+ if (status!=0)
+ ssh_set_error((session->connected?session:NULL),SSH_FATAL,"status %d inititalising zlib deflate",status);
+ return stream;
+}
+
+BUFFER *gzip_compress(SSH_SESSION *session,BUFFER *source,int level){
+ BUFFER *dest;
+ static unsigned char out_buf[BLOCKSIZE];
+ void *in_ptr=buffer_get(source);
+ unsigned long in_size=buffer_get_len(source);
+ unsigned long len;
+ int status;
+ z_stream *zout=session->current_crypto->compress_out_ctx;
+ if(!zout)
+ zout=session->current_crypto->compress_out_ctx=initcompress(session,level);
+ dest=buffer_new();
+ zout->next_out=out_buf;
+ zout->next_in=in_ptr;
+ zout->avail_in=in_size;
+ do {
+ zout->avail_out=BLOCKSIZE;
+ status=deflate(zout,Z_PARTIAL_FLUSH);
+ if(status !=0){
+ ssh_set_error((session->connected?session:NULL),SSH_FATAL,"status %d deflating zlib packet",status);
+ return NULL;
+ }
+ len=BLOCKSIZE-zout->avail_out;
+ buffer_add_data(dest,out_buf,len);
+ zout->next_out=out_buf;
+ } while (zout->avail_out == 0);
+
+ return dest;
+}
+
+int compress_buffer(SSH_SESSION *session,BUFFER *buf){
+ BUFFER *dest=gzip_compress(session,buf,9);
+ if(!dest)
+ return -1;
+ buffer_reinit(buf);
+ buffer_add_data(buf,buffer_get(dest),buffer_get_len(dest));
+ buffer_free(dest);
+ return 0;
+}
+
+/* decompression */
+
+static z_stream *initdecompress(SSH_SESSION *session){
+ z_stream *stream=malloc(sizeof(z_stream));
+ int status;
+ memset(stream,0,sizeof(z_stream));
+ status=inflateInit(stream);
+ if (status!=0){
+ ssh_set_error((session->connected?session:NULL),SSH_FATAL,"Status = %d initiating inflate context !",status);
+ free(stream);
+ stream=NULL;
+ }
+ return stream;
+}
+
+BUFFER *gzip_decompress(SSH_SESSION *session,BUFFER *source){
+ BUFFER *dest;
+ static unsigned char out_buf[BLOCKSIZE];
+ void *in_ptr=buffer_get_rest(source);
+ unsigned long in_size=buffer_get_rest_len(source);
+ unsigned long len;
+ int status;
+ z_stream *zin=session->current_crypto->compress_in_ctx;
+ if(!zin)
+ zin=session->current_crypto->compress_in_ctx=initdecompress(session);
+ dest=buffer_new();
+ zin->next_out=out_buf;
+ zin->next_in=in_ptr;
+ zin->avail_in=in_size;
+ do {
+ zin->avail_out=BLOCKSIZE;
+ status=inflate(zin,Z_PARTIAL_FLUSH);
+ if(status !=Z_OK){
+ ssh_set_error((session->connected?session:NULL),SSH_FATAL,"status %d inflating zlib packet",status);
+ buffer_free(dest);
+ return NULL;
+ }
+ len=BLOCKSIZE-zin->avail_out;
+ buffer_add_data(dest,out_buf,len);
+ zin->next_out=out_buf;
+ } while (zin->avail_out == 0);
+
+ return dest;
+}
+
+int decompress_buffer(SSH_SESSION *session,BUFFER *buf){
+ BUFFER *dest=gzip_decompress(session,buf);
+ buffer_reinit(buf);
+ if(!dest){
+ return -1; /* failed */
+ }
+ buffer_reinit(buf);
+ buffer_add_data(buf,buffer_get(dest),buffer_get_len(dest));
+ buffer_free(dest);
+ return 0;
+}
+
+#endif /* NO_GZIP */
diff --git a/kftpgrabber/src/misc/libs/ssh/kex.c b/kftpgrabber/src/misc/libs/ssh/kex.c
new file mode 100644
index 0000000..ae2c871
--- /dev/null
+++ b/kftpgrabber/src/misc/libs/ssh/kex.c
@@ -0,0 +1,264 @@
+/* kex.c is used well, in key exchange :-) */
+/*
+Copyright 2003 Aris Adamantiadis
+
+This file is part of the SSH Library
+
+The SSH Library is free software; you can redistribute it and/or modify
+it under the terms of the GNU Lesser General Public License as published by
+the Free Software Foundation; either version 2.1 of the License, or (at your
+option) any later version.
+
+The SSH Library 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 Lesser General Public
+License for more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with the SSH Library; see the file COPYING. If not, write to
+the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor, Boston,
+MA 02110-1301, USA. */
+
+#include <string.h>
+#include <stdlib.h>
+#include "priv.h"
+#include "ssh2.h"
+#ifdef HAVE_OPENSSL_BLOWFISH_H
+#define BLOWFISH "blowfish-cbc"
+#else
+#define BLOWFISH ""
+#endif
+#ifdef HAVE_OPENSSL_AES_H
+#define AES "aes256-cbc,aes192-cbc,aes128-cbc,"
+#else
+#define AES ""
+#endif
+#ifdef HAVE_LIBZ
+#define ZLIB "none,zlib"
+#else
+#define ZLIB "none"
+#endif
+char *default_methods[]={
+ "diffie-hellman-group1-sha1","ssh-dss,ssh-rsa",AES BLOWFISH, AES BLOWFISH,
+ "hmac-sha1","hmac-sha1","none","none","","",NULL };
+char *supported_methods[]={
+ "diffie-hellman-group1-sha1","ssh-dss,ssh-rsa",AES BLOWFISH,AES BLOWFISH,
+ "hmac-sha1","hmac-sha1",ZLIB,ZLIB,"","",NULL };
+/* descriptions of the key exchange packet */
+char *ssh_kex_nums[]={
+ "kex algos","server host key algo","encryption client->server","encryption server->client",
+ "mac algo client->server","mac algo server->client","compression algo client->server",
+ "compression algo server->client","languages client->server","languages server->client",NULL};
+
+/* tokenize will return a token of strings delimited by ",". the first element has to be freed */
+static char **tokenize(char *chain){
+ char **tokens;
+ int n=1;
+ int i=0;
+ char *ptr=chain=strdup(chain);
+ while(*ptr){
+ if(*ptr==','){
+ n++;
+ *ptr=0;
+ }
+ ptr++;
+ }
+ /* now n contains the number of tokens, the first possibly empty if the list was empty too e.g. "" */
+ tokens=malloc(sizeof(char *) * (n+1) ); /* +1 for the null */
+ ptr=chain;
+ for(i=0;i<n;i++){
+ tokens[i]=ptr;
+ while(*ptr)
+ ptr++; /* find a zero */
+ ptr++; /* then go one step further */
+ }
+ tokens[i]=NULL;
+ return tokens;
+}
+
+/* same as tokenize(), but with spaces instead of ',' */
+char **space_tokenize(char *chain){
+ char **tokens;
+ int n=1;
+ int i=0;
+ char *ptr=chain=strdup(chain);
+ while(*ptr==' ')
+ ++ptr; /* skip initial spaces */
+ while(*ptr){
+ if(*ptr==' '){
+ n++; /* count one token per word */
+ *ptr=0;
+ while(*(ptr+1)==' '){ /* don't count if the tokens have more than 2 spaces */
+ *(ptr++)=0;
+ }
+ }
+ ptr++;
+ }
+ /* now n contains the number of tokens, the first possibly empty if the list was empty too e.g. "" */
+ tokens=malloc(sizeof(char *) * (n+1) ); /* +1 for the null */
+ ptr=chain; /* we don't pass the initial spaces because the "chain" pointer is needed by the caller */
+ /* function to free the tokens. */
+ for(i=0;i<n;i++){
+ tokens[i]=ptr;
+ if(i!=n-1){
+ while(*ptr)
+ ptr++; /* find a zero */
+ while(!*(ptr+1))
+ ++ptr; /* if the zero is followed by other zeros, go through them */
+ ptr++; /* then go one step further */
+ }
+ }
+ tokens[i]=NULL;
+ return tokens;
+}
+
+/* find_matching gets 2 parameters : a list of available objects (in_d), separated by colons,*/
+/* and a list of prefered objects (what_d) */
+/* it will return a strduped pointer on the first prefered object found in the available objects list */
+
+static char *find_matching(char *in_d, char *what_d){
+ char ** tok_in, **tok_what;
+ int i_in, i_what;
+ char *ret;
+
+ if( ! (in_d && what_d))
+ return NULL; /* don't deal with null args */
+ ssh_say(3,"find_matching(\"%s\",\"%s\") = ",in_d,what_d);
+ tok_in=tokenize(in_d);
+ tok_what=tokenize(what_d);
+ for(i_in=0; tok_in[i_in]; ++i_in){
+ for(i_what=0; tok_what[i_what] ; ++i_what){
+ if(!strcmp(tok_in[i_in],tok_what[i_what])){
+ /* match */
+ ssh_say(3,"\"%s\"\n",tok_in[i_in]);
+ ret=strdup(tok_in[i_in]);
+ /* free the tokens */
+ free(tok_in[0]);
+ free(tok_what[0]);
+ free(tok_in);
+ free(tok_what);
+ return ret;
+ }
+ }
+ }
+ ssh_say(3,"NULL\n");
+ free(tok_in[0]);
+ free(tok_what[0]);
+ free(tok_in);
+ free(tok_what);
+ return NULL;
+}
+
+int ssh_get_kex(SSH_SESSION *session,int server_kex ){
+ STRING *str;
+ char *strings[10];
+ int i;
+ if(packet_wait(session,SSH2_MSG_KEXINIT,1))
+ return -1;
+ if(buffer_get_data(session->in_buffer,session->server_kex.cookie,16)!=16){
+ ssh_set_error((session->connected?session:NULL),SSH_FATAL,"get_kex(): no cookie in packet");
+ return -1;
+ }
+ hashbufin_add_cookie(session,session->server_kex.cookie);
+ memset(strings,0,sizeof(char *)*10);
+ for(i=0;i<10;++i){
+ str=buffer_get_ssh_string(session->in_buffer);
+ if(!str)
+ break;
+ if(str){
+ buffer_add_ssh_string(session->in_hashbuf,str);
+ strings[i]=string_to_char(str);
+ free(str);
+ } else
+ strings[i]=NULL;
+ }
+ /* copy the server kex info into an array of strings */
+ if(server_kex){
+ session->client_kex.methods=malloc( 10 * sizeof(char **));
+ for(i=0;i<10;++i)
+ session->client_kex.methods[i]=strings[i];
+ } else { /* client */
+ session->server_kex.methods=malloc( 10 * sizeof(char **));
+ for(i=0;i<10;++i)
+ session->server_kex.methods[i]=strings[i];
+ }
+ return 0;
+}
+
+void list_kex(KEX *kex){
+ int i=0;
+#ifdef DEBUG_CRYPTO
+ ssh_print_hexa("session cookie",kex->cookie,16);
+#endif
+ for(i=0;i<10;i++){
+ ssh_say(2,"%s : %s\n",ssh_kex_nums[i],kex->methods[i]);
+ }
+}
+
+/* set_kex basicaly look at the option structure of the session and set the output kex message */
+/* it must be aware of the server kex message */
+/* it can fail if option is null, not any user specified kex method matches the server one, if not any default kex matches */
+
+int set_kex(SSH_SESSION *session){
+ KEX *server = &session->server_kex;
+ KEX *client=&session->client_kex;
+ SSH_OPTIONS *options=session->options;
+ int i;
+ char *wanted;
+ /* the client might ask for a specific cookie to be sent. useful for server debugging */
+ if(options->wanted_cookie)
+ memcpy(client->cookie,options->wanted_cookie,16);
+ else
+ ssh_get_random(client->cookie,16);
+ client->methods=malloc(10 * sizeof(char **));
+ memset(client->methods,0,10*sizeof(char **));
+ for (i=0;i<10;i++){
+ if(!(wanted=options->wanted_methods[i]))
+ wanted=default_methods[i];
+ client->methods[i]=find_matching(server->methods[i],wanted);
+ if(!client->methods[i] && i < KEX_LANG_C_S){
+ ssh_set_error((session->connected?session:NULL),SSH_FATAL,"kex error : did not find one of algos %s in list %s for %s",
+ wanted,server->methods[i],ssh_kex_nums[i]);
+ return -1;
+ } else {
+ if(i>=KEX_LANG_C_S && !client->methods[i])
+ client->methods[i]=strdup(""); /* we can safely do that for languages */
+ }
+ }
+ return 0;
+}
+
+/* this function only sends the predefined set of kex methods */
+void send_kex(SSH_SESSION *session, int server_kex){
+ STRING *str;
+ int i=0;
+ KEX *kex=(server_kex ? &session->server_kex : &session->client_kex);
+ packet_clear_out(session);
+ buffer_add_u8(session->out_buffer,SSH2_MSG_KEXINIT);
+ buffer_add_data(session->out_buffer,kex->cookie,16);
+ hashbufout_add_cookie(session);
+ list_kex(kex);
+ for(i=0;i<10;i++){
+ str=string_from_char(kex->methods[i]);
+ buffer_add_ssh_string(session->out_hashbuf,str);
+ buffer_add_ssh_string(session->out_buffer,str);
+ free(str);
+ }
+ i=0;
+ buffer_add_u8(session->out_buffer,0);
+ buffer_add_u32(session->out_buffer,0);
+ packet_send(session);
+}
+
+/* returns 1 if at least one of the name algos is in the default algorithms table */
+int verify_existing_algo(int algo, char *name){
+ char *ptr;
+ if(algo>9 || algo <0)
+ return -1;
+ ptr=find_matching(supported_methods[algo],name);
+ if(ptr){
+ free(ptr);
+ return 1;
+ }
+ return 0;
+}
diff --git a/kftpgrabber/src/misc/libs/ssh/keyfiles.c b/kftpgrabber/src/misc/libs/ssh/keyfiles.c
new file mode 100644
index 0000000..660155e
--- /dev/null
+++ b/kftpgrabber/src/misc/libs/ssh/keyfiles.c
@@ -0,0 +1,341 @@
+/* keyfiles.c */
+/* This part of the library handles private and public key files needed for publickey authentication,*/
+/* as well as servers public hashes verifications and certifications. Lot of code here handles openssh */
+/* implementations (key files aren't standardized yet). */
+
+/*
+Copyright 2003,04 Aris Adamantiadis
+
+This file is part of the SSH Library
+
+The SSH Library is free software; you can redistribute it and/or modify
+it under the terms of the GNU Lesser General Public License as published by
+the Free Software Foundation; either version 2.1 of the License, or (at your
+option) any later version.
+
+The SSH Library 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 Lesser General Public
+License for more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with the SSH Library; see the file COPYING. If not, write to
+the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor, Boston,
+MA 02110-1301, USA. */
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <openssl/pem.h>
+#include <openssl/dsa.h>
+#include <openssl/err.h>
+#include <openssl/rsa.h>
+#include "priv.h"
+#define MAXLINESIZE 80
+
+static int default_get_password(char *buf, int size,int rwflag, char *descr){
+ char *pass;
+ char buffer[256];
+ int len;
+ snprintf(buffer,256,"Please enter passphrase for %s",descr);
+ pass=getpass(buffer);
+ snprintf(buf,size,"%s",buffer);
+ len=strlen(buf);
+ memset(pass,0,strlen(pass));
+ return len;
+}
+
+/* in case the passphrase has been given in parameter */
+static int get_password_specified(char *buf,int size, int rwflag, char *password){
+ snprintf(buf,size,"%s",password);
+ return strlen(buf);
+}
+
+/* TODO : implement it to read both DSA and RSA at once */
+PRIVATE_KEY *privatekey_from_file(SSH_SESSION *session,char *filename,int type,char *passphrase){
+ FILE *file=fopen(filename,"r");
+ PRIVATE_KEY *privkey;
+ DSA *dsa=NULL;
+ RSA *rsa=NULL;
+
+ if (!file) {
+ ssh_set_error(session,SSH_REQUEST_DENIED,"Error opening %s : %s",filename,strerror(errno));
+ return NULL;
+ }
+
+ if (!passphrase) {
+ return NULL;
+ }
+
+ /* Add all encryption algorythms to OpenSSL or this will fail */
+ OpenSSL_add_all_algorithms();
+
+ if (type == TYPE_DSS) {
+ dsa = PEM_read_DSAPrivateKey(file,NULL,(void *)get_password_specified,passphrase);
+
+ fclose(file);
+ if(!dsa) {
+ ssh_set_error(session,SSH_FATAL,"parsing private key %s : %s",filename,ERR_error_string(ERR_get_error(),NULL));
+ return NULL;
+ }
+ } else if (type == TYPE_RSA) {
+ rsa=PEM_read_RSAPrivateKey(file,NULL,(void *)get_password_specified,passphrase);
+
+ fclose(file);
+ if(!rsa){
+ ssh_set_error(session,SSH_FATAL,"parsing private key %s : %s",filename,ERR_error_string(ERR_get_error(),NULL));
+ return NULL;
+ }
+ } else {
+ ssh_set_error(session,SSH_FATAL,"Invalid private key type %d",type);
+ return NULL;
+ }
+
+ privkey = malloc(sizeof(PRIVATE_KEY));
+ privkey->type = type;
+ privkey->dsa_priv = dsa;
+ privkey->rsa_priv = rsa;
+
+ return privkey;
+}
+
+void private_key_free(PRIVATE_KEY *prv){
+ if(prv->dsa_priv)
+ DSA_free(prv->dsa_priv);
+ if(prv->rsa_priv)
+ RSA_free(prv->rsa_priv);
+ memset(prv,0,sizeof(PRIVATE_KEY));
+ free(prv);
+}
+
+STRING *publickey_from_file(char *filename,int *_type){
+ BUFFER *buffer;
+ int type;
+ STRING *str;
+ char buf[4096]; /* noone will have bigger keys that that */
+ /* where have i head that again ? */
+ int fd=open(filename,O_RDONLY);
+ int r;
+ char *ptr;
+ if(fd<0){
+ ssh_set_error(NULL,SSH_INVALID_REQUEST,"nonexistent public key file");
+ return NULL;
+ }
+ if(read(fd,buf,8)!=8){
+ close(fd);
+ ssh_set_error(NULL,SSH_INVALID_REQUEST,"Invalid public key file");
+ return NULL;
+ }
+ buf[7]=0;
+ if(!strcmp(buf,"ssh-dss"))
+ type=TYPE_DSS;
+ else if (!strcmp(buf,"ssh-rsa"))
+ type=TYPE_RSA;
+ else {
+ close(fd);
+ ssh_set_error(NULL,SSH_INVALID_REQUEST,"Invalid public key file");
+ return NULL;
+ }
+ r=read(fd,buf,sizeof(buf)-1);
+ close(fd);
+ if(r<=0){
+ ssh_set_error(NULL,SSH_INVALID_REQUEST,"Invalid public key file");
+ return NULL;
+ }
+ buf[r]=0;
+ ptr=strchr(buf,' ');
+ if(ptr)
+ *ptr=0; /* eliminates the garbage at end of file */
+ buffer=base64_to_bin(buf);
+ if(buffer){
+ str=string_new(buffer_get_len(buffer));
+ string_fill(str,buffer_get(buffer),buffer_get_len(buffer));
+ buffer_free(buffer);
+ if(_type)
+ *_type=type;
+ return str;
+ } else {
+ ssh_set_error(NULL,SSH_INVALID_REQUEST,"Invalid public key file");
+ return NULL; /* invalid file */
+ }
+}
+
+
+/* why recursing ? i'll explain. on top, publickey_from_next_file will be executed until NULL returned */
+/* we can't return null if one of the possible keys is wrong. we must test them before getting over */
+STRING *publickey_from_next_file(SSH_SESSION *session,char **pub_keys_path,char **keys_path,
+ char **privkeyfile,int *type,int *count){
+ static char *home=NULL;
+ char public[256];
+ char private[256];
+ char *priv;
+ char *pub;
+ STRING *pubkey;
+ if(!home)
+ home=ssh_get_user_home_dir();
+ if(home==NULL) {
+ ssh_set_error(session,SSH_FATAL,"User home dir impossible to guess");
+ return NULL;
+ }
+ ssh_set_error(session,SSH_NO_ERROR,"no public key matched");
+ if((pub=pub_keys_path[*count])==NULL)
+ return NULL;
+ if((priv=keys_path[*count])==NULL)
+ return NULL;
+ ++*count;
+ /* are them readable ? */
+ snprintf(public,256,pub,home);
+ ssh_say(2,"Trying to open %s\n",public);
+ if(!ssh_file_readaccess_ok(public)){
+ ssh_say(2,"Failed\n");
+ return publickey_from_next_file(session,pub_keys_path,keys_path,privkeyfile,type,count);
+ }
+ snprintf(private,256,priv,home);
+ ssh_say(2,"Trying to open %s\n",private);
+ if(!ssh_file_readaccess_ok(private)){
+ ssh_say(2,"Failed\n");
+ return publickey_from_next_file(session,pub_keys_path,keys_path,privkeyfile,type,count);
+ }
+ ssh_say(2,"Okay both files ok\n");
+ /* ok, we are sure both the priv8 and public key files are readable : we return the public one as a string,
+ and the private filename in arguments */
+ pubkey=publickey_from_file(public,type);
+ if(!pubkey){
+ ssh_say(2,"Wasn't able to open public key file %s : %s\n",public,ssh_get_error(session));
+ return publickey_from_next_file(session,pub_keys_path,keys_path,privkeyfile,type,count);
+ }
+ *privkeyfile=realloc(*privkeyfile,strlen(private)+1);
+ strcpy(*privkeyfile,private);
+ return pubkey;
+}
+
+#define FOUND_OTHER ( (void *)-1)
+#define FILE_NOT_FOUND ((void *)-2)
+/* will return a token array containing [host,]ip keytype key */
+/* NULL if no match was found, FOUND_OTHER if the match is on an other */
+/* type of key (ie dsa if type was rsa) */
+static char **ssh_parse_knownhost(char *filename, char *hostname, char *type){
+ FILE *file=fopen(filename,"r");
+ char buffer[4096];
+ char *ptr;
+ char **tokens;
+ char **ret=NULL;
+ if(!file)
+ return FILE_NOT_FOUND;
+ while(fgets(buffer,sizeof(buffer),file)){
+ ptr=strchr(buffer,'\n');
+ if(ptr) *ptr=0;
+ if((ptr=strchr(buffer,'\r'))) *ptr=0;
+ if(!buffer[0])
+ continue; /* skip empty lines */
+ tokens=space_tokenize(buffer);
+ if(!tokens[0] || !tokens[1] || !tokens[2]){
+ /* it should have exactly 3 tokens */
+ free(tokens[0]);
+ free(tokens);
+ continue;
+ }
+ if(tokens[3]){
+ /* 3 tokens only, not four */
+ free(tokens[0]);
+ free(tokens);
+ continue;
+ }
+ ptr=tokens[0];
+ while(*ptr==' ')
+ ptr++; /* skip the initial spaces */
+ /* we allow spaces or ',' to follow the hostname. It's generaly an IP */
+ /* we don't care about ip, if the host key match there is no problem with ip */
+ if(strncasecmp(ptr,hostname,strlen(hostname))==0){
+ if(ptr[strlen(hostname)]==' ' || ptr[strlen(hostname)]=='\0'
+ || ptr[strlen(hostname)]==','){
+ if(strcasecmp(tokens[1],type)==0){
+ fclose(file);
+ return tokens;
+ } else {
+ ret=FOUND_OTHER;
+ }
+ }
+ }
+ /* not the good one */
+ free(tokens[0]);
+ free(tokens);
+ }
+ fclose(file);
+ /* we did not find */
+ return ret;
+}
+
+/* public function to test if the server is known or not */
+int ssh_is_server_known(SSH_SESSION *session){
+ char *pubkey_64;
+ BUFFER *pubkey_buffer;
+ STRING *pubkey=session->current_crypto->server_pubkey;
+ char **tokens;
+ options_default_known_hosts_file(session->options);
+ if(!session->options->host){
+ ssh_set_error(session,SSH_FATAL,"Can't verify host in known hosts if the hostname isn't known");
+ return SSH_SERVER_ERROR;
+ }
+ tokens=ssh_parse_knownhost(session->options->known_hosts_file,
+ session->options->host,session->current_crypto->server_pubkey_type);
+ if(tokens==NULL)
+ return SSH_SERVER_NOT_KNOWN;
+ if(tokens==FOUND_OTHER)
+ return SSH_SERVER_FOUND_OTHER;
+ if(tokens==FILE_NOT_FOUND){
+ ssh_set_error(session,SSH_FATAL,"verifying that server is a known host : file %s not found",session->options->known_hosts_file);
+ return SSH_SERVER_ERROR;
+ }
+ /* ok we found some public key in known hosts file. now un-base64it */
+ /* Some time, we may verify the IP address did not change. I honestly think */
+ /* it's not an important matter as IP address are known not to be secure */
+ /* and the crypto stuff is enough to prove the server's identity */
+ pubkey_64=tokens[2];
+ pubkey_buffer=base64_to_bin(pubkey_64);
+ /* at this point, we may free the tokens */
+ free(tokens[0]);
+ free(tokens);
+ if(!pubkey_buffer){
+ ssh_set_error(session,SSH_FATAL,"verifying that server is a known host : base 64 error");
+ return SSH_SERVER_ERROR;
+ }
+ if(buffer_get_len(pubkey_buffer)!=string_len(pubkey)){
+ buffer_free(pubkey_buffer);
+ return SSH_SERVER_KNOWN_CHANGED;
+ }
+ /* now test that they are identical */
+ if(memcmp(buffer_get(pubkey_buffer),pubkey->string,buffer_get_len(pubkey_buffer))!=0){
+ buffer_free(pubkey_buffer);
+ return SSH_SERVER_KNOWN_CHANGED;
+ }
+ buffer_free(pubkey_buffer);
+ return SSH_SERVER_KNOWN_OK;
+}
+
+int ssh_write_knownhost(SSH_SESSION *session){
+ char *pubkey_64;
+ STRING *pubkey=session->current_crypto->server_pubkey;
+ char buffer[4096];
+ FILE *file;
+ options_default_known_hosts_file(session->options);
+ if(!session->options->host){
+ ssh_set_error(session,SSH_FATAL,"Cannot write host in known hosts if the hostname is unknown");
+ return -1;
+ }
+ /* a = append only */
+ file=fopen(session->options->known_hosts_file,"a");
+ if(!file){
+ ssh_set_error(session,SSH_FATAL,"Opening known host file %s for appending : %s",
+ session->options->known_hosts_file,strerror(errno));
+ return -1;
+ }
+ pubkey_64=bin_to_base64(pubkey->string,string_len(pubkey));
+ snprintf(buffer,sizeof(buffer),"%s %s %s\n",session->options->host,session->current_crypto->server_pubkey_type,pubkey_64);
+ free(pubkey_64);
+ fwrite(buffer,strlen(buffer),1,file);
+ fclose(file);
+ return 0;
+}
diff --git a/kftpgrabber/src/misc/libs/ssh/keys.c b/kftpgrabber/src/misc/libs/ssh/keys.c
new file mode 100644
index 0000000..f404f4b
--- /dev/null
+++ b/kftpgrabber/src/misc/libs/ssh/keys.c
@@ -0,0 +1,353 @@
+/* keys handle the public key related functions */
+/* decoding a public key (both rsa and dsa), decoding a signature (rsa and dsa), veryfying them */
+
+/*
+Copyright 2003,04 Aris Adamantiadis
+
+This file is part of the SSH Library
+
+The SSH Library is free software; you can redistribute it and/or modify
+it under the terms of the GNU Lesser General Public License as published by
+the Free Software Foundation; either version 2.1 of the License, or (at your
+option) any later version.
+
+The SSH Library 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 Lesser General Public
+License for more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with the SSH Library; see the file COPYING. If not, write to
+the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor, Boston,
+MA 02110-1301, USA. */
+#include <string.h>
+#include <openssl/dsa.h>
+#include <openssl/rsa.h>
+#include "priv.h"
+
+
+/* Public key decoding functions */
+
+char *ssh_type_to_char(int type){
+ switch(type){
+ case TYPE_DSS:
+ return "ssh-dss";
+ case TYPE_RSA:
+ case TYPE_RSA1:
+ return "ssh-rsa";
+ default:
+ return NULL;
+ }
+}
+
+PUBLIC_KEY *publickey_make_dss(BUFFER *buffer){
+ STRING *p,*q,*g,*pubkey;
+ PUBLIC_KEY *key=malloc(sizeof(PUBLIC_KEY));
+ key->type=TYPE_DSS;
+ key->type_c="ssh-dss";
+ p=buffer_get_ssh_string(buffer);
+ q=buffer_get_ssh_string(buffer);
+ g=buffer_get_ssh_string(buffer);
+ pubkey=buffer_get_ssh_string(buffer);
+ buffer_free(buffer); /* we don't need it anymore */
+ if(!p || !q || !g || !pubkey){
+ ssh_set_error(NULL,SSH_FATAL,"Invalid DSA public key");
+ if(p)
+ free(p);
+ if(q)
+ free(q);
+ if(g)
+ free(g);
+ if(pubkey)
+ free(pubkey);
+ free(key);
+ return NULL;
+ }
+ key->dsa_pub=DSA_new();
+ key->dsa_pub->p=make_string_bn(p);
+ key->dsa_pub->q=make_string_bn(q);
+ key->dsa_pub->g=make_string_bn(g);
+ key->dsa_pub->pub_key=make_string_bn(pubkey);
+ free(p);
+ free(q);
+ free(g);
+ free(pubkey);
+ return key;
+}
+
+PUBLIC_KEY *publickey_make_rsa(BUFFER *buffer){
+ STRING *e,*n;
+ PUBLIC_KEY *key=malloc(sizeof(PUBLIC_KEY));
+ key->type=TYPE_RSA;
+ key->type_c="ssh-rsa";
+ e=buffer_get_ssh_string(buffer);
+ n=buffer_get_ssh_string(buffer);
+ buffer_free(buffer); /* we don't need it anymore */
+ if(!e || !n){
+ ssh_set_error(NULL,SSH_FATAL,"Invalid RSA public key");
+ if(e)
+ free(e);
+ if(n)
+ free(n);
+ free(key);
+ return NULL;
+ }
+ key->rsa_pub=RSA_new();
+ key->rsa_pub->e=make_string_bn(e);
+ key->rsa_pub->n=make_string_bn(n);
+#ifdef DEBUG_CRYPTO
+ ssh_print_bignum("e",key->rsa_pub->e);
+ ssh_print_bignum("n",key->rsa_pub->n);
+#endif
+ free(e);
+ free(n);
+ return key;
+}
+
+void publickey_free(PUBLIC_KEY *key){
+ if(!key)
+ return;
+ switch(key->type){
+ case TYPE_DSS:
+ DSA_free(key->dsa_pub);
+ break;
+ case TYPE_RSA:
+ case TYPE_RSA1:
+ RSA_free(key->rsa_pub);
+ break;
+ default:
+ break;
+ }
+ free(key);
+}
+
+PUBLIC_KEY *publickey_from_string(STRING *pubkey_s){
+ BUFFER *tmpbuf=buffer_new();
+ STRING *type_s;
+ char *type;
+
+ buffer_add_data(tmpbuf,pubkey_s->string,string_len(pubkey_s));
+ type_s=buffer_get_ssh_string(tmpbuf);
+ if(!type_s){
+ buffer_free(tmpbuf);
+ ssh_set_error(NULL,SSH_FATAL,"Invalid public key format");
+ return NULL;
+ }
+ type=string_to_char(type_s);
+ free(type_s);
+ if(!strcmp(type,"ssh-dss")){
+ free(type);
+ return publickey_make_dss(tmpbuf);
+ }
+ if(!strcmp(type,"ssh-rsa")){
+ free(type);
+ return publickey_make_rsa(tmpbuf);
+ }
+ ssh_set_error(NULL,SSH_FATAL,"unknown public key protocol %s",type);
+ buffer_free(tmpbuf);
+ free(type);
+ return NULL;
+}
+
+/* Signature decoding functions */
+
+STRING *signature_to_string(SIGNATURE *sign){
+ STRING *str;
+ STRING *rs,*r,*s;
+ unsigned char buffer[40];
+ BUFFER *tmpbuf=buffer_new();
+ STRING *tmp;
+ tmp=string_from_char(ssh_type_to_char(sign->type));
+ buffer_add_ssh_string(tmpbuf,tmp);
+ free(tmp);
+ switch(sign->type){
+ case TYPE_DSS:
+ r=make_bignum_string(sign->dsa_sign->r);
+ s=make_bignum_string(sign->dsa_sign->s);
+ rs=string_new(40);
+ memset(buffer,0,40);
+ memcpy(buffer,r->string+string_len(r)-20,20);
+ memcpy(buffer+ 20, s->string + string_len(s) - 20, 20);
+ string_fill(rs,buffer,40);
+ free(r);
+ free(s);
+ buffer_add_ssh_string(tmpbuf,rs);
+ free(rs);
+ break;
+ case TYPE_RSA:
+ case TYPE_RSA1:
+ buffer_add_ssh_string(tmpbuf,sign->rsa_sign);
+ break;
+ }
+ str=string_new(buffer_get_len(tmpbuf));
+ string_fill(str,buffer_get(tmpbuf),buffer_get_len(tmpbuf));
+ buffer_free(tmpbuf);
+ return str;
+}
+
+/* TODO : split this function in two so it becomes smaller */
+SIGNATURE *signature_from_string(STRING *signature,PUBLIC_KEY *pubkey,int needed_type){
+ DSA_SIG *sig;
+ SIGNATURE *sign=malloc(sizeof(SIGNATURE));
+ BUFFER *tmpbuf=buffer_new();
+ STRING *rs;
+ STRING *r,*s,*type_s,*e;
+ int len,rsalen;
+ char *type;
+ buffer_add_data(tmpbuf,signature->string,string_len(signature));
+ type_s=buffer_get_ssh_string(tmpbuf);
+ if(!type_s){
+ ssh_set_error(NULL,SSH_FATAL,"Invalid signature packet");
+ buffer_free(tmpbuf);
+ return NULL;
+ }
+ type=string_to_char(type_s);
+ free(type_s);
+ switch(needed_type){
+ case TYPE_DSS:
+ if(strcmp(type,"ssh-dss")){
+ ssh_set_error(NULL,SSH_FATAL,"Invalid signature type : %s",type);
+ buffer_free(tmpbuf);
+ free(type);
+ return NULL;
+ }
+ break;
+ case TYPE_RSA:
+ if(strcmp(type,"ssh-rsa")){
+ ssh_set_error(NULL,SSH_FATAL,"Invalid signature type : %s",type);
+ buffer_free(tmpbuf);
+ free(type);
+ return NULL;
+ }
+ break;
+ default:
+ ssh_set_error(NULL,SSH_FATAL,"Invalid signature type : %s",type);
+ free(type);
+ buffer_free(tmpbuf);
+ return NULL;
+ }
+ free(type);
+ switch(needed_type){
+ case TYPE_DSS:
+ rs=buffer_get_ssh_string(tmpbuf);
+ buffer_free(tmpbuf);
+ if(!rs || string_len(rs)!=40){ /* 40 is the dual signature blob len. */
+ if(rs)
+ free(rs);
+ return NULL;
+ }
+ /* we make use of strings because we have all-made functions to convert them to bignums */
+ r=string_new(20);
+ s=string_new(20);
+ string_fill(r,rs->string,20);
+ string_fill(s,rs->string+20,20);
+ free(rs);
+ sig=DSA_SIG_new();
+ sig->r=make_string_bn(r); /* is that really portable ? Openssh's hack isn't better */
+ sig->s=make_string_bn(s);
+#ifdef DEBUG_CRYPTO
+ ssh_print_bignum("r",sig->r);
+ ssh_print_bignum("s",sig->s);
+#endif
+ free(r);
+ free(s);
+ sign->type=TYPE_DSS;
+ sign->dsa_sign=sig;
+ return sign;
+ case TYPE_RSA:
+ e=buffer_get_ssh_string(tmpbuf);
+ buffer_free(tmpbuf);
+ if(!e){
+ free(e);
+ return NULL;
+ }
+ len=string_len(e);
+ rsalen=RSA_size(pubkey->rsa_pub);
+ if(len>rsalen){
+ free(e);
+ free(sign);
+ ssh_set_error(NULL,SSH_FATAL,"signature too big ! %d instead of %d",len,rsalen);
+ return NULL;
+ }
+ if(len<rsalen)
+ ssh_say(0,"Len %d < %d\n",len,rsalen);
+ sign->type=TYPE_RSA;
+ sign->rsa_sign=e;
+#ifdef DEBUG_CRYPTO
+ ssh_say(0,"Len : %d\n",len);
+ ssh_print_hexa("rsa signature",e->string,len);
+#endif
+ return sign;
+ default:
+ return NULL;
+ }
+}
+
+void signature_free(SIGNATURE *sign){
+ if(!sign)
+ return;
+ switch(sign->type){
+ case TYPE_DSS:
+ DSA_SIG_free(sign->dsa_sign);
+ break;
+ case TYPE_RSA:
+ case TYPE_RSA1:
+ free(sign->rsa_sign);
+ break;
+ default:
+ ssh_say(1,"freeing a signature with no type !\n");
+ }
+ free(sign);
+}
+
+/* maybe the missing function from libcrypto */
+/* i think now, maybe it's a bad idea to name it has it should have be named in libcrypto */
+static STRING *RSA_do_sign(void *payload,int len,RSA *privkey){
+ STRING *sign;
+ void *buffer=malloc(RSA_size(privkey));
+ unsigned int size;
+ int err;
+ err=RSA_sign(NID_sha1,payload,len,buffer,&size,privkey);
+ if(!err){
+ free(buffer);
+ return NULL;
+ }
+ sign=string_new(size);
+ string_fill(sign,buffer,size);
+ free(buffer);
+ return sign;
+}
+
+STRING *ssh_do_sign(SSH_SESSION *session,BUFFER *sigbuf, PRIVATE_KEY *privatekey){
+ SHACTX *ctx;
+ STRING *session_str=string_new(SHA_DIGEST_LEN);
+ char hash[SHA_DIGEST_LEN];
+ SIGNATURE *sign;
+ STRING *signature;
+ string_fill(session_str,session->current_crypto->session_id,SHA_DIGEST_LENGTH);
+ ctx=sha1_init();
+ sha1_update(ctx,session_str,string_len(session_str)+4);
+ sha1_update(ctx,buffer_get(sigbuf),buffer_get_len(sigbuf));
+ sha1_final(hash,ctx);
+ free(session_str);
+ sign=malloc(sizeof(SIGNATURE));
+ switch(privatekey->type){
+ case TYPE_DSS:
+ sign->dsa_sign=DSA_do_sign(hash,SHA_DIGEST_LENGTH,privatekey->dsa_priv);
+ sign->rsa_sign=NULL;
+ break;
+ case TYPE_RSA:
+ sign->rsa_sign=RSA_do_sign(hash,SHA_DIGEST_LENGTH,privatekey->rsa_priv);
+ sign->dsa_sign=NULL;
+ break;
+ }
+ sign->type=privatekey->type;
+ if(!sign->dsa_sign && !sign->rsa_sign){
+ ssh_set_error(session,SSH_FATAL,"Signing : openssl error");
+ signature_free(sign);
+ return NULL;
+ }
+ signature=signature_to_string(sign);
+ signature_free(sign);
+ return signature;
+}
diff --git a/kftpgrabber/src/misc/libs/ssh/libssh.h b/kftpgrabber/src/misc/libs/ssh/libssh.h
new file mode 100644
index 0000000..7fdc939
--- /dev/null
+++ b/kftpgrabber/src/misc/libs/ssh/libssh.h
@@ -0,0 +1,218 @@
+/*
+Copyright 2003,04 Aris Adamantiadis
+
+This file is part of the SSH Library
+
+The SSH Library is free software; you can redistribute it and/or modify
+it under the terms of the GNU Lesser General Public License as published by
+the Free Software Foundation; either version 2.1 of the License, or (at your
+option) any later version.
+
+The SSH Library 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 Lesser General Public
+License for more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with the SSH Library; see the file COPYING. If not, write to
+the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor, Boston,
+MA 02110-1301, USA. */
+
+#ifndef _LIBSSH_H
+#define _LIBSSH_H
+#include "config.h"
+#include <unistd.h>
+#include <sys/select.h> /* for fd_set * */
+#include <sys/types.h>
+#define LIBSSH_VERSION "libssh-0.11-dev"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct string_struct STRING;
+typedef struct buffer_struct BUFFER;
+typedef struct public_key_struct PUBLIC_KEY;
+typedef struct private_key_struct PRIVATE_KEY;
+typedef struct ssh_options_struct SSH_OPTIONS;
+typedef struct channel_struct CHANNEL;
+typedef struct ssh_session SSH_SESSION;
+typedef struct ssh_kbdint SSH_KBDINT;
+
+/* integer values */
+typedef u_int32_t u32;
+typedef u_int16_t u16;
+typedef u_int64_t u64;
+typedef u_int8_t u8;
+
+/* the offsets of methods */
+#define KEX_ALGO 0
+#define KEX_HOSTKEY 1
+#define KEX_CRYPT_C_S 2
+#define KEX_CRYPT_S_C 3
+#define KEX_MAC_C_S 4
+#define KEX_MAC_S_C 5
+#define KEX_COMP_C_S 6
+#define KEX_COMP_S_C 7
+#define KEX_LANG_C_S 8
+#define KEX_LANG_S_C 9
+
+#define SSH_AUTH_SUCCESS 0
+#define SSH_AUTH_DENIED 1
+#define SSH_AUTH_PARTIAL 2
+#define SSH_AUTH_INFO 3
+#define SSH_AUTH_ERROR -1
+
+#define SSH_SERVER_ERROR -1
+#define SSH_SERVER_NOT_KNOWN 0
+#define SSH_SERVER_KNOWN_OK 1
+#define SSH_SERVER_KNOWN_CHANGED 2
+#define SSH_SERVER_FOUND_OTHER 3
+
+#ifndef MD5_DIGEST_LEN
+ #define MD5_DIGEST_LEN 16
+#endif
+/* errors */
+
+enum ssh_error {SSH_NO_ERROR, SSH_REQUEST_DENIED, SSH_INVALID_REQUEST, SSH_CONNECTION_LOST,SSH_FATAL,SSH_INVALID_DATA};
+char *ssh_get_error(SSH_SESSION *session); /* returns a static char array */
+enum ssh_error ssh_error_code(SSH_SESSION *session);
+void ssh_say(int priority,char *format,...);
+void ssh_set_verbosity(int num);
+
+ /* There is a verbosity level */
+ /* 3 : packet level */
+ /* 2 : protocol level */
+ /* 1 : functions level */
+ /* 0 : important messages only */
+ /* -1 : no messages */
+
+/* in client.c */
+
+SSH_SESSION *ssh_connect(SSH_OPTIONS *options);
+void ssh_disconnect(SSH_SESSION *session);
+int ssh_service_request(SSH_SESSION *session,char *service);
+char *ssh_get_issue_banner(SSH_SESSION *session);
+/* get copyright informations */
+const char *ssh_copyright();
+/* string.h */
+
+/* You can use these functions, they won't change */
+/* makestring returns a newly allocated string from a char * ptr */
+STRING *string_from_char(char *what);
+/* it returns the string len in host byte orders. str->size is big endian warning ! */
+int string_len(STRING *str);
+STRING *string_new(u32 size);
+/* string_fill copies the data in the string. it does NOT check for boundary so allocate enough place with new_string */
+/* right before */
+void string_fill(STRING *str,void *data,int len);
+/* returns a newly allocated char array with the str string and a final nul caracter */
+char *string_to_char(STRING *str);
+STRING *string_copy(STRING *str);
+
+/* deprecated */
+void ssh_crypto_init();
+
+/* useful for debug */
+void ssh_print_hexa(char *descr,unsigned char *what, int len);
+void ssh_get_random(void *,int);
+
+/* this one can be called by the client to see the hash of the public key before accepting it */
+int ssh_get_pubkey_hash(SSH_SESSION *session,char hash[MD5_DIGEST_LEN]);
+STRING *ssh_get_pubkey(SSH_SESSION *session);
+
+/* deprecated */
+int pubkey_get_hash(SSH_SESSION *session,char hash[MD5_DIGEST_LEN]);
+
+/* in connect.c */
+int ssh_fd_poll(SSH_SESSION *session);
+int ssh_select(CHANNEL **channels,CHANNEL **outchannels, int maxfd, fd_set *readfds, struct timeval *timeout);
+
+void publickey_free(PUBLIC_KEY *key);
+
+/* in keyfiles.c */
+
+PRIVATE_KEY *privatekey_from_file(SSH_SESSION *session,char *filename,int type,char *passphrase);
+void private_key_free(PRIVATE_KEY *prv);
+STRING *publickey_from_file(char *filename,int *_type);
+STRING *publickey_from_next_file(SSH_SESSION *session,char **pub_keys_path,char **keys_path,
+ char **privkeyfile,int *type,int *count);
+int ssh_is_server_known(SSH_SESSION *session);
+int ssh_write_knownhost(SSH_SESSION *session);
+
+/* in channels.c */
+
+/* this one is deprecated */
+CHANNEL *open_session_channel(SSH_SESSION *session,int window,int maxpacket);
+CHANNEL *channel_open_forward(SSH_SESSION *session,char *remotehost, int remoteport, char *sourcehost, int localport);
+CHANNEL *channel_open_session(SSH_SESSION *session);
+void channel_free(CHANNEL *channel);
+int channel_request_pty(CHANNEL *channel);
+int channel_request_pty_size(CHANNEL *channel, char *term,int cols, int rows);
+int channel_change_pty_size(CHANNEL *channel,int cols,int rows);
+int channel_request_shell(CHANNEL *channel);
+int channel_request_subsystem(CHANNEL *channel, char *system);
+int channel_request_env(CHANNEL *channel,char *name, char *value);
+int channel_request_exec(CHANNEL *channel, char *cmd);
+int channel_request_sftp(CHANNEL *channel);
+int channel_write(CHANNEL *channel,void *data,int len);
+int channel_set_write_handler(CHANNEL *channel,
+ void (*write_fct)(CHANNEL *channel, void *data, int len, void *userdefined),
+ void *user);
+int channel_set_stderr_write_handler(CHANNEL *channel,
+ void (*write_err_fct)(CHANNEL *channel, void *data, int len, void *userdefined),
+ void *user);
+int channel_send_eof(CHANNEL *channel);
+int channel_read(CHANNEL *channel, BUFFER *buffer,int bytes,int is_stderr);
+int channel_poll(CHANNEL *channel, int is_stderr);
+int channel_close(CHANNEL *channel);
+int channel_read_nonblocking(CHANNEL *channel, char *dest, int len, int is_stderr);
+int channel_is_open(CHANNEL *channel);
+/* in options.c */
+
+SSH_OPTIONS *options_new();
+SSH_OPTIONS *options_copy(SSH_OPTIONS *opt);
+int options_set_wanted_method(SSH_OPTIONS *opt,int method, char *list);
+void options_set_username(SSH_OPTIONS *opt,char *username);
+void options_set_port(SSH_OPTIONS *opt, unsigned int port);
+SSH_OPTIONS *ssh_getopt(int *argcptr, char **argv);
+void options_set_host(SSH_OPTIONS *opt, const char *host);
+/* don't connect to host, use fd instead */
+void options_set_fd(SSH_OPTIONS *opt, int fd);
+void options_set_bindaddr(SSH_OPTIONS *opt, char *bindaddr);
+void options_set_identity(SSH_OPTIONS *opt, char *identity);
+void options_set_status_callback(SSH_OPTIONS *opt, void (*callback)(void *arg, float status), void *arg);
+void options_set_timeout(SSH_OPTIONS *opt, long seconds, long usec);
+void options_set_ssh_dir(SSH_OPTIONS *opt, char *dir);
+void options_set_known_hosts_file(SSH_OPTIONS *opt, char *dir);
+/* buffer.c */
+
+BUFFER *buffer_new();
+void buffer_free(BUFFER *buffer);
+/* buffer_get returns a pointer to the begining of the buffer. no position is taken into account */
+void *buffer_get(BUFFER *buffer);
+/* same here */
+int buffer_get_len(BUFFER *buffer);
+
+
+/* in auth.c */
+/* these functions returns AUTH_ERROR is some serious error has happened,
+ AUTH_SUCCESS if success,
+ AUTH_PARTIAL if partial success,
+ AUTH_DENIED if refused */
+int ssh_userauth_none(SSH_SESSION *session,char *username);
+int ssh_userauth_password(SSH_SESSION *session,char *username,char *password);
+int ssh_userauth_offer_pubkey(SSH_SESSION *session, char *username,int type, STRING *publickey);
+int ssh_userauth_pubkey(SSH_SESSION *session, char *username, STRING *publickey, PRIVATE_KEY *privatekey);
+int ssh_userauth_autopubkey(SSH_SESSION *session, const char *passphrase);
+int ssh_userauth_kbdint(SSH_SESSION *session, char *user, char *submethods);
+int ssh_userauth_kbdint_getnprompts(SSH_SESSION *session);
+char *ssh_userauth_kbdint_getname(SSH_SESSION *session);
+char *ssh_userauth_kbdint_getinstruction(SSH_SESSION *session);
+char *ssh_userauth_kbdint_getprompt(SSH_SESSION *session, int i, char *echo);
+void ssh_userauth_kbdint_setanswer(SSH_SESSION *session, unsigned int i, char *answer);
+
+#ifdef __cplusplus
+}
+#endif
+#endif /* _LIBSSH_H */
diff --git a/kftpgrabber/src/misc/libs/ssh/misc.c b/kftpgrabber/src/misc/libs/ssh/misc.c
new file mode 100644
index 0000000..fc3cb79
--- /dev/null
+++ b/kftpgrabber/src/misc/libs/ssh/misc.c
@@ -0,0 +1,98 @@
+/* misc.c */
+/* some misc routines than aren't really part of the ssh protocols but can be useful to the client */
+
+/*
+Copyright 2003 Aris Adamantiadis
+
+This file is part of the SSH Library
+
+The SSH Library is free software; you can redistribute it and/or modify
+it under the terms of the GNU Lesser General Public License as published by
+the Free Software Foundation; either version 2.1 of the License, or (at your
+option) any later version.
+
+The SSH Library 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 Lesser General Public
+License for more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with the SSH Library; see the file COPYING. If not, write to
+the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor, Boston,
+MA 02110-1301, USA. */
+#include <stdio.h>
+#include <unistd.h>
+#include <string.h>
+#include <stdlib.h>
+#include <pwd.h>
+#include <sys/types.h>
+#include <netdb.h>
+#include "libssh.h"
+
+/* if the program was executed suid root, don't trust the user ! */
+static int is_trusted(){
+ if(geteuid()!=getuid())
+ return 0;
+ return 1;
+}
+
+static char *get_homedir_from_uid(int uid){
+ struct passwd *pwd;
+ char *home;
+ while((pwd=getpwent())){
+ if(pwd->pw_uid == uid){
+ home=strdup(pwd->pw_dir);
+ endpwent();
+ return home;
+ }
+ }
+ endpwent();
+ return NULL;
+}
+
+static char *get_homedir_from_login(char *user){
+ struct passwd *pwd;
+ char *home;
+ while((pwd=getpwent())){
+ if(!strcmp(pwd->pw_name,user)){
+ home=strdup(pwd->pw_dir);
+ endpwent();
+ return home;
+ }
+ }
+ endpwent();
+ return NULL;
+}
+
+char *ssh_get_user_home_dir(){
+ char *home;
+ char *user;
+ int trusted=is_trusted();
+ if(trusted){
+ if((home=getenv("HOME")))
+ return strdup(home);
+ if((user=getenv("USER")))
+ return get_homedir_from_login(user);
+ }
+ return get_homedir_from_uid(getuid());
+}
+
+/* we have read access on file */
+int ssh_file_readaccess_ok(char *file){
+ if(!access(file,R_OK))
+ return 1;
+ return 0;
+}
+
+
+u64 ntohll(u64 a){
+#ifdef WORDS_BIGENDIAN
+ return a;
+#else
+ u32 low=a & 0xffffffff;
+ u32 high = a >> 32 ;
+ low=ntohl(low);
+ high=ntohl(high);
+ return (( ((u64)low) << 32) | ( high));
+#endif
+}
diff --git a/kftpgrabber/src/misc/libs/ssh/options.c b/kftpgrabber/src/misc/libs/ssh/options.c
new file mode 100644
index 0000000..74ab189
--- /dev/null
+++ b/kftpgrabber/src/misc/libs/ssh/options.c
@@ -0,0 +1,341 @@
+/* options.c */
+/* handle pre-connection options */
+/*
+Copyright 2003 Aris Adamantiadis
+
+This file is part of the SSH Library
+
+The SSH Library is free software; you can redistribute it and/or modify
+it under the terms of the GNU Lesser General Public License as published by
+the Free Software Foundation; either version 2.1 of the License, or (at your
+option) any later version.
+
+The SSH Library 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 Lesser General Public
+License for more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with the SSH Library; see the file COPYING. If not, write to
+the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor, Boston,
+MA 02110-1301, USA. */
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <pwd.h>
+#include <sys/types.h>
+#include "priv.h"
+
+SSH_OPTIONS *options_new(){
+ SSH_OPTIONS *option=malloc(sizeof(SSH_OPTIONS));
+ memset(option,0,sizeof(SSH_OPTIONS));
+ option->port=22; /* set the default port */
+ option->fd=-1;
+ return option;
+}
+
+void options_set_port(SSH_OPTIONS *opt, unsigned int port){
+ opt->port=port&0xffff;
+}
+SSH_OPTIONS *options_copy(SSH_OPTIONS *opt){
+ SSH_OPTIONS *ret=options_new();
+ int i;
+ ret->fd=opt->fd;
+ ret->port=opt->port;
+ if(opt->username)
+ ret->username=strdup(opt->username);
+ if(opt->host)
+ ret->host=strdup(opt->host);
+ if(opt->bindaddr)
+ ret->host=strdup(opt->bindaddr);
+ if(opt->identity)
+ ret->identity=strdup(opt->identity);
+ if(opt->ssh_dir)
+ ret->ssh_dir=strdup(opt->ssh_dir);
+ if(opt->known_hosts_file)
+ ret->known_hosts_file=strdup(opt->known_hosts_file);
+ for(i=0;i<10;++i)
+ if(opt->wanted_methods[i])
+ ret->wanted_methods[i]=strdup(opt->wanted_methods[i]);
+ ret->passphrase_function=opt->passphrase_function;
+ ret->connect_status_function=opt->connect_status_function;
+ ret->connect_status_arg=opt->connect_status_arg;
+ ret->timeout=opt->timeout;
+ ret->timeout_usec=opt->timeout_usec;
+ return ret;
+}
+
+void options_free(SSH_OPTIONS *opt){
+ int i;
+ if(opt->username)
+ free(opt->username);
+ if(opt->identity)
+ free(opt->identity);
+ /* we don't touch the banner. if the implementation did use it, they have to free it */
+ if(opt->host)
+ free(opt->host);
+ if(opt->bindaddr)
+ free(opt->bindaddr);
+ if(opt->ssh_dir)
+ free(opt->ssh_dir);
+ for(i=0;i<10;i++)
+ if(opt->wanted_methods[i])
+ free(opt->wanted_methods[i]);
+ memset(opt,0,sizeof(SSH_OPTIONS));
+ free(opt);
+}
+
+
+void options_set_host(SSH_OPTIONS *opt, const char *hostname){
+ char *ptr=strdup(hostname);
+ char *ptr2=strchr(ptr,'@');
+ if(opt->host) /* don't leak memory */
+ free(opt->host);
+ if(ptr2){
+ *ptr2=0;
+ opt->host=strdup(ptr2+1);
+ if(opt->username)
+ free(opt->username);
+ opt->username=strdup(ptr);
+ free(ptr);
+ } else
+ opt->host=ptr;
+}
+
+void options_set_fd(SSH_OPTIONS *opt, int fd){
+ opt->fd=fd;
+}
+
+void options_set_bindaddr(SSH_OPTIONS *opt, char *bindaddr){
+ opt->bindaddr=strdup(bindaddr);
+}
+
+void options_set_username(SSH_OPTIONS *opt,char *username){
+ opt->username=strdup(username);
+}
+
+void options_set_ssh_dir(SSH_OPTIONS *opt, char *dir){
+ char buffer[1024];
+ snprintf(buffer,1024,dir,ssh_get_user_home_dir());
+ opt->ssh_dir=strdup(buffer);
+}
+void options_set_known_hosts_file(SSH_OPTIONS *opt, char *dir){
+ char buffer[1024];
+ snprintf(buffer,1024,dir,ssh_get_user_home_dir());
+ opt->known_hosts_file=strdup(buffer);
+}
+
+void options_set_identity(SSH_OPTIONS *opt, char *identity){
+ char buffer[1024];
+ snprintf(buffer,1024,identity,ssh_get_user_home_dir());
+ opt->identity=strdup(buffer);
+}
+
+/* what's the deal here ? some options MUST be set before authentication or key exchange,
+ * otherwise default values are going to be used. what must be configurable :
+ * Public key certification method *
+ * key exchange method (dh-sha1 for instance)*
+ * c->s, s->c ciphers *
+ * c->s s->c macs *
+ * c->s s->c compression */
+
+/* they all return 0 if all went well, 1 or !=0 if not. the most common error is unmatched algo (unimplemented) */
+/* don't forget other errors can happen if no matching algo is found in sshd answer */
+
+int options_set_wanted_method(SSH_OPTIONS *opt,int method, char *list){
+ if(method > 9 || method < 0){
+ ssh_set_error(NULL,SSH_FATAL,"method %d out of range",method);
+ return -1;
+ }
+ if( (!opt->use_nonexisting_algo) && !verify_existing_algo(method,list)){
+ ssh_set_error(NULL,SSH_FATAL,"Setting method : no algorithm for method \"%s\" (%s)\n",ssh_kex_nums[method],list);
+ return -1;
+ }
+ if(opt->wanted_methods[method])
+ free(opt->wanted_methods[method]);
+ opt->wanted_methods[method]=strdup(list);
+ return 0;
+}
+
+static char *get_username_from_uid(int uid){
+ struct passwd *pwd;
+ char *user;
+ while((pwd=getpwent())){
+ if(pwd->pw_uid == uid){
+ user=strdup(pwd->pw_name);
+ endpwent();
+ return user;
+ }
+ }
+ endpwent();
+ ssh_set_error(NULL,SSH_FATAL,"uid %d doesn't exist !",uid);
+ return NULL;
+}
+
+/* this function must be called when no specific username has been asked. it has to guess it */
+int options_default_username(SSH_OPTIONS *opt){
+ char *user;
+ if(opt->username)
+ return 0;
+ user=getenv("USER");
+ if(user){
+ opt->username=strdup(user);
+ return 0;
+ }
+ user=get_username_from_uid(getuid());
+ if(user){
+ opt->username=user;
+ return 0;
+ }
+ return -1;
+}
+
+int options_default_ssh_dir(SSH_OPTIONS *opt){
+ char buffer[256];
+ if(opt->ssh_dir)
+ return 0;
+ snprintf(buffer,256,"%s/.ssh/",ssh_get_user_home_dir());
+ opt->ssh_dir=strdup(buffer);
+ return 0;
+}
+
+int options_default_known_hosts_file(SSH_OPTIONS *opt){
+ char buffer[1024];
+ if(opt->known_hosts_file)
+ return 0;
+ options_default_ssh_dir(opt);
+ snprintf(buffer,1024,"%s/known_hosts",opt->ssh_dir);
+ opt->known_hosts_file=strdup(buffer);
+ return 0;
+}
+
+void options_set_status_callback(SSH_OPTIONS *opt, void (*callback)(void *arg, float status), void *arg ){
+ opt->connect_status_function=callback;
+ opt->connect_status_arg=arg;
+}
+
+void options_set_timeout(SSH_OPTIONS *opt, long seconds,long usec){
+ opt->timeout=seconds;
+ opt->timeout_usec=usec;
+}
+
+SSH_OPTIONS *ssh_getopt(int *argcptr, char **argv){
+ int i;
+ int argc=*argcptr;
+ char *user=NULL;
+ int port=22;
+ int debuglevel=0;
+ int usersa=0;
+ int usedss=0;
+ int compress=0;
+ int cont=1;
+ char *cipher=NULL;
+ char *localaddr=NULL;
+ char *identity=NULL;
+ char **save=malloc(argc * sizeof(char *));
+ int current=0;
+
+ int saveoptind=optind; /* need to save 'em */
+ int saveopterr=opterr;
+ SSH_OPTIONS *options;
+ opterr=0; /* shut up getopt */
+ while(cont && ((i=getopt(argc,argv,"c:i:Cl:p:vb:rd12"))!=-1)){
+
+ switch(i){
+ case 'l':
+ user=optarg;
+ break;
+ case 'p':
+ port=atoi(optarg)&0xffff;
+ break;
+ case 'v':
+ debuglevel++;
+ break;
+ case 'r':
+ usersa++;
+ break;
+ case 'd':
+ usedss++;
+ break;
+ case 'c':
+ cipher=optarg;
+ break;
+ case 'i':
+ identity=optarg;
+ break;
+ case 'b':
+ localaddr=optarg;
+ break;
+ case 'C':
+ compress++;
+ break;
+ case '2':
+ break; /* only ssh2 support till now */
+ case '1':
+ ssh_set_error(NULL,SSH_FATAL,"libssh does not support SSH1 protocol");
+ cont =0;
+ break;
+ default:
+ {
+ char opt[3]="- ";
+ opt[1]=optopt;
+ save[current++]=strdup(opt);
+ if(optarg)
+ save[current++]=argv[optind+1];
+ }
+ }
+ }
+ opterr=saveopterr;
+ while(optind < argc)
+ save[current++]=argv[optind++];
+
+ if(usersa && usedss){
+ ssh_set_error(NULL,SSH_FATAL,"either RSA or DSS must be chosen");
+ cont=0;
+ }
+ ssh_set_verbosity(debuglevel);
+ optind=saveoptind;
+ if(!cont){
+ free(save);
+ return NULL;
+ }
+ /* first recopy the save vector into original's */
+ for(i=0;i<current;i++)
+ argv[i+1]=save[i]; /* don't erase argv[0] */
+ argv[current+1]=NULL;
+ *argcptr=current+1;
+ free(save);
+ /* set a new option struct */
+ options=options_new();
+ if(compress){
+ if(options_set_wanted_method(options,KEX_COMP_C_S,"zlib"))
+ cont=0;
+ if(options_set_wanted_method(options,KEX_COMP_S_C,"zlib"))
+ cont=0;
+ }
+ if(cont &&cipher){
+ if(options_set_wanted_method(options,KEX_CRYPT_C_S,cipher))
+ cont=0;
+ if(cont && options_set_wanted_method(options,KEX_CRYPT_S_C,cipher))
+ cont=0;
+ }
+ if(cont && usersa)
+ if(options_set_wanted_method(options,KEX_HOSTKEY,"ssh-rsa"))
+ cont=0;
+ if(cont && usedss)
+ if(options_set_wanted_method(options,KEX_HOSTKEY,"ssh-dss"))
+ cont=0;
+ if(cont && user)
+ options_set_username(options,user);
+ if(cont && identity)
+ options_set_identity(options,identity);
+ if(cont && localaddr)
+ options_set_bindaddr(options,localaddr);
+ options_set_port(options,port);
+ if(!cont){
+ options_free(options);
+ return NULL;
+ } else
+ return options;
+}
diff --git a/kftpgrabber/src/misc/libs/ssh/packet.c b/kftpgrabber/src/misc/libs/ssh/packet.c
new file mode 100644
index 0000000..c41e3a5
--- /dev/null
+++ b/kftpgrabber/src/misc/libs/ssh/packet.c
@@ -0,0 +1,303 @@
+/* packet.c */
+/* packet building functions */
+/*
+Copyright 2003 Aris Adamantiadis
+
+This file is part of the SSH Library
+
+The SSH Library is free software; you can redistribute it and/or modify
+it under the terms of the GNU Lesser General Public License as published by
+the Free Software Foundation; either version 2.1 of the License, or (at your
+option) any later version.
+
+The SSH Library 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 Lesser General Public
+License for more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with the SSH Library; see the file COPYING. If not, write to
+the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor, Boston,
+MA 02110-1301, USA. */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <string.h>
+#include "priv.h"
+#include "ssh2.h"
+#include <netdb.h>
+#include <errno.h>
+#include "crypto.h"
+
+/* XXX include selected mac size */
+static int macsize=SHA_DIGEST_LENGTH;
+
+/* completeread will read blocking until len bytes have been read */
+static int completeread(int fd, void *buffer, int len){
+ int r;
+ int total=0;
+ int toread=len;
+ while((r=read(fd,buffer+total,toread))){
+ if(r==-1)
+ return -1;
+ total += r;
+ toread-=r;
+ if(total==len)
+ return len;
+ if(r==0)
+ return 0;
+ }
+ return total ; /* connection closed */
+}
+
+int packet_read(SSH_SESSION *session){
+ u32 len;
+ void *packet=NULL;
+ char mac[30];
+ char buffer[16];
+ int be_read,i;
+ int to_be_read;
+ u8 padding;
+ unsigned int blocksize=(session->current_crypto?session->current_crypto->in_cipher->blocksize:8);
+ session->datatoread=0; /* clear the dataavailable flag */
+ memset(&session->in_packet,0,sizeof(PACKET));
+ if(session->in_buffer)
+ buffer_free(session->in_buffer);
+ session->in_buffer=buffer_new();
+
+ be_read=completeread(session->fd,buffer,blocksize);
+ if(be_read!=blocksize){
+ if(be_read<=0){
+ session->alive=0;
+ close(session->fd);
+ session->fd=-1;
+ ssh_set_error((session->connected?session:NULL),SSH_FATAL,
+ (be_read==0)?"Connection closed by remote host" : "Error reading socket");
+ return -1;
+ }
+ ssh_set_error((session->connected?session:NULL),SSH_FATAL,"read_packet(): asked %d bytes, received %d",blocksize,be_read);
+ return -1;
+ }
+ len=packet_decrypt_len(session,buffer);
+ buffer_add_data(session->in_buffer,buffer,blocksize);
+
+ if(len> MAX_PACKET_LEN){
+ ssh_set_error((session->connected?session:NULL),SSH_FATAL,"read_packet(): Packet len too high(%uld %.8lx)",len,len);
+ return -1;
+ }
+ to_be_read=len-be_read+sizeof(u32);
+ if(to_be_read<0){
+ /* remote sshd is trying to get me ?*/
+ ssh_set_error((session->connected?session:NULL),SSH_FATAL,"given numbers of bytes left to be read <0 (%d)!",to_be_read);
+ return -1;
+ }
+ /* handle the case in which the whole packet size = blocksize */
+ if(to_be_read !=0){
+ packet=malloc(to_be_read);
+ i=completeread(session->fd,packet,to_be_read);
+ if(i<=0){
+ session->alive=0;
+ close(session->fd);
+ session->fd=-1;
+ ssh_set_error((session->connected?session:NULL),SSH_FATAL,"Server closed connection");
+ return -1;
+ }
+ if(i!=to_be_read){
+ free(packet);
+ packet=NULL;
+ ssh_say(3,"Read only %d, wanted %d\n",i,to_be_read);
+ ssh_set_error((session->connected?session:NULL),SSH_FATAL,"read_packet(): read only %d, wanted %d",i,to_be_read);
+ return -1;
+ }
+ ssh_say(3,"Read a %d bytes packet\n",len);
+ buffer_add_data(session->in_buffer,packet,to_be_read);
+ free(packet);
+ }
+ if(session->current_crypto){
+ packet_decrypt(session,buffer_get(session->in_buffer)+blocksize,buffer_get_len(session->in_buffer)-blocksize);
+ if((i=completeread(session->fd,mac,macsize))!=macsize){
+ if(i<=0){
+ session->alive=0;
+ close(session->fd);
+ session->fd=-1;
+ ssh_set_error((session->connected?session:NULL),SSH_FATAL,"Server closed connection");
+ return -1;
+ }
+ ssh_set_error((session->connected?session:NULL),SSH_FATAL,"read_packet(): wanted %d, had %d",i,macsize);
+ return -1;
+ }
+ if(packet_hmac_verify(session,session->in_buffer,mac)){
+ ssh_set_error((session->connected?session:NULL),SSH_FATAL,"HMAC error");
+ return -1;
+ }
+ }
+ buffer_pass_bytes(session->in_buffer,sizeof(u32)); /*pass the size which has been processed before*/
+ if(!buffer_get_u8(session->in_buffer,&padding)){
+ ssh_set_error((session->connected?session:NULL),SSH_FATAL,"Packet too short to read padding");
+ return -1;
+ }
+ ssh_say(3,"%hhd bytes padding\n",padding);
+ if(padding > buffer_get_rest_len(session->in_buffer)){
+ ssh_set_error((session->connected?session:NULL),SSH_FATAL,"invalid padding: %d (%d resting)",padding,buffer_get_rest_len(session->in_buffer));
+ ssh_print_hexa("incrimined packet",buffer_get(session->in_buffer),buffer_get_len(session->in_buffer));
+ return -1;
+ }
+ buffer_pass_bytes_end(session->in_buffer,padding);
+#ifdef HAVE_LIBZ
+ if(session->current_crypto && session->current_crypto->do_compress_in){
+ decompress_buffer(session,session->in_buffer);
+ }
+#endif
+ session->recv_seq++;
+ return 0;
+}
+
+int packet_translate(SSH_SESSION *session){
+ memset(&session->in_packet,0,sizeof(PACKET));
+ if(!session->in_buffer)
+ return -1;
+ ssh_say(3,"Final size %d\n",buffer_get_rest_len(session->in_buffer));
+ if(!buffer_get_u8(session->in_buffer,&session->in_packet.type)){
+ ssh_set_error((session->connected?session:NULL),SSH_FATAL,"Packet too short to read type");
+ return -1;
+ }
+ ssh_say(3,"type %hhd\n",session->in_packet.type);
+ session->in_packet.valid=1;
+ return 0;
+}
+
+static int atomic_write(int fd, void *buffer, int len){
+ int written;
+ int total=0;
+ do {
+ written=write(fd,buffer,len);
+ if(written==0)
+ return 0;
+ if(written==-1)
+ return total;
+ total+=written;
+ len-=written;
+ buffer+=written;
+ } while (len > 0);
+ return total;
+}
+
+int packet_send(SSH_SESSION *session){
+ char padstring[32];
+ u32 finallen;
+ u8 padding;
+ u32 currentlen=buffer_get_len(session->out_buffer);
+ char *hmac;
+ int ret=0;
+ unsigned int blocksize=(session->current_crypto?session->current_crypto->out_cipher->blocksize:8);
+ ssh_say(3,"Writing on the wire a packet having %ld bytes before",currentlen);
+#ifdef HAVE_LIBZ
+ if(session->current_crypto && session->current_crypto->do_compress_out){
+ compress_buffer(session,session->out_buffer);
+ currentlen=buffer_get_len(session->out_buffer);
+ }
+#endif
+ padding=(blocksize- ((currentlen+5) % blocksize));
+ if(padding<4)
+ padding+=blocksize;
+ if(session->current_crypto)
+ ssh_get_random(padstring,padding);
+ else
+ memset(padstring,0,padding);
+ finallen=htonl(currentlen+padding+1);
+ ssh_say(3,",%d bytes after comp + %d padding bytes = %d bytes packet\n",currentlen,padding,(ntohl(finallen)));
+ buffer_add_data_begin(session->out_buffer,&padding,sizeof(u8));
+ buffer_add_data_begin(session->out_buffer,&finallen,sizeof(u32));
+ buffer_add_data(session->out_buffer,padstring,padding);
+ hmac=packet_encrypt(session,buffer_get(session->out_buffer),buffer_get_len(session->out_buffer));
+ if(hmac)
+ buffer_add_data(session->out_buffer,hmac,20);
+ if(atomic_write(session->fd,buffer_get(session->out_buffer),buffer_get_len(session->out_buffer))!=buffer_get_len(session->out_buffer)){
+ session->alive=0;
+ close(session->fd);
+ session->fd=-1;
+ ssh_set_error((session->connected?session:NULL),SSH_FATAL,"Writing packet : error on socket (or connection closed): %s",
+ strerror(errno));
+ ret=-1;
+ }
+ session->send_seq++;
+ buffer_reinit(session->out_buffer);
+ return ret;
+}
+
+void packet_parse(SSH_SESSION *session){
+ int type=session->in_packet.type;
+ u32 foo;
+ STRING *error_s;
+ char *error=NULL;
+
+ switch(type){
+ case SSH2_MSG_DISCONNECT:
+ buffer_get_u32(session->in_buffer,&foo);
+ error_s=buffer_get_ssh_string(session->in_buffer);
+ if(error_s)
+ error=string_to_char(error_s);
+ ssh_say(2,"Received SSH_MSG_DISCONNECT\n");
+ ssh_set_error((session->connected?session:NULL),SSH_FATAL,"Received SSH_MSG_DISCONNECT : %s",error);
+ if(error_s){
+ free(error_s);
+ free(error);
+ }
+ close(session->fd);
+ session->fd=-1;
+ session->alive=0;
+ return;
+ case SSH2_MSG_CHANNEL_WINDOW_ADJUST:
+ case SSH2_MSG_CHANNEL_DATA:
+ case SSH2_MSG_CHANNEL_EXTENDED_DATA:
+ case SSH2_MSG_CHANNEL_REQUEST:
+ case SSH2_MSG_CHANNEL_EOF:
+ case SSH2_MSG_CHANNEL_CLOSE:
+
+ channel_handle(session,type);
+ case SSH2_MSG_IGNORE:
+ return;
+ default:
+ ssh_say(0,"Received unhandled msg %d\n",type);
+ }
+}
+int packet_wait(SSH_SESSION *session,int type,int blocking){
+ while(1){
+ if(packet_read(session))
+ return -1;
+ if(packet_translate(session))
+ return -1;
+ switch(session->in_packet.type){
+ case SSH2_MSG_DISCONNECT:
+ packet_parse(session);
+ return -1;
+ case SSH2_MSG_CHANNEL_WINDOW_ADJUST:
+ case SSH2_MSG_CHANNEL_DATA:
+ case SSH2_MSG_CHANNEL_EXTENDED_DATA:
+ case SSH2_MSG_CHANNEL_REQUEST:
+ case SSH2_MSG_CHANNEL_EOF:
+ case SSH2_MSG_CHANNEL_CLOSE:
+ packet_parse(session);
+ break;;
+ case SSH2_MSG_IGNORE:
+ break;
+ default:
+ if(type && (type != session->in_packet.type)){
+ ssh_set_error((session->connected?session:NULL),SSH_FATAL,"waitpacket(): Received a %d type packet, was waiting for a %d\n",session->in_packet.type,type);
+ return -1;
+ }
+ return 0;
+ }
+ if(blocking==0)
+ return 0;
+ }
+ return 0;
+}
+
+void packet_clear_out(SSH_SESSION *session){
+ if(session->out_buffer)
+ buffer_reinit(session->out_buffer);
+ else
+ session->out_buffer=buffer_new();
+}
diff --git a/kftpgrabber/src/misc/libs/ssh/priv.h b/kftpgrabber/src/misc/libs/ssh/priv.h
new file mode 100644
index 0000000..2c93081
--- /dev/null
+++ b/kftpgrabber/src/misc/libs/ssh/priv.h
@@ -0,0 +1,384 @@
+/*
+Copyright 2003,04 Aris Adamantiadis
+
+This file is part of the SSH Library
+
+The SSH Library is free software; you can redistribute it and/or modify
+it under the terms of the GNU Lesser General Public License as published by
+the Free Software Foundation; either version 2.1 of the License, or (at your
+option) any later version.
+
+The SSH Library 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 Lesser General Public
+License for more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with the SSH Library; see the file COPYING. If not, write to
+the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor, Boston,
+MA 02110-1301, USA. */
+
+/* priv.h file */
+/* This include file contains everything you shouldn't deal with in user programs. */
+/* Consider that anything in this file might change without notice; libssh.h file will keep */
+/* backward compatibility on binary & source */
+
+#ifndef _LIBSSH_PRIV_H
+#define _LIBSSH_PRIV_H
+#include "libssh.h"
+
+/* Debugging constants */
+
+/* Define this if you want to debug crypto systems */
+/* it's usefull when you are debugging the lib */
+/*#define DEBUG_CRYPTO */
+
+/* some constants */
+#define MAX_PACKET_LEN 262144
+#define ERROR_BUFFERLEN 1024
+#define CLIENTBANNER "SSH-2.0-" LIBSSH_VERSION
+#define KBDINT_MAX_PROMPT 256 /* more than openssh's :) */
+/* some types for public keys */
+#define TYPE_DSS 1
+#define TYPE_RSA 2
+#define TYPE_RSA1 3
+
+/* profiling constants. Don't touch them unless you know what you do */
+#define OPENSSL_CRYPTO
+#define OPENSSL_BIGNUMS
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* wrapper things */
+
+#ifdef OPENSSL_CRYPTO
+#include <openssl/dsa.h>
+#include <openssl/rsa.h>
+#include <openssl/sha.h>
+#include <openssl/md5.h>
+#include <openssl/hmac.h>
+typedef SHA_CTX SHACTX;
+typedef MD5_CTX MD5CTX;
+typedef HMAC_CTX HMACCTX;
+#ifdef MD5_DIGEST_LEN
+ #undef MD5_DIGEST_LEN
+#endif
+#define SHA_DIGEST_LEN SHA_DIGEST_LENGTH
+#define MD5_DIGEST_LEN MD5_DIGEST_LENGTH
+
+#endif /* OPENSSL_CRYPTO */
+#ifdef OPENSSL_BIGNUMS
+#include <openssl/bn.h>
+typedef BIGNUM* bignum;
+typedef BN_CTX* bignum_CTX;
+
+#define bignum_new() BN_new()
+#define bignum_free(num) BN_clear_free(num)
+#define bignum_set_word(bn,n) BN_set_word(bn,n)
+#define bignum_bin2bn(bn,datalen,data) BN_bin2bn(bn,datalen,data)
+#define bignum_bn2hex(num) BN_bn2hex(num)
+#define bignum_rand(rnd, bits, top, bottom) BN_rand(rnd,bits,top,bottom)
+#define bignum_ctx_new() BN_CTX_new()
+#define bignum_ctx_free(num) BN_CTX_free(num)
+#define bignum_mod_exp(dest,generator,exp,modulo,ctx) BN_mod_exp(dest,generator,exp,modulo,ctx)
+#define bignum_num_bytes(num) BN_num_bytes(num)
+#define bignum_num_bits(num) BN_num_bits(num)
+#define bignum_is_bit_set(num,bit) BN_is_bit_set(num,bit)
+#define bignum_bn2bin(num,ptr) BN_bn2bin(num,ptr)
+
+#endif /* OPENSSL_BIGNUMS */
+#ifdef HAVE_SYS_TIME_H
+#include <sys/time.h>
+#endif
+
+/* wrapper.c */
+MD5CTX *md5_init(void);
+void md5_update(MD5CTX *c, const void *data, unsigned long len);
+void md5_final(unsigned char *md,MD5CTX *c);
+SHACTX *sha1_init(void);
+void sha1_update(SHACTX *c, const void *data, unsigned long len);
+void sha1_final(unsigned char *md,SHACTX *c);
+void sha1(unsigned char *digest,int len,unsigned char *hash);
+#define HMAC_SHA1 1
+#define HMAC_MD5 2
+HMACCTX *hmac_init(const void *key,int len,int type);
+void hmac_update(HMACCTX *c, const void *data, unsigned long len);
+void hmac_final(HMACCTX *ctx,unsigned char *hashmacbuf,int *len);
+
+/* strings and buffers */
+/* must be 32 bits number + immediatly our data */
+struct string_struct {
+ u32 size;
+ char string[MAX_PACKET_LEN];
+} __attribute__ ((packed));
+
+
+struct buffer_struct {
+ char *data;
+ int used;
+ int allocated;
+ int pos;
+};
+
+/* i should remove it one day */
+typedef struct packet_struct {
+ int valid;
+ u32 len;
+ u8 type;
+} PACKET;
+
+typedef struct kex_struct {
+ char cookie[16];
+ char **methods;
+} KEX;
+
+struct public_key_struct {
+ int type;
+ char *type_c; /* Don't free it ! it is static */
+ DSA *dsa_pub;
+ RSA *rsa_pub;
+};
+
+struct private_key_struct {
+ int type;
+ DSA *dsa_priv;
+ RSA *rsa_priv;
+};
+
+typedef struct signature_struct {
+ int type;
+ DSA_SIG *dsa_sign;
+ STRING *rsa_sign;
+} SIGNATURE;
+
+struct ssh_options_struct {
+ char *clientbanner; /* explicit banner to send */
+ char *username;
+ char *host;
+ char *bindaddr;
+ char *identity;
+ char *ssh_dir;
+ char *known_hosts_file;
+ int fd; /* specificaly wanted file descriptor, don't connect host */
+ int port;
+ int dont_verify_hostkey; /* Don't spare time, don't check host key ! unneeded to say it's dangerous and not safe */
+ int use_nonexisting_algo; /* if user sets a not supported algorithm for kex, don't complain */
+ char *wanted_methods[10]; /* the kex methods can be choosed. better use the kex fonctions to do that */
+ void *wanted_cookie; /* wants a specific cookie to be sent ? if null, generate a new one */
+ void *passphrase_function; /* this functions will be called if a keyphrase is needed. look keyfiles.c for more info */
+ void (*connect_status_function)(void *arg, float status); /* status callback function */
+ void *connect_status_arg; /* arbitrary argument */
+ long timeout; /* seconds */
+ long timeout_usec;
+ };
+
+typedef struct ssh_crypto_struct {
+ bignum e,f,x,k;
+ char session_id[SHA_DIGEST_LEN];
+
+ char encryptIV[SHA_DIGEST_LEN];
+ char decryptIV[SHA_DIGEST_LEN];
+
+ char decryptkey[SHA_DIGEST_LEN*2];
+ char encryptkey[SHA_DIGEST_LEN*2];
+
+ char encryptMAC[SHA_DIGEST_LEN];
+ char decryptMAC[SHA_DIGEST_LEN];
+ char hmacbuf[EVP_MAX_MD_SIZE];
+ struct crypto_struct *in_cipher, *out_cipher; /* the cipher structures/objects */
+ STRING *server_pubkey;
+ char *server_pubkey_type;
+ int do_compress_out; /* idem */
+ int do_compress_in; /* don't set them, set the option instead */
+ void *compress_out_ctx; /* don't touch it */
+ void *compress_in_ctx; /* really, don't */
+} CRYPTO;
+
+struct channel_struct {
+ struct channel_struct *prev;
+ struct channel_struct *next;
+ SSH_SESSION *session; /* SSH_SESSION pointer */
+ u32 local_channel;
+ u32 local_window;
+ int local_eof;
+ u32 local_maxpacket;
+ u32 remote_channel;
+ u32 remote_window;
+ int remote_eof; /* end of file received */
+ u32 remote_maxpacket;
+ int open; /* shows if the channel is still opened */
+ void (*write_fct)(struct channel_struct *channel, void *data, int len, void *userarg);
+ /* this write function is a callback on some userdefined function which is used for writing datas *coming from remote ssh* */
+ /* use channel_write() to write into a ssh pipe */
+ void (*write_err_fct)(struct channel_struct *channel, void *data, int len, void *userarg);
+ /* same as write_fct for stderr */
+ BUFFER *stdout_buffer;
+ BUFFER *stderr_buffer;
+ void *userarg;
+};
+
+struct ssh_session {
+ int fd;
+ SSH_OPTIONS *options;
+ char *serverbanner;
+ char *clientbanner;
+ int protoversion;
+ u32 send_seq;
+ u32 recv_seq;
+ int connected; /* !=0 when the user got a session handle */
+ int alive;
+ int auth_service_asked;
+ int datatoread; /* reading now on socket will not block */
+ STRING *banner; /* that's the issue banner from the server */
+ BUFFER *in_buffer;
+ PACKET in_packet;
+ BUFFER *out_buffer;
+ KEX server_kex;
+ KEX client_kex;
+ BUFFER *in_hashbuf;
+ BUFFER *out_hashbuf;
+ CRYPTO *current_crypto;
+ CRYPTO *next_crypto; /* next_crypto is going to be used after a SSH2_MSG_NEWKEYS */
+ CHANNEL *channels; /* linked list of channels */
+ int maxchannel;
+ int error_code;
+ char error_buffer[ERROR_BUFFERLEN];
+ struct ssh_kbdint *kbdint;
+};
+
+struct ssh_kbdint {
+ u32 nprompts;
+ char *name;
+ char *instruction;
+ char **prompts;
+ char *echo; /* bool array */
+ char **answers;
+};
+
+/* errors.c */
+void ssh_set_error(SSH_SESSION *session,enum ssh_error code,char *descr,...);
+
+/* in dh.c */
+/* DH key generation */
+void dh_generate_e(SSH_SESSION *session);
+void dh_generate_x(SSH_SESSION *session);
+STRING *dh_get_e(SSH_SESSION *session);
+void dh_import_f(SSH_SESSION *session,STRING *f_string);
+void dh_import_pubkey(SSH_SESSION *session,STRING *pubkey_string);
+void dh_build_k(SSH_SESSION *session);
+void make_sessionid(SSH_SESSION *session);
+/* add data for the final cookie */
+void hashbufin_add_cookie(SSH_SESSION *session,unsigned char *cookie);
+void hashbufout_add_cookie(SSH_SESSION *session);
+void generate_session_keys(SSH_SESSION *session);
+/* returns 1 if server signature ok, 0 otherwise. The NEXT crypto is checked, not the current one */
+int signature_verify(SSH_SESSION *session,STRING *signature);
+bignum make_string_bn(STRING *string);
+STRING *make_bignum_string(bignum num);
+
+/* in crypt.c */
+u32 packet_decrypt_len(SSH_SESSION *session,char *crypted);
+int packet_decrypt(SSH_SESSION *session, void *packet,unsigned int len);
+char *packet_encrypt(SSH_SESSION *session,void *packet,unsigned int len);
+ /* it returns the hmac buffer if exists*/
+int packet_hmac_verify(SSH_SESSION *session,BUFFER *buffer,char *mac);
+
+/* in packet.c */
+void packet_clear_out(SSH_SESSION *session);
+void packet_parse(SSH_SESSION *session);
+int packet_send(SSH_SESSION *session);
+int packet_read(SSH_SESSION *session);
+int packet_translate(SSH_SESSION *session);
+int packet_wait(SSH_SESSION *session,int type,int blocking);
+
+/* connect.c */
+SSH_SESSION *ssh_session_new();
+int ssh_connect_host(const char *host,const char *bind_addr, int port, long timeout, long usec);
+
+/* in kex.c */
+extern char *ssh_kex_nums[];
+void send_kex(SSH_SESSION *session,int server_kex);
+void list_kex(KEX *kex);
+int set_kex(SSH_SESSION *session);
+int ssh_get_kex(SSH_SESSION *session, int server_kex);
+int verify_existing_algo(int algo,char *name);
+char **space_tokenize(char *chain);
+
+/* in keys.c */
+char *ssh_type_to_char(int type);
+PUBLIC_KEY *publickey_make_dss(BUFFER *buffer);
+PUBLIC_KEY *publickey_make_rsa(BUFFER *buffer);
+PUBLIC_KEY *publickey_from_string(STRING *pubkey_s);
+SIGNATURE *signature_from_string(STRING *signature,PUBLIC_KEY *pubkey,int needed_type);
+void signature_free(SIGNATURE *sign);
+STRING *ssh_do_sign(SSH_SESSION *session,BUFFER *sigbuf, PRIVATE_KEY *privatekey);
+
+/* channel.c */
+void channel_handle(SSH_SESSION *session, int type);
+
+/* options.c */
+void options_free(SSH_OPTIONS *opt);
+/* this function must be called when no specific username has been asked. it has to guess it */
+int options_default_username(SSH_OPTIONS *opt);
+int options_default_ssh_dir(SSH_OPTIONS *opt);
+int options_default_known_hosts_file(SSH_OPTIONS *opt);
+
+/* buffer.c */
+void buffer_add_ssh_string(BUFFER *buffer,STRING *string);
+void buffer_add_u8(BUFFER *buffer, u8 data);
+void buffer_add_u32(BUFFER *buffer, u32 data);
+void buffer_add_u64(BUFFER *buffer,u64 data);
+void buffer_add_data(BUFFER *buffer, void *data, int len);
+void buffer_add_data_begin(BUFFER *buffer,void *data,int len);
+void buffer_add_buffer(BUFFER *buffer, BUFFER *source);
+void buffer_reinit(BUFFER *buffer);
+
+/* buffer_get_rest returns a pointer to the current position into the buffer */
+void *buffer_get_rest(BUFFER *buffer);
+/* buffer_get_rest_len returns the number of bytes which can be read */
+int buffer_get_rest_len(BUFFER *buffer);
+
+/* buffer_read_*() returns the number of bytes read, except for ssh strings */
+int buffer_get_u8(BUFFER *buffer,u8 *data);
+int buffer_get_u32(BUFFER *buffer,u32 *data);
+int buffer_get_u64(BUFFER *buffer, u64 *data);
+
+int buffer_get_data(BUFFER *buffer,void *data,int requestedlen);
+/* buffer_get_ssh_string() is an exception. if the String read is too large or invalid, it will answer NULL. */
+STRING *buffer_get_ssh_string(BUFFER *buffer);
+/* buffer_pass_bytes acts as if len bytes have been read (used for padding) */
+int buffer_pass_bytes_end(BUFFER *buffer,int len);
+int buffer_pass_bytes(BUFFER *buffer, int len);
+
+/* in base64.c */
+BUFFER *base64_to_bin(char *source);
+char *bin_to_base64(unsigned char *source, int len);
+
+/* gzip.c */
+int compress_buffer(SSH_SESSION *session,BUFFER *buf);
+int decompress_buffer(SSH_SESSION *session,BUFFER *buf);
+
+/* wrapper.c */
+int crypt_set_algorithms(SSH_SESSION *);
+CRYPTO *crypto_new();
+void crypto_free(CRYPTO *crypto);
+bignum bignum_new();
+
+/* in misc.c */
+/* gets the user home dir. */
+char *ssh_get_user_home_dir();
+int ssh_file_readaccess_ok(char *file);
+
+/* macro for byte ordering */
+u64 ntohll(u64);
+#define htonll(x) ntohll(x)
+
+
+#ifdef __cplusplus
+} ;
+#endif
+
+#endif /* _LIBSSH_PRIV_H */
diff --git a/kftpgrabber/src/misc/libs/ssh/sftp.c b/kftpgrabber/src/misc/libs/ssh/sftp.c
new file mode 100644
index 0000000..9895456
--- /dev/null
+++ b/kftpgrabber/src/misc/libs/ssh/sftp.c
@@ -0,0 +1,1289 @@
+/* scp.c contains the needed function to work with file transfer protocol over ssh*/
+/* don't look further if you believe this is just FTP over some tunnel. It IS different */
+/* This file contains code written by Nick Zitzmann */
+/*
+Copyright 2003 Aris Adamantiadis
+
+This file is part of the SSH Library
+
+The SSH Library is free software; you can redistribute it and/or modify
+it under the terms of the GNU Lesser General Public License as published by
+the Free Software Foundation; either version 2.1 of the License, or (at your
+option) any later version.
+
+The SSH Library 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 Lesser General Public
+License for more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with the SSH Library; see the file COPYING. If not, write to
+the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor, Boston,
+MA 02110-1301, USA. */
+
+
+#include <string.h>
+#include <fcntl.h>
+#include <netdb.h>
+#include "priv.h"
+#include "ssh2.h"
+#include "sftp.h"
+#ifndef NO_SFTP
+/* here how it works : sftp commands are channeled by the ssh sftp subsystem. */
+/* every packet are sent/read using a SFTP_PACKET type structure. */
+/* into these packets, most of the server answers are messages having an ID and */
+/* having a message specific part. it is described by SFTP_MESSAGE */
+/* when reading a message, the sftp system puts it into the queue, so the process having asked for it */
+/* can fetch it, while continuing to read for other messages (it is inspecified in which order messages may */
+/* be sent back to the client */
+
+
+/* functions */
+static void sftp_packet_free(SFTP_PACKET *packet);
+void sftp_enqueue(SFTP_SESSION *session, SFTP_MESSAGE *msg);
+static void sftp_message_free(SFTP_MESSAGE *msg);
+
+SFTP_SESSION *sftp_new(SSH_SESSION *session){
+ SFTP_SESSION *sftp=malloc(sizeof(SFTP_SESSION));
+ memset(sftp,0,sizeof(SFTP_SESSION));
+ sftp->session=session;
+ sftp->channel=open_session_channel(session,131000,32000);
+ if(!sftp->channel){
+ free(sftp);
+ return NULL;
+ }
+ if(channel_request_sftp(sftp->channel)){
+ sftp_free(sftp);
+ return NULL;
+ }
+ return sftp;
+}
+
+void sftp_free(SFTP_SESSION *sftp){
+ struct request_queue *ptr;
+ channel_send_eof(sftp->channel);
+ /* let libssh handle the channel closing from the server reply */
+ ptr=sftp->queue;
+ while(ptr){
+ struct request_queue *old;
+ sftp_message_free(ptr->message);
+ old=ptr->next;
+ free(ptr);
+ ptr=old;
+ }
+ memset(sftp,0,sizeof(*sftp));
+ free(sftp);
+}
+
+int sftp_packet_write(SFTP_SESSION *sftp,u8 type, BUFFER *payload){
+ u32 size;
+ buffer_add_data_begin(payload,&type,sizeof(u8));
+ size=htonl(buffer_get_len(payload));
+ buffer_add_data_begin(payload,&size,sizeof(u32));
+ size=channel_write(sftp->channel,buffer_get(payload),buffer_get_len(payload));
+ if(size != buffer_get_len(payload)){
+ ssh_say(1,"had to write %d bytes, wrote only %d\n",buffer_get_len(payload),size);
+ }
+ return size;
+}
+
+SFTP_PACKET *sftp_packet_read(SFTP_SESSION *sftp){
+ SFTP_PACKET *packet=malloc(sizeof(SFTP_PACKET));
+ u32 size;
+ packet->sftp=sftp;
+ packet->payload=buffer_new();
+ if(channel_read(sftp->channel,packet->payload,4,0)<=0){
+ buffer_free(packet->payload);
+ free(packet);
+ return NULL;
+ }
+ buffer_get_u32(packet->payload,&size);
+ size=ntohl(size);
+ if(channel_read(sftp->channel,packet->payload,1,0)<=0){
+ buffer_free(packet->payload);
+ free(packet);
+ return NULL;
+ }
+ buffer_get_u8(packet->payload,&packet->type);
+ if(size>1)
+ if(channel_read(sftp->channel,packet->payload,size-1,0)<=0){
+ buffer_free(packet->payload);
+ free(packet);
+ return NULL;
+ }
+ return packet;
+}
+
+static SFTP_MESSAGE *sftp_message_new(){
+ SFTP_MESSAGE *msg=malloc(sizeof(SFTP_MESSAGE));
+ memset(msg,0,sizeof(*msg));
+ msg->payload=buffer_new();
+ return msg;
+}
+
+static void sftp_message_free(SFTP_MESSAGE *msg){
+ if(msg->payload)
+ buffer_free(msg->payload);
+ free(msg);
+}
+
+SFTP_MESSAGE *sftp_get_message(SFTP_PACKET *packet){
+ SFTP_MESSAGE *msg=sftp_message_new();
+ msg->sftp=packet->sftp;
+ msg->packet_type=packet->type;
+ if((packet->type!=SSH_FXP_STATUS)&&(packet->type!=SSH_FXP_HANDLE) &&
+ (packet->type != SSH_FXP_DATA) && (packet->type != SSH_FXP_ATTRS)
+ && (packet->type != SSH_FXP_NAME)){
+ ssh_set_error(packet->sftp->session,SSH_INVALID_DATA,"get_message : unknown packet type %d\n",packet->type);
+ sftp_message_free(msg);
+ return NULL;
+ }
+ if(buffer_get_u32(packet->payload,&msg->id)!=sizeof(u32)){
+ ssh_set_error(packet->sftp->session,SSH_INVALID_DATA,"invalid packet %d : no ID",packet->type);
+ sftp_message_free(msg);
+ return NULL;
+ }
+ ssh_say(2,"packet with id %d type %d\n",msg->id,msg->packet_type);
+ buffer_add_data(msg->payload,buffer_get_rest(packet->payload),buffer_get_rest_len(packet->payload));
+ return msg;
+}
+
+int sftp_read_and_dispatch(SFTP_SESSION *session){
+ SFTP_PACKET *packet;
+ SFTP_MESSAGE *message=NULL;
+ packet=sftp_packet_read(session);
+ if(!packet)
+ return -1; /* something nasty happened reading the packet */
+ message=sftp_get_message(packet);
+ sftp_packet_free(packet);
+ if(!message)
+ return -1;
+ sftp_enqueue(session,message);
+ return 0;
+}
+
+static void sftp_packet_free(SFTP_PACKET *packet){
+ if(packet->payload)
+ buffer_free(packet->payload);
+ free(packet);
+}
+
+int sftp_init(SFTP_SESSION *sftp){
+ SFTP_PACKET *packet;
+ BUFFER *buffer=buffer_new();
+ STRING *ext_name_s=NULL, *ext_data_s=NULL;
+ char *ext_name,*ext_data;
+ u32 version=htonl(LIBSFTP_VERSION);
+ buffer_add_u32(buffer,version);
+ sftp_packet_write(sftp,SSH_FXP_INIT,buffer);
+ buffer_free(buffer);
+ packet=sftp_packet_read(sftp);
+ if(!packet)
+ return -1;
+ if(packet->type != SSH_FXP_VERSION){
+ ssh_set_error(sftp->session,SSH_INVALID_DATA,"Received a %d messages instead of SSH_FXP_VERSION",packet->type);
+ sftp_packet_free(packet);
+ return -1;
+ }
+ buffer_get_u32(packet->payload,&version);
+ version=ntohl(version);
+ if(!(ext_name_s=buffer_get_ssh_string(packet->payload))||!(ext_data_s=buffer_get_ssh_string(packet->payload)))
+ ssh_say(2,"sftp server version %d\n",version);
+ else{
+ ext_name=string_to_char(ext_name_s);
+ ext_data=string_to_char(ext_data_s);
+ ssh_say(2,"sftp server version %d (%s,%s)\n",version,ext_name,ext_data);
+ free(ext_name);
+ free(ext_data);
+ }
+ if(ext_name_s)
+ free(ext_name_s);
+ if(ext_data_s)
+ free(ext_data_s);
+ sftp_packet_free(packet);
+ sftp->server_version=version;
+ return 0;
+}
+
+REQUEST_QUEUE *request_queue_new(SFTP_MESSAGE *msg){
+ REQUEST_QUEUE *queue=malloc(sizeof(REQUEST_QUEUE));
+ memset(queue,0,sizeof(REQUEST_QUEUE));
+ queue->message=msg;
+ return queue;
+}
+
+void request_queue_free(REQUEST_QUEUE *queue){
+ memset(queue,0,sizeof(*queue));
+ free(queue);
+}
+
+void sftp_enqueue(SFTP_SESSION *session, SFTP_MESSAGE *msg){
+ REQUEST_QUEUE *queue=request_queue_new(msg);
+ REQUEST_QUEUE *ptr;
+ ssh_say(2,"queued msg type %d id %d\n",msg->id,msg->packet_type);
+ if(!session->queue)
+ session->queue=queue;
+ else {
+ ptr=session->queue;
+ while(ptr->next){
+ ptr=ptr->next; /* find end of linked list */
+ }
+ ptr->next=queue; /* add it on bottom */
+ }
+}
+
+/* pulls of a message from the queue based on the ID. returns null if no message has been found */
+SFTP_MESSAGE *sftp_dequeue(SFTP_SESSION *session, u32 id){
+ REQUEST_QUEUE *queue,*prev=NULL;
+ SFTP_MESSAGE *msg;
+ if(session->queue==NULL){
+ return NULL;
+ }
+ queue=session->queue;
+ while(queue){
+ if(queue->message->id==id){
+ /* remove from queue */
+ if(prev==NULL){
+ session->queue=queue->next;
+ } else {
+ prev->next=queue->next;
+ }
+ msg=queue->message;
+ request_queue_free(queue);
+ ssh_say(2,"dequeued msg id %d type %d\n",msg->id,msg->packet_type);
+ return msg;
+ }
+ prev=queue;
+ queue=queue->next;
+ }
+ return NULL;
+}
+
+/* assigns a new sftp ID for new requests and assures there is no collision between them. */
+u32 sftp_get_new_id(SFTP_SESSION *session){
+ return ++session->id_counter;
+}
+
+STATUS_MESSAGE *parse_status_msg(SFTP_MESSAGE *msg){
+ STATUS_MESSAGE *status;
+ if(msg->packet_type != SSH_FXP_STATUS){
+ ssh_set_error(msg->sftp->session, SSH_INVALID_DATA,"Not a ssh_fxp_status message passed in !");
+ return NULL;
+ }
+ status=malloc(sizeof(STATUS_MESSAGE));
+ memset(status,0,sizeof(*status));
+ status->id=msg->id;
+ if( (buffer_get_u32(msg->payload,&status->status)!= 4)
+ || !(status->error=buffer_get_ssh_string(msg->payload)) ||
+ !(status->lang=buffer_get_ssh_string(msg->payload))){
+ if(status->error)
+ free(status->error);
+ /* status->lang never get allocated if something failed */
+ free(status);
+ ssh_set_error(msg->sftp->session,SSH_INVALID_DATA,"invalid SSH_FXP_STATUS message");
+ return NULL;
+ }
+ status->status=ntohl(status->status);
+ status->errormsg=string_to_char(status->error);
+ status->langmsg=string_to_char(status->lang);
+ return status;
+}
+
+void status_msg_free(STATUS_MESSAGE *status){
+ if(status->errormsg)
+ free(status->errormsg);
+ if(status->error)
+ free(status->error);
+ if(status->langmsg)
+ free(status->langmsg);
+ if(status->lang)
+ free(status->lang);
+ free(status);
+}
+
+SFTP_FILE *parse_handle_msg(SFTP_MESSAGE *msg){
+ SFTP_FILE *file;
+ if(msg->packet_type != SSH_FXP_HANDLE){
+ ssh_set_error(msg->sftp->session,SSH_INVALID_DATA,"Not a ssh_fxp_handle message passed in !");
+ return NULL;
+ }
+ file=malloc(sizeof(SFTP_FILE));
+ memset(file,0,sizeof(*file));
+ file->sftp=msg->sftp;
+ file->handle=buffer_get_ssh_string(msg->payload);
+ file->offset=0;
+ file->eof=0;
+ if(!file->handle){
+ ssh_set_error(msg->sftp->session,SSH_INVALID_DATA,"Invalid SSH_FXP_HANDLE message");
+ free(file);
+ return NULL;
+ }
+ return file;
+}
+
+SFTP_DIR *sftp_opendir(SFTP_SESSION *sftp, char *path){
+ SFTP_DIR *dir=NULL;
+ SFTP_FILE *file;
+ STATUS_MESSAGE *status;
+ SFTP_MESSAGE *msg=NULL;
+ STRING *path_s;
+ BUFFER *payload=buffer_new();
+ u32 id=sftp_get_new_id(sftp);
+ buffer_add_u32(payload,id);
+ path_s=string_from_char(path);
+ buffer_add_ssh_string(payload,path_s);
+ free(path_s);
+ sftp_packet_write(sftp,SSH_FXP_OPENDIR,payload);
+ buffer_free(payload);
+ while(!msg){
+ if(sftp_read_and_dispatch(sftp))
+ /* something nasty has happened */
+ return NULL;
+ msg=sftp_dequeue(sftp,id);
+ }
+ switch (msg->packet_type){
+ case SSH_FXP_STATUS:
+ status=parse_status_msg(msg);
+ sftp_message_free(msg);
+ if(!status)
+ return NULL;
+ ssh_set_error(sftp->session,SSH_REQUEST_DENIED,"sftp server : %s",status->errormsg);
+ status_msg_free(status);
+ return NULL;
+ case SSH_FXP_HANDLE:
+ file=parse_handle_msg(msg);
+ sftp_message_free(msg);
+ if(file){
+ dir=malloc(sizeof(SFTP_DIR));
+ memset(dir,0,sizeof(*dir));
+ dir->sftp=sftp;
+ dir->name=strdup(path);
+ dir->handle=file->handle;
+ free(file);
+ }
+ return dir;
+ default:
+ ssh_set_error(sftp->session,SSH_INVALID_DATA,"Received message %d during opendir!",msg->packet_type);
+ sftp_message_free(msg);
+ }
+ return NULL;
+}
+
+/* parse the attributes from a payload from some messages */
+/* i coded it on baselines from the protocol version 4. */
+/* please excuse me for the inaccuracy of the code. it isn't my fault, it's sftp draft's one */
+/* this code is dead anyway ... */
+/* version 4 specific code */
+SFTP_ATTRIBUTES *sftp_parse_attr_4(SFTP_SESSION *sftp,BUFFER *buf,int expectnames){
+ u32 flags=0;
+ SFTP_ATTRIBUTES *attr=malloc(sizeof(SFTP_ATTRIBUTES));
+ STRING *owner=NULL;
+ STRING *group=NULL;
+ int ok=0;
+ memset(attr,0,sizeof(*attr));
+ /* it isn't really a loop, but i use it because it's like a try..catch.. construction in C */
+ do {
+ if(buffer_get_u32(buf,&flags)!=4)
+ break;
+ flags=ntohl(flags);
+ attr->flags=flags;
+ if(flags & SSH_FILEXFER_ATTR_SIZE){
+ if(buffer_get_u64(buf,&attr->size)!=8)
+ break;
+ attr->size=ntohll(attr->size);
+ }
+ if(flags & SSH_FILEXFER_ATTR_OWNERGROUP){
+ if(!(owner=buffer_get_ssh_string(buf)))
+ break;
+ if(!(group=buffer_get_ssh_string(buf)))
+ break;
+ }
+ if(flags & SSH_FILEXFER_ATTR_PERMISSIONS){
+ if(buffer_get_u32(buf,&attr->permissions)!=4)
+ break;
+ attr->permissions=ntohl(attr->permissions);
+ }
+ if(flags & SSH_FILEXFER_ATTR_ACCESSTIME){
+ if(buffer_get_u64(buf,&attr->atime64)!=8)
+ break;
+ attr->atime64=ntohll(attr->atime64);
+ }
+ if(flags & SSH_FILEXFER_ATTR_SUBSECOND_TIMES){
+ if(buffer_get_u32(buf,&attr->atime_nseconds)!=4)
+ break;
+ attr->atime_nseconds=ntohl(attr->atime_nseconds);
+ }
+ if(flags & SSH_FILEXFER_ATTR_CREATETIME){
+ if(buffer_get_u64(buf,&attr->createtime)!=8)
+ break;
+ attr->createtime=ntohll(attr->createtime);
+ }
+ if(flags & SSH_FILEXFER_ATTR_SUBSECOND_TIMES){
+ if(buffer_get_u32(buf,&attr->createtime_nseconds)!=4)
+ break;
+ attr->createtime_nseconds=ntohl(attr->createtime_nseconds);
+ }
+ if(flags & SSH_FILEXFER_ATTR_MODIFYTIME){
+ if(buffer_get_u64(buf,&attr->mtime64)!=8)
+ break;
+ attr->mtime64=ntohll(attr->mtime64);
+ }
+ if(flags & SSH_FILEXFER_ATTR_SUBSECOND_TIMES){
+ if(buffer_get_u32(buf,&attr->mtime_nseconds)!=4)
+ break;
+ attr->mtime_nseconds=ntohl(attr->mtime_nseconds);
+ }
+ if(flags & SSH_FILEXFER_ATTR_ACL){
+ if(!(attr->acl=buffer_get_ssh_string(buf)))
+ break;
+ }
+ if (flags & SSH_FILEXFER_ATTR_EXTENDED){
+ if(buffer_get_u32(buf,&attr->extended_count)!=4)
+ break;
+ attr->extended_count=ntohl(attr->extended_count);
+ while(attr->extended_count && (attr->extended_type=buffer_get_ssh_string(buf))
+ && (attr->extended_data=buffer_get_ssh_string(buf))){
+ attr->extended_count--;
+ }
+ if(attr->extended_count)
+ break;
+ }
+ ok=1;
+ } while (0);
+ if(!ok){
+ /* break issued somewhere */
+ if(owner)
+ free(owner);
+ if(group)
+ free(group);
+ if(attr->acl)
+ free(attr->acl);
+ if(attr->extended_type)
+ free(attr->extended_type);
+ if(attr->extended_data)
+ free(attr->extended_data);
+ free(attr);
+ ssh_set_error(sftp->session,SSH_INVALID_DATA,"Invalid ATTR structure");
+ return NULL;
+ }
+ /* everything went smoothly */
+ if(owner){
+ attr->owner=string_to_char(owner);
+ free(owner);
+ }
+ if(group){
+ attr->group=string_to_char(group);
+ free(group);
+ }
+ return attr;
+}
+
+/* Version 3 code. it is the only one really supported (the draft for the 4 misses clarifications) */
+/* maybe a paste of the draft is better than the code */
+/*
+ uint32 flags
+ uint64 size present only if flag SSH_FILEXFER_ATTR_SIZE
+ uint32 uid present only if flag SSH_FILEXFER_ATTR_UIDGID
+ uint32 gid present only if flag SSH_FILEXFER_ATTR_UIDGID
+ uint32 permissions present only if flag SSH_FILEXFER_ATTR_PERMISSIONS
+ uint32 atime present only if flag SSH_FILEXFER_ACMODTIME
+ uint32 mtime present only if flag SSH_FILEXFER_ACMODTIME
+ uint32 extended_count present only if flag SSH_FILEXFER_ATTR_EXTENDED
+ string extended_type
+ string extended_data
+ ... more extended data (extended_type - extended_data pairs),
+ so that number of pairs equals extended_count */
+SFTP_ATTRIBUTES *sftp_parse_attr_3(SFTP_SESSION *sftp,BUFFER *buf,int expectname){
+ u32 flags=0;
+ STRING *name;
+ STRING *longname;
+ SFTP_ATTRIBUTES *attr=malloc(sizeof(SFTP_ATTRIBUTES));
+ int ok=0;
+ memset(attr,0,sizeof(*attr));
+ /* it isn't really a loop, but i use it because it's like a try..catch.. construction in C */
+ do {
+ if(expectname){
+ if(!(name=buffer_get_ssh_string(buf)))
+ break;
+ attr->name=string_to_char(name);
+ free(name);
+ ssh_say(2,"name : %s\n",attr->name);
+ if(!(longname=buffer_get_ssh_string(buf)))
+ break;
+ attr->longname=string_to_char(longname);
+ free(longname);
+ }
+ if(buffer_get_u32(buf,&flags)!=sizeof(u32))
+ break;
+ flags=ntohl(flags);
+ attr->flags=flags;
+ ssh_say(2,"flags : %.8lx\n",flags);
+ if(flags & SSH_FILEXFER_ATTR_SIZE){
+ if(buffer_get_u64(buf,&attr->size)!=sizeof(u64))
+ break;
+ attr->size=ntohll(attr->size);
+ ssh_say(2,"size : %lld\n",attr->size);
+ }
+ if(flags & SSH_FILEXFER_ATTR_UIDGID){
+ if(buffer_get_u32(buf,&attr->uid)!=sizeof(u32))
+ break;
+ if(buffer_get_u32(buf,&attr->gid)!=sizeof(u32))
+ break;
+ attr->uid=ntohl(attr->uid);
+ attr->gid=ntohl(attr->gid);
+ }
+ if(flags & SSH_FILEXFER_ATTR_PERMISSIONS){
+ if(buffer_get_u32(buf,&attr->permissions)!=sizeof(u32))
+ break;
+ attr->permissions=ntohl(attr->permissions);
+ }
+ if(flags & SSH_FILEXFER_ATTR_ACMODTIME){
+ if(buffer_get_u32(buf,&attr->atime)!=sizeof(u32))
+ break;
+ attr->atime=ntohl(attr->atime);
+ if(buffer_get_u32(buf,&attr->mtime)!=sizeof(u32))
+ break;
+ attr->mtime=ntohl(attr->mtime);
+ }
+ if (flags & SSH_FILEXFER_ATTR_EXTENDED){
+ if(buffer_get_u32(buf,&attr->extended_count)!=sizeof(u32))
+ break;
+ attr->extended_count=ntohl(attr->extended_count);
+ while(attr->extended_count && (attr->extended_type=buffer_get_ssh_string(buf))
+ && (attr->extended_data=buffer_get_ssh_string(buf))){
+ attr->extended_count--;
+ }
+ if(attr->extended_count)
+ break;
+ }
+ ok=1;
+ } while (0);
+ if(!ok){
+ /* break issued somewhere */
+ if(attr->name)
+ free(attr->name);
+ if(attr->extended_type)
+ free(attr->extended_type);
+ if(attr->extended_data)
+ free(attr->extended_data);
+ free(attr);
+ ssh_set_error(sftp->session,SSH_INVALID_DATA,"Invalid ATTR structure");
+ return NULL;
+ }
+ /* everything went smoothly */
+ return attr;
+}
+
+void buffer_add_attributes(BUFFER *buffer, SFTP_ATTRIBUTES *attr){
+ u32 flags=(attr?attr->flags:0);
+ flags &= (SSH_FILEXFER_ATTR_SIZE | SSH_FILEXFER_ATTR_UIDGID | SSH_FILEXFER_ATTR_PERMISSIONS | SSH_FILEXFER_ATTR_ACMODTIME);
+ buffer_add_u32(buffer,htonl(flags));
+ if(attr){
+ if (flags & SSH_FILEXFER_ATTR_SIZE)
+ {
+ buffer_add_u64(buffer, htonll(attr->size));
+ }
+ if(flags & SSH_FILEXFER_ATTR_UIDGID){
+ buffer_add_u32(buffer,htonl(attr->uid));
+ buffer_add_u32(buffer,htonl(attr->gid));
+ }
+ if(flags & SSH_FILEXFER_ATTR_PERMISSIONS){
+ buffer_add_u32(buffer,htonl(attr->permissions));
+ }
+ if (flags & SSH_FILEXFER_ATTR_ACMODTIME)
+ {
+ buffer_add_u32(buffer, htonl(attr->atime));
+ buffer_add_u32(buffer, htonl(attr->mtime));
+ }
+ }
+}
+
+
+SFTP_ATTRIBUTES *sftp_parse_attr(SFTP_SESSION *session, BUFFER *buf,int expectname){
+ switch(session->server_version){
+ case 4:
+ return sftp_parse_attr_4(session,buf,expectname);
+ case 3:
+ return sftp_parse_attr_3(session,buf,expectname);
+ default:
+ ssh_set_error(session->session,SSH_INVALID_DATA,"Version %d unsupported by client",session->server_version);
+ return NULL;
+ }
+ return NULL;
+}
+
+int sftp_server_version(SFTP_SESSION *sftp){
+ return sftp->server_version;
+}
+
+SFTP_ATTRIBUTES *sftp_readdir(SFTP_SESSION *sftp, SFTP_DIR *dir){
+ BUFFER *payload;
+ u32 id;
+ SFTP_MESSAGE *msg=NULL;
+ STATUS_MESSAGE *status;
+ SFTP_ATTRIBUTES *attr;
+ if(!dir->buffer){
+ payload=buffer_new();
+ id=sftp_get_new_id(sftp);
+ buffer_add_u32(payload,id);
+ buffer_add_ssh_string(payload,dir->handle);
+ sftp_packet_write(sftp,SSH_FXP_READDIR,payload);
+ buffer_free(payload);
+ ssh_say(2,"sent a ssh_fxp_readdir with id %d\n",id);
+ while(!msg){
+ if(sftp_read_and_dispatch(sftp))
+ /* something nasty has happened */
+ return NULL;
+ msg=sftp_dequeue(sftp,id);
+ }
+ switch (msg->packet_type){
+ case SSH_FXP_STATUS:
+ status=parse_status_msg(msg);
+ sftp_message_free(msg);
+ if(!status)
+ return NULL;
+ if(status->status==SSH_FX_EOF){
+ dir->eof=1;
+ status_msg_free(status);
+ return NULL;
+ }
+ ssh_set_error(sftp->session,SSH_INVALID_DATA,"Unknown error status : %d",status->status);
+ status_msg_free(status);
+ return NULL;
+ case SSH_FXP_NAME:
+ buffer_get_u32(msg->payload,&dir->count);
+ dir->count=ntohl(dir->count);
+ dir->buffer=msg->payload;
+ msg->payload=NULL;
+ sftp_message_free(msg);
+ break;
+ default:
+ ssh_set_error(sftp->session,SSH_INVALID_DATA,"unsupported message back %d",msg->packet_type);
+ sftp_message_free(msg);
+ return NULL;
+ }
+ }
+ /* now dir->buffer contains a buffer and dir->count != 0 */
+ if(dir->count==0){
+ ssh_set_error(sftp->session,SSH_INVALID_DATA,"Count of files sent by the server is zero, which is invalid, or libsftp bug");
+ return NULL;
+ }
+ ssh_say(2,"Count is %d\n",dir->count);
+ attr=sftp_parse_attr(sftp,dir->buffer,1);
+ dir->count--;
+ if(dir->count==0){
+ buffer_free(dir->buffer);
+ dir->buffer=NULL;
+ }
+ return attr;
+}
+
+int sftp_dir_eof(SFTP_DIR *dir){
+ return (dir->eof);
+}
+
+void sftp_attributes_free(SFTP_ATTRIBUTES *file){
+ if(file->name)
+ free(file->name);
+ if(file->longname)
+ free(file->longname);
+ if(file->acl)
+ free(file->acl);
+ if(file->extended_data)
+ free(file->extended_data);
+ if(file->extended_type)
+ free(file->extended_type);
+ if(file->group)
+ free(file->group);
+ if(file->owner)
+ free(file->owner);
+ free(file);
+}
+
+static int sftp_handle_close(SFTP_SESSION *sftp, STRING *handle){
+ SFTP_MESSAGE *msg=NULL;
+ STATUS_MESSAGE *status;
+ int id=sftp_get_new_id(sftp);
+ int err=0;
+ BUFFER *buffer=buffer_new();
+ buffer_add_u32(buffer,id);
+ buffer_add_ssh_string(buffer,handle);
+ sftp_packet_write(sftp,SSH_FXP_CLOSE,buffer);
+ buffer_free(buffer);
+ while(!msg){
+ if(sftp_read_and_dispatch(sftp))
+ /* something nasty has happened */
+ return -1;
+ msg=sftp_dequeue(sftp,id);
+ }
+ switch (msg->packet_type){
+ case SSH_FXP_STATUS:
+ status=parse_status_msg(msg);
+ sftp_message_free(msg);
+ if(!status)
+ return -1;
+ if(status->status != SSH_FX_OK){
+ ssh_set_error(sftp->session,SSH_REQUEST_DENIED,"sftp server : %s",status->errormsg);
+ err=-1;
+ }
+ status_msg_free(status);
+ return err;
+ default:
+ ssh_set_error(sftp->session,SSH_INVALID_DATA,"Received message %d during sftp_handle_close!",msg->packet_type);
+ sftp_message_free(msg);
+ }
+ return -1;
+}
+
+int sftp_file_close(SFTP_FILE *file){
+ int err=0;
+ if(file->name)
+ free(file->name);
+ if(file->handle){
+ err=sftp_handle_close(file->sftp,file->handle);
+ free(file->handle);
+ }
+ free(file);
+ return err;
+}
+
+int sftp_dir_close(SFTP_DIR *dir){
+ int err=0;
+ if(dir->name)
+ free(dir->name);
+ if(dir->handle){
+ err=sftp_handle_close(dir->sftp,dir->handle);
+ free(dir->handle);
+ }
+ if(dir->buffer)
+ buffer_free(dir->buffer);
+ free(dir);
+ return err;
+}
+
+SFTP_FILE *sftp_open(SFTP_SESSION *sftp, char *file, int access, SFTP_ATTRIBUTES *attr){
+ SFTP_FILE *handle;
+ SFTP_MESSAGE *msg=NULL;
+ STATUS_MESSAGE *status;
+ u32 flags=0;
+ u32 id=sftp_get_new_id(sftp);
+ BUFFER *buffer=buffer_new();
+ STRING *filename;
+ if(access & O_RDONLY)
+ flags|=SSH_FXF_READ;
+ if(access & O_WRONLY)
+ flags |= SSH_FXF_WRITE;
+ if(access & O_RDWR)
+ flags|=(SSH_FXF_WRITE | SSH_FXF_READ);
+ if(access & O_CREAT)
+ flags |=SSH_FXF_CREAT;
+ if(access & O_TRUNC)
+ flags |=SSH_FXF_TRUNC;
+ if(access & O_EXCL)
+ flags |= SSH_FXF_EXCL;
+ buffer_add_u32(buffer,id);
+ filename=string_from_char(file);
+ buffer_add_ssh_string(buffer,filename);
+ free(filename);
+ buffer_add_u32(buffer,htonl(flags));
+ buffer_add_attributes(buffer,attr);
+ sftp_packet_write(sftp,SSH_FXP_OPEN,buffer);
+ buffer_free(buffer);
+ while(!msg){
+ if(sftp_read_and_dispatch(sftp))
+ /* something nasty has happened */
+ return NULL;
+ msg=sftp_dequeue(sftp,id);
+ }
+ switch (msg->packet_type){
+ case SSH_FXP_STATUS:
+ status=parse_status_msg(msg);
+ sftp_message_free(msg);
+ if(!status)
+ return NULL;
+ ssh_set_error(sftp->session,SSH_REQUEST_DENIED,"sftp server : %s",status->errormsg);
+ status_msg_free(status);
+ return NULL;
+ case SSH_FXP_HANDLE:
+ handle=parse_handle_msg(msg);
+ sftp_message_free(msg);
+ return handle;
+ default:
+ ssh_set_error(sftp->session,SSH_INVALID_DATA,"Received message %d during open!",msg->packet_type);
+ sftp_message_free(msg);
+ }
+ return NULL;
+}
+
+void sftp_file_set_nonblocking(SFTP_FILE *handle){
+ handle->nonblocking=1;
+}
+void sftp_file_set_blocking(SFTP_FILE *handle){
+ handle->nonblocking=0;
+}
+
+int sftp_read(SFTP_FILE *handle, void *data, int len){
+ SFTP_MESSAGE *msg=NULL;
+ STATUS_MESSAGE *status;
+ SFTP_SESSION *sftp=handle->sftp;
+ STRING *datastring;
+ int id;
+ int err=0;
+ BUFFER *buffer;
+ if(handle->eof)
+ return 0;
+ buffer=buffer_new();
+ id=sftp_get_new_id(handle->sftp);
+ buffer_add_u32(buffer,id);
+ buffer_add_ssh_string(buffer,handle->handle);
+ buffer_add_u64(buffer,htonll(handle->offset));
+ buffer_add_u32(buffer,htonl(len));
+ sftp_packet_write(handle->sftp,SSH_FXP_READ,buffer);
+ buffer_free(buffer);
+ while(!msg){
+ if (handle->nonblocking){
+ if(channel_poll(handle->sftp->channel,0)==0){
+ /* we cannot block */
+ return 0;
+ }
+ }
+ if(sftp_read_and_dispatch(handle->sftp))
+ /* something nasty has happened */
+ return -1;
+ msg=sftp_dequeue(handle->sftp,id);
+ }
+ switch (msg->packet_type){
+ case SSH_FXP_STATUS:
+ status=parse_status_msg(msg);
+ sftp_message_free(msg);
+ if(!status)
+ return -1;
+ if(status->status != SSH_FX_EOF){
+ ssh_set_error(sftp->session,SSH_REQUEST_DENIED,"sftp server : %s",status->errormsg);
+ err=-1;
+ }
+ else
+ handle->eof=1;
+ status_msg_free(status);
+ return err?err:0;
+ case SSH_FXP_DATA:
+ datastring=buffer_get_ssh_string(msg->payload);
+ sftp_message_free(msg);
+ if(!datastring){
+ ssh_set_error(sftp->session,SSH_INVALID_DATA,"Received invalid DATA packet from sftp server");
+ return -1;
+ }
+ if(string_len(datastring)>len){
+ ssh_set_error(sftp->session,SSH_INVALID_DATA,"Received a too big DATA packet from sftp server : %d and asked for %d",
+ string_len(datastring),len);
+ free(datastring);
+ return -1;
+ }
+ len=string_len(datastring);
+ handle->offset+=len;
+ memcpy(data,datastring->string,len);
+ free(datastring);
+ return len;
+ default:
+ ssh_set_error(sftp->session,SSH_INVALID_DATA,"Received message %d during read!",msg->packet_type);
+ sftp_message_free(msg);
+ return -1;
+ }
+ return -1; /* not reached */
+}
+
+int sftp_write(SFTP_FILE *file, void *data, int len){
+ SFTP_MESSAGE *msg=NULL;
+ STATUS_MESSAGE *status;
+ STRING *datastring;
+ SFTP_SESSION *sftp=file->sftp;
+ int id;
+ int err=0;
+ BUFFER *buffer;
+ buffer=buffer_new();
+ id=sftp_get_new_id(file->sftp);
+ buffer_add_u32(buffer,id);
+ buffer_add_ssh_string(buffer,file->handle);
+ buffer_add_u64(buffer,htonll(file->offset));
+ datastring=string_new(len);
+ string_fill(datastring,data,len);
+ buffer_add_ssh_string(buffer,datastring);
+ free(datastring);
+ if(sftp_packet_write(file->sftp,SSH_FXP_WRITE,buffer) != buffer_get_len(buffer)){
+ ssh_say(1,"sftp_packet_write did not write as much data as expected\n");
+ }
+ buffer_free(buffer);
+ while(!msg){
+ if(sftp_read_and_dispatch(file->sftp))
+ /* something nasty has happened */
+ return -1;
+ msg=sftp_dequeue(file->sftp,id);
+ }
+ switch (msg->packet_type){
+ case SSH_FXP_STATUS:
+ status=parse_status_msg(msg);
+ sftp_message_free(msg);
+ if(!status)
+ return -1;
+ if(status->status != SSH_FX_OK){
+ ssh_set_error(sftp->session,SSH_REQUEST_DENIED,"sftp server : %s",status->errormsg);
+ err=-1;
+ }
+ file->offset+=len;
+ status_msg_free(status);
+ return (err?err:len);
+ default:
+ ssh_set_error(sftp->session,SSH_INVALID_DATA,"Received message %d during write!",msg->packet_type);
+ sftp_message_free(msg);
+ return -1;
+ }
+ return -1; /* not reached */
+}
+
+void sftp_seek(SFTP_FILE *file, int new_offset){
+ file->offset=new_offset;
+}
+
+unsigned long sftp_tell(SFTP_FILE *file){
+ return file->offset;
+}
+
+void sftp_rewind(SFTP_FILE *file){
+ file->offset=0;
+}
+
+/* code written by Nick */
+int sftp_rm(SFTP_SESSION *sftp, char *file) {
+ u32 id = sftp_get_new_id(sftp);
+ BUFFER *buffer = buffer_new();
+ STRING *filename = string_from_char(file);
+ SFTP_MESSAGE *msg = NULL;
+ STATUS_MESSAGE *status = NULL;
+
+ buffer_add_u32(buffer, id);
+ buffer_add_ssh_string(buffer, filename);
+ free(filename);
+ sftp_packet_write(sftp, SSH_FXP_REMOVE, buffer);
+ buffer_free(buffer);
+ while (!msg) {
+ if (sftp_read_and_dispatch(sftp)) {
+ return -1;
+ }
+ msg = sftp_dequeue(sftp, id);
+ }
+ if (msg->packet_type == SSH_FXP_STATUS) {
+ /* by specification, this command's only supposed to return SSH_FXP_STATUS */
+ status = parse_status_msg(msg);
+ sftp_message_free(msg);
+ if (!status)
+ return -1;
+ if (status->status != SSH_FX_OK) {
+ /* status should be SSH_FX_OK if the command was successful, if it didn't, then there was an error */
+ ssh_set_error(sftp->session,SSH_REQUEST_DENIED, "sftp server: %s", status->errormsg);
+ status_msg_free(status);
+ return -1;
+ }
+ status_msg_free(status);
+ return 0; /* at this point, everything turned out OK */
+ } else {
+ ssh_set_error(sftp->session,SSH_INVALID_DATA, "Received message %d when attempting to remove file", msg->packet_type);
+ sftp_message_free(msg);
+ }
+ return -1;
+}
+
+/* code written by Nick */
+int sftp_rmdir(SFTP_SESSION *sftp, char *directory) {
+ u32 id = sftp_get_new_id(sftp);
+ BUFFER *buffer = buffer_new();
+ STRING *filename = string_from_char(directory);
+ SFTP_MESSAGE *msg = NULL;
+ STATUS_MESSAGE *status = NULL;
+
+ buffer_add_u32(buffer, id);
+ buffer_add_ssh_string(buffer, filename);
+ free(filename);
+ sftp_packet_write(sftp, SSH_FXP_RMDIR, buffer);
+ buffer_free(buffer);
+ while (!msg) {
+ if (sftp_read_and_dispatch(sftp))
+ {
+ return -1;
+ }
+ msg = sftp_dequeue(sftp, id);
+ }
+ if (msg->packet_type == SSH_FXP_STATUS) /* by specification, this command's only supposed to return SSH_FXP_STATUS */
+ {
+ status = parse_status_msg(msg);
+ sftp_message_free(msg);
+ if (!status)
+ {
+ return -1;
+ }
+ else if (status->status != SSH_FX_OK) /* status should be SSH_FX_OK if the command was successful, if it didn't, then there was an error */
+ {
+ ssh_set_error(sftp->session,SSH_REQUEST_DENIED, "sftp server: %s", status->errormsg);
+ status_msg_free(status);
+ return -1;
+ }
+ status_msg_free(status);
+ return 0; /* at this point, everything turned out OK */
+ }
+ else
+ {
+ ssh_set_error(sftp->session,SSH_INVALID_DATA, "Received message %d when attempting to remove directory", msg->packet_type);
+ sftp_message_free(msg);
+ }
+ return -1;
+}
+
+/* Code written by Nick */
+int sftp_mkdir(SFTP_SESSION *sftp, char *directory, SFTP_ATTRIBUTES *attr) {
+ u32 id = sftp_get_new_id(sftp);
+ BUFFER *buffer = buffer_new();
+ STRING *path = string_from_char(directory);
+ SFTP_MESSAGE *msg = NULL;
+ STATUS_MESSAGE *status = NULL;
+
+ buffer_add_u32(buffer, id);
+ buffer_add_ssh_string(buffer, path);
+ free(path);
+ buffer_add_attributes(buffer, attr);
+ sftp_packet_write(sftp, SSH_FXP_MKDIR, buffer);
+ buffer_free(buffer);
+ while (!msg) {
+ if (sftp_read_and_dispatch(sftp))
+ return -1;
+ msg = sftp_dequeue(sftp, id);
+ }
+ if (msg->packet_type == SSH_FXP_STATUS) {
+ /* by specification, this command's only supposed to return SSH_FXP_STATUS */
+ status = parse_status_msg(msg);
+ sftp_message_free(msg);
+ if (!status)
+ return -1;
+ else
+ if (status->status != SSH_FX_OK) {
+ /* status should be SSH_FX_OK if the command was successful, if it didn't, then there was an error */
+ ssh_set_error(sftp->session,SSH_REQUEST_DENIED, "sftp server: %s", status->errormsg);
+ status_msg_free(status);
+ return -1;
+ }
+ status_msg_free(status);
+ return 0; /* at this point, everything turned out OK */
+ } else {
+ ssh_set_error(sftp->session,SSH_INVALID_DATA, "Received message %d when attempting to make directory", msg->packet_type);
+ sftp_message_free(msg);
+ }
+ return -1;
+}
+
+/* code written by nick */
+int sftp_rename(SFTP_SESSION *sftp, char *original, char *newname) {
+ u32 id = sftp_get_new_id(sftp);
+ BUFFER *buffer = buffer_new();
+ STRING *oldpath = string_from_char(original);
+ STRING *newpath = string_from_char(newname);
+ SFTP_MESSAGE *msg = NULL;
+ STATUS_MESSAGE *status = NULL;
+
+ buffer_add_u32(buffer, id);
+ buffer_add_ssh_string(buffer, oldpath);
+ free(oldpath);
+ buffer_add_ssh_string(buffer, newpath);
+ free(newpath);
+ sftp_packet_write(sftp, SSH_FXP_RENAME, buffer);
+ buffer_free(buffer);
+ while (!msg) {
+ if (sftp_read_and_dispatch(sftp))
+ return -1;
+ msg = sftp_dequeue(sftp, id);
+ }
+ if (msg->packet_type == SSH_FXP_STATUS) {
+ /* by specification, this command's only supposed to return SSH_FXP_STATUS */
+ status = parse_status_msg(msg);
+ sftp_message_free(msg);
+ if (!status)
+ return -1;
+ else if (status->status != SSH_FX_OK) {
+ /* status should be SSH_FX_OK if the command was successful, if it didn't, then there was an error */
+ ssh_set_error(sftp->session,SSH_REQUEST_DENIED, "sftp server: %s", status->errormsg);
+ status_msg_free(status);
+ return -1;
+ }
+ status_msg_free(status);
+ return 0; /* at this point, everything turned out OK */
+ } else {
+ ssh_set_error(sftp->session,SSH_INVALID_DATA, "Received message %d when attempting to rename", msg->packet_type);
+ sftp_message_free(msg);
+ }
+ return -1;
+}
+
+/* Code written by Nick */
+int sftp_setstat(SFTP_SESSION *sftp, char *file, SFTP_ATTRIBUTES *attr) {
+ u32 id = sftp_get_new_id(sftp);
+ BUFFER *buffer = buffer_new();
+ STRING *path = string_from_char(file);
+ SFTP_MESSAGE *msg = NULL;
+ STATUS_MESSAGE *status = NULL;
+
+ buffer_add_u32(buffer, id);
+ buffer_add_ssh_string(buffer, path);
+ free(path);
+ buffer_add_attributes(buffer, attr);
+ sftp_packet_write(sftp, SSH_FXP_SETSTAT, buffer);
+ buffer_free(buffer);
+ while (!msg) {
+ if (sftp_read_and_dispatch(sftp))
+ return -1;
+ msg = sftp_dequeue(sftp, id);
+ }
+ if (msg->packet_type == SSH_FXP_STATUS) {
+ /* by specification, this command's only supposed to return SSH_FXP_STATUS */
+ status = parse_status_msg(msg);
+ sftp_message_free(msg);
+ if (!status)
+ return -1;
+ else if (status->status != SSH_FX_OK) {
+ /* status should be SSH_FX_OK if the command was successful, if it didn't, then there was an error */
+ ssh_set_error(sftp->session,SSH_REQUEST_DENIED, "sftp server: %s", status->errormsg);
+ status_msg_free(status);
+ return -1;
+ }
+ status_msg_free(status);
+ return 0; /* at this point, everything turned out OK */
+ } else {
+ ssh_set_error(sftp->session,SSH_INVALID_DATA, "Received message %d when attempting to set stats", msg->packet_type);
+ sftp_message_free(msg);
+ }
+ return -1;
+}
+
+/* another code written by Nick */
+char *sftp_canonicalize_path(SFTP_SESSION *sftp, char *path)
+{
+ u32 id = sftp_get_new_id(sftp);
+ BUFFER *buffer = buffer_new();
+ STRING *pathstr = string_from_char(path);
+ STRING *name = NULL;
+ SFTP_MESSAGE *msg = NULL;
+ STATUS_MESSAGE *status = NULL;
+ char *cname;
+ u32 ignored;
+
+ buffer_add_u32(buffer, id);
+ buffer_add_ssh_string(buffer, pathstr);
+ free(pathstr);
+ sftp_packet_write(sftp, SSH_FXP_REALPATH, buffer);
+ buffer_free(buffer);
+ while (!msg)
+ {
+ if (sftp_read_and_dispatch(sftp))
+ return NULL;
+ msg = sftp_dequeue(sftp, id);
+ }
+ if (msg->packet_type == SSH_FXP_NAME) /* good response */
+ {
+ buffer_get_u32(msg->payload, &ignored); /* we don't care about "count" */
+ name = buffer_get_ssh_string(msg->payload); /* we only care about the file name string */
+ cname = string_to_char(name);
+ free(name);
+ return cname;
+ }
+ else if (msg->packet_type == SSH_FXP_STATUS) /* bad response (error) */
+ {
+ status = parse_status_msg(msg);
+ sftp_message_free(msg);
+ if (!status)
+ return NULL;
+ ssh_set_error(sftp->session,SSH_REQUEST_DENIED, "sftp server: %s", status->errormsg);
+ status_msg_free(status);
+ }
+ else /* this shouldn't happen */
+ {
+ ssh_set_error(sftp->session,SSH_INVALID_DATA, "Received message %d when attempting to set stats", msg->packet_type);
+ sftp_message_free(msg);
+ }
+ return NULL;
+}
+
+SFTP_ATTRIBUTES *sftp_xstat(SFTP_SESSION *sftp, char *path,int param){
+ u32 id=sftp_get_new_id(sftp);
+ BUFFER *buffer=buffer_new();
+ STRING *pathstr= string_from_char(path);
+ SFTP_MESSAGE *msg=NULL;
+ STATUS_MESSAGE *status=NULL;
+ SFTP_ATTRIBUTES *pattr=NULL;
+
+ buffer_add_u32(buffer,id);
+ buffer_add_ssh_string(buffer,pathstr);
+ free(pathstr);
+ sftp_packet_write(sftp,param,buffer);
+ buffer_free(buffer);
+ while(!msg){
+ if(sftp_read_and_dispatch(sftp))
+ return NULL;
+ msg=sftp_dequeue(sftp,id);
+ }
+ if(msg->packet_type==SSH_FXP_ATTRS){
+ pattr=sftp_parse_attr(sftp,msg->payload,0);
+ return pattr;
+ }
+ if(msg->packet_type== SSH_FXP_STATUS){
+ status=parse_status_msg(msg);
+ sftp_message_free(msg);
+ if(!status)
+ return NULL;
+ ssh_set_error(sftp->session,SSH_REQUEST_DENIED,"sftp server: %s",status->errormsg);
+ status_msg_free(status);
+ return NULL;
+ }
+ ssh_set_error(sftp->session,SSH_INVALID_DATA,"Received mesg %d during stat(),mesg->packet_type");
+ sftp_message_free(msg);
+ return NULL;
+}
+
+SFTP_ATTRIBUTES *sftp_stat(SFTP_SESSION *session, char *path){
+ return sftp_xstat(session,path,SSH_FXP_STAT);
+}
+SFTP_ATTRIBUTES *sftp_lstat(SFTP_SESSION *session, char *path){
+ return sftp_xstat(session,path,SSH_FXP_LSTAT);
+}
+
+SFTP_ATTRIBUTES *sftp_fstat(SFTP_FILE *file) {
+ u32 id=sftp_get_new_id(file->sftp);
+ BUFFER *buffer=buffer_new();
+ SFTP_MESSAGE *msg=NULL;
+ STATUS_MESSAGE *status=NULL;
+ SFTP_ATTRIBUTES *pattr=NULL;
+
+ buffer_add_u32(buffer,id);
+ buffer_add_ssh_string(buffer,file->handle);
+ sftp_packet_write(file->sftp,SSH_FXP_FSTAT,buffer);
+ buffer_free(buffer);
+ while(!msg){
+ if(sftp_read_and_dispatch(file->sftp))
+ return NULL;
+ msg=sftp_dequeue(file->sftp,id);
+ }
+ if(msg->packet_type==SSH_FXP_ATTRS){
+ pattr=sftp_parse_attr(file->sftp,msg->payload,0);
+ return pattr;
+ }
+ if(msg->packet_type== SSH_FXP_STATUS){
+ status=parse_status_msg(msg);
+ sftp_message_free(msg);
+ if(!status)
+ return NULL;
+ ssh_set_error(file->sftp->session,SSH_REQUEST_DENIED,"sftp server: %s",status->errormsg);
+ status_msg_free(status);
+ return NULL;
+ }
+ ssh_set_error(file->sftp->session,SSH_INVALID_DATA,"Received mesg %d during fstat(),mesg->packet_type");
+ sftp_message_free(msg);
+ return NULL;
+}
+
+
+#endif /* NO_SFTP */
diff --git a/kftpgrabber/src/misc/libs/ssh/sftp.h b/kftpgrabber/src/misc/libs/ssh/sftp.h
new file mode 100644
index 0000000..10334ab
--- /dev/null
+++ b/kftpgrabber/src/misc/libs/ssh/sftp.h
@@ -0,0 +1,225 @@
+/* sftp headers */
+/*
+Copyright 2003 Aris Adamantiadis
+
+This file is part of the SSH Library
+
+The SSH Library is free software; you can redistribute it and/or modify
+it under the terms of the GNU Lesser General Public License as published by
+the Free Software Foundation; either version 2.1 of the License, or (at your
+option) any later version.
+
+The SSH Library 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 Lesser General Public
+License for more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with the SSH Library; see the file COPYING. If not, write to
+the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor, Boston,
+MA 02110-1301, USA. */
+
+#ifndef SFTP_H
+#define SFTP_H
+#include "libssh.h"
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct sftp_session_struct {
+ SSH_SESSION *session;
+ CHANNEL *channel;
+ int server_version;
+ struct request_queue *queue;
+ u32 id_counter;
+} SFTP_SESSION ;
+
+typedef struct {
+ SFTP_SESSION *sftp;
+ u8 type;
+ BUFFER *payload;
+} SFTP_PACKET;
+
+/* file handler */
+typedef struct sftp_file{
+ SFTP_SESSION *sftp;
+ char *name;
+ u64 offset;
+ STRING *handle;
+ int eof;
+ int nonblocking;
+} SFTP_FILE ;
+
+typedef struct sftp_dir {
+ SFTP_SESSION *sftp;
+ char *name;
+ STRING *handle; /* handle to directory */
+ BUFFER *buffer; /* contains raw attributes from server which haven't been parsed */
+ u32 count; /* counts the number of following attributes structures into buffer */
+ int eof; /* end of directory listing */
+} SFTP_DIR;
+
+typedef struct {
+ SFTP_SESSION *sftp;
+ u8 packet_type;
+ BUFFER *payload;
+ u32 id;
+} SFTP_MESSAGE;
+
+typedef struct request_queue{
+ struct request_queue *next;
+ SFTP_MESSAGE *message;
+} REQUEST_QUEUE;
+
+/* SSH_FXP_MESSAGE described into .7 page 26 */
+typedef struct {
+ u32 id;
+ u32 status;
+ STRING *error;
+ STRING *lang;
+ char *errormsg;
+ char *langmsg;
+} STATUS_MESSAGE;
+
+/* don't worry much of these aren't really used */
+typedef struct {
+ char *name;
+ char *longname; /* some weird stuff */
+ u32 flags;
+ u8 type;
+ u64 size;
+ u32 uid;
+ u32 gid;
+ char *owner;
+ char *group;
+ u32 permissions;
+ u64 atime64;
+ u32 atime;
+ u32 atime_nseconds;
+ u64 createtime;
+ u32 createtime_nseconds;
+ u64 mtime64;
+ u32 mtime;
+ u32 mtime_nseconds;
+ STRING *acl;
+ u32 extended_count;
+ STRING *extended_type;
+ STRING *extended_data;
+} SFTP_ATTRIBUTES;
+
+#define LIBSFTP_VERSION 3
+
+SFTP_SESSION *sftp_new(SSH_SESSION *session);
+void sftp_free(SFTP_SESSION *sftp);
+int sftp_init(SFTP_SESSION *sftp);
+SFTP_DIR *sftp_opendir(SFTP_SESSION *session, char *path);
+/* reads one file and attribute from opened directory. fails at end */
+SFTP_ATTRIBUTES *sftp_readdir(SFTP_SESSION *session, SFTP_DIR *dir);
+/* returns 1 if the directory was EOF */
+int sftp_dir_eof(SFTP_DIR *dir);
+SFTP_ATTRIBUTES *sftp_stat(SFTP_SESSION *session, char *path);
+SFTP_ATTRIBUTES *sftp_lstat(SFTP_SESSION *session, char *path);
+/* sftp_lstat stats a file but doesn't follow symlinks */
+SFTP_ATTRIBUTES *sftp_fstat(SFTP_FILE *file);
+void sftp_attributes_free(SFTP_ATTRIBUTES *file);
+int sftp_dir_close(SFTP_DIR *dir);
+int sftp_file_close(SFTP_FILE *file);
+/* access are the sames than the ones from ansi fopen() */
+SFTP_FILE *sftp_open(SFTP_SESSION *session, char *file, int access, SFTP_ATTRIBUTES *attr);
+int sftp_read(SFTP_FILE *file, void *dest, int len);
+int sftp_write(SFTP_FILE *file, void *source, int len);
+void sftp_seek(SFTP_FILE *file, int new_offset);
+unsigned long sftp_tell(SFTP_FILE *file);
+void sftp_rewind(SFTP_FILE *file);
+int sftp_rm(SFTP_SESSION *sftp, char *file);
+int sftp_rmdir(SFTP_SESSION *sftp, char *directory);
+int sftp_mkdir(SFTP_SESSION *sftp, char *directory, SFTP_ATTRIBUTES *attr);
+int sftp_rename(SFTP_SESSION *sftp, char *original, char *newname);
+int sftp_setstat(SFTP_SESSION *sftp, char *file, SFTP_ATTRIBUTES *attr);
+char *sftp_canonicalize_path(SFTP_SESSION *sftp, char *path);
+
+/* SFTP commands and constants */
+#define SSH_FXP_INIT 1
+#define SSH_FXP_VERSION 2
+#define SSH_FXP_OPEN 3
+#define SSH_FXP_CLOSE 4
+#define SSH_FXP_READ 5
+#define SSH_FXP_WRITE 6
+#define SSH_FXP_LSTAT 7
+#define SSH_FXP_FSTAT 8
+#define SSH_FXP_SETSTAT 9
+#define SSH_FXP_FSETSTAT 10
+#define SSH_FXP_OPENDIR 11
+#define SSH_FXP_READDIR 12
+#define SSH_FXP_REMOVE 13
+#define SSH_FXP_MKDIR 14
+#define SSH_FXP_RMDIR 15
+#define SSH_FXP_REALPATH 16
+#define SSH_FXP_STAT 17
+#define SSH_FXP_RENAME 18
+#define SSH_FXP_READLINK 19
+#define SSH_FXP_SYMLINK 20
+
+#define SSH_FXP_STATUS 101
+#define SSH_FXP_HANDLE 102
+#define SSH_FXP_DATA 103
+#define SSH_FXP_NAME 104
+#define SSH_FXP_ATTRS 105
+
+#define SSH_FXP_EXTENDED 200
+#define SSH_FXP_EXTENDED_REPLY 201
+
+/* attributes */
+/* sftp draft is completely braindead : version 3 and 4 have different flags for same constants */
+/* and even worst, version 4 has same flag for 2 different constants */
+/* follow up : i won't develop any sftp4 compliant library before having a clarification */
+
+#define SSH_FILEXFER_ATTR_SIZE 0x00000001
+#define SSH_FILEXFER_ATTR_PERMISSIONS 0x00000004
+#define SSH_FILEXFER_ATTR_ACCESSTIME 0x00000008
+#define SSH_FILEXFER_ATTR_ACMODTIME 0x00000008
+#define SSH_FILEXFER_ATTR_CREATETIME 0x00000010
+#define SSH_FILEXFER_ATTR_MODIFYTIME 0x00000020
+#define SSH_FILEXFER_ATTR_ACL 0x00000040
+#define SSH_FILEXFER_ATTR_OWNERGROUP 0x00000080
+#define SSH_FILEXFER_ATTR_SUBSECOND_TIMES 0x00000100
+#define SSH_FILEXFER_ATTR_EXTENDED 0x80000000
+#define SSH_FILEXFER_ATTR_UIDGID 0x00000002
+
+/* types */
+#define SSH_FILEXFER_TYPE_REGULAR 1
+#define SSH_FILEXFER_TYPE_DIRECTORY 2
+#define SSH_FILEXFER_TYPE_SYMLINK 3
+#define SSH_FILEXFER_TYPE_SPECIAL 4
+#define SSH_FILEXFER_TYPE_UNKNOWN 5
+
+/* server responses */
+#define SSH_FX_OK 0
+#define SSH_FX_EOF 1
+#define SSH_FX_NO_SUCH_FILE 2
+#define SSH_FX_PERMISSION_DENIED 3
+#define SSH_FX_FAILURE 4
+#define SSH_FX_BAD_MESSAGE 5
+#define SSH_FX_NO_CONNECTION 6
+#define SSH_FX_CONNECTION_LOST 7
+#define SSH_FX_OP_UNSUPPORTED 8
+#define SSH_FX_INVALID_HANDLE 9
+#define SSH_FX_NO_SUCH_PATH 10
+#define SSH_FX_FILE_ALREADY_EXISTS 11
+#define SSH_FX_WRITE_PROTECT 12
+#define SSH_FX_NO_MEDIA 13
+
+/* file flags */
+#define SSH_FXF_READ 0x01
+#define SSH_FXF_WRITE 0x02
+#define SSH_FXF_APPEND 0x04
+#define SSH_FXF_CREAT 0x08
+#define SSH_FXF_TRUNC 0x10
+#define SSH_FXF_EXCL 0x20
+#define SSH_FXF_TEXT 0x40
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* SFTP_H */
diff --git a/kftpgrabber/src/misc/libs/ssh/ssh2.h b/kftpgrabber/src/misc/libs/ssh/ssh2.h
new file mode 100644
index 0000000..e6dc04f
--- /dev/null
+++ b/kftpgrabber/src/misc/libs/ssh/ssh2.h
@@ -0,0 +1,69 @@
+#ifndef __SSH2_H
+#define __SSH2_H
+
+#define SSH2_MSG_DISCONNECT 1
+#define SSH2_MSG_IGNORE 2
+#define SSH2_MSG_UNIMPLEMENTED 3
+#define SSH2_MSG_DEBUG 4
+#define SSH2_MSG_SERVICE_REQUEST 5
+#define SSH2_MSG_SERVICE_ACCEPT 6
+
+#define SSH2_MSG_KEXINIT 20
+#define SSH2_MSG_NEWKEYS 21
+
+#define SSH2_MSG_KEXDH_INIT 30
+#define SSH2_MSG_KEXDH_REPLY 31
+
+#define SSH2_MSG_KEX_DH_GEX_REQUEST_OLD 30
+#define SSH2_MSG_KEX_DH_GEX_GROUP 31
+#define SSH2_MSG_KEX_DH_GEX_INIT 32
+#define SSH2_MSG_KEX_DH_GEX_REPLY 33
+#define SSH2_MSG_KEX_DH_GEX_REQUEST 34
+#define SSH2_MSG_USERAUTH_REQUEST 50
+#define SSH2_MSG_USERAUTH_FAILURE 51
+#define SSH2_MSG_USERAUTH_SUCCESS 52
+#define SSH2_MSG_USERAUTH_BANNER 53
+#define SSH2_MSG_USERAUTH_PK_OK 60
+#define SSH2_MSG_USERAUTH_PASSWD_CHANGEREQ 60
+#define SSH2_MSG_USERAUTH_INFO_REQUEST 60
+#define SSH2_MSG_USERAUTH_INFO_RESPONSE 61
+#define SSH2_MSG_GLOBAL_REQUEST 80
+#define SSH2_MSG_REQUEST_SUCCESS 81
+#define SSH2_MSG_REQUEST_FAILURE 82
+#define SSH2_MSG_CHANNEL_OPEN 90
+#define SSH2_MSG_CHANNEL_OPEN_CONFIRMATION 91
+#define SSH2_MSG_CHANNEL_OPEN_FAILURE 92
+#define SSH2_MSG_CHANNEL_WINDOW_ADJUST 93
+#define SSH2_MSG_CHANNEL_DATA 94
+#define SSH2_MSG_CHANNEL_EXTENDED_DATA 95
+#define SSH2_MSG_CHANNEL_EOF 96
+#define SSH2_MSG_CHANNEL_CLOSE 97
+#define SSH2_MSG_CHANNEL_REQUEST 98
+#define SSH2_MSG_CHANNEL_SUCCESS 99
+#define SSH2_MSG_CHANNEL_FAILURE 100
+
+#define SSH2_DISCONNECT_HOST_NOT_ALLOWED_TO_CONNECT 1
+#define SSH2_DISCONNECT_PROTOCOL_ERROR 2
+#define SSH2_DISCONNECT_KEY_EXCHANGE_FAILED 3
+#define SSH2_DISCONNECT_HOST_AUTHENTICATION_FAILED 4
+#define SSH2_DISCONNECT_RESERVED 4
+#define SSH2_DISCONNECT_MAC_ERROR 5
+#define SSH2_DISCONNECT_COMPRESSION_ERROR 6
+#define SSH2_DISCONNECT_SERVICE_NOT_AVAILABLE 7
+#define SSH2_DISCONNECT_PROTOCOL_VERSION_NOT_SUPPORTED 8
+#define SSH2_DISCONNECT_HOST_KEY_NOT_VERIFIABLE 9
+#define SSH2_DISCONNECT_CONNECTION_LOST 10
+#define SSH2_DISCONNECT_BY_APPLICATION 11
+#define SSH2_DISCONNECT_TOO_MANY_CONNECTIONS 12
+#define SSH2_DISCONNECT_AUTH_CANCELLED_BY_USER 13
+#define SSH2_DISCONNECT_NO_MORE_AUTH_METHODS_AVAILABLE 14
+#define SSH2_DISCONNECT_ILLEGAL_USER_NAME 15
+
+#define SSH2_OPEN_ADMINISTRATIVELY_PROHIBITED 1
+#define SSH2_OPEN_CONNECT_FAILED 2
+#define SSH2_OPEN_UNKNOWN_CHANNEL_TYPE 3
+#define SSH2_OPEN_RESOURCE_SHORTAGE 4
+
+#define SSH2_EXTENDED_DATA_STDERR 1
+
+#endif
diff --git a/kftpgrabber/src/misc/libs/ssh/string.c b/kftpgrabber/src/misc/libs/ssh/string.c
new file mode 100644
index 0000000..1126e7a
--- /dev/null
+++ b/kftpgrabber/src/misc/libs/ssh/string.c
@@ -0,0 +1,65 @@
+/*string.c */
+/* string manipulations... */
+/*
+Copyright 2003 Aris Adamantiadis
+
+This file is part of the SSH Library
+
+The SSH Library is free software; you can redistribute it and/or modify
+it under the terms of the GNU Lesser General Public License as published by
+the Free Software Foundation; either version 2.1 of the License, or (at your
+option) any later version.
+
+The SSH Library 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 Lesser General Public
+License for more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with the SSH Library; see the file COPYING. If not, write to
+the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor, Boston,
+MA 02110-1301, USA. */
+
+#include <stdlib.h>
+#include <netdb.h>
+#include <unistd.h>
+#include <string.h>
+#include "priv.h"
+
+STRING *string_new(u32 size){
+ STRING *str=malloc(size + 4);
+ str->size=htonl(size);
+ return str;
+}
+
+void string_fill(STRING *str,void *data,int len){
+ memcpy(str->string,data,len);
+}
+
+STRING *string_from_char(char *what){
+ STRING *ptr;
+ int len=strlen(what);
+ ptr=malloc(4 + len);
+ ptr->size=htonl(len);
+ memcpy(ptr->string,what,len);
+ return ptr;
+}
+
+int string_len(STRING *str){
+ return ntohl(str->size);
+}
+
+char *string_to_char(STRING *str){
+ int len=ntohl(str->size)+1;
+ char *string=malloc(len);
+ memcpy(string,str->string,len-1);
+ string[len-1]=0;
+ return string;
+}
+
+STRING *string_copy(STRING *str){
+ STRING *ret=malloc(ntohl(str->size)+4);
+ ret->size=str->size;
+ memcpy(ret->string,str->string,ntohl(str->size));
+ return ret;
+}
diff --git a/kftpgrabber/src/misc/libs/ssh/wrapper.c b/kftpgrabber/src/misc/libs/ssh/wrapper.c
new file mode 100644
index 0000000..b99beeb
--- /dev/null
+++ b/kftpgrabber/src/misc/libs/ssh/wrapper.c
@@ -0,0 +1,241 @@
+/* wrapper.c */
+/* wrapping functions for crypto functions. */
+/* why a wrapper ? let's say you want to port libssh from libcrypto of openssl to libfoo */
+/* you are going to spend hours to remove every references to SHA1_Update() to libfoo_sha1_update */
+/* after the work is finished, you're going to have only this file to modify */
+/* it's not needed to say that your modifications are welcome */
+
+/*
+Copyright 2003 Aris Adamantiadis
+
+This file is part of the SSH Library
+
+The SSH Library is free software; you can redistribute it and/or modify
+it under the terms of the GNU Lesser General Public License as published by
+the Free Software Foundation; either version 2.1 of the License, or (at your
+option) any later version.
+
+The SSH Library 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 Lesser General Public
+License for more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with the SSH Library; see the file COPYING. If not, write to
+the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor, Boston,
+MA 02110-1301, USA. */
+
+#include "priv.h"
+#include "crypto.h"
+#include <string.h>
+#ifdef OPENSSL_CRYPTO
+#include <openssl/sha.h>
+#include <openssl/md5.h>
+#include <openssl/dsa.h>
+#include <openssl/rsa.h>
+#include <openssl/hmac.h>
+#include <openssl/opensslv.h>
+#ifdef HAVE_OPENSSL_AES_H
+#define HAS_AES
+#include <openssl/aes.h>
+#endif
+#ifdef HAVE_OPENSSL_BLOWFISH_H
+#define HAS_BLOWFISH
+#include <openssl/blowfish.h>
+#endif
+#if (OPENSSL_VERSION_NUMBER<0x009070000)
+#define OLD_CRYPTO
+#endif
+
+SHACTX *sha1_init(){
+ SHACTX *c=malloc(sizeof(SHACTX));
+ SHA1_Init(c);
+ return c;
+}
+void sha1_update(SHACTX *c, const void *data, unsigned long len){
+ SHA1_Update(c,data,len);
+}
+void sha1_final(unsigned char *md,SHACTX *c){
+ SHA1_Final(md,c);
+ free(c);
+}
+void sha1(unsigned char *digest,int len,unsigned char *hash){
+ SHA1(digest,len,hash);
+}
+
+MD5CTX *md5_init(){
+ MD5CTX *c=malloc(sizeof(MD5CTX));
+ MD5_Init(c);
+ return c;
+}
+void md5_update(MD5CTX *c, const void *data, unsigned long len){
+ MD5_Update(c,data,len);
+}
+void md5_final(unsigned char *md,MD5CTX *c){
+ MD5_Final(md,c);
+ free(c);
+}
+
+HMACCTX *hmac_init(const void *key, int len,int type){
+ HMAC_CTX *ctx;
+ ctx=malloc(sizeof(HMAC_CTX));
+#ifndef OLD_CRYPTO
+ HMAC_CTX_init(ctx); // openssl 0.9.7 requires it.
+#endif
+ switch(type){
+ case HMAC_SHA1:
+ HMAC_Init(ctx,key,len,EVP_sha1());
+ break;
+ case HMAC_MD5:
+ HMAC_Init(ctx,key,len,EVP_md5());
+ break;
+ default:
+ free(ctx);
+ ctx=NULL;
+ }
+ return ctx;
+}
+void hmac_update(HMACCTX *ctx,const void *data, unsigned long len){
+ HMAC_Update(ctx,data,len);
+}
+void hmac_final(HMACCTX *ctx,unsigned char *hashmacbuf,int *len){
+ HMAC_Final(ctx,hashmacbuf,len);
+#ifndef OLD_CRYPTO
+ HMAC_CTX_cleanup(ctx);
+#else
+ HMAC_cleanup(ctx);
+#endif
+ free(ctx);
+}
+
+static void alloc_key(struct crypto_struct *cipher){
+ cipher->key=malloc(cipher->keylen);
+}
+
+#ifdef HAS_BLOWFISH
+/* the wrapper functions for blowfish */
+static void blowfish_set_key(struct crypto_struct *cipher, void *key){
+ if(!cipher->key){
+ alloc_key(cipher);
+ BF_set_key(cipher->key,16,key);
+ }
+}
+
+static void blowfish_encrypt(struct crypto_struct *cipher, void *in, void *out,unsigned long len,void *IV){
+ BF_cbc_encrypt(in,out,len,cipher->key,IV,BF_ENCRYPT);
+}
+
+static void blowfish_decrypt(struct crypto_struct *cipher, void *in, void *out,unsigned long len,void *IV){
+ BF_cbc_encrypt(in,out,len,cipher->key,IV,BF_DECRYPT);
+}
+#endif
+#ifdef HAS_AES
+static void aes_set_encrypt_key(struct crypto_struct *cipher, void *key){
+ if(!cipher->key){
+ alloc_key(cipher);
+ AES_set_encrypt_key(key,cipher->keysize,cipher->key);
+ }
+}
+static void aes_set_decrypt_key(struct crypto_struct *cipher, void *key){
+ if(!cipher->key){
+ alloc_key(cipher);
+ AES_set_decrypt_key(key,cipher->keysize,cipher->key);
+ }
+}
+static void aes_encrypt(struct crypto_struct *cipher, void *in, void *out, unsigned long len, void *IV){
+ AES_cbc_encrypt(in,out,len,cipher->key,IV,AES_ENCRYPT);
+}
+static void aes_decrypt(struct crypto_struct *cipher, void *in, void *out, unsigned long len, void *IV){
+ AES_cbc_encrypt(in,out,len,cipher->key,IV,AES_DECRYPT);
+}
+#endif
+/* the table of supported ciphers */
+static struct crypto_struct ssh_ciphertab[]={
+#ifdef HAS_BLOWFISH
+ { "blowfish-cbc", 8 ,sizeof (BF_KEY),NULL,128,blowfish_set_key,blowfish_set_key,blowfish_encrypt, blowfish_decrypt},
+#endif
+#ifdef HAS_AES
+ { "aes128-cbc",16,sizeof(AES_KEY),NULL,128,aes_set_encrypt_key,aes_set_decrypt_key,aes_encrypt,aes_decrypt},
+ { "aes192-cbc",16,sizeof(AES_KEY),NULL,192,aes_set_encrypt_key,aes_set_decrypt_key,aes_encrypt,aes_decrypt},
+ { "aes256-cbc",16,sizeof(AES_KEY),NULL,256,aes_set_encrypt_key,aes_set_decrypt_key,aes_encrypt,aes_decrypt},
+#endif
+ { NULL,0,0,NULL,0,NULL,NULL,NULL}
+};
+#endif /* OPENSSL_CRYPTO */
+
+/* it allocates a new cipher structure based on its offset into the global table */
+struct crypto_struct *cipher_new(int offset){
+ struct crypto_struct *cipher=malloc(sizeof(struct crypto_struct));
+ /* note the memcpy will copy the pointers : so, you shouldn't free them */
+ memcpy(cipher,&ssh_ciphertab[offset],sizeof(*cipher));
+ return cipher;
+}
+
+void cipher_free(struct crypto_struct *cipher){
+ if(cipher->key){
+ /* destroy the key */
+ memset(cipher->key,0,cipher->keylen);
+ free(cipher->key);
+ }
+ free(cipher);
+}
+
+CRYPTO *crypto_new(){
+ CRYPTO *crypto=malloc(sizeof (CRYPTO));
+ memset(crypto,0,sizeof(*crypto));
+ return crypto;
+}
+
+void crypto_free(CRYPTO *crypto){
+ if(crypto->server_pubkey)
+ free(crypto->server_pubkey);
+ if(crypto->in_cipher)
+ cipher_free(crypto->in_cipher);
+ if(crypto->out_cipher)
+ cipher_free(crypto->out_cipher);
+ if(crypto->e)
+ bignum_free(crypto->e);
+ if(crypto->f)
+ bignum_free(crypto->f);
+ if(crypto->x)
+ bignum_free(crypto->x);
+ if(crypto->k)
+ bignum_free(crypto->k);
+ /* lot of other things */
+ /* i'm lost in my own code. good work */
+ memset(crypto,0,sizeof(*crypto));
+ free(crypto);
+}
+
+int crypt_set_algorithms(SSH_SESSION *session){
+ /* we must scan the kex entries to find crypto algorithms and set their appropriate structure */
+ int i=0;
+ /* out */
+ char *wanted=session->client_kex.methods[KEX_CRYPT_C_S];
+ while(ssh_ciphertab[i].name && strcmp(wanted,ssh_ciphertab[i].name))
+ i++;
+ if(!ssh_ciphertab[i].name){
+ ssh_set_error((session->connected?session:NULL),SSH_FATAL,"Crypt_set_algorithms : no crypto algorithm function found for %s",wanted);
+ return -1;
+ }
+ ssh_say(2,"Set output algorithm %s\n",wanted);
+ session->next_crypto->out_cipher=cipher_new(i);
+ i=0;
+ /* in */
+ wanted=session->client_kex.methods[KEX_CRYPT_S_C];
+ while(ssh_ciphertab[i].name && strcmp(wanted,ssh_ciphertab[i].name))
+ i++;
+ if(!ssh_ciphertab[i].name){
+ ssh_set_error((session->connected?session:NULL),SSH_FATAL,"Crypt_set_algorithms : no crypto algorithm function found for %s",wanted);
+ return -1;
+ }
+ ssh_say(2,"Set input algorithm %s\n",wanted);
+ session->next_crypto->in_cipher=cipher_new(i);
+
+ /* compression */
+ if(strstr(session->client_kex.methods[KEX_COMP_C_S],"zlib"))
+ session->next_crypto->do_compress_out=1;
+ if(strstr(session->client_kex.methods[KEX_COMP_S_C],"zlib"))
+ session->next_crypto->do_compress_in=1;
+ return 0;
+}
diff --git a/kftpgrabber/src/misc/misc.cpp b/kftpgrabber/src/misc/misc.cpp
new file mode 100644
index 0000000..c4e3bfa
--- /dev/null
+++ b/kftpgrabber/src/misc/misc.cpp
@@ -0,0 +1,193 @@
+/*
+ * This file is part of the KFTPGrabber project
+ *
+ * Copyright (C) 2003-2004 by the KFTPGrabber developers
+ * Copyright (C) 2003-2004 Jernej Kos <kostko@jweb-network.net>
+ *
+ * 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
+ * is provided AS IS, WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, and
+ * NON-INFRINGEMENT. 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 Steet, Fifth Floor, Boston,
+ * MA 02110-1301, USA.
+ *
+ * In addition, as a special exception, the copyright holders give
+ * permission to link the code of portions of this program with the
+ * OpenSSL library under certain conditions as described in each
+ * individual source file, and distribute linked combinations
+ * including the two.
+ * You must obey the GNU General Public License in all respects
+ * for all of the code used other than OpenSSL. If you modify
+ * file(s) with this exception, you may extend this exception to your
+ * version of the file(s), but you are not obligated to do so. If you
+ * do not wish to do so, delete this exception statement from your
+ * version. If you delete this exception statement from all source
+ * files in the program, then also delete it here.
+ */
+
+#include "misc.h"
+
+#include <kurl.h>
+#include <kmdcodec.h>
+#include <kapplication.h>
+#include <kstandarddirs.h>
+#include <kconfig.h>
+
+#include <qcolor.h>
+#include <qpixmapcache.h>
+
+#include <X11/Xlib.h>
+
+namespace KFTPGrabberBase {
+
+QPixmap loadPanelPixmap(const QString &name)
+{
+ return KGlobal::iconLoader()->loadIcon(name, KIcon::Panel, 0, true);
+}
+
+QIconSet loadToolbarIcon(const QString &name, int state)
+{
+ return KGlobal::iconLoader()->loadIconSet(name, KIcon::Toolbar,0,state);
+}
+
+QIconSet loadSmallIcon(const QString &name, int state)
+{
+ return KGlobal::iconLoader()->loadIconSet(name, KIcon::Small,0,state);
+}
+
+QPixmap loadToolbarPixmap(const QString &name)
+{
+ return KGlobal::iconLoader()->loadIcon(name, KIcon::Toolbar,0, true);
+}
+
+QPixmap loadSmallPixmap(const QString &name)
+{
+ return KGlobal::iconLoader()->loadIcon(name, KIcon::Small,0, true);
+}
+
+QPixmap createColorPixmap(QString color)
+{
+ QPixmap tmp(28, 12);
+ tmp.fill(QColor(color));
+
+ QPixmap pixmap(32, 16);
+ pixmap.fill(QColor(0, 0, 0));
+
+ copyBlt(&pixmap, 2, 2, &tmp, 0, 0, 28, 12);
+
+ return pixmap;
+}
+
+QString getStoreDir(const QString &filename)
+{
+ return locateLocal("appdata", filename);
+}
+
+QPixmap createProgressPixmap(int progress, int current)
+{
+ if (progress > 100)
+ progress = 100;
+
+ if (current > 100)
+ current = 100;
+
+ QPixmap pixmap;
+ QString key = QString("%1:%2").arg(progress).arg(current);
+
+ if(!QPixmapCache::find(key, pixmap)) {
+ QPixmap tmp(100, 16);
+ tmp.fill(QColor(237, 237, 237));
+
+ if (progress > 0) {
+ QPixmap p_pix(progress, 16);
+ p_pix.fill(QColor(0, 115, 255));
+
+ QPixmap c_pix(current, 16);
+ c_pix.fill(QColor(0, 88, 192));
+
+ copyBlt(&tmp, 0, 0, &p_pix, 0, 0, progress, 16);
+ copyBlt(&tmp, 0, 0, &c_pix, 0, 0, current, 16);
+ }
+
+ QPixmapCache::insert(key, tmp);
+ return tmp;
+ }
+
+ return pixmap;
+}
+
+bool isModifierKeysPressed(unsigned int mask)
+{
+ Window root;
+ Window child;
+ int root_x, root_y, win_x, win_y;
+ unsigned int keybstate;
+ XQueryPointer(qt_xdisplay(), qt_xrootwin(), &root, &child, &root_x, &root_y, &win_x, &win_y, &keybstate);
+
+ return keybstate & mask;
+}
+
+QString appendPath(const QString &path, const QString &what)
+{
+ if (path.right(1) == "/")
+ return path + what;
+ else
+ return path + "/" + what;
+}
+
+QString path2Name(const QString &path)
+{
+ // Convert full path to filename
+ return (path == "/") ? QString("/") : path.mid(path.findRev('/')+1);
+}
+
+QString path2Dir(const QString &path)
+{
+ // Convert full path to path
+ return path.mid(0, path.findRev('/'));
+}
+
+QString genID()
+{
+ return kapp->randomString(5);
+}
+
+QString encodePassword(const QString& password)
+{
+ return KCodecs::base64Encode(password.ascii(), true).data();
+}
+
+QString decodePassword(const QString& password)
+{
+ return KCodecs::base64Decode(password.ascii()).data();
+}
+
+KConfig *config(const QString &section)
+{
+ KConfig *conf = kapp->config();
+ conf->setGroup(section);
+
+ return conf;
+}
+
+KURL remoteUrl(const QString &path, KURL url)
+{
+ if (path.isEmpty())
+ return KURL();
+
+ KURL tmp = url;
+ tmp.setPath(path);
+
+ return tmp;
+}
+
+} // end namespace
+
diff --git a/kftpgrabber/src/misc/misc.h b/kftpgrabber/src/misc/misc.h
new file mode 100644
index 0000000..654804c
--- /dev/null
+++ b/kftpgrabber/src/misc/misc.h
@@ -0,0 +1,74 @@
+/*
+ * This file is part of the KFTPGrabber project
+ *
+ * Copyright (C) 2003-2004 by the KFTPGrabber developers
+ * Copyright (C) 2003-2004 Jernej Kos <kostko@jweb-network.net>
+ *
+ * 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
+ * is provided AS IS, WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, and
+ * NON-INFRINGEMENT. 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 Steet, Fifth Floor, Boston,
+ * MA 02110-1301, USA.
+ *
+ * In addition, as a special exception, the copyright holders give
+ * permission to link the code of portions of this program with the
+ * OpenSSL library under certain conditions as described in each
+ * individual source file, and distribute linked combinations
+ * including the two.
+ * You must obey the GNU General Public License in all respects
+ * for all of the code used other than OpenSSL. If you modify
+ * file(s) with this exception, you may extend this exception to your
+ * version of the file(s), but you are not obligated to do so. If you
+ * do not wish to do so, delete this exception statement from your
+ * version. If you delete this exception statement from all source
+ * files in the program, then also delete it here.
+ */
+
+#ifndef MISC_H
+#define MISC_H
+
+#include <qiconset.h>
+#include <qptrlist.h>
+
+#include <kiconloader.h>
+
+class KURL;
+class KConfig;
+
+namespace KFTPGrabberBase {
+ // Icon loading stuff
+ QPixmap loadPanelPixmap(const QString &name);
+ QIconSet loadToolbarIcon(const QString &name, int state = 0);
+ QIconSet loadSmallIcon(const QString &name, int state = 0);
+ QPixmap loadToolbarPixmap(const QString &name);
+ QPixmap loadSmallPixmap(const QString &name);
+
+ // Other stuff
+ QPixmap createColorPixmap(QString color);
+ QPixmap createProgressPixmap(int progress, int current = 0);
+ QString appendPath(const QString &path, const QString &what);
+ QString path2Name(const QString &path);
+ QString path2Dir(const QString &path);
+ bool isModifierKeysPressed(unsigned int mask);
+ QString genID();
+ QString getStoreDir(const QString &filename = 0);
+
+ KConfig *config(const QString &section);
+ KURL remoteUrl(const QString &path, KURL url);
+
+ // For "safer" password storage
+ QString encodePassword(const QString& password);
+ QString decodePassword(const QString& password);
+}
+
+#endif
+
diff --git a/kftpgrabber/src/misc/plugins/Makefile.am b/kftpgrabber/src/misc/plugins/Makefile.am
new file mode 100644
index 0000000..0a48ec2
--- /dev/null
+++ b/kftpgrabber/src/misc/plugins/Makefile.am
@@ -0,0 +1,3 @@
+INCLUDES = $(all_includes)
+METASOURCES = AUTO
+SUBDIRS = bookmarkimport
diff --git a/kftpgrabber/src/misc/plugins/bookmarkimport/Makefile.am b/kftpgrabber/src/misc/plugins/bookmarkimport/Makefile.am
new file mode 100644
index 0000000..54d0366
--- /dev/null
+++ b/kftpgrabber/src/misc/plugins/bookmarkimport/Makefile.am
@@ -0,0 +1,3 @@
+INCLUDES = $(all_includes)
+METASOURCES = AUTO
+SUBDIRS = gftp ncftp kftp filezilla3
diff --git a/kftpgrabber/src/misc/plugins/bookmarkimport/filezilla3/Makefile.am b/kftpgrabber/src/misc/plugins/bookmarkimport/filezilla3/Makefile.am
new file mode 100644
index 0000000..737df95
--- /dev/null
+++ b/kftpgrabber/src/misc/plugins/bookmarkimport/filezilla3/Makefile.am
@@ -0,0 +1,14 @@
+INCLUDES = -I$(srcdir)/../../../interfaces \
+ $(all_includes)
+METASOURCES = AUTO
+
+kde_module_LTLIBRARIES = kftpimportplugin_filezilla3.la
+kftpimportplugin_filezilla3_la_SOURCES = kftpimportfz3plugin.cpp
+kftpimportplugin_filezilla3_la_LIBADD = $(LIB_QT) $(LIB_KDECORE) $(LIB_KDEUI) $(LIB_KPARTS) ../../../interfaces/libkftpinterfaces.la
+kftpimportplugin_filezilla3_la_LDFLAGS = -module $(KDE_PLUGIN) $(all_libraries)
+
+kde_services_DATA = kftpimportplugin_filezilla3.desktop
+noinst_HEADERS = kftpimportfz3plugin.h
+
+pluginsdir = $(kde_datadir)/kftpimportplugin_filezilla3
+
diff --git a/kftpgrabber/src/misc/plugins/bookmarkimport/filezilla3/kftpimportfz3plugin.cpp b/kftpgrabber/src/misc/plugins/bookmarkimport/filezilla3/kftpimportfz3plugin.cpp
new file mode 100644
index 0000000..0928c79
--- /dev/null
+++ b/kftpgrabber/src/misc/plugins/bookmarkimport/filezilla3/kftpimportfz3plugin.cpp
@@ -0,0 +1,166 @@
+/*
+ * This file is part of the KFTPGrabber project
+ *
+ * Copyright (C) 2004 by the KFTPGrabber developers
+ * Copyright (C) 2004 Jernej Kos <kostko@jweb-network.net>
+ *
+ * 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
+ * is provided AS IS, WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, and
+ * NON-INFRINGEMENT. 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 Steet, Fifth Floor, Boston,
+ * MA 02110-1301, USA.
+ *
+ * In addition, as a special exception, the copyright holders give
+ * permission to link the code of portions of this program with the
+ * OpenSSL library under certain conditions as described in each
+ * individual source file, and distribute linked combinations
+ * including the two.
+ * You must obey the GNU General Public License in all respects
+ * for all of the code used other than OpenSSL. If you modify
+ * file(s) with this exception, you may extend this exception to your
+ * version of the file(s), but you are not obligated to do so. If you
+ * do not wish to do so, delete this exception statement from your
+ * version. If you delete this exception statement from all source
+ * files in the program, then also delete it here.
+ */
+
+#include "kftpimportfz3plugin.h"
+
+#include <qdir.h>
+#include <qfile.h>
+
+#include <kgenericfactory.h>
+#include <klocale.h>
+#include <kconfig.h>
+#include <kmdcodec.h>
+
+K_EXPORT_COMPONENT_FACTORY(kftpimportplugin_filezilla3,
+ KGenericFactory<KFTPImportFz3Plugin>("kftpimportplugin_filezilla3"))
+
+KFTPImportFz3Plugin::KFTPImportFz3Plugin(QObject *parent, const char *name, const QStringList&)
+ : KFTPBookmarkImportPlugin(parent, name)
+{
+ KGlobal::locale()->insertCatalogue("kftpgrabber");
+}
+
+QDomDocument KFTPImportFz3Plugin::getImportedXml()
+{
+ return m_domDocument;
+}
+
+void KFTPImportFz3Plugin::import(const QString &fileName)
+{
+ m_domDocument.setContent(QString("<category name=\"%1\"/>").arg(i18n("FileZilla 3 import")));
+
+ QFile file(fileName);
+ if (!file.open(IO_ReadOnly)) {
+ emit progress(100);
+ return;
+ }
+
+ m_workDocument.setContent(&file);
+ file.close();
+
+ // Import categories recursively
+ importCategory(m_domDocument.documentElement(), m_workDocument.documentElement().firstChild());
+
+ emit progress(100);
+}
+
+void KFTPImportFz3Plugin::importCategory(QDomNode parent, const QDomNode &node)
+{
+ QDomNode n = node.firstChild();
+
+ while (!n.isNull()) {
+ if (!n.isElement()) {
+ n = n.nextSibling();
+ continue;
+ }
+
+ QDomElement e = n.toElement();
+
+ if (e.tagName() == "Folder") {
+ QDomElement categoryElement = m_domDocument.createElement("category");
+ categoryElement.setAttribute("name", e.firstChild().nodeValue().stripWhiteSpace());
+ parent.appendChild(categoryElement);
+
+ importCategory(categoryElement, n);
+ } else if (e.tagName() == "Server") {
+ QString name = e.lastChild().nodeValue().stripWhiteSpace();
+ QString host = e.namedItem("Host").toElement().text();
+ QString port = e.namedItem("Port").toElement().text();
+ QString localDir = e.namedItem("LocalDir").toElement().text();
+ QString remoteDir = e.namedItem("RemoteDir").toElement().text();
+ QString username = e.namedItem("User").toElement().text();
+ QString password = e.namedItem("Pass").toElement().text();
+
+ // Set name
+ QDomElement siteElement = m_domDocument.createElement("server");
+ siteElement.setAttribute("name", name);
+ parent.appendChild(siteElement);
+
+ // Set host
+ QDomElement tmpElement = m_domDocument.createElement("host");
+ QDomText txtNode = m_domDocument.createTextNode(host);
+ tmpElement.appendChild(txtNode);
+ siteElement.appendChild(tmpElement);
+
+ // Set port
+ tmpElement = m_domDocument.createElement("port");
+ txtNode = m_domDocument.createTextNode(port);
+ tmpElement.appendChild(txtNode);
+ siteElement.appendChild(tmpElement);
+
+ // Set remote directory
+ tmpElement = m_domDocument.createElement("defremotepath");
+ txtNode = m_domDocument.createTextNode(remoteDir);
+ tmpElement.appendChild(txtNode);
+ siteElement.appendChild(tmpElement);
+
+ // Set local directory
+ tmpElement = m_domDocument.createElement("deflocalpath");
+ txtNode = m_domDocument.createTextNode(localDir);
+ tmpElement.appendChild(txtNode);
+ siteElement.appendChild(tmpElement);
+
+ // Set username
+ if (username.isNull()) {
+ username = "anonymous";
+
+ tmpElement = m_domDocument.createElement("anonlogin");
+ txtNode = m_domDocument.createTextNode("1");
+ tmpElement.appendChild(txtNode);
+ siteElement.appendChild(tmpElement);
+ }
+
+ tmpElement = m_domDocument.createElement("username");
+ txtNode = m_domDocument.createTextNode(username);
+ tmpElement.appendChild(txtNode);
+ siteElement.appendChild(tmpElement);
+
+ // Set password
+ tmpElement = m_domDocument.createElement("password");
+ txtNode = m_domDocument.createTextNode(KCodecs::base64Encode(password.ascii(), true).data());
+ tmpElement.appendChild(txtNode);
+ siteElement.appendChild(tmpElement);
+ }
+
+ n = n.nextSibling();
+ }
+}
+
+QString KFTPImportFz3Plugin::getDefaultPath()
+{
+ return QString(".filezilla/sitemanager.xml");
+}
+
+#include "kftpimportfz3plugin.moc"
diff --git a/kftpgrabber/src/misc/plugins/bookmarkimport/filezilla3/kftpimportfz3plugin.h b/kftpgrabber/src/misc/plugins/bookmarkimport/filezilla3/kftpimportfz3plugin.h
new file mode 100644
index 0000000..c340ef5
--- /dev/null
+++ b/kftpgrabber/src/misc/plugins/bookmarkimport/filezilla3/kftpimportfz3plugin.h
@@ -0,0 +1,82 @@
+/*
+ * This file is part of the KFTPGrabber project
+ *
+ * Copyright (C) 2004 by the KFTPGrabber developers
+ * Copyright (C) 2004 Jernej Kos <kostko@jweb-network.net>
+ *
+ * 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
+ * is provided AS IS, WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, and
+ * NON-INFRINGEMENT. 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 Steet, Fifth Floor, Boston,
+ * MA 02110-1301, USA.
+ *
+ * In addition, as a special exception, the copyright holders give
+ * permission to link the code of portions of this program with the
+ * OpenSSL library under certain conditions as described in each
+ * individual source file, and distribute linked combinations
+ * including the two.
+ * You must obey the GNU General Public License in all respects
+ * for all of the code used other than OpenSSL. If you modify
+ * file(s) with this exception, you may extend this exception to your
+ * version of the file(s), but you are not obligated to do so. If you
+ * do not wish to do so, delete this exception statement from your
+ * version. If you delete this exception statement from all source
+ * files in the program, then also delete it here.
+ */
+
+#ifndef KFTPIMPORTFZ3PLUGIN_H
+#define KFTPIMPORTFZ3PLUGIN_H
+
+#include <qdom.h>
+#include <kftpbookmarkimportplugin.h>
+
+/**
+ * This plugin enables importing of FileZilla 3 bookmark files into KFTPGrabber.
+ *
+ * @author Jernej Kos
+ */
+class KFTPImportFz3Plugin : public KFTPBookmarkImportPlugin
+{
+Q_OBJECT
+public:
+ KFTPImportFz3Plugin(QObject *parent, const char *name, const QStringList&);
+
+ /**
+ * This method should return the properly formated XML for KFTPGrabber
+ * bookmarks that is generated from the import.
+ *
+ * @return The @ref QDomDocument representation of XML
+ */
+ QDomDocument getImportedXml();
+
+ /**
+ * This method should start the import procedure.
+ *
+ * @param fileName is the path to the file that will be imported
+ */
+ void import(const QString &fileName);
+
+ /**
+ * This method should return the default path where the bookmarks could
+ * be located. The path must be relative to the user's home directory.
+ *
+ * @return The default path where bookmarks are located
+ */
+ QString getDefaultPath();
+private:
+ QDomDocument m_domDocument;
+ QDomDocument m_workDocument;
+
+ void importCategory(QDomNode parent, const QDomNode &node);
+};
+
+#endif
diff --git a/kftpgrabber/src/misc/plugins/bookmarkimport/filezilla3/kftpimportplugin_filezilla3.desktop b/kftpgrabber/src/misc/plugins/bookmarkimport/filezilla3/kftpimportplugin_filezilla3.desktop
new file mode 100644
index 0000000..f3b91ae
--- /dev/null
+++ b/kftpgrabber/src/misc/plugins/bookmarkimport/filezilla3/kftpimportplugin_filezilla3.desktop
@@ -0,0 +1,38 @@
+[Desktop Entry]
+Name=FileZilla 3 Import plugin
+Name[ar]=قابس الإستيراد FileZilla 3
+Name[bg]=Приставка за импортиране на FileZilla 3
+Name[da]=Import-plugin
+Name[de]=FileZilla3-Importmodul
+Name[el]=Πρόσθετο εισαγωγής FileZilla 3
+Name[es]=Complemento de importación de FileZilla 3
+Name[et]=FileZilla 3 impordiplugin
+Name[ga]=Breiseán Iompórtála FileZilla 3
+Name[it]=Plugin di importazione FileZilla 3
+Name[ja]=FileZilla 3 インポートプラグイン
+Name[nl]=FileZilla 3-importplugin
+Name[pt]='Plugin' de Importação do FileZilla 3
+Name[pt_BR]=Plug-in de importação do FileZilla 3
+Name[sv]=FileZilla 3-importinsticksprogram
+Name[uk]=Втулок імпорту FileZilla 3
+Name[zh_CN]=FileZilla 3 导入插件
+Comment=FileZilla 3 bookmarks import plugin
+Comment[ar]=قابس FileZilla 3 لإستيراد علامات المواقع
+Comment[bg]=Приставка за импортиране на FileZilla 3 отметки в KFTPGrabber
+Comment[da]=Filezilla 3 bogmærkeimport-plugin
+Comment[de]=FileZilla3-Lesezeichenimportmodul
+Comment[el]=Πρόσθετο εισαγωγής σελιδοδεικτών FileZilla 3
+Comment[es]=Complemento de importación de marcadores de FileZilla 3
+Comment[et]=FileZilla 3 järjehoidjate impordiplugin
+Comment[ga]=Breiseán iompórtála leabharmharcanna FileZilla 3
+Comment[it]=Plugin di importazione dei segnalibri di FileZilla 3
+Comment[ja]=FileZilla 3 ブックマークをインポートするプラグイン
+Comment[nl]=FileZilla 3-bladwijzers importplugin
+Comment[pt]='Plugin' de importação de favoritos do FileZilla 3
+Comment[pt_BR]=Plug-in de importação de favoritos do FileZilla 3
+Comment[sv]=Insticksprogram för FileZilla 3-bokmärkesimport
+Comment[uk]=Втулок імпортування закладок FileZilla 3
+ServiceTypes=KFTPGrabber/BookmarkImportPlugin
+Type=Service
+X-KDE-Library=kftpimportplugin_filezilla3
+
diff --git a/kftpgrabber/src/misc/plugins/bookmarkimport/gftp/Makefile.am b/kftpgrabber/src/misc/plugins/bookmarkimport/gftp/Makefile.am
new file mode 100644
index 0000000..15a7928
--- /dev/null
+++ b/kftpgrabber/src/misc/plugins/bookmarkimport/gftp/Makefile.am
@@ -0,0 +1,14 @@
+INCLUDES = -I$(srcdir)/../../../interfaces \
+ $(all_includes)
+METASOURCES = AUTO
+
+kde_module_LTLIBRARIES = kftpimportplugin_gftp.la
+kftpimportplugin_gftp_la_SOURCES = kftpimportgftpplugin.cpp
+kftpimportplugin_gftp_la_LIBADD = $(LIB_QT) $(LIB_KDECORE) $(LIB_KDEUI) $(LIB_KPARTS) ../../../interfaces/libkftpinterfaces.la
+kftpimportplugin_gftp_la_LDFLAGS = -module $(KDE_PLUGIN) $(all_libraries)
+
+kde_services_DATA = kftpimportplugin_gftp.desktop
+noinst_HEADERS = kftpimportgftpplugin.h
+
+pluginsdir = $(kde_datadir)/kftpimportplugin_gftp
+
diff --git a/kftpgrabber/src/misc/plugins/bookmarkimport/gftp/kftpimportgftpplugin.cpp b/kftpgrabber/src/misc/plugins/bookmarkimport/gftp/kftpimportgftpplugin.cpp
new file mode 100644
index 0000000..9bd5e56
--- /dev/null
+++ b/kftpgrabber/src/misc/plugins/bookmarkimport/gftp/kftpimportgftpplugin.cpp
@@ -0,0 +1,236 @@
+/*
+ * This file is part of the KFTPGrabber project
+ *
+ * Copyright (C) 2004 by the KFTPGrabber developers
+ * Copyright (C) 2004 Jernej Kos <kostko@jweb-network.net>
+ *
+ * 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
+ * is provided AS IS, WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, and
+ * NON-INFRINGEMENT. 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 Steet, Fifth Floor, Boston,
+ * MA 02110-1301, USA.
+ *
+ * In addition, as a special exception, the copyright holders give
+ * permission to link the code of portions of this program with the
+ * OpenSSL library under certain conditions as described in each
+ * individual source file, and distribute linked combinations
+ * including the two.
+ * You must obey the GNU General Public License in all respects
+ * for all of the code used other than OpenSSL. If you modify
+ * file(s) with this exception, you may extend this exception to your
+ * version of the file(s), but you are not obligated to do so. If you
+ * do not wish to do so, delete this exception statement from your
+ * version. If you delete this exception statement from all source
+ * files in the program, then also delete it here.
+ */
+
+#include "kftpimportgftpplugin.h"
+
+#include <qdir.h>
+
+#include <kgenericfactory.h>
+#include <klocale.h>
+#include <kconfig.h>
+#include <kmdcodec.h>
+
+K_EXPORT_COMPONENT_FACTORY(kftpimportplugin_gftp,
+ KGenericFactory<KFTPImportGftpPlugin>("kftpimportplugin_gftp"))
+
+KFTPImportGftpPlugin::KFTPImportGftpPlugin(QObject *parent, const char *name, const QStringList&)
+ : KFTPBookmarkImportPlugin(parent, name)
+{
+ KGlobal::locale()->insertCatalogue("kftpgrabber");
+ m_domDocument.setContent(QString("<category name=\"%1\"/>").arg(i18n("gFTP import")));
+}
+
+QDomDocument KFTPImportGftpPlugin::getImportedXml()
+{
+ return m_domDocument;
+}
+
+void KFTPImportGftpPlugin::import(const QString &fileName)
+{
+ // First we fetch some global settings
+ KConfig tmpConfig(userPath(".gftp/gftprc"), true, false, "HOME");
+ QString email = tmpConfig.readEntry("email", "anonymous@");
+ int numRetries = tmpConfig.readNumEntry("retries", -1);
+ int sleepTime = tmpConfig.readNumEntry("sleep_time", -1);
+
+ // Open the bookmarks file (it has INI-like file format, so we can use the KConfig
+ // class to do the parsing and converting)
+ KConfig config(fileName, true, false, "HOME");
+ QStringList groupList = config.groupList();
+
+ float size = (float) groupList.count();
+ if (size == 0) {
+ // There are no bookmarks (or incorrect file), we are done
+
+ emit progress(100);
+ return;
+ }
+
+ int counter = 0;
+ QStringList::Iterator end( groupList.end() );
+ for( QStringList::Iterator it( groupList.begin() ); it != end; ++it ) {
+ // gFTP bookmarks can have subgroups
+ QString groupName = *it;
+ QStringList groupNames = QStringList::split("/", groupName);
+
+ QDomNode groupNode;
+ QDomElement parentElement = m_domDocument.documentElement();
+ config.setGroup(groupName);
+ QString tmp = config.readEntry("hostname");
+
+ for (unsigned int i = 0; ! tmp.isNull() && i < groupNames.count() - 1; ++i ) {
+ // First see if parenElement has any sub group
+ groupNode = findSubGroup(parentElement, groupNames[i]);
+
+ if( groupNode.isNull() ) {
+ // No, it has no subgroup, let's create one
+ while (i < groupNames.count() -1) {
+ QDomElement tmpElement = m_domDocument.createElement("category");
+ tmpElement.setAttribute("name", groupNames[i]);
+ parentElement.appendChild(tmpElement);
+ parentElement = tmpElement;
+
+ ++i;
+ }
+ } else {
+ // Sub group found, lets check next level
+ parentElement = groupNode.toElement();
+ }
+ }
+
+ // Now group tree is updated so lets create the site (if it has hostname)
+ if (!tmp.isNull()) {
+ // Set name
+ QDomElement siteElement = m_domDocument.createElement("server");
+ siteElement.setAttribute("name", groupNames.last());
+ parentElement.appendChild(siteElement);
+
+ // Set host
+ tmp = config.readEntry("hostname");
+ QDomElement tmpElement = m_domDocument.createElement("host");
+ QDomText txtNode = m_domDocument.createTextNode(tmp);
+ tmpElement.appendChild(txtNode);
+ siteElement.appendChild(tmpElement);
+
+ // Set port
+ int p = config.readNumEntry("port", 21);
+ tmpElement = m_domDocument.createElement("port");
+ txtNode = m_domDocument.createTextNode(QString::number(p));
+ tmpElement.appendChild(txtNode);
+ siteElement.appendChild(tmpElement);
+
+ // Set remote directory
+ tmp = config.readEntry("remote directory", "/");
+ tmpElement = m_domDocument.createElement("defremotepath");
+ txtNode = m_domDocument.createTextNode(tmp);
+ tmpElement.appendChild(txtNode);
+ siteElement.appendChild(tmpElement);
+
+ // Set local directory
+ tmp = config.readEntry("local directory", QDir::homeDirPath());
+ tmpElement = m_domDocument.createElement("deflocalpath");
+ txtNode = m_domDocument.createTextNode(tmp);
+ tmpElement.appendChild(txtNode);
+ siteElement.appendChild(tmpElement);
+
+ // Set username
+ tmp = config.readEntry("username", "anonymous");
+ tmpElement = m_domDocument.createElement("username");
+ txtNode = m_domDocument.createTextNode(tmp);
+ tmpElement.appendChild(txtNode);
+ siteElement.appendChild(tmpElement);
+
+ if (tmp == "anonymous") {
+ tmpElement = m_domDocument.createElement("anonlogin");
+ txtNode = m_domDocument.createTextNode("1");
+ tmpElement.appendChild(txtNode);
+ siteElement.appendChild(tmpElement);
+ }
+
+ // Set password
+ tmp = config.readEntry("password");
+ tmpElement = m_domDocument.createElement("password");
+
+ if (tmp == "@EMAIL@" || tmp.isNull() || tmp.isEmpty())
+ tmp = email;
+ else
+ tmp = decodePassword(tmp);
+
+ // We have to encode the password
+ tmp = KCodecs::base64Encode(tmp.ascii(), true).data();
+ txtNode = m_domDocument.createTextNode(tmp);
+ tmpElement.appendChild(txtNode);
+ siteElement.appendChild(tmpElement);
+
+ // Set retries
+ if (numRetries >= 0) {
+ tmpElement = m_domDocument.createElement("retrytime");
+ txtNode = m_domDocument.createTextNode(QString::number(sleepTime));
+ tmpElement.appendChild(txtNode);
+ siteElement.appendChild(tmpElement);
+
+ tmpElement = m_domDocument.createElement("retrycount");
+ txtNode = m_domDocument.createTextNode(QString::number(numRetries));
+ tmpElement.appendChild(txtNode);
+ siteElement.appendChild(tmpElement);
+ }
+ }
+
+ emit progress(int(float(counter) / size * 100));
+ ++counter;
+ }
+
+ emit progress(100);
+}
+
+QString KFTPImportGftpPlugin::decodePassword(const QString &password)
+{
+ // Leave unencoded passwords as they are
+ if (password[0] != '$')
+ return password;
+
+ QString work = password;
+ work.remove(0, 1);
+
+ QString result;
+
+ for (uint i = 0; i < work.length() - 1; i += 2) {
+ char c = work.at(i).latin1();
+ char n = work.at(i+1).latin1();
+
+ result.append( ((c & 0x3c) << 2) | ((n & 0x3c) >> 2) );
+ }
+
+ return result;
+}
+
+QDomNode KFTPImportGftpPlugin::findSubGroup(QDomElement parent, const QString& name)
+{
+ QDomNodeList nodeList = parent.childNodes();
+
+ for(unsigned int i = 0; i < nodeList.count(); ++i) {
+ if(nodeList.item(i).toElement().attribute("name") == name)
+ return nodeList.item(i);
+ }
+
+ return QDomNode();
+}
+
+QString KFTPImportGftpPlugin::getDefaultPath()
+{
+ return QString(".gftp/bookmarks");
+}
+
+#include "kftpimportgftpplugin.moc"
diff --git a/kftpgrabber/src/misc/plugins/bookmarkimport/gftp/kftpimportgftpplugin.h b/kftpgrabber/src/misc/plugins/bookmarkimport/gftp/kftpimportgftpplugin.h
new file mode 100644
index 0000000..af2bceb
--- /dev/null
+++ b/kftpgrabber/src/misc/plugins/bookmarkimport/gftp/kftpimportgftpplugin.h
@@ -0,0 +1,83 @@
+/*
+ * This file is part of the KFTPGrabber project
+ *
+ * Copyright (C) 2004 by the KFTPGrabber developers
+ * Copyright (C) 2004 Jernej Kos <kostko@jweb-network.net>
+ *
+ * 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
+ * is provided AS IS, WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, and
+ * NON-INFRINGEMENT. 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 Steet, Fifth Floor, Boston,
+ * MA 02110-1301, USA.
+ *
+ * In addition, as a special exception, the copyright holders give
+ * permission to link the code of portions of this program with the
+ * OpenSSL library under certain conditions as described in each
+ * individual source file, and distribute linked combinations
+ * including the two.
+ * You must obey the GNU General Public License in all respects
+ * for all of the code used other than OpenSSL. If you modify
+ * file(s) with this exception, you may extend this exception to your
+ * version of the file(s), but you are not obligated to do so. If you
+ * do not wish to do so, delete this exception statement from your
+ * version. If you delete this exception statement from all source
+ * files in the program, then also delete it here.
+ */
+
+#ifndef KFTPIMPORTGFTPPLUGIN_H
+#define KFTPIMPORTGFTPPLUGIN_H
+
+#include <qdom.h>
+#include <kftpbookmarkimportplugin.h>
+
+/**
+This plugin can import GFTP bookmarks into KFTPGrabber. This plugin has been ported
+from "KBear by Bj�n Sahlstr� <kbjorn@users.sourceforge.net>".
+
+@author Jernej Kos
+*/
+class KFTPImportGftpPlugin : public KFTPBookmarkImportPlugin
+{
+Q_OBJECT
+public:
+ KFTPImportGftpPlugin(QObject *parent, const char *name, const QStringList&);
+
+ /**
+ * This method should return the properly formated XML for KFTPGrabber
+ * bookmarks that is generated from the import.
+ *
+ * @return The @ref QDomDocument representation of XML
+ */
+ QDomDocument getImportedXml();
+
+ /**
+ * This method should start the import procedure.
+ *
+ * @param fileName is the path to the file that will be imported
+ */
+ void import(const QString &fileName);
+
+ /**
+ * This method should return the default path where the bookmarks could
+ * be located. The path must be relative to the user's home directory.
+ *
+ * @return The default path where bookmarks are located
+ */
+ QString getDefaultPath();
+private:
+ QDomDocument m_domDocument;
+
+ QDomNode findSubGroup(QDomElement parent, const QString& name);
+ QString decodePassword(const QString &password);
+};
+
+#endif
diff --git a/kftpgrabber/src/misc/plugins/bookmarkimport/gftp/kftpimportplugin_gftp.desktop b/kftpgrabber/src/misc/plugins/bookmarkimport/gftp/kftpimportplugin_gftp.desktop
new file mode 100644
index 0000000..815f1d4
--- /dev/null
+++ b/kftpgrabber/src/misc/plugins/bookmarkimport/gftp/kftpimportplugin_gftp.desktop
@@ -0,0 +1,61 @@
+[Desktop Entry]
+Name=gFTP Import plugin
+Name[ar]=قابس أستيراد gFTP
+Name[bg]=Приставка за импортиране на gFTP
+Name[br]=Lugent enporzh gFTP
+Name[cs]=gFTP importní modul
+Name[da]=gFTP import-plugin
+Name[de]=gFTP-Importmodul
+Name[el]=Πρόσθετο εισαγωγής gFTP
+Name[es]=Complemento de importación de gFTP
+Name[et]=gFTP impordiplugin
+Name[fr]=Module d'importation de gFTP
+Name[ga]=Breiseán Iompórtála gFTP
+Name[gl]=Plugin de importazón de gFTP
+Name[it]=Plugin di importazione gFTP
+Name[ja]=gFTP インポートプラグイン
+Name[ka]=gFTP-ის იმპორტის მოდული
+Name[lt]=gFTP importavimo įskiepis
+Name[nl]=gFTP-importplugin
+Name[pa]=gFTP ਆਯਾਤ ਪਲੱਗਿੰਨ
+Name[pt]='Plugin' de importação do gFTP
+Name[pt_BR]=Plug-in de importação do gFTP
+Name[ru]=Модуль импорта из gFTP
+Name[sr]=Прикључак gFTP увоза
+Name[sr@Latn]=Priključak gFTP uvoza
+Name[sv]=gFTP-importinsticksprogram
+Name[tr]=gFTP'den alma Eklentisi
+Name[uk]=Втулок імпорту gFTP
+Name[xx]=xxgFTP Import pluginxx
+Name[zh_CN]=gFTP 导入插件
+Comment=gFTP bookmarks import plugin for KFTPGrabber
+Comment[ar]=قابس gFTP لإستيراد علامات المواقع لِــ KFTPGrabber
+Comment[bg]=Приставка за импортиране на gFTP отметки в KFTPGrabber
+Comment[br]=Lugent enporzh sinedoù gFTP evit KFTPGrabber
+Comment[cs]=gFTP modul importu záložek pro KFTPGrabber
+Comment[da]=gFTP bogmærker import-plugin for KFTPGrabber
+Comment[de]=gFTP-Lesezeichenimportmodul für KFTPGrabber
+Comment[el]=Πρόσθετο εισαγωγής σελιδοδεικτών του gFTP για το KFTPGrabber
+Comment[es]=Complemento de importación de marcadores de gFTP para KFTPGrabber
+Comment[et]=KFTPGrabberi gFTP järjehoidjate impordiplugin
+Comment[fr]=Module d'importation des signets gFTP pour KFTPGrabber
+Comment[ga]=Breiseán iompórtála leabharmharcanna gFTP le haghaidh KFTPGrabber
+Comment[gl]=Plugin de importazón de marcadores de gFTP para KFTPGrabber
+Comment[it]=Plugin di importazione dei segnalibri di gFTP per KFTPGrabber
+Comment[ja]=KFTPGrabber gFTP のブックマークをインポートするプラグイン
+Comment[ka]=gFTP-ის სანიშნეების იმპორტის მოდული KFTPGrabber-თვის
+Comment[lt]=gFTP žymelių importavimo į KFTPGrabber įskiepis
+Comment[nl]=KFTPGrabber-plugin voor het importeren van gFTP-bladwijzers
+Comment[pt]='Plugin' de importação de favoritos do gFTP para o KFTPGrabber
+Comment[pt_BR]=Plug-in de importação de favoritos do gFTP para o KFTPGrabber
+Comment[ru]=Импорт закладок gFTP в KFTPGrabber
+Comment[sr]=KFTPGrabber-ов прикључак за увоз gFTP маркера
+Comment[sr@Latn]=KFTPGrabber-ov priključak za uvoz gFTP markera
+Comment[sv]=Insticksprogram för gFTP-bokmärkesimport till KFTPgrabber
+Comment[tr]=KFTPGrabber için gFTP yer imlerini alma eklentisi
+Comment[uk]=Втулок імпортування закладок gFTP для KFTPGrabber
+Comment[xx]=xxgFTP bookmarks import plugin for KFTPGrabberxx
+ServiceTypes=KFTPGrabber/BookmarkImportPlugin
+Type=Service
+X-KDE-Library=kftpimportplugin_gftp
+
diff --git a/kftpgrabber/src/misc/plugins/bookmarkimport/kftp/Makefile.am b/kftpgrabber/src/misc/plugins/bookmarkimport/kftp/Makefile.am
new file mode 100644
index 0000000..572413c
--- /dev/null
+++ b/kftpgrabber/src/misc/plugins/bookmarkimport/kftp/Makefile.am
@@ -0,0 +1,14 @@
+INCLUDES = -I$(srcdir)/../../../interfaces \
+ $(all_includes)
+METASOURCES = AUTO
+
+kde_module_LTLIBRARIES = kftpimportplugin_kftp.la
+kftpimportplugin_kftp_la_SOURCES = kftpimportkftpplugin.cpp
+kftpimportplugin_kftp_la_LIBADD = $(LIB_QT) $(LIB_KDECORE) $(LIB_KDEUI) $(LIB_KPARTS) ../../../interfaces/libkftpinterfaces.la
+kftpimportplugin_kftp_la_LDFLAGS = -module $(KDE_PLUGIN) $(all_libraries)
+
+kde_services_DATA = kftpimportplugin_kftp.desktop
+noinst_HEADERS = kftpimportkftpplugin.h
+
+pluginsdir = $(kde_datadir)/kftpimportplugin_kftp
+
diff --git a/kftpgrabber/src/misc/plugins/bookmarkimport/kftp/kftpimportkftpplugin.cpp b/kftpgrabber/src/misc/plugins/bookmarkimport/kftp/kftpimportkftpplugin.cpp
new file mode 100644
index 0000000..3ea06d8
--- /dev/null
+++ b/kftpgrabber/src/misc/plugins/bookmarkimport/kftp/kftpimportkftpplugin.cpp
@@ -0,0 +1,118 @@
+/*
+ * This file is part of the KFTPGrabber project
+ *
+ * Copyright (C) 2004 by the KFTPGrabber developers
+ * Copyright (C) 2004 Jernej Kos <kostko@jweb-network.net>
+ *
+ * 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
+ * is provided AS IS, WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, and
+ * NON-INFRINGEMENT. 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 Steet, Fifth Floor, Boston,
+ * MA 02110-1301, USA.
+ *
+ * In addition, as a special exception, the copyright holders give
+ * permission to link the code of portions of this program with the
+ * OpenSSL library under certain conditions as described in each
+ * individual source file, and distribute linked combinations
+ * including the two.
+ * You must obey the GNU General Public License in all respects
+ * for all of the code used other than OpenSSL. If you modify
+ * file(s) with this exception, you may extend this exception to your
+ * version of the file(s), but you are not obligated to do so. If you
+ * do not wish to do so, delete this exception statement from your
+ * version. If you delete this exception statement from all source
+ * files in the program, then also delete it here.
+ */
+
+#include "kftpimportkftpplugin.h"
+
+#include <qdir.h>
+#include <qfile.h>
+
+#include <kgenericfactory.h>
+#include <klocale.h>
+#include <kconfig.h>
+#include <kmdcodec.h>
+
+K_EXPORT_COMPONENT_FACTORY(kftpimportplugin_kftp,
+ KGenericFactory<KFTPImportKftpPlugin>("kftpimportplugin_kftp"))
+
+KFTPImportKftpPlugin::KFTPImportKftpPlugin(QObject *parent, const char *name, const QStringList&)
+ : KFTPBookmarkImportPlugin(parent, name)
+{
+ KGlobal::locale()->insertCatalogue("kftpgrabber");
+}
+
+QDomDocument KFTPImportKftpPlugin::getImportedXml()
+{
+ return m_domDocument;
+}
+
+void KFTPImportKftpPlugin::import(const QString &fileName)
+{
+ m_domDocument.setContent(QString("<category name=\"%1\"/>").arg(i18n("KFTPGrabber import")));
+
+ // There is actually nothing to import, we just have to read the existing XML and
+ // remove site ids.
+ QFile file(fileName);
+ if (!file.open(IO_ReadOnly)) {
+ emit progress(100);
+ return;
+ }
+
+ m_workDocument.setContent(&file);
+ file.close();
+
+ // Strip all ids
+ stripIds();
+
+ // Now append the bookmarks
+ QDomNode n = m_workDocument.documentElement().firstChild();
+
+ while (!n.isNull()) {
+ QDomNode import = m_domDocument.importNode(n, true);
+ m_domDocument.documentElement().appendChild(import);
+
+ n = n.nextSibling();
+ }
+
+ emit progress(100);
+}
+
+void KFTPImportKftpPlugin::stripIds(QDomNode node)
+{
+ if (node.isNull())
+ node = m_workDocument.documentElement();
+
+ QDomNode n = node.firstChild();
+
+ while (!n.isNull()) {
+ if (n.toElement().tagName() == "category") {
+ if (!n.toElement().hasAttribute("id"))
+ n.toElement().removeAttribute("id");
+
+ stripIds(n);
+ } else if (n.toElement().tagName() == "server") {
+ if (n.toElement().hasAttribute("id"))
+ n.toElement().removeAttribute("id");
+ }
+
+ n = n.nextSibling();
+ }
+}
+
+QString KFTPImportKftpPlugin::getDefaultPath()
+{
+ return QString("");
+}
+
+#include "kftpimportkftpplugin.moc"
diff --git a/kftpgrabber/src/misc/plugins/bookmarkimport/kftp/kftpimportkftpplugin.h b/kftpgrabber/src/misc/plugins/bookmarkimport/kftp/kftpimportkftpplugin.h
new file mode 100644
index 0000000..9f2e593
--- /dev/null
+++ b/kftpgrabber/src/misc/plugins/bookmarkimport/kftp/kftpimportkftpplugin.h
@@ -0,0 +1,83 @@
+/*
+ * This file is part of the KFTPGrabber project
+ *
+ * Copyright (C) 2004 by the KFTPGrabber developers
+ * Copyright (C) 2004 Jernej Kos <kostko@jweb-network.net>
+ *
+ * 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
+ * is provided AS IS, WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, and
+ * NON-INFRINGEMENT. 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 Steet, Fifth Floor, Boston,
+ * MA 02110-1301, USA.
+ *
+ * In addition, as a special exception, the copyright holders give
+ * permission to link the code of portions of this program with the
+ * OpenSSL library under certain conditions as described in each
+ * individual source file, and distribute linked combinations
+ * including the two.
+ * You must obey the GNU General Public License in all respects
+ * for all of the code used other than OpenSSL. If you modify
+ * file(s) with this exception, you may extend this exception to your
+ * version of the file(s), but you are not obligated to do so. If you
+ * do not wish to do so, delete this exception statement from your
+ * version. If you delete this exception statement from all source
+ * files in the program, then also delete it here.
+ */
+
+#ifndef KFTPIMPORTKFTPPLUGIN_H
+#define KFTPIMPORTKFTPPLUGIN_H
+
+#include <qdom.h>
+#include <kftpbookmarkimportplugin.h>
+
+/**
+ * This plugin enables importing of KFTPGrabber XML bookmark files into KFTPGrabber,
+ * so the users can import bookmarks that were previously exported.
+ *
+ * @author Jernej Kos
+ */
+class KFTPImportKftpPlugin : public KFTPBookmarkImportPlugin
+{
+Q_OBJECT
+public:
+ KFTPImportKftpPlugin(QObject *parent, const char *name, const QStringList&);
+
+ /**
+ * This method should return the properly formated XML for KFTPGrabber
+ * bookmarks that is generated from the import.
+ *
+ * @return The @ref QDomDocument representation of XML
+ */
+ QDomDocument getImportedXml();
+
+ /**
+ * This method should start the import procedure.
+ *
+ * @param fileName is the path to the file that will be imported
+ */
+ void import(const QString &fileName);
+
+ /**
+ * This method should return the default path where the bookmarks could
+ * be located. The path must be relative to the user's home directory.
+ *
+ * @return The default path where bookmarks are located
+ */
+ QString getDefaultPath();
+private:
+ QDomDocument m_domDocument;
+ QDomDocument m_workDocument;
+
+ void stripIds(QDomNode node = QDomNode());
+};
+
+#endif
diff --git a/kftpgrabber/src/misc/plugins/bookmarkimport/kftp/kftpimportplugin_kftp.desktop b/kftpgrabber/src/misc/plugins/bookmarkimport/kftp/kftpimportplugin_kftp.desktop
new file mode 100644
index 0000000..0cb42ba
--- /dev/null
+++ b/kftpgrabber/src/misc/plugins/bookmarkimport/kftp/kftpimportplugin_kftp.desktop
@@ -0,0 +1,57 @@
+[Desktop Entry]
+Name=KFTPGrabber XML Import plugin
+Name[ar]=قابس الإستيراد لِــ KFTPGrabber XML
+Name[bg]=Приставка за импортиране на XML в KFTPGrabber
+Name[br]=Lugent enporzh XML evit KFTPGrabber
+Name[cs]=KFTPGrabber XML importní modul
+Name[da]=KFTPGrabber XML Import-plugin
+Name[de]=KFTPGrabber XML-Importmodul
+Name[el]=Πρόσθετο εισαγωγής XML του KFTPGrabber
+Name[es]=Complemento de importación de XML de KFTPGrabber
+Name[et]=KFTPGrabberi XML-i impordiplugin
+Name[ga]=Breiseán Iompórtála XML KFTPGrabber
+Name[gl]=Plugin de importazón de XML para KFTPGrabber
+Name[it]=KFTPGrabber Plugin di importazione XML
+Name[ja]=KFTPGrabber XML インポートプラグイン
+Name[ka]=KFTPGrabber-ის XML-ის იმპორტის მოდული
+Name[lt]=KFTPGrabber XML importavimo įskiepis
+Name[nl]=KFTPGrabber XML Importplugin
+Name[pt]='Plugin' de importação XML do KFTPGrabber
+Name[pt_BR]=Plug-in de importação XML do KFTPGrabber
+Name[sr]=Прикључак KFTPGrabber-а за XML увоз
+Name[sr@Latn]=Priključak KFTPGrabber-a za XML uvoz
+Name[sv]=Insticksprogram för XML-import till KFTPgrabber
+Name[tr]=KFTPGrabber XML alma eklentisi
+Name[uk]=Втулок імпортування XML для KFTPGrabber
+Name[xx]=xxKFTPGrabber XML Import pluginxx
+Name[zh_CN]=KFTPGrabber XML 导入插件
+Comment=KFTPGrabber XML bookmarks import plugin
+Comment[ar]=قابس الإستيراد KFTPGrabber XML لعلامات المواقع
+Comment[bg]=Приставка за импортиране на XML отметки в KFTPGrabber
+Comment[br]=Lugent enporzh sinedoù XML KFTPGrabber evit KFTPGrabber
+Comment[cs]=XML modul importu záložek pro KFTPGrabber
+Comment[da]=KFTPGrabber XML bogmærkeimport-plugin
+Comment[de]=KFTPGrabber XML-Lesezeichenimportmodul
+Comment[el]=Πρόσθετο εισαγωγής σελιδοδεικτών XML του KFTPGrabber
+Comment[es]=Complemento de importación de marcadores en XML de KFTPGrabber
+Comment[et]=KFTPGrabberi XML-järjehoidjate impordiplugin
+Comment[ga]=Breiseán iompórtála leabharmharcanna XML le haghaidh KFTPGrabber
+Comment[gl]=Plugin de importazón de marcadores XML para KFTPGrabber
+Comment[it]=Plugin di importazione dei segnalibri XML per KFTPGrabber
+Comment[ja]=KFTPGrabber XML ブックマークをインポートするプラグイン
+Comment[ka]=KFTPGrabber-ის XML-ის სანიშნეების იმპორტის მოდული
+Comment[lt]=KFTPGrabber XML importavimo įskiepis
+Comment[nl]=KFTPGrabber-plugin voor het importeren van XML-bladwijzers
+Comment[pt]='Plugin' de importação de favoritos em XML para o KFTPGrabber
+Comment[pt_BR]=Plug-in de importação de favoritos em XML para o KFTPGrabber
+Comment[sr]=KFTPGrabber-ов прикључак за увоз XML маркера
+Comment[sr@Latn]=KFTPGrabber-ov priključak za uvoz XML markera
+Comment[sv]=Insticksprogram för XML-bokmärkesimport till KFTPgrabber
+Comment[tr]=KFTPGrabber için XML yer imlerini alma eklentisi
+Comment[uk]=Втулок імпортування XML-закладок для KFTPGrabber
+Comment[xx]=xxKFTPGrabber XML bookmarks import pluginxx
+Comment[zh_CN]=KFTPGrabber XML 书签导入插件
+ServiceTypes=KFTPGrabber/BookmarkImportPlugin
+Type=Service
+X-KDE-Library=kftpimportplugin_kftp
+
diff --git a/kftpgrabber/src/misc/plugins/bookmarkimport/ncftp/Makefile.am b/kftpgrabber/src/misc/plugins/bookmarkimport/ncftp/Makefile.am
new file mode 100644
index 0000000..feb557e
--- /dev/null
+++ b/kftpgrabber/src/misc/plugins/bookmarkimport/ncftp/Makefile.am
@@ -0,0 +1,14 @@
+INCLUDES = -I$(srcdir)/../../../interfaces \
+ $(all_includes)
+METASOURCES = AUTO
+
+kde_module_LTLIBRARIES = kftpimportplugin_ncftp.la
+kftpimportplugin_ncftp_la_SOURCES = kftpimportncftpplugin.cpp
+kftpimportplugin_ncftp_la_LIBADD = $(LIB_QT) $(LIB_KDECORE) $(LIB_KDEUI) $(LIB_KPARTS) ../../../interfaces/libkftpinterfaces.la
+kftpimportplugin_ncftp_la_LDFLAGS = -module $(KDE_PLUGIN) $(all_libraries)
+
+kde_services_DATA = kftpimportplugin_ncftp.desktop
+noinst_HEADERS = kftpimportncftpplugin.h
+
+pluginsdir = $(kde_datadir)/kftpimportplugin_ncftp
+
diff --git a/kftpgrabber/src/misc/plugins/bookmarkimport/ncftp/kftpimportncftpplugin.cpp b/kftpgrabber/src/misc/plugins/bookmarkimport/ncftp/kftpimportncftpplugin.cpp
new file mode 100644
index 0000000..e146f88
--- /dev/null
+++ b/kftpgrabber/src/misc/plugins/bookmarkimport/ncftp/kftpimportncftpplugin.cpp
@@ -0,0 +1,165 @@
+/*
+ * This file is part of the KFTPGrabber project
+ *
+ * Copyright (C) 2004 by the KFTPGrabber developers
+ * Copyright (C) 2004 Jernej Kos <kostko@jweb-network.net>
+ *
+ * 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
+ * is provided AS IS, WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, and
+ * NON-INFRINGEMENT. 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 Steet, Fifth Floor, Boston,
+ * MA 02110-1301, USA.
+ *
+ * In addition, as a special exception, the copyright holders give
+ * permission to link the code of portions of this program with the
+ * OpenSSL library under certain conditions as described in each
+ * individual source file, and distribute linked combinations
+ * including the two.
+ * You must obey the GNU General Public License in all respects
+ * for all of the code used other than OpenSSL. If you modify
+ * file(s) with this exception, you may extend this exception to your
+ * version of the file(s), but you are not obligated to do so. If you
+ * do not wish to do so, delete this exception statement from your
+ * version. If you delete this exception statement from all source
+ * files in the program, then also delete it here.
+ */
+#include "kftpimportncftpplugin.h"
+
+#include <qdir.h>
+#include <qfile.h>
+
+#include <kgenericfactory.h>
+#include <klocale.h>
+#include <kconfig.h>
+#include <kmdcodec.h>
+
+K_EXPORT_COMPONENT_FACTORY(kftpimportplugin_ncftp,
+ KGenericFactory<KFTPImportNcftpPlugin>("kftpimportplugin_ncftp"))
+
+KFTPImportNcftpPlugin::KFTPImportNcftpPlugin(QObject *parent, const char *name, const QStringList&)
+ : KFTPBookmarkImportPlugin(parent, name)
+{
+ KGlobal::locale()->insertCatalogue("kftpgrabber");
+ m_domDocument.setContent(QString("<category name=\"%1\"/>").arg(i18n("NcFtp import")));
+}
+
+QDomDocument KFTPImportNcftpPlugin::getImportedXml()
+{
+ return m_domDocument;
+}
+
+void KFTPImportNcftpPlugin::import(const QString &fileName)
+{
+ /*
+ ARNES FTP serve,ftp.arnes.si,username,*encoded*cGFzc3dvcmQA,,/remote,I,21,4294967295,1,1,-1,1,193.2.1.79,Komentar,,,,,S,-1,/local
+ Redhat,ftp.redhat.com,,,,,I,21,1102099812,-1,-1,-1,1,66.187.224.30,,,,,,S,-1,
+ */
+
+ QFile f(fileName);
+ if (!f.open(IO_ReadOnly)) {
+ emit progress(100);
+ return;
+ }
+
+ QTextStream stream(&f);
+ QString line;
+ int lineNum = 0;
+
+ while (!stream.atEnd()) {
+ line = stream.readLine();
+ if (++lineNum <= 2) continue;
+
+ // Add the imported bookmark
+ QDomElement parentElement = m_domDocument.documentElement();
+
+ // Set name
+ QDomElement siteElement = m_domDocument.createElement("server");
+ siteElement.setAttribute("name", subSection(line, 0));
+ parentElement.appendChild(siteElement);
+
+ // Set host
+ QString tmp = subSection(line, 1);
+ QDomElement tmpElement = m_domDocument.createElement("host");
+ QDomText txtNode = m_domDocument.createTextNode(tmp);
+ tmpElement.appendChild(txtNode);
+ siteElement.appendChild(tmpElement);
+
+ // Set port
+ tmp = subSection(line, 7, "21");
+ tmpElement = m_domDocument.createElement("port");
+ txtNode = m_domDocument.createTextNode(tmp);
+ tmpElement.appendChild(txtNode);
+ siteElement.appendChild(tmpElement);
+
+ // Set remote directory
+ tmp = subSection(line, 5, "/");
+ tmpElement = m_domDocument.createElement("defremotepath");
+ txtNode = m_domDocument.createTextNode(tmp);
+ tmpElement.appendChild(txtNode);
+ siteElement.appendChild(tmpElement);
+
+ // Set local directory
+ tmp = subSection(line, 21, QDir::homeDirPath());
+ tmpElement = m_domDocument.createElement("deflocalpath");
+ txtNode = m_domDocument.createTextNode(tmp);
+ tmpElement.appendChild(txtNode);
+ siteElement.appendChild(tmpElement);
+
+ // Set username
+ tmp = subSection(line, 2, "anonymous");
+ tmpElement = m_domDocument.createElement("username");
+ txtNode = m_domDocument.createTextNode(tmp);
+ tmpElement.appendChild(txtNode);
+ siteElement.appendChild(tmpElement);
+
+ if (tmp == "anonymous") {
+ tmpElement = m_domDocument.createElement("anonlogin");
+ txtNode = m_domDocument.createTextNode("1");
+ tmpElement.appendChild(txtNode);
+ siteElement.appendChild(tmpElement);
+ }
+
+ // Set password
+ tmp = subSection(line, 3, "");
+ tmp.replace("*encoded*", "");
+
+ tmpElement = m_domDocument.createElement("password");
+ txtNode = m_domDocument.createTextNode(tmp);
+ tmpElement.appendChild(txtNode);
+ siteElement.appendChild(tmpElement);
+
+ // Set description
+ tmp = subSection(line, 14, "");
+ if (!tmp.isEmpty()) {
+ tmpElement = m_domDocument.createElement("description");
+ txtNode = m_domDocument.createTextNode(tmp);
+ tmpElement.appendChild(txtNode);
+ siteElement.appendChild(tmpElement);
+ }
+ }
+
+ emit progress(100);
+}
+
+QString KFTPImportNcftpPlugin::subSection(const QString &text, int section, const QString &def)
+{
+ QString tmp = text.section(',', section, section);
+
+ return tmp.isEmpty() ? def : tmp;
+}
+
+QString KFTPImportNcftpPlugin::getDefaultPath()
+{
+ return QString(".ncftp/bookmarks");
+}
+
+#include "kftpimportncftpplugin.moc"
diff --git a/kftpgrabber/src/misc/plugins/bookmarkimport/ncftp/kftpimportncftpplugin.h b/kftpgrabber/src/misc/plugins/bookmarkimport/ncftp/kftpimportncftpplugin.h
new file mode 100644
index 0000000..7a58d0e
--- /dev/null
+++ b/kftpgrabber/src/misc/plugins/bookmarkimport/ncftp/kftpimportncftpplugin.h
@@ -0,0 +1,80 @@
+/*
+ * This file is part of the KFTPGrabber project
+ *
+ * Copyright (C) 2004 by the KFTPGrabber developers
+ * Copyright (C) 2004 Jernej Kos <kostko@jweb-network.net>
+ *
+ * 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
+ * is provided AS IS, WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, and
+ * NON-INFRINGEMENT. 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 Steet, Fifth Floor, Boston,
+ * MA 02110-1301, USA.
+ *
+ * In addition, as a special exception, the copyright holders give
+ * permission to link the code of portions of this program with the
+ * OpenSSL library under certain conditions as described in each
+ * individual source file, and distribute linked combinations
+ * including the two.
+ * You must obey the GNU General Public License in all respects
+ * for all of the code used other than OpenSSL. If you modify
+ * file(s) with this exception, you may extend this exception to your
+ * version of the file(s), but you are not obligated to do so. If you
+ * do not wish to do so, delete this exception statement from your
+ * version. If you delete this exception statement from all source
+ * files in the program, then also delete it here.
+ */
+#ifndef KFTPIMPORTNCFTPPLUGIN_H
+#define KFTPIMPORTNCFTPPLUGIN_H
+
+#include <qdom.h>
+#include <kftpbookmarkimportplugin.h>
+
+/**
+This plugin can import NcFTP bookmarks into KFTPGrabber.
+
+@author Jernej Kos
+*/
+class KFTPImportNcftpPlugin : public KFTPBookmarkImportPlugin
+{
+Q_OBJECT
+public:
+ KFTPImportNcftpPlugin(QObject *parent, const char *name, const QStringList&);
+
+ /**
+ * This method should return the properly formated XML for KFTPGrabber
+ * bookmarks that is generated from the import.
+ *
+ * @return The @ref QDomDocument representation of XML
+ */
+ QDomDocument getImportedXml();
+
+ /**
+ * This method should start the import procedure.
+ *
+ * @param fileName is the path to the file that will be imported
+ */
+ void import(const QString &fileName);
+
+ /**
+ * This method should return the default path where the bookmarks could
+ * be located. The path must be relative to the user's home directory.
+ *
+ * @return The default path where bookmarks are located
+ */
+ QString getDefaultPath();
+private:
+ QDomDocument m_domDocument;
+
+ QString subSection(const QString &text, int section, const QString &def = QString::null);
+};
+
+#endif
diff --git a/kftpgrabber/src/misc/plugins/bookmarkimport/ncftp/kftpimportplugin_ncftp.desktop b/kftpgrabber/src/misc/plugins/bookmarkimport/ncftp/kftpimportplugin_ncftp.desktop
new file mode 100644
index 0000000..226f2cc
--- /dev/null
+++ b/kftpgrabber/src/misc/plugins/bookmarkimport/ncftp/kftpimportplugin_ncftp.desktop
@@ -0,0 +1,62 @@
+[Desktop Entry]
+Name=NcFTP Import plugin
+Name[ar]=قابس أستيراد NcFTP
+Name[bg]=Приставка за импортиране на NcFTP
+Name[br]=Lugent enporzh NcFTP
+Name[cs]=NcFTP importní modul
+Name[da]=NcFTP import-plugin
+Name[de]=NcFTP Importmodul
+Name[el]=Πρόσθετο εισαγωγής NcFTP
+Name[es]=Complemento de importación de NcFTP
+Name[et]=NcFTP impordiplugin
+Name[fr]=Module d'importation de NcFTP
+Name[ga]=Breiseán Iompórtála NcFTP
+Name[gl]=Plugin de Importazón de NcFTP
+Name[it]=Plugin di importazione NcFTP
+Name[ja]=NcFTP インポートプラグイン
+Name[ka]=NcFTP-ის იმპორტის მოდული
+Name[lt]=NcFTP importavimo įskiepis
+Name[nl]=NcFTP-importplugin
+Name[pa]=NcFTP ਆਯਾਤ ਪਲੱਗਿੰਨ
+Name[pt]='Plugin' de importação do NcFTP
+Name[pt_BR]=Plug-in de importação NcFTP
+Name[ru]=Модуль импорта из NcFTP
+Name[sr]=Прикључак NcFTP увоза
+Name[sr@Latn]=Priključak NcFTP uvoza
+Name[sv]=NcFTP-importinsticksprogram
+Name[tr]=NcFTP'den alma eklentisi
+Name[uk]=Втулок імпорту NcFTP
+Name[xx]=xxNcFTP Import pluginxx
+Name[zh_CN]=NcFTP 导入插件
+Comment=NcFTP bookmarks import plugin for KFTPGrabber
+Comment[ar]=قابس NcFTP لإستيراد علامات المواقع لِــ KFTPGrabber
+Comment[bg]=Приставка за импортиране на NcFTP отметки в KFTPGrabber
+Comment[br]=Lugent enporzh sinedoù NcFTP evit KFTPGrabber
+Comment[cs]=NcFTP modul importu záložek pro KFTPGrabber
+Comment[da]=NcFTP bogmærker import-plugin for KFTPGrabber
+Comment[de]=NcFTP Lesezeichenimportmodul für KFTPGrabber
+Comment[el]=Πρόσθετο εισαγωγής σελιδοδεικτών NcFTP για το KFTPGrabber
+Comment[es]=Complemento de importación de marcadores de NcFTP de KFTPGrabber
+Comment[et]=KFTPGrabberi NcFTP järjehoidjate impordiplugin
+Comment[fr]=Module d'importation des signets NcFTP pour KFTPGrabber
+Comment[ga]=Breiseán iompórtála leabharmharcanna NcFTP le haghaidh KFTPGrabber
+Comment[gl]=Plugin de importazón de marcadores NcFTP para KFTPGrabber
+Comment[it]=Plugin di importazione dei segnalibri di NcFTP per KFTPGrabber
+Comment[ja]=KFTPGrabber NcFTP ブックマークをインポートするプラグイン
+Comment[ka]=NcFTP-ის სანიშნეების იმპორტის მოდული KFTPGrabber-თვის
+Comment[lt]=NcFTP žymelių importavimo į KFTPGrabber įskiepis
+Comment[nl]=Een KFTPGrabber-plugin voor het importeren van NcFTP-bladwijzers
+Comment[pt]='Plugin' de importação de favoritos do NcFTP para o KFTPGrabber
+Comment[pt_BR]=Plug-in de importação de favoritos do NcFTP para o KFTPGrabber
+Comment[ru]=Импорт закладок NcFTP в KFTPGrabber
+Comment[sr]=KFTPGrabber-ов прикључак за увоз NcFTP маркера
+Comment[sr@Latn]=KFTPGrabber-ov priključak za uvoz NcFTP markera
+Comment[sv]=Insticksprogram för NcFTP-bokmärkesimport till KFTPgrabber
+Comment[tr]=KFTPGrabber için NcFTP'den yer imleri alma eklentisi
+Comment[uk]=Втулок імпортування закладок NcFTP для KFTPGrabber
+Comment[xx]=xxNcFTP bookmarks import plugin for KFTPGrabberxx
+Comment[zh_CN]=KFTPGrabber 的 NcFTP 书签导入插件
+ServiceTypes=KFTPGrabber/BookmarkImportPlugin
+Type=Service
+X-KDE-Library=kftpimportplugin_ncftp
+