diff options
Diffstat (limited to 'kftpgrabber/src/misc')
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 §ion) +{ + 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 §ion); + 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 + |