summaryrefslogtreecommitdiffstats
path: root/kmymoney2/plugins
diff options
context:
space:
mode:
Diffstat (limited to 'kmymoney2/plugins')
-rw-r--r--kmymoney2/plugins/Makefile.am24
-rw-r--r--kmymoney2/plugins/importinterface.cpp34
-rw-r--r--kmymoney2/plugins/importinterface.h63
-rw-r--r--kmymoney2/plugins/interfaces/Makefile.am13
-rw-r--r--kmymoney2/plugins/interfaces/kmmimportinterface.cpp41
-rw-r--r--kmymoney2/plugins/interfaces/kmmimportinterface.h60
-rw-r--r--kmymoney2/plugins/interfaces/kmmstatementinterface.cpp56
-rw-r--r--kmymoney2/plugins/interfaces/kmmstatementinterface.h77
-rw-r--r--kmymoney2/plugins/interfaces/kmmviewinterface.cpp60
-rw-r--r--kmymoney2/plugins/interfaces/kmmviewinterface.h79
-rw-r--r--kmymoney2/plugins/kmymoneyimporterplugin.desktop6
-rw-r--r--kmymoney2/plugins/kmymoneyplugin.cpp91
-rw-r--r--kmymoney2/plugins/kmymoneyplugin.desktop6
-rw-r--r--kmymoney2/plugins/kmymoneyplugin.h214
-rw-r--r--kmymoney2/plugins/ofximport/Makefile.am33
-rw-r--r--kmymoney2/plugins/ofximport/dialogs/Makefile.am16
-rw-r--r--kmymoney2/plugins/ofximport/dialogs/kofxdirectconnectdlg.cpp223
-rw-r--r--kmymoney2/plugins/ofximport/dialogs/kofxdirectconnectdlg.h86
-rw-r--r--kmymoney2/plugins/ofximport/dialogs/kofxdirectconnectdlgdecl.ui109
-rw-r--r--kmymoney2/plugins/ofximport/dialogs/konlinebankingsetupdecl.ui488
-rw-r--r--kmymoney2/plugins/ofximport/dialogs/konlinebankingsetupwizard.cpp445
-rw-r--r--kmymoney2/plugins/ofximport/dialogs/konlinebankingsetupwizard.h106
-rw-r--r--kmymoney2/plugins/ofximport/dialogs/konlinebankingstatus.cpp112
-rw-r--r--kmymoney2/plugins/ofximport/dialogs/konlinebankingstatus.h58
-rw-r--r--kmymoney2/plugins/ofximport/dialogs/konlinebankingstatusdecl.ui483
-rw-r--r--kmymoney2/plugins/ofximport/dialogs/mymoneyofxconnector.cpp725
-rw-r--r--kmymoney2/plugins/ofximport/dialogs/mymoneyofxconnector.h128
-rw-r--r--kmymoney2/plugins/ofximport/kmm_ofximport.desktop12
-rw-r--r--kmymoney2/plugins/ofximport/kmm_ofximport.rc10
-rw-r--r--kmymoney2/plugins/ofximport/ofximporterplugin.cpp688
-rw-r--r--kmymoney2/plugins/ofximport/ofximporterplugin.h145
-rw-r--r--kmymoney2/plugins/ofximport/ofxpartner.cpp429
-rw-r--r--kmymoney2/plugins/ofximport/ofxpartner.h102
-rw-r--r--kmymoney2/plugins/pluginloader.cpp163
-rw-r--r--kmymoney2/plugins/pluginloader.h76
-rw-r--r--kmymoney2/plugins/statementinterface.cpp34
-rw-r--r--kmymoney2/plugins/statementinterface.h72
-rw-r--r--kmymoney2/plugins/viewinterface.cpp34
-rw-r--r--kmymoney2/plugins/viewinterface.h123
39 files changed, 5724 insertions, 0 deletions
diff --git a/kmymoney2/plugins/Makefile.am b/kmymoney2/plugins/Makefile.am
new file mode 100644
index 0000000..9b67654
--- /dev/null
+++ b/kmymoney2/plugins/Makefile.am
@@ -0,0 +1,24 @@
+KDE_OPTIONS = noautodist
+
+METASOURCES = AUTO
+INCLUDES = $(all_includes) -I$(top_srcdir) -I.
+
+# since some of the subdirs are conditional, we need to define DIST_SUBDIRS
+SUBDIRS = interfaces @OFX_IMPORTERPLUGIN@
+DIST_SUBDIRS = interfaces ofximport
+
+# The library containing the plugin base class
+lib_LTLIBRARIES = libkmm_plugin.la
+libkmm_plugin_la_SOURCES = kmymoneyplugin.cpp pluginloader.cpp viewinterface.cpp statementinterface.cpp importinterface.cpp
+libkmm_plugin_la_LDFLAGS = $(all_libraries) -version-info 0:0:0
+
+#definition of the service type
+kde_servicetypes_DATA = kmymoneyplugin.desktop kmymoneyimporterplugin.desktop
+
+# make sure this lib is build before any subdirectory
+BUILT_SOURCES = libkmm_plugin.la
+
+pluginsincludedir = $(includedir)/kmymoney
+pluginsinclude_HEADERS = kmymoneyplugin.h pluginloader.h viewinterface.h statementinterface.h importinterface.h
+
+EXTRA_DIST = kmymoneyplugin.desktop kmymoneyimporterplugin.desktop
diff --git a/kmymoney2/plugins/importinterface.cpp b/kmymoney2/plugins/importinterface.cpp
new file mode 100644
index 0000000..ce867c8
--- /dev/null
+++ b/kmymoney2/plugins/importinterface.cpp
@@ -0,0 +1,34 @@
+/***************************************************************************
+ importinterface.cpp
+ -------------------
+ begin : Mon Apr 14 2008
+ copyright : (C) 2008 Thomas Baumgart
+ email : ipwizard@users.sourceforge.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. *
+ * *
+ ***************************************************************************/
+
+// ----------------------------------------------------------------------------
+// QT Includes
+
+// ----------------------------------------------------------------------------
+// KDE Includes
+
+// ----------------------------------------------------------------------------
+// Project Includes
+
+#include "importinterface.h"
+
+KMyMoneyPlugin::ImportInterface::ImportInterface(QObject* parent, const char* name) :
+ QObject(parent, name)
+{
+}
+
+#include "importinterface.moc"
diff --git a/kmymoney2/plugins/importinterface.h b/kmymoney2/plugins/importinterface.h
new file mode 100644
index 0000000..4b8a347
--- /dev/null
+++ b/kmymoney2/plugins/importinterface.h
@@ -0,0 +1,63 @@
+/***************************************************************************
+ importinterface.h
+ -------------------
+ begin : Mon Apr 14 2008
+ copyright : (C) 2008 Thomas Baumgart
+ email : ipwizard@users.sourceforge.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. *
+ * *
+ ***************************************************************************/
+
+#ifndef IMPORTINTERFACE_H
+#define IMPORTINTERFACE_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+// ----------------------------------------------------------------------------
+// QT Includes
+
+#include <qobject.h>
+#include <qstring.h>
+
+// ----------------------------------------------------------------------------
+// KDE Includes
+
+#include <kfile.h>
+#include <kurl.h>
+class KPopupMenu;
+
+// ----------------------------------------------------------------------------
+// Project Includes
+
+#include <kmymoney/export.h>
+
+namespace KMyMoneyPlugin {
+
+/**
+ * This abstract class represents the ImportInterface to
+ * add new importers to KMyMoney.
+ */
+class KMYMONEY_EXPORT ImportInterface : public QObject
+{
+ Q_OBJECT
+
+public:
+ ImportInterface(QObject* parent, const char* name = 0);
+ ~ImportInterface() {}
+
+ virtual KURL selectFile(const QString& title, const QString& path, const QString& mask, KFile::Mode mode) const = 0;
+
+signals:
+};
+
+}; // namespace
+#endif
diff --git a/kmymoney2/plugins/interfaces/Makefile.am b/kmymoney2/plugins/interfaces/Makefile.am
new file mode 100644
index 0000000..2b3c761
--- /dev/null
+++ b/kmymoney2/plugins/interfaces/Makefile.am
@@ -0,0 +1,13 @@
+KDE_OPTIONS = noautodist
+
+METASOURCES = AUTO
+INCLUDES = $(all_includes) -I$(top_srcdir) -I. -I$(top_srcdir)/kmymoney2/widgets
+
+SUBDIRS =
+
+noinst_LIBRARIES = libinterfaces.a
+
+libinterfaces_a_SOURCES = kmmviewinterface.cpp kmmstatementinterface.cpp kmmimportinterface.cpp
+
+noinst_HEADERS = kmmviewinterface.h kmmstatementinterface.h kmmimportinterface.h
+
diff --git a/kmymoney2/plugins/interfaces/kmmimportinterface.cpp b/kmymoney2/plugins/interfaces/kmmimportinterface.cpp
new file mode 100644
index 0000000..b3c54d8
--- /dev/null
+++ b/kmymoney2/plugins/interfaces/kmmimportinterface.cpp
@@ -0,0 +1,41 @@
+/***************************************************************************
+ kmmimportinterface.cpp
+ -------------------
+ begin : Mon Apr 14 2008
+ copyright : (C) 2008 Thomas Baumgart
+ email : ipwizard@users.sourceforge.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. *
+ * *
+ ***************************************************************************/
+
+// ----------------------------------------------------------------------------
+// QT Includes
+
+// ----------------------------------------------------------------------------
+// KDE Includes
+
+// ----------------------------------------------------------------------------
+// Project Includes
+
+#include "../../kmymoney2.h"
+#include "kmmimportinterface.h"
+
+KMyMoneyPlugin::KMMImportInterface::KMMImportInterface(KMyMoney2App* app, QObject* parent, const char* name) :
+ ImportInterface(parent, name),
+ m_app(app)
+{
+}
+
+KURL KMyMoneyPlugin::KMMImportInterface::selectFile(const QString& title, const QString& path, const QString& mask, KFile::Mode mode) const
+{
+ return m_app->selectFile(title, path, mask, mode);
+}
+
+#include "kmmimportinterface.moc"
diff --git a/kmymoney2/plugins/interfaces/kmmimportinterface.h b/kmymoney2/plugins/interfaces/kmmimportinterface.h
new file mode 100644
index 0000000..484a228
--- /dev/null
+++ b/kmymoney2/plugins/interfaces/kmmimportinterface.h
@@ -0,0 +1,60 @@
+/***************************************************************************
+ kmmimportinterface.h
+ -------------------
+ begin : Mon Apr 14 2008
+ copyright : (C) 2008 Thomas Baumgart
+ email : ipwizard@users.sourceforge.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. *
+ * *
+ ***************************************************************************/
+
+#ifndef KMMIMPORTINTERFACE_H
+#define KMMIMPORTINTERFACE_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+// ----------------------------------------------------------------------------
+// QT Includes
+
+// ----------------------------------------------------------------------------
+// KDE Includes
+
+#include <kfile.h>
+#include <kurl.h>
+class KMyMoney2App;
+
+// ----------------------------------------------------------------------------
+// Project Includes
+
+#include "../importinterface.h"
+
+namespace KMyMoneyPlugin {
+
+/**
+ * This class represents the implementation of the
+ * ViewInterface.
+ */
+class KMMImportInterface : public ImportInterface {
+ Q_OBJECT
+
+public:
+ KMMImportInterface(KMyMoney2App* app, QObject* parent, const char* name = 0);
+ ~KMMImportInterface() {}
+
+ KURL selectFile(const QString& title, const QString& path, const QString& mask, KFile::Mode mode) const;
+
+private:
+ KMyMoney2App* m_app;
+};
+
+}; // namespace
+#endif
diff --git a/kmymoney2/plugins/interfaces/kmmstatementinterface.cpp b/kmymoney2/plugins/interfaces/kmmstatementinterface.cpp
new file mode 100644
index 0000000..9e09db2
--- /dev/null
+++ b/kmymoney2/plugins/interfaces/kmmstatementinterface.cpp
@@ -0,0 +1,56 @@
+/***************************************************************************
+ kmmstatementinterface.cpp
+ -------------------
+ begin : Wed Jan 5 2005
+ copyright : (C) 2005 Thomas Baumgart
+ email : ipwizard@users.sourceforge.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. *
+ * *
+ ***************************************************************************/
+
+// ----------------------------------------------------------------------------
+// QT Includes
+
+#include <qstring.h>
+
+// ----------------------------------------------------------------------------
+// KDE Includes
+
+// ----------------------------------------------------------------------------
+// Project Includes
+
+#include "kmmstatementinterface.h"
+#include "../../kmymoney2.h"
+#include <kmymoney/mymoneyaccount.h>
+#include <kmymoney/mymoneykeyvaluecontainer.h>
+
+KMyMoneyPlugin::KMMStatementInterface::KMMStatementInterface(KMyMoney2App* app, QObject* parent, const char* name) :
+ StatementInterface(parent, name),
+ m_app(app)
+{
+}
+
+bool KMyMoneyPlugin::KMMStatementInterface::import(const MyMoneyStatement& s)
+{
+ qDebug("KMyMoneyPlugin::KMMStatementInterface::import start");
+ return m_app->slotStatementImport(s);
+}
+
+const MyMoneyAccount& KMyMoneyPlugin::KMMStatementInterface::account(const QString& key, const QString& value) const
+{
+ return m_app->account(key, value);
+}
+
+void KMyMoneyPlugin::KMMStatementInterface::setAccountOnlineParameters(const MyMoneyAccount& acc, const MyMoneyKeyValueContainer& kvps) const
+{
+ m_app->setAccountOnlineParameters(acc, kvps);
+}
+
+#include "kmmstatementinterface.moc"
diff --git a/kmymoney2/plugins/interfaces/kmmstatementinterface.h b/kmymoney2/plugins/interfaces/kmmstatementinterface.h
new file mode 100644
index 0000000..7890002
--- /dev/null
+++ b/kmymoney2/plugins/interfaces/kmmstatementinterface.h
@@ -0,0 +1,77 @@
+/***************************************************************************
+ kmmstatementinterface.h
+ -------------------
+ begin : Wed Jan 5 2005
+ copyright : (C) 2005 Thomas Baumgart
+ email : ipwizard@users.sourceforge.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. *
+ * *
+ ***************************************************************************/
+
+#ifndef KMMSTATEMENTINTERFACE_H
+#define KMMSTATEMENTINTERFACE_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+// ----------------------------------------------------------------------------
+// QT Includes
+
+// ----------------------------------------------------------------------------
+// KDE Includes
+
+// ----------------------------------------------------------------------------
+// Project Includes
+
+class KMyMoney2App;
+class MyMoneyAccount;
+class MyMoneyKeyValueContainer;
+
+#include "../statementinterface.h"
+
+namespace KMyMoneyPlugin {
+
+/**
+ * This class represents the implementation of the
+ * StatementInterface.
+ */
+class KMMStatementInterface : public StatementInterface
+{
+ Q_OBJECT
+
+public:
+ KMMStatementInterface(KMyMoney2App* app, QObject* parent, const char* name = 0);
+ ~KMMStatementInterface() {}
+
+ /**
+ * This method imports a MyMoneyStatement into the engine
+ */
+ bool import(const MyMoneyStatement& s);
+
+ /**
+ * This method returns the account for a given @a key - @a value pair.
+ * If the account is not found in the list of accounts, MyMoneyAccount()
+ * is returned.
+ */
+ const MyMoneyAccount& account(const QString& key, const QString& value) const;
+
+ /**
+ * This method stores the online parameters in @a kvps used by the plugin
+ * with the account @a acc.
+ */
+ void setAccountOnlineParameters(const MyMoneyAccount&acc, const MyMoneyKeyValueContainer& kvps) const;
+
+private:
+ KMyMoney2App* m_app;
+};
+
+}; // namespace
+#endif
diff --git a/kmymoney2/plugins/interfaces/kmmviewinterface.cpp b/kmymoney2/plugins/interfaces/kmmviewinterface.cpp
new file mode 100644
index 0000000..9779876
--- /dev/null
+++ b/kmymoney2/plugins/interfaces/kmmviewinterface.cpp
@@ -0,0 +1,60 @@
+/***************************************************************************
+ viewinterface.cpp
+ -------------------
+ begin : Wed Jan 5 2005
+ copyright : (C) 2005 Thomas Baumgart
+ email : ipwizard@users.sourceforge.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. *
+ * *
+ ***************************************************************************/
+
+// ----------------------------------------------------------------------------
+// QT Includes
+
+// ----------------------------------------------------------------------------
+// KDE Includes
+
+// ----------------------------------------------------------------------------
+// Project Includes
+
+#include "../../kmymoney2.h"
+#include "../../views/kmymoneyview.h"
+#include "../../widgets/selectedtransaction.h"
+#include "kmmviewinterface.h"
+
+KMyMoneyPlugin::KMMViewInterface::KMMViewInterface(KMyMoney2App* app, KMyMoneyView* view, QObject* parent, const char* name) :
+ ViewInterface(parent, name),
+ m_app(app),
+ m_view(view)
+{
+ connect(app, SIGNAL(accountSelected(const MyMoneyAccount&)), this, SIGNAL(accountSelected(const MyMoneyAccount&)));
+ connect(app, SIGNAL(transactionsSelected(const KMyMoneyRegister::SelectedTransactions&)), this, SIGNAL(transactionsSelected(const KMyMoneyRegister::SelectedTransactions&)));
+ connect(app, SIGNAL(accountReconciled(const MyMoneyAccount&, const QDate&, const MyMoneyMoney&, const MyMoneyMoney&, const QValueList<QPair<MyMoneyTransaction, MyMoneySplit> >&)),
+ this, SIGNAL(accountReconciled(const MyMoneyAccount&, const QDate&, const MyMoneyMoney&, const MyMoneyMoney&, const QValueList<QPair<MyMoneyTransaction, MyMoneySplit> >&)));
+
+ connect(app, SIGNAL(institutionSelected(const MyMoneyInstitution&)), this, SIGNAL(institutionSelected(const MyMoneyInstitution&)));
+
+ connect(m_view, SIGNAL(viewStateChanged(bool)), this, SIGNAL(viewStateChanged(bool)));
+ connect(m_view, SIGNAL(kmmFilePlugin(unsigned int)), this, SIGNAL(kmmFilePlugin(unsigned int)));
+}
+
+KMyMoneyViewBase* KMyMoneyPlugin::KMMViewInterface::addPage(const QString& item, const QString& icon)
+{
+ return m_view->addPage(item, icon);
+}
+
+void KMyMoneyPlugin::KMMViewInterface::addWidget(KMyMoneyViewBase* view, QWidget* w)
+{
+ if(view && w)
+ view->addWidget(w);
+}
+
+
+#include "kmmviewinterface.moc"
diff --git a/kmymoney2/plugins/interfaces/kmmviewinterface.h b/kmymoney2/plugins/interfaces/kmmviewinterface.h
new file mode 100644
index 0000000..d06b4f8
--- /dev/null
+++ b/kmymoney2/plugins/interfaces/kmmviewinterface.h
@@ -0,0 +1,79 @@
+/***************************************************************************
+ kmmviewinterface.h
+ -------------------
+ begin : Wed Jan 5 2005
+ copyright : (C) 2005 Thomas Baumgart
+ email : ipwizard@users.sourceforge.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. *
+ * *
+ ***************************************************************************/
+
+#ifndef KMMVIEWINTERFACE_H
+#define KMMVIEWINTERFACE_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+// ----------------------------------------------------------------------------
+// QT Includes
+
+// ----------------------------------------------------------------------------
+// KDE Includes
+
+class KMyMoney2App;
+class KMyMoneyView;
+class KMyMoneyViewBase;
+
+// ----------------------------------------------------------------------------
+// Project Includes
+
+#include "../viewinterface.h"
+
+namespace KMyMoneyPlugin {
+
+/**
+ * This class represents the implementation of the
+ * ViewInterface.
+ */
+class KMMViewInterface : public ViewInterface {
+ Q_OBJECT
+
+public:
+ KMMViewInterface(KMyMoney2App* app, KMyMoneyView* view, QObject* parent, const char* name = 0);
+ ~KMMViewInterface() {}
+
+ /**
+ * This method returns a pointer to a newly created view
+ * with title @p item and icon @p pixmap.
+ *
+ * @param item Name of view
+ * @param icon name for the icon to be used for the view
+ *
+ * @return pointer to KMyMoneyViewBase object
+ */
+ KMyMoneyViewBase* addPage(const QString& item, const QString& icon);
+
+ /**
+ * This method allows to add a widget to the view
+ * created with addPage()
+ *
+ * @param view pointer to view object
+ * @param w pointer to widget
+ */
+ void addWidget(KMyMoneyViewBase* view, QWidget* w);
+
+private:
+ KMyMoney2App* m_app;
+ KMyMoneyView* m_view;
+};
+
+}; // namespace
+#endif
diff --git a/kmymoney2/plugins/kmymoneyimporterplugin.desktop b/kmymoney2/plugins/kmymoneyimporterplugin.desktop
new file mode 100644
index 0000000..d8277e6
--- /dev/null
+++ b/kmymoney2/plugins/kmymoneyimporterplugin.desktop
@@ -0,0 +1,6 @@
+[Desktop Entry]
+Type=ServiceType
+Name=KMyMoney Importer Plugin
+X-KDE-ServiceType=KMyMoneyImporterPlugin
+Comment=A KMyMoney plugin
+
diff --git a/kmymoney2/plugins/kmymoneyplugin.cpp b/kmymoney2/plugins/kmymoneyplugin.cpp
new file mode 100644
index 0000000..ddca52a
--- /dev/null
+++ b/kmymoney2/plugins/kmymoneyplugin.cpp
@@ -0,0 +1,91 @@
+/***************************************************************************
+ kmymoneyplugin.cpp
+ -------------------
+ begin : Wed Jan 5 2005
+ copyright : (C) 2005 Thomas Baumgart
+ email : ipwizard@users.sourceforge.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. *
+ * *
+ ***************************************************************************/
+
+// ----------------------------------------------------------------------------
+// QT Includes
+
+// ----------------------------------------------------------------------------
+// KDE Includes
+
+#include <kinstance.h>
+#include <kaboutdata.h>
+#include <kaction.h>
+
+// ----------------------------------------------------------------------------
+// Project Includes
+
+
+#include "kmymoneyplugin.h"
+
+KMyMoneyPlugin::Plugin::Plugin(QObject* o, const char* name) :
+ QObject(o, name)
+{
+}
+
+KMyMoneyPlugin::Plugin::~Plugin()
+{
+}
+
+KAction* KMyMoneyPlugin::Plugin::action(const QString& actionName) const
+{
+ static KShortcut shortcut("");
+ static KAction dummyAction(QString("Dummy"), QString(), shortcut, static_cast<const QObject*>(this), 0, static_cast<KActionCollection*>(0), "");
+
+ KAction* p = actionCollection()->action(actionName.latin1());
+ if(p)
+ return p;
+
+ qWarning("Action with name '%s' not found!", actionName.latin1());
+ return &dummyAction;
+}
+
+KToggleAction* KMyMoneyPlugin::Plugin::toggleAction(const QString& actionName) const
+{
+ static KShortcut shortcut("");
+ static KToggleAction dummyAction(QString("Dummy"), QString(), shortcut, static_cast<const QObject*>(this), 0, static_cast<KActionCollection*>(0), "");
+
+ KAction* q = actionCollection()->action(actionName.latin1());
+
+ if(q) {
+ KToggleAction* p = dynamic_cast<KToggleAction*>(q);
+ if(!p) {
+ qWarning("Action '%s' is not of type KToggleAction", actionName.latin1());
+ p = &dummyAction;
+ }
+ return p;
+ }
+
+ qWarning("Action with name '%s' not found!", actionName.latin1());
+ return &dummyAction;
+}
+
+KMyMoneyPlugin::ViewInterface* KMyMoneyPlugin::Plugin::viewInterface() const
+{
+ return static_cast<ViewInterface*>( parent()->child( 0, "KMyMoneyPlugin::ViewInterface" ) );
+}
+
+KMyMoneyPlugin::StatementInterface* KMyMoneyPlugin::Plugin::statementInterface() const
+{
+ return static_cast<StatementInterface*>( parent()->child( 0, "KMyMoneyPlugin::StatementInterface" ) );
+}
+
+KMyMoneyPlugin::ImportInterface* KMyMoneyPlugin::Plugin::importInterface() const
+{
+ return static_cast<ImportInterface*>( parent()->child( 0, "KMyMoneyPlugin::ImportInterface" ) );
+}
+
+#include "kmymoneyplugin.moc"
diff --git a/kmymoney2/plugins/kmymoneyplugin.desktop b/kmymoney2/plugins/kmymoneyplugin.desktop
new file mode 100644
index 0000000..000b84a
--- /dev/null
+++ b/kmymoney2/plugins/kmymoneyplugin.desktop
@@ -0,0 +1,6 @@
+[Desktop Entry]
+Type=ServiceType
+Name=KMyMoney Plugin
+X-KDE-ServiceType=KMyMoneyPlugin
+Comment=A KMyMoney plugin
+
diff --git a/kmymoney2/plugins/kmymoneyplugin.h b/kmymoney2/plugins/kmymoneyplugin.h
new file mode 100644
index 0000000..2978fde
--- /dev/null
+++ b/kmymoney2/plugins/kmymoneyplugin.h
@@ -0,0 +1,214 @@
+/***************************************************************************
+ kmymoneyplugin.h
+ -------------------
+ begin : Wed Jan 5 2005
+ copyright : (C) 2005 Thomas Baumgart
+ email : ipwizard@users.sourceforge.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. *
+ * *
+ ***************************************************************************/
+
+#ifndef KMYMONEYPLUGIN_H
+#define KMYMONEYPLUGIN_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+// ----------------------------------------------------------------------------
+// QT Includes
+
+#include <qobject.h>
+
+// ----------------------------------------------------------------------------
+// KDE Includes
+
+#include <kxmlguiclient.h>
+class KAboutData;
+class KInstance;
+class KAction;
+class KToggleAction;
+
+// ----------------------------------------------------------------------------
+// Project Includes
+
+#include <kmymoney/viewinterface.h>
+#include <kmymoney/statementinterface.h>
+#include <kmymoney/importinterface.h>
+#include <kmymoney/export.h>
+
+namespace KMyMoneyPlugin {
+
+/**
+ * This class describes the interface between the KMyMoney
+ * application and it's plugins. All plugins must be derived
+ * from this class.
+ *
+ * A good tutorial on how to design and develop a plugin
+ * structure for a KDE application (e.g. KMyMoney) can be found at
+ * http://developer.kde.org/documentation/tutorials/developing-a-plugin-structure/index.html
+ *
+ */
+ class KMYMONEY_EXPORT Plugin : public QObject, public KXMLGUIClient
+ {
+ Q_OBJECT
+ public:
+ Plugin(QObject* parent, const char* name);
+ virtual ~Plugin();
+
+ protected:
+ /** See KMyMoney2App::action() for a description */
+ KAction* action(const QString& name) const;
+
+ /** See KMyMoney2App::toggleAction() for a description */
+ KToggleAction* toggleAction(const QString& name) const;
+
+ // define interface classes here. The interface classes provide a mechanism
+ // for the plugin to interact with KMyMoney
+ // they are defined in the following form for an interface
+ // named Xxx:
+ //
+ // XxxInterface* xxxInterface();
+ ViewInterface* viewInterface() const;
+ StatementInterface* statementInterface() const;
+ ImportInterface* importInterface() const;
+ };
+
+/**
+ * This class describes the interface between the KMyMoney
+ * application and it's ONLINE-BANKING plugins. All online banking plugins
+ * must provide this interface.
+ *
+ * A good tutorial on how to design and develop a plugin
+ * structure for a KDE application (e.g. KMyMoney) can be found at
+ * http://developer.kde.org/documentation/tutorials/developing-a-plugin-structure/index.html
+ *
+ */
+ class KMYMONEY_EXPORT OnlinePlugin
+ {
+ public:
+ OnlinePlugin() {}
+ virtual ~OnlinePlugin() {}
+
+ virtual void protocols(QStringList& protocolList) const = 0;
+
+ /**
+ * This method returns a pointer to a widget representing an additional
+ * tab that will be added to the KNewAccountDlg. The string referenced
+ * with @a tabName will be filled with the text that should be placed
+ * on the tab. It should return 0 if no additional tab is needed.
+ *
+ * Information about the account can be taken out of @a account.
+ *
+ * Once the pointer to the widget is returned to KMyMoney, it takes care
+ * of destruction of all included widgets when the dialog is closed. The plugin
+ * can access the widgets created after the call to storeConfigParameters()
+ * happened.
+ */
+ virtual QWidget* accountConfigTab(const MyMoneyAccount& account, QString& tabName) = 0;
+
+ /**
+ * This method is called by the framework whenever it is time to store
+ * the configuration data maintained by the plugin. The plugin should use
+ * the widgets created in accountConfigTab() to extract the current values.
+ *
+ * @param current The @a current container contains the current settings
+ */
+ virtual MyMoneyKeyValueContainer onlineBankingSettings(const MyMoneyKeyValueContainer& current) = 0;
+
+ /**
+ * This method is called by the framework when the user wants to map
+ * a KMyMoney account onto an online account. The KMyMoney account is identified
+ * by @a acc and the online provider should store its data in @a onlineBankingSettings
+ * upon success.
+ *
+ * @retval true if account is mapped
+ * @retval false if account is not mapped
+ */
+ virtual bool mapAccount(const MyMoneyAccount& acc, MyMoneyKeyValueContainer& onlineBankingSettings) = 0;
+
+ /**
+ * This method is called by the framework when the user wants to update
+ * a KMyMoney account with data from an online account. The KMyMoney account is identified
+ * by @a acc. The online provider should read its data from acc.onlineBankingSettings().
+ * @a true is returned upon success. The plugin might consider to stack the requests
+ * in case @a moreAccounts is @p true. @a moreAccounts defaults to @p false.
+ *
+ * @retval true if account is updated
+ * @retval false if account is not updated
+ */
+ virtual bool updateAccount(const MyMoneyAccount& acc, bool moreAccounts = false) = 0;
+ };
+
+/**
+ * This class describes the interface between the KMyMoney
+ * application and it's IMPORTER plugins. All importer plugins
+ * must provide this interface.
+ *
+ * A good tutorial on how to design and develop a plugin
+ * structure for a KDE application (e.g. KMyMoney) can be found at
+ * http://developer.kde.org/documentation/tutorials/developing-a-plugin-structure/index.html
+ *
+ */
+ class KMYMONEY_EXPORT ImporterPlugin
+ {
+ public:
+ ImporterPlugin() {}
+ virtual ~ImporterPlugin() {}
+
+ /**
+ * This method returns the english-language name of the format
+ * this plugin imports, e.g. "OFX"
+ *
+ * @return QString Name of the format
+ */
+ virtual QString formatName(void) const = 0;
+
+ /**
+ * This method returns the filename filter suitable for passing to
+ * KFileDialog::setFilter(), e.g. "*.ofx *.qfx" which describes how
+ * files of this format are likely to be named in the file system
+ *
+ * @return QString Filename filter string
+ */
+ virtual QString formatFilenameFilter(void) const = 0;
+
+ /**
+ * This method returns whether this plugin is able to import
+ * a particular file.
+ *
+ * @param filename Fully-qualified pathname to a file
+ *
+ * @return bool Whether the indicated file is importable by this plugin
+ */
+ virtual bool isMyFormat( const QString& filename ) const = 0;
+
+ /**
+ * Import a file
+ *
+ * @param filename File to import
+ *
+ * @return bool Whether the import was successful.
+ */
+ virtual bool import( const QString& filename) = 0;
+
+ /**
+ * Returns the error result of the last import
+ *
+ * @return QString English-language name of the error encountered in the
+ * last import, or QString() if it was successful.
+ *
+ */
+ virtual QString lastError(void) const = 0;
+
+ };
+
+}; // end of namespace
+#endif
diff --git a/kmymoney2/plugins/ofximport/Makefile.am b/kmymoney2/plugins/ofximport/Makefile.am
new file mode 100644
index 0000000..d4729f4
--- /dev/null
+++ b/kmymoney2/plugins/ofximport/Makefile.am
@@ -0,0 +1,33 @@
+KDE_OPTIONS = noautodist
+
+INCLUDES = $(all_includes) -I.. -I. -I${srcdir}/dialogs -Idialogs
+METASOURCES = AUTO
+
+# Install this plugin in the KDE modules directory
+kde_module_LTLIBRARIES = kmm_ofximport.la
+
+# Srcs for the plugin
+kmm_ofximport_la_SOURCES = ofximporterplugin.cpp ofxpartner.cpp
+#nodeparser.cpp
+
+# Libs needed by the plugin
+kmm_ofximport_la_LIBADD = @OFX_LIBS@ dialogs/libdialogs.la ../libkmm_plugin.la ../libkmm_plugin.la $(top_builddir)/kmymoney2/mymoney/libkmm_mymoney.la
+
+# LD flags for the plugin
+# -module says: this is a module, i.e. something you're going to dlopen
+# so e.g. it has no version number like a normal shared lib would have.
+kmm_ofximport_la_LDFLAGS = -module $(KDE_PLUGIN) $(all_libraries) $(LIB_KHTML) $(LIB_KDECORE) $(LIB_KDEUI) $(LIB_QT) -L../.libs
+
+# rc file containing the GUI for the plugin
+pluginsdir = $(kde_datadir)/kmm_ofximport
+plugins_DATA = kmm_ofximport.rc
+
+# Install the desktop file needed to detect the plugin
+kde_services_DATA = kmm_ofximport.desktop
+
+noinst_HEADERS = ofximporterplugin.h ofxpartner.h
+# nodeparser.h
+
+EXTRA_DIST = kmm_ofximport.desktop kmm_ofximport.rc
+
+SUBDIRS = dialogs
diff --git a/kmymoney2/plugins/ofximport/dialogs/Makefile.am b/kmymoney2/plugins/ofximport/dialogs/Makefile.am
new file mode 100644
index 0000000..5d79074
--- /dev/null
+++ b/kmymoney2/plugins/ofximport/dialogs/Makefile.am
@@ -0,0 +1,16 @@
+noinst_LTLIBRARIES = libdialogs.la
+KDE_OPTIONS = noautodist
+
+INCLUDES = $(all_includes) -I$(top_srcdir)
+
+libdialogs_la_METASOURCES = AUTO
+
+libdialogs_la_SOURCES = konlinebankingsetupdecl.ui konlinebankingstatusdecl.ui konlinebankingsetupwizard.cpp konlinebankingstatus.cpp kofxdirectconnectdlgdecl.ui kofxdirectconnectdlg.cpp mymoneyofxconnector.cpp
+
+EXTRA_DIST = konlinebankingsetupdecl.ui konlinebankingstatusdecl.ui kofxdirectconnectdlgdecl.ui
+
+DISTCLEANFILES= konlinebankingsetupdecl.h konlinebankingsetupdecl.cpp konlinebankingstatusdecl.h konlinebankingstatusdecl.cpp kofxdirectconnectdlgdecl.h kofxdirectconnectdlgdecl.cpp
+
+noinst_HEADERS = konlinebankingsetupwizard.h konlinebankingstatus.h kofxdirectconnectdlg.h mymoneyofxconnector.h
+
+messages: rc.cpp
diff --git a/kmymoney2/plugins/ofximport/dialogs/kofxdirectconnectdlg.cpp b/kmymoney2/plugins/ofximport/dialogs/kofxdirectconnectdlg.cpp
new file mode 100644
index 0000000..3db8fbc
--- /dev/null
+++ b/kmymoney2/plugins/ofximport/dialogs/kofxdirectconnectdlg.cpp
@@ -0,0 +1,223 @@
+/***************************************************************************
+ kofxdirectconnectdlg.cpp
+ -------------------
+ begin : Sat Nov 13 2004
+ copyright : (C) 2002 by Ace Jones
+ email : acejones@users.sourceforge.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. *
+ * *
+ ***************************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+// ----------------------------------------------------------------------------
+// QT Includes
+
+#include <qlabel.h>
+#include <qdir.h>
+#include <qfile.h>
+#include <qtextstream.h>
+
+// ----------------------------------------------------------------------------
+// KDE Includes
+
+#include <kurl.h>
+#include <kio/job.h>
+#include <kio/jobclasses.h>
+#include <kdebug.h>
+#include <ktempfile.h>
+#include <kprogress.h>
+#include <kmessagebox.h>
+#include <klocale.h>
+
+// ----------------------------------------------------------------------------
+// Project Includes
+
+#include <kmymoney/mymoneyinstitution.h>
+#include <kmymoney/mymoneyfile.h>
+#include "mymoneyofxconnector.h"
+#include "kofxdirectconnectdlg.h"
+
+
+class KOfxDirectConnectDlg::Private
+{
+public:
+ QFile m_fpTrace;
+};
+
+KOfxDirectConnectDlg::KOfxDirectConnectDlg(const MyMoneyAccount& account, QWidget *parent, const char *name) :
+ KOfxDirectConnectDlgDecl(parent, name),
+ d(new Private),
+ m_tmpfile(NULL),
+ m_connector(account),
+ m_job(NULL)
+{
+}
+
+KOfxDirectConnectDlg::~KOfxDirectConnectDlg()
+{
+ if(d->m_fpTrace.isOpen()) {
+ d->m_fpTrace.close();
+ }
+ delete m_tmpfile;
+ delete d;
+}
+
+void KOfxDirectConnectDlg::init(void)
+{
+ show();
+
+ QByteArray request = m_connector.statementRequest();
+
+ // For debugging, dump out the request
+#if 0
+ QFile g( "request.ofx" );
+ g.open( IO_WriteOnly );
+ QTextStream(&g) << m_connector.url() << "\n" << QString(request);
+ g.close();
+#endif
+
+ QDir homeDir(QDir::home());
+ if(homeDir.exists("ofxlog.txt")) {
+ d->m_fpTrace.setName(QString("%1/ofxlog.txt").arg(QDir::homeDirPath()));
+ d->m_fpTrace.open(IO_WriteOnly | IO_Append);
+ }
+
+ m_job = KIO::http_post(
+ m_connector.url(),
+ request,
+ true
+ );
+ if(d->m_fpTrace.isOpen()) {
+ QByteArray data = m_connector.url().utf8();
+ d->m_fpTrace.writeBlock("url: ", 5);
+ d->m_fpTrace.writeBlock(data, strlen(data));
+ d->m_fpTrace.writeBlock("\n", 1);
+ d->m_fpTrace.writeBlock("request:\n", 9);
+ d->m_fpTrace.writeBlock(request, request.size());
+ d->m_fpTrace.writeBlock("\n", 1);
+ d->m_fpTrace.writeBlock("response:\n", 10);
+ }
+
+ m_job->addMetaData("content-type", "Content-type: application/x-ofx" );
+ connect(m_job,SIGNAL(result(KIO::Job*)),this,SLOT(slotOfxFinished(KIO::Job*)));
+ connect(m_job,SIGNAL(data(KIO::Job*, const QByteArray&)),this,SLOT(slotOfxData(KIO::Job*,const QByteArray&)));
+ connect(m_job,SIGNAL(connected(KIO::Job*)),this,SLOT(slotOfxConnected(KIO::Job*)));
+
+ setStatus(QString("Contacting %1...").arg(m_connector.url()));
+ kProgress1->setTotalSteps(3);
+ kProgress1->setProgress(1);
+}
+
+void KOfxDirectConnectDlg::setStatus(const QString& _status)
+{
+ textLabel1->setText(_status);
+ kdDebug(2) << "STATUS: " << _status << endl;
+}
+
+void KOfxDirectConnectDlg::setDetails(const QString& _details)
+{
+ kdDebug(2) << "DETAILS: " << _details << endl;
+}
+
+void KOfxDirectConnectDlg::slotOfxConnected(KIO::Job*)
+{
+ if ( m_tmpfile )
+ {
+// throw new MYMONEYEXCEPTION(QString("Already connected, using %1.").arg(m_tmpfile->name()));
+ kdDebug(2) << "Already connected, using " << m_tmpfile->name() << endl;
+ delete m_tmpfile; //delete otherwise we mem leak
+ }
+ m_tmpfile = new KTempFile();
+ setStatus("Connection established, retrieving data...");
+ setDetails(QString("Downloading data to %1...").arg(m_tmpfile->name()));
+ kProgress1->advance(1);
+}
+
+void KOfxDirectConnectDlg::slotOfxData(KIO::Job*,const QByteArray& _ba)
+{
+ if ( !m_tmpfile )
+// throw new MYMONEYEXCEPTION("Not currently connected!!");
+ kdDebug(2) << "void ofxdcon::slotOfxData():: Not currently connected!" << endl;
+ *(m_tmpfile->textStream()) << QString(_ba);
+
+ if(d->m_fpTrace.isOpen()) {
+ d->m_fpTrace.writeBlock(_ba, _ba.size());
+ }
+
+ setDetails(QString("Got %1 bytes").arg(_ba.size()));
+}
+
+void KOfxDirectConnectDlg::slotOfxFinished(KIO::Job* /* e */)
+{
+ kProgress1->advance(1);
+ setStatus("Completed.");
+
+ if(d->m_fpTrace.isOpen()) {
+ d->m_fpTrace.writeBlock("\nCompleted\n\n\n\n", 14);
+ }
+
+ int error = m_job->error();
+
+ if ( m_tmpfile )
+ {
+ m_tmpfile->close();
+ }
+
+ if ( error )
+ {
+ m_job->showErrorDialog();
+ }
+ else if ( m_job->isErrorPage() )
+ {
+ QString details;
+ QFile f( m_tmpfile->name() );
+ if ( f.open( IO_ReadOnly ) )
+ {
+ QTextStream stream( &f );
+ QString line;
+ while ( !stream.atEnd() ) {
+ details += stream.readLine(); // line of text excluding '\n'
+ }
+ f.close();
+
+ kdDebug(2) << "The HTTP request failed: " << details << endl;
+ }
+ KMessageBox::detailedSorry( this, i18n("The HTTP request failed."), details, i18n("Failed") );
+ }
+ else if ( m_tmpfile )
+ {
+
+ emit statementReady(m_tmpfile->name());
+
+// TODO (Ace) unlink this file, when I'm sure this is all really working.
+// in the meantime, I'll leave the file around to assist people in debugging.
+// m_tmpfile->unlink();
+ }
+ delete m_tmpfile;
+ m_tmpfile = 0;
+ hide();
+}
+
+void KOfxDirectConnectDlg::reject(void)
+{
+ m_job->kill();
+ if ( m_tmpfile )
+ {
+ m_tmpfile->close();
+ delete m_tmpfile;
+ m_tmpfile = NULL;
+ }
+ QDialog::reject();
+}
+
+#include "kofxdirectconnectdlg.moc"
diff --git a/kmymoney2/plugins/ofximport/dialogs/kofxdirectconnectdlg.h b/kmymoney2/plugins/ofximport/dialogs/kofxdirectconnectdlg.h
new file mode 100644
index 0000000..e5d92cd
--- /dev/null
+++ b/kmymoney2/plugins/ofximport/dialogs/kofxdirectconnectdlg.h
@@ -0,0 +1,86 @@
+/***************************************************************************
+ kofxdirectconnectdlg.h
+ -------------------
+ begin : Sat Nov 13 2004
+ copyright : (C) 2002 by Ace Jones
+ email : acejones@users.sourceforge.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. *
+ * *
+ ***************************************************************************/
+
+#ifndef KOFXDIRECTCONNECTDLG_H
+#define KOFXDIRECTCONNECTDLG_H
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+// ----------------------------------------------------------------------------
+// QT Includes
+
+// ----------------------------------------------------------------------------
+// KDE Includes
+
+class KTempFile;
+class KOfxDirectConnectDlgPrivate;
+
+namespace KIO
+{
+class Job;
+class TransferJob;
+}
+
+// ----------------------------------------------------------------------------
+// Project Includes
+
+#include "mymoneyofxconnector.h"
+#include "kofxdirectconnectdlgdecl.h"
+
+/**
+@author ace jones
+*/
+class KOfxDirectConnectDlg : public KOfxDirectConnectDlgDecl
+{
+Q_OBJECT
+public:
+ KOfxDirectConnectDlg(const MyMoneyAccount&, QWidget *parent = 0, const char *name = 0);
+ ~KOfxDirectConnectDlg();
+
+ void init(void);
+
+signals:
+ /**
+ * This signal is emitted when the statement is downloaded
+ * and stored in file @a fname.
+ */
+ void statementReady(const QString& fname);
+
+protected slots:
+ void slotOfxFinished(KIO::Job*);
+ void slotOfxData(KIO::Job*,const QByteArray&);
+ void slotOfxConnected(KIO::Job*);
+ virtual void reject(void);
+
+protected:
+ void setStatus(const QString& _status);
+ void setDetails(const QString& _details);
+
+ KTempFile* m_tmpfile;
+ MyMoneyOfxConnector m_connector;
+ KIO::TransferJob* m_job;
+
+private:
+ /// \internal d-pointer class.
+ class Private;
+ /// \internal d-pointer instance.
+ Private* const d;
+};
+
+#endif // KOFXDIRECTCONNECTDLG_H
diff --git a/kmymoney2/plugins/ofximport/dialogs/kofxdirectconnectdlgdecl.ui b/kmymoney2/plugins/ofximport/dialogs/kofxdirectconnectdlgdecl.ui
new file mode 100644
index 0000000..3937012
--- /dev/null
+++ b/kmymoney2/plugins/ofximport/dialogs/kofxdirectconnectdlgdecl.ui
@@ -0,0 +1,109 @@
+<!DOCTYPE UI><UI version="3.0" stdsetdef="1">
+<class>KOfxDirectConnectDlgDecl</class>
+<widget class="QDialog">
+ <property name="name">
+ <cstring>KOfxDirectConnectDlgDecl</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>511</width>
+ <height>108</height>
+ </rect>
+ </property>
+ <property name="caption">
+ <string>OFX Direct Connect</string>
+ </property>
+ <property name="sizeGripEnabled">
+ <bool>true</bool>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>textLabel1</cstring>
+ </property>
+ <property name="text">
+ <string>Contacting bank...</string>
+ </property>
+ </widget>
+ <widget class="KProgress">
+ <property name="name">
+ <cstring>kProgress1</cstring>
+ </property>
+ </widget>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout2</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <spacer>
+ <property name="name">
+ <cstring>spacer4</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>51</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="QPushButton">
+ <property name="name">
+ <cstring>buttonCancel</cstring>
+ </property>
+ <property name="text">
+ <string>Cancel</string>
+ </property>
+ <property name="accel">
+ <string></string>
+ </property>
+ <property name="autoDefault">
+ <bool>true</bool>
+ </property>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>spacer3</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>61</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </hbox>
+ </widget>
+ </vbox>
+</widget>
+<customwidgets>
+</customwidgets>
+<connections>
+ <connection>
+ <sender>buttonCancel</sender>
+ <signal>clicked()</signal>
+ <receiver>KOfxDirectConnectDlgDecl</receiver>
+ <slot>reject()</slot>
+ </connection>
+</connections>
+<layoutdefaults spacing="6" margin="11"/>
+</UI>
diff --git a/kmymoney2/plugins/ofximport/dialogs/konlinebankingsetupdecl.ui b/kmymoney2/plugins/ofximport/dialogs/konlinebankingsetupdecl.ui
new file mode 100644
index 0000000..3ee9b6a
--- /dev/null
+++ b/kmymoney2/plugins/ofximport/dialogs/konlinebankingsetupdecl.ui
@@ -0,0 +1,488 @@
+<!DOCTYPE UI><UI version="3.3" stdsetdef="1">
+<class>KOnlineBankingSetupDecl</class>
+<widget class="QWizard">
+ <property name="name">
+ <cstring>KOnlineBankingSetupDecl</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>653</width>
+ <height>502</height>
+ </rect>
+ </property>
+ <property name="caption">
+ <string>Online Banking Account Setup</string>
+ </property>
+ <widget class="QWidget">
+ <property name="name">
+ <cstring>FIPage</cstring>
+ </property>
+ <attribute name="title">
+ <string>Select Financial Institution</string>
+ </attribute>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>textLabel1</cstring>
+ </property>
+ <property name="frameShape">
+ <enum>WinPanel</enum>
+ </property>
+ <property name="frameShadow">
+ <enum>Sunken</enum>
+ </property>
+ <property name="text">
+ <string></string>
+ </property>
+ <property name="pixmap">
+ <pixmap>image0</pixmap>
+ </property>
+ </widget>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>m_listLayout</cstring>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>textLabel2</cstring>
+ </property>
+ <property name="text">
+ <string>Please select your financial institution from the list below...</string>
+ </property>
+ <property name="alignment">
+ <set>WordBreak|AlignVCenter</set>
+ </property>
+ </widget>
+ <widget class="QTabWidget">
+ <property name="name">
+ <cstring>m_selectionTab</cstring>
+ </property>
+ <widget class="QWidget">
+ <property name="name">
+ <cstring>tab</cstring>
+ </property>
+ <attribute name="title">
+ <string>Automatic</string>
+ </attribute>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="KListView">
+ <column>
+ <property name="text">
+ <string>Financial Institution</string>
+ </property>
+ <property name="clickable">
+ <bool>true</bool>
+ </property>
+ <property name="resizable">
+ <bool>true</bool>
+ </property>
+ </column>
+ <property name="name">
+ <cstring>m_listFi</cstring>
+ </property>
+ <property name="allColumnsShowFocus">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </vbox>
+ </widget>
+ <widget class="QWidget">
+ <property name="name">
+ <cstring>tab</cstring>
+ </property>
+ <attribute name="title">
+ <string>Manual</string>
+ </attribute>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout8</cstring>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="KURLRequester" row="2" column="1">
+ <property name="name">
+ <cstring>m_url</cstring>
+ </property>
+ </widget>
+ <widget class="QLabel" row="0" column="0">
+ <property name="name">
+ <cstring>textLabel4</cstring>
+ </property>
+ <property name="text">
+ <string>Org</string>
+ </property>
+ </widget>
+ <widget class="QLabel" row="1" column="0">
+ <property name="name">
+ <cstring>textLabel1_5</cstring>
+ </property>
+ <property name="text">
+ <string>FID</string>
+ </property>
+ </widget>
+ <widget class="KLineEdit" row="0" column="1">
+ <property name="name">
+ <cstring>m_bankName</cstring>
+ </property>
+ </widget>
+ <widget class="KLineEdit" row="1" column="1">
+ <property name="name">
+ <cstring>m_fid</cstring>
+ </property>
+ </widget>
+ <widget class="QLabel" row="2" column="0">
+ <property name="name">
+ <cstring>textLabel2_4</cstring>
+ </property>
+ <property name="text">
+ <string>URL</string>
+ </property>
+ </widget>
+ </grid>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>spacer3</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Vertical</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>20</width>
+ <height>90</height>
+ </size>
+ </property>
+ </spacer>
+ </vbox>
+ </widget>
+ </widget>
+ </vbox>
+ </widget>
+ </hbox>
+ </widget>
+ <widget class="QWidget">
+ <property name="name">
+ <cstring>LoginPage</cstring>
+ </property>
+ <attribute name="title">
+ <string>Enter Login Details</string>
+ </attribute>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>textLabel1_3</cstring>
+ </property>
+ <property name="frameShape">
+ <enum>WinPanel</enum>
+ </property>
+ <property name="frameShadow">
+ <enum>Sunken</enum>
+ </property>
+ <property name="text">
+ <string></string>
+ </property>
+ <property name="pixmap">
+ <pixmap>image0</pixmap>
+ </property>
+ </widget>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout6</cstring>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <spacer row="3" column="2" rowspan="2" colspan="1">
+ <property name="name">
+ <cstring>spacer4_2</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>120</width>
+ <height>21</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="KActiveLabel" row="0" column="0" rowspan="1" colspan="3">
+ <property name="name">
+ <cstring>kActiveLabel1</cstring>
+ </property>
+ <property name="focusPolicy">
+ <enum>NoFocus</enum>
+ </property>
+ <property name="text">
+ <string>Please enter the username and password you use to log into this bank for online banking. Please note that many banks require a separate signup, and assign a separate PIN or password just for online banking from home.</string>
+ </property>
+ </widget>
+ <widget class="KComboBox" row="4" column="1">
+ <property name="name">
+ <cstring>m_headerVersionCombo</cstring>
+ </property>
+ </widget>
+ <widget class="QLabel" row="5" column="0" rowspan="1" colspan="3">
+ <property name="name">
+ <cstring>textLabel3</cstring>
+ </property>
+ <property name="text">
+ <string>Connection Details</string>
+ </property>
+ </widget>
+ <widget class="KComboBox" row="3" column="1">
+ <property name="name">
+ <cstring>m_applicationCombo</cstring>
+ </property>
+ </widget>
+ <widget class="QLabel" row="1" column="0">
+ <property name="name">
+ <cstring>textLabel1_4</cstring>
+ </property>
+ <property name="text">
+ <string>Username</string>
+ </property>
+ </widget>
+ <widget class="QLabel" row="4" column="0">
+ <property name="name">
+ <cstring>textLabel1_6</cstring>
+ </property>
+ <property name="text">
+ <string>Header Version</string>
+ </property>
+ </widget>
+ <widget class="QLineEdit" row="2" column="1" rowspan="1" colspan="2">
+ <property name="name">
+ <cstring>m_editPassword</cstring>
+ </property>
+ <property name="echoMode">
+ <enum>Password</enum>
+ </property>
+ </widget>
+ <widget class="QLineEdit" row="1" column="1" rowspan="1" colspan="2">
+ <property name="name">
+ <cstring>m_editUsername</cstring>
+ </property>
+ </widget>
+ <widget class="QLabel" row="3" column="0">
+ <property name="name">
+ <cstring>textLabel1_2_3</cstring>
+ </property>
+ <property name="text">
+ <string>Identify as</string>
+ </property>
+ </widget>
+ <widget class="QLabel" row="2" column="0">
+ <property name="name">
+ <cstring>textLabel2_3</cstring>
+ </property>
+ <property name="text">
+ <string>Password</string>
+ </property>
+ </widget>
+ <widget class="QTextBrowser" row="6" column="0" rowspan="1" colspan="3">
+ <property name="name">
+ <cstring>m_textDetails</cstring>
+ </property>
+ </widget>
+ </grid>
+ </widget>
+ </hbox>
+ </widget>
+ <widget class="QWidget">
+ <property name="name">
+ <cstring>AccountPage</cstring>
+ </property>
+ <attribute name="title">
+ <string>Select Account</string>
+ </attribute>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>textLabel1_2</cstring>
+ </property>
+ <property name="frameShape">
+ <enum>WinPanel</enum>
+ </property>
+ <property name="frameShadow">
+ <enum>Sunken</enum>
+ </property>
+ <property name="text">
+ <string></string>
+ </property>
+ <property name="pixmap">
+ <pixmap>image0</pixmap>
+ </property>
+ </widget>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout29</cstring>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>textLabel2_2</cstring>
+ </property>
+ <property name="text">
+ <string>Please select the account from your financial institution from the list below which matches this account.</string>
+ </property>
+ <property name="alignment">
+ <set>WordBreak|AlignVCenter</set>
+ </property>
+ </widget>
+ <widget class="QListView">
+ <column>
+ <property name="text">
+ <string>Number</string>
+ </property>
+ <property name="clickable">
+ <bool>true</bool>
+ </property>
+ <property name="resizable">
+ <bool>true</bool>
+ </property>
+ </column>
+ <column>
+ <property name="text">
+ <string>Type</string>
+ </property>
+ <property name="clickable">
+ <bool>true</bool>
+ </property>
+ <property name="resizable">
+ <bool>true</bool>
+ </property>
+ </column>
+ <column>
+ <property name="text">
+ <string>Bank</string>
+ </property>
+ <property name="clickable">
+ <bool>true</bool>
+ </property>
+ <property name="resizable">
+ <bool>true</bool>
+ </property>
+ </column>
+ <column>
+ <property name="text">
+ <string>Branch</string>
+ </property>
+ <property name="clickable">
+ <bool>true</bool>
+ </property>
+ <property name="resizable">
+ <bool>true</bool>
+ </property>
+ </column>
+ <property name="name">
+ <cstring>m_listAccount</cstring>
+ </property>
+ </widget>
+ </vbox>
+ </widget>
+ </hbox>
+ </widget>
+ <widget class="QWidget">
+ <property name="name">
+ <cstring>WizardPage</cstring>
+ </property>
+ <attribute name="title">
+ <string>WizardPage</string>
+ </attribute>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>textLabel1_2_2</cstring>
+ </property>
+ <property name="frameShape">
+ <enum>WinPanel</enum>
+ </property>
+ <property name="frameShadow">
+ <enum>Sunken</enum>
+ </property>
+ <property name="text">
+ <string></string>
+ </property>
+ <property name="pixmap">
+ <pixmap>image0</pixmap>
+ </property>
+ </widget>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout6</cstring>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>m_labelFinal</cstring>
+ </property>
+ <property name="text">
+ <string>Congratulations! You have successfully set up your bank for online banking via OFX.</string>
+ </property>
+ <property name="alignment">
+ <set>WordBreak|AlignVCenter</set>
+ </property>
+ </widget>
+ </vbox>
+ </widget>
+ </hbox>
+ </widget>
+</widget>
+<customwidgets>
+</customwidgets>
+<images>
+ <image name="image0">
+ <data format="PNG" length="18409">89504e470d0a1a0a0000000d49484452000000b700000164080600000062b3aaaa0000200049444154789ced9d7b7c54d5d5f77f13c630263064429ad8099090385c26354447218fc638c608f5e111e205ac5a354d63c5372a78ad85965b955aad0a563fd2823168a5af201aa23c568b318dc89baad1814a22991226c150833197c1e01081f3feb1b3cf9c3973cedc72cedcb2bf9f0f1f923367ce9c24bfbdceda6bafbd9666efdebd508ba1a1210e0012131335aa7d48002c5fbe9caba9a9c1d1a347237a1f8cf092a0e6c51b1b1b919292a2e647044457d711381c8e48df0623cca82a6e87c38113274e44dc5adaed87d0d8d818e9db60841955c5ddd6b64fcdcb07456f6f6fa46f8111665415f79e3dcd6a5e3e20a8df6fb3d9227d2b8c30a39ab893929238b5ae1d0aa74e1d8ff42d30c28c6ae2eeefef57ebd221110d4f114678514ddcd132818b96fb60841fd5c4dddbdb0babd5aad6e54382fadf8cd1816ae266133846a4514ddc5d5d47d4ba74c8b00137ba504ddc76fb21b52e1d324ea733d2b7c00823aa88db6834468d6f5b5f5fcf7fcd96e04717aa889b8a282727478dcb874c7b7b7ba46f8111465415777676b61a97673002421571777676aa71d911d3d0d010e95b608411ad1a17552b4969686888733a9db2518fe2e2626467677be46dd7d4d4a0bcbc9c097b14a28ab8950ab925252571353535f8e4930f3c96cf2d799ee7b51fd1a1cfe9e2bf2f2ab270d75f7f0bcacbcbd1d2d2a259b76e1d7a7a7ab8fbefbf1766b3996b696989781a2e437d5411f748309bcddc33cf3c83975fdec287130d7a1dcae602f3b380b9c51a4c481607635cb07701db1a81cdefe8b0674f33f6ec69c69a950fe39aeb6fe256ae5c09009a8f3f6e8e9a280e437d5411f7be4f9b827e0f15f5fc1f97f056d892072cb918985b7c12c7fa01db7e60e9cb1c8e7401cd07dcef35e875a89ce7c25d0b34b86bc1492c7d19a87d17e873ba505d5d8deaea6a545454702b57ae645bcd4611aa4c28852e4220b4b5b57153a79c83952b57a2cfe982250f78e949e0f5873568eb070aaac6e2a2bb81db3711d10a854d3fef89ede4bc7f1ce350b304787091e739d5d5d5c8cece465b5b1bb3dea304c52db7d96c0e583c66b399bbedb69bb173e72e00c4023f7e830b8bae021efd2bb0f49db1b8acd085ca792e9c5708cc4c044c99e4bdf62e62c9dbfa892bd2e774a1cfe9c2adf7031fff11587123601f208341c8bdf72cc1fb8d4d5c346c7f63a88be2e20e7432999494c44d9d720e6fe5cbe6021b6e39094083f28d1ce66701b6e74e6242b2f4fb4d996ea1afb8d185bac3c0d23544e47357e870b8c68515577b8bbbcfe9c2b265cbb06eddba107f4246aca0ea3633397a7a7ab8cb8b0bd1e774c1a0d761d3ed40cd12f013c59a25c0a2ab2031719467c154e0708d0b65738980eb0ebbc52fa6a1a121ea760a3194477171fb4b4e6a6b6be3162c58c00bfbdd47891b420946d052d42c214f017fd4d5d58de87318d18fe2e2f6e59624252571e5e5e5004824e4dd475d5ed6d5de055cf19b91ddc38aab8925f7054ba28a7f548d73ebf57afe6bb3d9cc4d9d720e0022ecd71ff68e5753bff9b2c2e0a22d62e8801918d400907e12b024aaf84771cb4d97de0d7a1da8950680db6ebb997745362e018ef57b8a6e6050c34f08e76729732fef36cabb38050505ca7c08236a512d5a72ef03cb4197b93ffae8236ee7ce5dbc8f0d007357e878b1e74c76a1fdc858fefb4557c95b6e6108d03e407c6c397675c8bf969a9a1ac24fc7882554714b4ca65cdc73cf3d68696981d96ce6e6ffb80400f0f80d6e1ffbdd475d58b211683ee01a5e9471f1e7081918d4e0dd460ebb3a807f3479e69088176a84d8bbbcc380428a8b8b43f9d11831842ae2deb4e905de6adf77df7de8739210dda285a918a3cfc7e99e06983289df5d50359617acd06adbbb8047df04fed1345620684fe14ff3516373c946f9d70c7a5dc42bcf32d44771714f9890cc0b67686888abaeae06402218c917fe15aeb6dff1e71eebe73c2c71ce6417ca3742943b22efa28c9d217d7cfbdbde4bf442ee7d6079603f0c23a6517c42b961c373fcd7ab57af0640dc07f3a5772161dc4538ddd3c0bf6edbeff9dee603d2b92300b1b6624e7ee17d9ebd0b78e855ef7385d7b9e79e7b7cfe0c8cf8407171d3acbba4a424aea1a10106bd0e772dd04077ee5a9c3ab6cde3dc8d3eeade5bf2c8a078e949922b22958c257ebfbdcb3d51ad4a97beae70a2cb886f548b733ff3cc330080ca792ea49d771712920d38e5fc9c7f7d605083e603ee509d250f2831133f5a9cb35d3eec3f0b13abc40c0c6ab06423c7475c52b35cc031cf7384135d46fca39ab8df786d2b00e0ae051a9ccafa0900e08c40dcc7fa396cba9df8cddeab896e61d3a80759f8914ea4b277014b3672bc3b73d77417fef784f779c2892e23fe5145dc4949491c8d904c48e6a04fb904003cfc6d61569f2fb635d28c41a91d389eae080054a503530a80e64d9ee7ad5dbb9645484619aa889bee7ef75a694c4c058682db3cbce246fa95b7b0b7bf4d268f54d885c9c0af2e35e2faad473dceaba8a84069692913f62843959457ba4a3976063026cdca1f1fa3cf57ec33b6bf4d76e608b7a4bdf66323167e71144d83eef38a8a2c78eaa9a714fb5c46ec10d67ceec4493f19f13506063528df48844da94a0776ce30e2771f1cf50823161559f0d65bef313f7b94a28a5b3265ca1400240e7d7a6a83fbc3d2170389cb83764d28246bd07345f3f11b5cb8aa9758ec664174c464ca65c21ee5a862b969c61d8d430f1dfe13f9b06403ce3607bfbd8b5aeb5bef87c7c4f15f57a6e2aa5e23aeff9ba7c55eb8703e3efeb899097b94a38ae53e71e284c664cae59a0f1c42dd616041e272b80c3f823ee512244ebd0300f09dcd473adf3003831a3c5bc761f33b633d7ceb9d338c00803f751ec5b30775e813f8d8ebd7afc7ecd9b3352c96cdd0a8d51e7bf7eeddb4180e1fca4b3baf0a89e75c8d847117e1dbef5bc07db840d2451116d8115aea5f5d4a44fd76ea51bcb0151e1347abd58af5ebd7474553574674a09ab8cd6633575656c6d7e833e8c90e9b15574bc7b7eb0e03ff6af22cc760d0eb70d77417ee98e2b6d47f6ff114b5c9948b152b7e8369d3a629226ab3d9ccd96c3616138f03541337656868887bfae927f8da24145aef4f5ce7cfa0d7e1269d0ba959c01d538c783bf5286c3b81ad2ecff3ac562bcacbcb1513b5f07e013071c7019ab56bd7720b162c50fd716e341ab9dada5abcf6dacb3e7b42fee622f27f6f87b7a04da65ccc9f7f35cacbcb55bb5f26eef881df411b0ee1508c4623d7d0d08037ded8ee65d185141559306dda2ce4e7e7a3acac2c2c75fe68b935a59f088cf0a3299b0b4ebc7daba8c882cacabbc3f207a63eae10718d6d35686b6be3a47ebeddbb777300d8727d1c90b0e3f55e7cd95889979e74fbc17bf634a3bcbc1cb7dd760ba776e1c89696164d6262a2c7bf7058e837ded8aef64730224c4242b20149b3fe885beee3b0f7cd8de87859c3576cb2db0ff122efe9e9899bf26346a3911b1818947c4dadae108cf09330f08606df7e70394eecbb1b09495391f23f1fa06609d9fd422db9dd7e080b162cc0f2e5cbb9686ac3172a0e8703a74e1d977ccd66b379b4f763c42e0900c9b3febefd590cee9d07eefd22002416fdde6f814db7bbf72f363434e0fcfc19315fe3bab1b1d167c486111ff8cd2d59741529254c5d953ea70be5e5e5d8bc7973cc0a9cb91ea3039fe2b67791ff2724936e05422b5e5d5d8d871eba9b0ba6d87cb4e0af8638eb7c161f68b7bfedaeff71f20b7799b27f34913267effdd67df2a2ab80827c5a298a44552ebac8828f3f6e8ec90e6146a39113476642e9e7c3884ee4cba0829456706ff3723330a8c1b58fb937e4c6daa6808b2fbe9803888516af44d2d7fafbfb63e6e76148e3d32d592c534e6f423287d71fd678c4c52fbac8a2f4bd4514a57a6932224702e0eef328aeea3477858ef7bbc550810b63e2b13cc964c41f090089805c3b8ff49479e949e28e18f4eee649be045eb3c41d0fafaeae86dc624fb44c3c03ed85c33a2fc43ebc5bb2740db1da0ba6123ffb708d0b9b6e072e2b2402dffeb6fc455e7f58c35bfdc71f5f23794e59599982b71d3afdfdfd019d47cb533062175edc7d4e979780175d458abbdb9e3b0980b6e1f0664232c7d7d5deb3a759d23a363434f0e9a4d1426363a3c7f7d1f27461284302752900f9eaa8139239bfadf3165de5f6d9699d400a15bb584cd1069b44c6170993055bbefa9c2e59ff3a102ae711eb5d5d5ded6105e923beb9f99fa15f5c21fcb512a4b0fc92d82741dc5a435c333b18ce2b747f5d5353e3bee6b04594cbc40b27cc3a8f1ebce2dc6d81cdb77884967e66a2fbebfdfbdda3845a41b6accd0827099b6e27a13fa1ef1d0cdb046e747a8a7bc229ecf3d8d57524d4fb5315619f4c46fca1a585dc570c1ff0d59854ccf6b7491e0ae51fc7dcefcbc9c90140221076fb21056e5579582fcaf8c6cb2d09b4f7faa37f25c52885658a853d6a6ebdf55600d1e7e3fa9a2846dbbd32464650e5d4684f485a135bdc109584125da8a9a9e11392a23dfc2724d0480a23369015b7bd0b681d72a7c1d6b740d0c3c6e5d10d18202e4a9f93085bb8ab5cb88c6d32e52aff130489707bd9f02efb08de0d434db40011e6c6bdbe7b370a21b5ff487f1a5aacf289edf0123600b4b5ede3bfcecc9cace0ad87c6238f3c89828202b4b4b468c4c2a6a59719f18176fbdb6475914e2ca9c50648ed3e807418a31b1a2e4b27bd69060689df4d2bb04a091b40d4ed554c4c4c94ad003b6dda34cddebd7b313434c4b1c4a9d8470380a3452ae76779b7c91362ef228b3cbb3a3cfbaacb093b292989134624d6ae5dab4ab11b5ad8c7e17078ac86fa5a349a30211916cb1c00a40f7c380a0131c28b1620be72edbb402d006c22c216c6bdc5c52a2906bd0e5bfeb20d69696992a210471f94882bd39a83fbf7ef477b7b7bc00b4334ef45f873884bb919f43aaef8f22b70cd358b5839b53820f0a0b688a2220b9e7df6059f75058535ba01e96d5d81303434c4d5d6d662d7ae37218e995bf280c999806982db7d9a99e8bf0da0f484d9fdbadcd388113b68ac562bb7efd32649cb2c8541afc3bd0f2c0fc8bd58be7c3927b4acc1ec4b4c4a4ae26a6a6abc045d369708f9bc42a9e6acd2d41d768b182083a0209f885b780d7b17f0e89b6e978b093cb6f1a8cf4df3ad85beab90e2e2e2a02cef430fddcdd109a541afc3aebfd5fb7d6f5b5b1b575353e355b47e7e1624db62070315f9ae0eb2bb5fd88aa4c44cba1d4f48e6f8368040e84f1b46e451b5f83cdd490e9062f1ebd6ad9315495b5b1bf7e8a3bfe5ad74d95c78097a6ab9efee0cc1e0eeb7e329f2d71f26027ff4afc013dbc9e03adcf915db091f83a8266e71a464d9b26558bc78b19740a4442d27de2b7ee3f68b1f5c44dc8b5d1dc0912eb7df4dad6fa088db6b5bf24819b981410d0aaa4898d3dfc0644427aa743303bcf72a6667677b7c6f341ab9f2f272defda0a2365f7a17be6f7fd6eb7a03831ac10a29b1aa94071709451ddcfcd89409bcfba80b17dd4dbe6f3e40046fca245be76edf445c939e9e1e4e2e2ac4884e54eb202cce29115af1b6b636eefcfc196868688041afc34b4f022fffda8afcf91bf1fd975bbdae458b0089b1e4916ab42b6e0c3ce14b0a5326f81215807b118b2e5c01c0fdf7df1bf2f51991216cedb1a9b8376fdecc959797a3cfe942d95cb2f9f8ba2beec299f31ec1772ddedd85ed5df0a86e05103f78d3edc47d18a9ef4d1166370a375df0f7613f245bb682119da8e69608534b0d7a1d5a5a5a349b376fe6aaabab0190a29a8b16a622f9c2bf2261dc4538de70ae97b0e9a44e789dca792edcb580e4b52809b5d2963cf78079fd1def9f69f1e2c5ca7e3043355413b790591714424ad89a4beaa04db904df7e70b987b0ed5de08b6d8a79623bf0c4766917450c9d6452ce2b74e7c68839f9853b5a029070a0d7fe529b8d893b865055dc4545163cf2c893686c6c045da9140a5b9f72094eecbb1ba77b1af8f70c0c6a3077c558c945255f0b4d5203417cec41000b6e94f62c0af281f7ae02a8b0699c9b11bba8de64d5683472345242abc69e5db0118953efc099c13e4977042022176e5b0b84935f80df4821c492072cad086c45b37ca3b7c5a6d0bef241dd142362a8ee96ac5dbb160011d88a1b0124a62271ea1d008053c7b6490a1b20d18f4097d70192932e16b6250f587271602b9bbe5c21803c8598b0630bd5c5fdc66b24b4576226df9f35e926feb553cecf477c7dcf8d169e167be312ffd114e1660b390c7a1d4d121bf1fd32c287aae21e1a1ae27cf9c967421437cd2b97724184f81336b1f6d2febd90a79fd9a87a576586f284255a22e4fb2fb7e2ccb96b91906c40e2a49fe03bc164520e2a66716a6ad95c9250357686db9fa69b987775485fcb3ba7c4b7b0596660eca2fa84f2b6db6ee1ecf6432401a98608e9ac9cbb9034eb8f3833d887139f5eeb112d1163eff22cfc030497ee4ad9feb6f70e225f18f43a3cfdcc4626ec18c6afb87ffffb47b95ffe7245c87fe0b6b636aebcbc1c0059e2ae59428ed38889b3ff43701f2e909d58868ad0828b7bdbfbc364cac5f6ed3b982b12e3f815f7c5175fccd5d5d5c96e250b04615eb730eb6f4c9a1589937e0200f8ceb624d4cb03f0ccd53ed215f84e7e31cb962dc3ead5ab598a6b1c1090b8e5d2550365686888b35aad1ec7849b10c6ce905f3914527798fc2fdc1a26b7bf3358ac562bd6af5fcfac751ce153dc3427db64cac5962d2f8fe88f2ede4fa92685c9c0c1318189de6ab562f5ead56cb74d1ce2335a4273b2edf643309bcd236aa45a5a5aaa71381c7c7e895218f43a4c3fedc29566604a01d06903fedee27ba9dea0d7e1b68a2558b66c192be710c7f814b7b0769ecd664362a2442e68103cf5d453686bdbc717ea294c065efbb1116fa71e45ea7b806d6260d79952005cf821f083994600c0dba94761db09fcf663f9f7984cb9b8f4d2cb505656c6cf1f5829b5f8c6a7b88575476c361b66cf9e3da20f6b6969d1bcf5d67bdc7df7dd87eaea6a340d0293761c456132f07d36f0dfc3e74d290052df037aaff0febfd346fe6dd400ed7fef95b5d026532ecce619b8fcf22b61b55a992f3d0a09781147a90aa82d2d2d9acaca4a3cf5d4539ccd6643636323eaebeb71f0d326fc960a955ae07699ff795c30997291993919393939c8cece467171315f0b909ec596cd47273ec5ad6683a69696164d6262224a4b4b515a5a0ac05d160d90dea626ac58e56b0228570b9031baf0296e61adbde6e67ff222540b2a7800aa7f1623fe09780f65347422633082c1a7b859f731462c13b0e5a60d9c188c584156dc46a3d1632d5c5c5487c1887664c5cd3a0b30629db015e56130c24dc0969b75db65c41ab2e216d7e766dd7619b106734b18714bc0e266d11246ac11b0cfcdf29e19b1866c6e497bbb570a5e50188d46cee170c0e9747ab5eca3e8f57ade97677d20194a1350caabbf9eed66b399a3a9ab369b6d24cbf65c519105175e78294a4a4a505c5ccc36ea32422620714bf56c379bcd5c6d6d2dde7863bb57b3d291b0674f33f6ec69c6faf5eb01000b17cee77efef33b46b4fb9e313a09bae294d168e4d6af5f8f2dd51b2577c1d0a6a7be76b5fb6b702a64e7ce5dd8b973174ca65c6ec58adfb022398c80f1296e835e87556b1fc3ecd9b33566b3997be6996720dec1eeb76f7ca20163f4f9008004fd8fa0d5ff08e69ccf61fa722b309514e25901cf223a5255a1ecf643282f2f87c994cb6ddaf402dbadcef08b6c6907a3d1c8a5a4a4a0a5a545333434c4dd7efbcf3d3af94a96074e4cc5187d3e1227fd04094953a1cd205d94ce0cf6e1d4b16d18faf2fffa2c9d46a125d4843d22c5b0e2390c7ff82dcab36ddb368efabf80449fc8c4549c35e926249e73352f662078414b216e570d0055e9c05617117d20fde719a317597127252571ab56ade0278b5edd098645ad1baed84a39d5fd2e86be7a53b29764a808db781426033fbf89ec801797721057b592a2a4a4c4e3fbe2e26200404a4a0a1b247186c6e17070e2051b87c30161575fdaee837256ce5d5ea276f67f88847ffd3a642bed0f719f9adf5c444a40bcb015685278071cdd510fb8078330262fde5dcf884e48eb2e1f6cbadded578f49b3e2cc798f409f7209fffa99c13eb8febd52514b2d8758e055e9c0af2e35e2fabf1d555ce0fe58bb762d4a4b4b99c055a4a0dfc18df9e114347f9710d2efd9a7b8c5c24ebae0752f1764f0931b7d961fae3b0cfcab09585cac4c4354290b7ec71423cefb7b2fd2323271cb2db7057caddede5eaf7a2cdf7cd3edb119fad4a9e338b0ff80e4c496766b63911be5989d6de44eecacc1f1e757f3c732fee6c0478ee057af65c52daca54d8bc50b193afc277c675bc287f00af2dde2a5c71e7a550780f45657aad32fe0dd7c75470ea94675fb26a0a2a2429524affafa7ad9955716b9193996b3cf70c79f5f83934d7ff77a8d3319f1c32d9fe39ffbbf08eaf7ab31997239ea5feefbb4097d4e170c7a1d6ccf9dc484640e63d2ac1877e9fb1e6f3ab1ef6ede0db1770117dd4d8e1bf43ae44c76f1658569d3d291f46597636ab93b4c68c90376ce30e2771f1cc556970ef73eb05cf1cf0388a5975bbc329972c1e2efc131277f06f75ded4be87fe37168ecbeeb364e78683df6e704d74d2ee1965b6e434949090a0a0af83fdae337b87841265df0bac71b84c20688b536e88985ee73bad07c007c5ff7f77e0b55844def91d27c8014c3fcd5a546720f2a55ca4a4d4dc5bd0f2c475191c5eb35bbfd10ac562bb66ddbc699cd66d623de07b3b38ddcccdd35dc5717a762e0f165b2c2e64c468cbf733532fee6085ad80090408570f8b01d00112af5b3cfcab9cbc3c71e3afc27c98963e53c4f4b267469d4626eb1e7cf6adb49fe277de6bf50f7b3e72e444545053fa885ac5fbf1e175d64c1d0d01013b808cbd967b86935abb8ee1f67e3c46b7f963d6ffc9dab91b6650f3aef7f4df3f9acb99a50fc6d0048b058e600002f08a145d4ea7fc47fedecff50b2b587bd8bac2452c2216c803c1184fdde9b7e40febf49e7424f7797ea9f9f9d9dcdac7800ccc99fc115f43bb8294f5ecff5dc5624e9530340d2f5bf80e1b1ade8d8b857f3f9acb99a50232442f8dc121ad31e3bc3fd624292bb6558c2bf7e8dd3a2378bfbb41bf43a6cb8e524fc4417c9e78992a7ec03a4970d405a81d0ce6781d27e4407cc0052b380be8f5d7c0e8c41af435a86f76c562ad371c284644c9c98e1714cafd723353555f673e7ce5d88acac1cfcef9b6f7af9e2ebd7afc7ae5d6fe2c9279fe6465b56238d7a7cb5e46200247221666ce195482afb196c29d9aafc6eb400992851842df0e872faa9ee77251767ae7d8cf3f883e64c76e1d93ae90faa1f2ebc1a480f9b071705dfe346ee9a7d4e17fa9c87bc8e0bf36482459cdf9e99391979f9797c517df1e72c58b0000b17cee7b66c7925ee232a96b3cf7027de7c09dd326e07673222f5e77fc0d8e21f071dfd08166d7d7d3d4e9d3aeef32457dbefbc8ed9253a86351ff0df45cc92474448db658b93a3cae67aae86068a94ffab16e28111c840d9b9731752525260d0ebb859171462c28464582c73f895cf585ffe2fe87770276a5f448f4c282fe59a87a02b29c3478ea39a4e00d8afeebc0800b4be76cd9cea7e17da8cb9b24bea429f97323913304d707f7f5e21f95f2eaf7bf33b9ed70bd55fcf994c06c8df5b8865955acce9ededc5d75ffbf6c73ffae853c9e33ddd5d8a744deb73baf878b9789387d56ae56a6a6a6266bbdd9cfc19dcc9c6bfa1f78507d0278a787026239267fd0f92aebe15cddf2510413bc2dba6454b1fb1d4fa0c0cba4578e6c4619c19ec937ca3299384fa02c75bd87357785aed8d410a5bf89428fc1ac00c92676242e875566eb8e19680cf6d6f6ff758e13c78f05ffcd71d1dede8ee7637cc0a848686069c9f3f03abd63ec6cd9e1d7ce82b5cccc99fc10dbefc8ca43f9d74fd2f78410300be8bc00d0ea3a9ababe37a7b7b41bbfc0a97dccfcab90b5afd8f46dc00558cbd0b58b2d1db850926d2225e86df74bb3b53f0e69b1761ecd8f1004854235a0a0ad1c1409f201f7df4a9acf0a3319d7776b6913bbe799d57182fe9fa5f60ec8556d52686a1a2a9ababe300d269aca1a1c15360c369ad4a264549596c8ab03fbc3fca37baf3bc0d7a1dfe75652a167e7154d2e737e875f8efabafc69557cef719f98804b5b5b578e3b5adb2bf0fba132a02b7c64327894251ab1de950028dc994cb016e9f52b8f40e10ebad94b8b7bf0d3cf4aa8e5fc1bc769ef739c2688d1c03831a14548df55a7e9fb4c3b74f6732e562c58adf449dc0dbdbdbf1dc737f94b5e256ab15b5b5b5618fb4d049228d4d53418723d2a104928953e2fced912274430c7a1d36ac7205246239c489535f5e6794b5da620c7a1d9e7e6663d4091c005e78e14fb295040c7a1db6fc655b58aa0014f43bb8de171e80c67e34e6042d44362b70d3ed9e0b3a62e8e28b3fc43bdb1f5ce43e2e8738e2224628ecc264f27f30f9dcd16ac101927d28979c05900cc4c58b172b2e326112936e625ecc0a5a88dfcd0af14a340bdc9f9b525464c15b6fbda7889b42231fa7bf3e8ab1175a635ed04264c5edafca54a86464a4202b2b32fd7584e1397a2f95957747a5c07b7b7bb179f31f25573d01e2a6bcdfd834a2680a8d53c793a08568d6ae5dcb454ba88ce18d2f3f1c006a6a6a58a12219f85020237a89941f1eebb0e2f3314049490956ad7d4c367f66fdfaf5d8bc7933335222f838b792289971170c9999939199f9039fe7fce00799b23ef6942953a2d2ffa6f4f6f67a94dc10b370e17c8c86ccc34019b5d1926090cb09379b6760dcb8248f63d3a79fe7759ed2731aba9a2c859291946886e68b6bb3a6c9ae9232714700a97c70e11347fc74917aa2d4d6d6a2baba5af2faf12a70cbd967b8ef0f7c0257e32e8f1d3de7eced958cf668007006bd0e79f912f9abc34c9c780e0a0a2605740356eb85c1df75186868f824a0f36cb62ff1cd375f49bed6dddd3f22974b09844f115f69b826532e3efeb839a6053e3bdbc80dd9f6e2e4270d3ef75c1a1edb2a69bd351cf719b3dc23c4d93f884f6dad5ec7a506d47bef791e932bf8a304151515a8acac8c2971d3ccc3c17d6ff92df740195b7825dacad73071473badadede8ee766ffbb3d90ea2bf9fec94eaef3f8ee6e683fc6b720b3c426241e005fd0ece9f75f647da963d5e65d798b8e380dadaf75153f39eec624fb42df4d0955161c661a08c2dbc1263264dc5981f1831b6b01400646b093271c711ab576fc49a357f927ccd66b34574e3c3ec6c23e7aaaff59a0cca41457c568e1967e55d08adc91c7c393526eed8a3b5b51d0b173e84d9b32f4065e55c8f49fca597564aba2b9158c5a482f6552e4d0911cbc1c41da308ad2e8c38270000200049444154f4c285f3f152cdafa04f49466b6b3bcce6ebbcce379972b165cbcbaa8b9beeda114f08399311ba8979483cff128c2d2cc5988c4921556e0d0626ee1866dab4ebf9d0645191051f7cb01900f0d39faec32baf6cf73a5f0dd784facf74422814b1366b1a46525f7ba43071c730b5b5efe39a6beee3bf7ff1c535282f5f80d6d6765c5278b364052c25f663d2c59433c7fb71faeba3aab8144ac0c41de3087d6c9329176d6daf0100caca7eed153d59b8703e7ef9cb1551233eb561598131cefdf7dfcc7f6db71f426b6b3b00c06a9de9756ee3fbef85edbea20126ee18a7acec728f5c95575f25f52ee6cdfb2faf73fb9c2e2425258d9a273513771c70d34da5fcd75bb7ee0600cc9c992399ff6db3d9c2765f9126e8deef9120d0a4274a46462a66ce8ccc3ecd4870c30d73f9b0a0dd7e08cefe41e85392252bcfda6c364c9b362d12b719768216b738f70190169f380f424c2079116a6332e5222323c5e35856560ece3dd79d5e9a9d6d4476b61140f40e1a6aa56974a4bee12394955d8e2baeb85052dc8b172f8ec46d861dedb2654fc88a50cd8cb568c06e3f04bbddf358a0834e3830aeb882ac1016144c474aca785c503013fa946445efd51f422b6db31d4459d9e5282898ee759eafaabef18676c386ad91be8798443830e40644519105595939b8fefaff4259d9e5aade8fd04adb6c5f0200a64fcf923cd7683472b152267924c8eec42994313c161f06e9dc44604aa2ef0f2c1c17e09da9c0b15340bbc483a87308f8f790e7b1664105ab8363fc7783f087c9948bc71faf524de40d0d9fe0f2cb6fe73f8bc6bb359af325ce6d18152d05355df9a3679b999cb8831970c26b0807051d0cfecabadd7cf322fce52fcaf7c974f60f6282a188ff9ee33e03209d48a5d44a65b4a3bd2e845d53966460f939cadf4c3878a29bfc1f486d41835e87e9a7dda341f8d42a19479e528b2536cbd301f044b7f7e7d09c0fa505ae4f4986c994cbe79ad0884956568e97b8c52dc1e3156da00524e91ffa0683f41f14009abef5fcbefe5bef734a4456329c6e4aba16d821aa1ce1d3129f76798853f8f573c73caf53984cc47f6e2260d5939f6bc738605b2f70ef979ee7bef2ca769496fe08e5e50b14f9b928b3675fc08bfb535b2bacd60b3d223f94e6e67fa2b4b4d4eb78bce1150aa4be36b552f48fd5e074614a2290a32322aeff36f047b110b128a43e97faee6a0bbfe95bb77515ce312cc9ee9fff0603b9173a509b65c4de34e8f9bd41afc34abd8b37046281af5bf712ae2dbb42d1a84a69e98fbcb201a52226030341fcc16218ed8e1c790b5b388e08a0c109bcdaa7ccc44a8e269981422d22bd1f25a1d6b5e95b69fff9e0181dfa8e85f6f3f6395db877f8e9bf38955c5b38b0edf643f83f776d50d43d9933c7dd14d7663b08abf542a4a48cf73acf5ff7ba78c1235a62d0eb7093ce85e64122a8adaed0c52cec741648efc940294c26d6d4aa276e86926ceb750b5cec3ed57f4b8e853289fc6cb82de1f9a29ae406bd0ebd03ff6f64372d2275c27fa1cfe9c2aa557760f5ea25b29b17f6eedd1bff134a00787ab824c9bf875cbc75217f3069415af248817800c89a0974b492ff01c03245ea1dded769ee24ff770c574438d215d820103efe0b9381073394b3e8563df0ef1e225a29f743cea5f247839358efaa74cf6bf4395dfcc44f29c44beed1b8a23a122c679fe100e0f47f3a71aaa30d0030f4d9870000d73707f8dd3f86c7b642fbf424e272f8b23e06bd0e9715ba780177b4bac598d3e5e2856e99e2295adaee7a72a667ff1b7a0e20ee8be3e25fa7eff7d50aa46910b8aedddbbf0d9574ad3b0a249c1ce7e8dc4f097a9c5af040acb7f069201e2074e2a7147431e7dfffeef57f721411a8687b7c5c43f8283ad5d106ad78a2e3f5a17900e0c23f9a74e87bd7c50bbda814281a1663472bb06737b0e180dbaa67cd24c2a542dd50ed699985d69f5a7b39d1d36bfca349dab253ff76ad5319910344bcfe7e3781b2d5a5c372b8249f30b4268952d0096447473b7f4c1822a40c0d0d71e158c8515ab48172faeba39ed11261f20dc56d39ddc7a9d029657389508b86a34b54ec2f0d8b990e88c999c4fa0bc5dcd10abcf4a2fb730d7a1de9065cea3ecf3285fcbb769e0bcd9de4da52165d28f2cd69d2620a94c5a9eed5567a1da94520611445ce7afb72b5681e8852482db96764a478e5d08c94d9d946ee743719fd279b489aede9af8fe2f4978755156da09cfef23011b7258f0873cf6e97df8e60527f28da0f12efba8f59f22070655cbc6f2d143de016331d1896292e5ef47b76bbadbd41afc3ad3f7311a15790735f7f47f0d9a27bbcce497cf2e7b3429f78168e03d67d455c1fa5284c0e2e741a2c6afad8c2bd9327f679bf3ee607468cf9811189b80450398c4e371ffb3c67e952f285d07a2a41f38161eb2a129fa7e8012afc3d64f063c301f779e469e01ab6e044f4af0b7ac567cd045e9a475c1ea941d93408947c393257a532cd3b72421186507d59ee7053546451e5bacddf256890335b956b87849fd6db5af7235eddd456deddc0b0b595103d756de8c4b4a3d5db6da1d7baacd03df95c3a6cc9a5444e5d957f0f11a1066bc5d3b540fa3880a6290863fde2e5f9c264ff6b01e118005959391e3eb7d412fc68401b48635225e873cabb3c6573496444eccb532c792e7e924a84ef6deda9db52542afd147aee18b1aea1ba293718485469fa6917402377a2e57942e4f3dfcf3d37151f7df4a9c7f7a311edf84be6e1ac8c4c7cdfdd85ef7bbec2d9ff3918f60d0a6ebfd9c55b78711c9d8a7f83c882e74c26adb6b366badc31f69f11f18bfdf1a641b290b22327f8d8389d608a577385c954a1c4c169eeb59258ad17cad60c1c4d688f7f489cd8f197ccc38492324c285980f1875a71b2c38e13fb9ba0fdd73fc22af69cc92eb41fd1a1f9c0f0670e0b54287ab1bf2e14be7082ba74a6b415afecd161b34c68cee7bde9c8e4529887128c9b71ec94f731b942f723212363745a6a31da8c3b57e1fbee233871a019ddcfafc1d02bbf87a6f426a4dd58850925246b4df3d7e7d0fbba748b0aa511fbff6e51bb70a48b08596891dd7177fa1e17efabd3452431349af299393817255d4bde230c078a97e37d895d2a975c0de26d553254b403f5b548cab320fd670f42973b13ae43de1d02d26eacc2b8d92538d961c7407d2d5c0725e2402a417d75297f9d0a5bce5727c82b2a1417255d0b94f4784e24fd596fb95d4d0c75d126e55970e240337a5faf46c69dab786b2d46973b13badc991eaf0b07c2c90e3bbeef3ee2f19e13079a55f5e1fb9cae612b2e7f7d835e074de94d1837bb04c75e7cc26b6056f6e850af730565c13fcf76f169bf80dbef0e2505582dd40a07c612da71b34b907663155c875aa1cbf52ec1e50be1f9bede3bfe502bbefda81edceead210bdda0d7e1d47997e1ac8c4c9c95311963b34cfc803a71a099172d3d2f29bf1063b34c1ef735e5916a7cfdf34b3ceea1cfe9c29d1dc147512a7bd44bff652883b6efcd97f1c365eb8216763050ab8f1bab82f2df855657eafe42b9e7f1cb37a3efe19f7a1c6b1a0436f704b7758e5a6f2038bf3b5c4c9c18a3fb001544fbc365ebc2fa81d47f977211004fcb2be7228d045dee4c4c79ec2fe81409fcb963c16d883876cabd1f13f02d685f1503d4a2ac2c8a5612234444caa9e9726762ca23d5700dbb2b00785743cd2788f0f353afadf07a8254f6e8f0f9b8c05c8d742d71651a86573f85028e06eb4dab6401ca671ec60ada507c6da5e0dd950890766395d71ca0cfe9c2b65ef90dd052289516ab265215c54643dd12edc90e7bc40416295cc38b54dffd703ae0f4748dd63a75589c1ab8f5eeca97de412fb4dee726ba5f63840f2d80902225b1c6407d1d4eec6f025d91952358eb2d55ba410ccd0b1757b562a88b76a0be1667a59d83704f2cc381eb502bfade7c39e8148257fb0217b770534334464d46335aba32196f0cd4d761e895dfe3b81f51d302ed42f1370d125723d0b8b75465292139de35e079b2b2d45f2a3fb0df737957d889219ed1763efc5318f43a8c5fbe396e44fe9ff5cbfdba1fee4dcfd2198474c77a203c9f457c6eba62497d6cbaf19a0e92668901108e7454f1532b33737248d729e87770a73ada30f4d987707d7300ba8979fedf24016d6f1d2801edba91e8a4a69df2d85f42bac168c59fb0dddbd55c78fd1d41590a91b883f18fdb5dca6e458b566c29d91aa46403b3e6f2c7e85e4abafd8c6efe0db6a7bb1264892a166b699c39edc6aab0df8cd20cd4d7490adb739fa68bdfc749f7640a77dd53a4acac1c85e3484d12a9423ec15c474968b908dadd4c2d4817e004f0dbcfa8f0cbd70070ef7ea79b88c3257ece64742fe2c443c4e4c4fe26d9d7da8fe8d0fe2278911709362d4b17120a8e7313fd57908dc40453dce205004a4a4ac2f6f97cf7602a7a19f1fb2bfd102cba897924710a082d4f23daf8be473af15fb8bb9e6e4f13170a1297b508568856bd67e17da982f60c6f78f1a764937f8087db43a1830000ef0201ee721214e11341dbf9f04fa19b3e0bf1103539fb3f0725935f693e382d614177f26ca8766f2ece99ecbfac853fa4fc6e9acb2db50b0790aec2aa24c176828b563cfac7fbda813ffc440000edb4edf1b32b5a2e964d454dad76b36043b152a46b49cd45a1b56e1e241b8b01f95d38525558d5a6a0a020ec9f1909b4c2fce6298ffd25e6adb714c29d3c06bd0e4b97baf8e23f4a32259184ffc4c72289d40664bd5e1f813b093f5a4de94dc80863465e24f02ce4e9f2a86b48ab578909656b588ece5dac5eec73472aaf448d0dc8b182f6c481669cbd7b2bba9d2ee8a6cf42529e2526c382527b3f01e97d96963c60e952cf288912f55bd2b524f1aacfe9e207070d0fca4d2e95acf02a85787512206e494b4b8bc4d9f18516004e9d7719523332412327b1c8c90ee94a8f749fa5413f2c6a41752a61b14d31a16e30d89ce602d2c8d79d43be97dec381d43ca4a5a525eed35d81e10dc200d9cc2bcc6fa63b620c57df1213eecad02bbf973c4e2793744572e91a6259859d1fa47cef7343f495851193c264f7127e241673d45ec08976b4c2dd282eb845adc9c84452c6e4981076e7af2be0125928ea8e1ce922857968a52a4b9e8baf4748e990f068ac21ceb976e4b8fd6d7f0344ed1dea520b3856ab55d5cf8c26b4e32f99e7b5539cfaaf273bec443807f741377d16a63c129ec23c8140b7a8c96d3676977d00005a728d7c474382d445f947930ec2f21085c9a1973d16660856a5bb8f476275325e62dca1a2fdbee72b0cd4d70280c7865d835e87ef7e38dda3604fb4d013c00e7a613e09cd1f918a7137777afba534361d0a3718dcfeba5ce9638adae9aea375ef2445eb3ab88f1772eab515382b83a4438ecd3241339c5475ecc527009015c048a7c60692ce5a3617a09658e8920863dc14255d120af5af4b041d19a4503bdd556aef6438f34a228d960afbecff1c44af8f3269b486482485ed3ad4ea57d8803837db2599e64af34ac479dc55e9236b013825d16db969a42452ab935261402510e67900a2a5f12842dbe77401ce7d92391934ee4d8be2b80eb562a0be4e957a2281d0f7e6cb019f2b5cb8a1a27ee945728c0a7b838467539936b27bccd1b9b3032b05214129d4cc2b71f60f4a860195589d6cfe2e41333bdbc80dd9f6e2e4270d98b2ef2d4e633f8ab1855702706f46185b58ca9f3fe20f0d01af864fc282387497b8701fa241af832b02ab99815a6d71e84fb81ab96195fb8fdddce9bd703352ab0d90f73f98e1fe1a905fc051b3d4f0a736e9452da5f24a3e721c251b174acb81d27208c53eb8ef2d68ec4771fcf9d500c82602ce64846e621ec64c9a8ab372cc382bef42c9dd334ac277101617a1174f2e8565cd2291fb4da33672085bffd1967e7452b954d0208a7667a0f16e8a41af43fda4e00a624ad1f4adbb86f78ee1ad8aebbe922e4ccf719f8decc37cb07efd2bb8f7de3f781defefef0fcb228e94d8e5185b78a52aa2f7688f2d44377d16269494f12142ba939c5acf7085065d875a654bafc9415d12da07937645a33b6fa4baa085d26d410a610d137abdeb0e798702d5688d2de4a73f5d87575ed9ee71cc64cac5962d2f47c4450846ec142afab1175a31e6875382766fbcc44de3dedf771fc1f7dd5d5e6511e8ebd46d01d4dde8e0cf6253a4ba1c93f835785103d2c27e7a527055a6fc71dd2132a9a4853533f77b9f535464c1071f6c56ee4345d01ef0422a2a2a505959191593bf50c40e90ed63ba8979483cff127ee3b09ce8bd1ec2c73f7cc7cbb7155a71c07b712792717071e705ea9258f23c450d102b2e151d5152d880db1df185c5a2de64b2b6f67dc9c9647171b16a9f192c629f7d4efe0cee64e3dffc8a5d633f8a93f6a31e3b6e843e7d5bf91a5ee83e3dccd46b89b37a56c6649cd8df84a1577ecfffd252afade0453d505f87632f3ec1f7d451127f565bd87981f6b814b6e5a62b91cd9dc0860d9eef2d4c0eae6c7128347d2b7d5ccd30e06baf49bb3b0505053871e2846a9f3b12feb9ff8b90c44ed1d88f7a45fc7c8a5bb80a48232919c32ec9407d9d870f4e8bdb841bb13bb267b77bb25836575ed855e9ea0b1b900f03aa99eafabf6fbee975cca0d7e1c4891351e192044228624f9ef53f1edffb8d0d505127e61742d37d0403f5b5e87e7e0dffdaf84be6f1998303f575e8fc7585626e8a5c8e36fd6cd268d5e5d1044a389904a41baf864bd840f8c380adaded922ec9ac0b0a55f9bc701188d893aebed5a3abb05f71f7395d80c80fa73eb894054fbdb64231ff9bd65491bb2fa1ff2c8c6fd3145671b80f507ef2e80fa95457835ea75ac7b1575f7d57f278bc2dbb8bc53e3bdbc8911a2a6e828eeaeaa6cfc25969e778587000bc050748fec7480b6bba0eb5fa4d8ea28206dc6db43b0add39254261172693c51525c27dc170708c67c62100e4e58756862c10de7b4f3a13309a26936a2016361082b85d07f7793557325c7d0b4e76d8f978b46efa2cb2a2b8ae12e39793709770c249d355858b42273becfc64b4e7afcf81dbbd55f61e84bbd9a988697444aa977d557a687ddf47cab153d23b61d48c94c8f5781f0dc5e6c568972e8540108133fe9279d0646402dd5d38beaed2e38f98feb30789986ffe2500e0f8ba4ab89c2ea4ffec413e5dd5a0d74177631506eaebd0fdfc1a64dcb90aae43ad5ebd6ac418f43ab41f019a37b83c26937b767b4f1a0d7a1d56ea5d61754384c8254ca995532297bf3d9a362808d16ed8405244a9253cd21598d0e56af28d5fbe197d6fbe8ca43c0bc6669978e167dcb90a273becbcab9178f32fe13ad48aeee7d740377d167fae3fa89516d6fd13c7ae016aad47be9c3e12c47de22973e6fc4895cf9313f768a95322c6638552ecc31ee922cbd681166ecfb87315df6158d85089ae6ad238396dc9ddfb7a35bf08e4cf620bef11901f80917241a4905a7607d4cb29b9f4d24a49b7a4aeae0e696969a3ce2d91cd2d71471f489c38f128503f5c0d205817465c874f377d9687dfae44b3d2681235259ccbeecefe414c301449be16ae64a96843fb999934181567ad89ab345d56e8b9b19686dba88517be4f8c58bcc255c73e7ee32ef99e66f651fc3d3da251d480fcee9b2bae5067f1a6bee123c9e356ab75540a1b00b4e7b79030d96766d24d80760310c2c7944571652a44eaca48d500912b5926354800399fdf53d885c964af62a4268a81b0b947fab85a2b9372fe76bcc5b7834153954edc92e64192c95699e66e813192a645161fa1dc60fc784a553a299560d5479f95164373baa518e8db037d8af22d85a74dbb1e76fb21afe3369b2da696dd958417b71c25e3a47b2baa8941afc3f4d32ebeee5eb8175e46c2b153c0f93295ca4ca65cb4b5bda6f867caf9db06bd0ebbfe563f2a850d005aa91d22429e3b467e4937e95cfc0a5fd3b79e8207c84a5c30d6980a18204f8c73138990737440ba56b9d2c2e1e4d829e0ce0ef9d7fffbbfe7a8f2b9afd7be2779fc9aeb6f52e5f36205ad78078a7027891b72a07308a8ff8ab82eded6345841c6a680e568fad67fcb3eb5fcedddbb3f973c5e5656a6cae7c50ab2a1403984169712ed933b25a1835ff8e40af4a9a5567c5b6ad70d307a438014ed8ea093d3dcbf44e242287a3f1145b8b140b8ba485d2f79abec5fd837dfbc28e4fbf285dcae9b850be72b2eecd9d946ce555f8b84d474d2b62fcad10aff88feca7f459b98e576b950a496bfc529a8e19a20af58f11355ae2db7ebe69a6b941f4c1f398e6a90331b96b3cf70d39e5fc58d993415e32b974b66e4450341bb2581104c57826027a2b1c81b6f3c85b2b2cb55b9b6944b12ae284941bf83eb7de101e826e621a9ec675167cd55b1c3c159c3f815b641af43f59675aa095bce25095794c49692adc1fdaf21bffd23aeefe19b90057049d7ff024957df1a1525d654b1dc0c9243f2e73f2f576dc70d009495fd1a3b77eef23a1e89859b39f933b8c1979fe1ab4c712623527ffe078c2dfeb1aa55a57cc1c4ad300b17cec7b26565aaf7ba696d6d87d97c9dd771abd58a75ebd645cc6a8a450e0049d7ff02632fb486dd6d61e20e11932917191929b058a62325653cacd60b7141c14c5596d6a590aa28050035353598366d5ac45d82d9d946eef8e67538f1da9ff9639cc9087de92f90b4b03c2c93d051296e2a4c29a858292929e33d76cea86d910341ce6a47b25c9a1c52220748a934b527a11111b72f7101c0c489e7a0a06092eceb62c1c9110d42548368b7da52c8891c206e8b1a9350cdfbef6f524cdcf12aa6682296acb614be44ce998c48b9e6219c5d76ab32555e39eeb351e796c432725bc9a2d96a4be14be48032935026ee18a2b6f67d5c73cd7d5ec763c56a4b21155d113292492813778cd0dada8e4b0a6f965cb469686888f9ba2473f26770dfd5be84fe371e972d7a99f1374750024f50ecee18aab270e143b20952b12e6c809447db9f335bd379ff6b1ac3635bc1998c1eaf732623b3dcf1885c74c4a0d7e170e757719bd66a39fb0c77fcf93538d9f477a46dd9137c670526eee8a5b5b51dbff8c53ad91269a3a51ec99cfc195c28d11326ee28a3b5b51defbcf3ffb063c7fbb2a206622f3a1209b4ebd7bf8279f3fe4bd5041f06116d77772fffbdc371140e079938d96c5fe29b6fbef22966214cd881a1edef3f8e575f7d170505d3554bcd8c17c4b541c4df8bcb071fd87f40d15c759329179b36bd101713c870c0e773db6c0761b379f70a0780ec6c23b2b38d92af499191911a154f0267ffa06cb351b130fbfb8f7bf54a0fd492aa8941afc3ac0b0a51565686f2f2f2b89d3caac1a84c9c8a568a8a2c9838f11c582c7350505080fcfc7c1c3d1a9d5bb8620126ee3042ad30e02e73565c5c8c949494515b154a4d98b803c064f2dd5852aa8c59434303ff75b03eb2d96ce61c0e0713fc08d1fafbc301404f77d788264606bd0e691999fe4ff44346460ab4dac0fa374e98908c891333fc9e979d9ded75acb7b7174ea793fffe9b6fba31304036869e3a751cddddfdfc6b3ddd5d5eef070217b4d168e41c0e071a1b1bd1dcfc4f4c9d6a42414101cacacad0d22253978d11109ab56bd7c695e5160b1300dadb3dab524a0954e91df8e27d8c4949495c6767276c361b9a9bffe911fa5bb8703eaeb966111534b3d60aa175381cfc377abd1ea9a9ea948e127e8e14274f1e4757d7d792af89c5485143944a61b3d9306dda3498cd666eea9473bcee73e1c2f9a8a9a9f11034b3d4caa2adaef6dd0e8f111a8d8d8d98366d1a152e0790cdbbe5e5e54cd061824d2855429863ddd3d3c3b1b05ef8d158ad562ed8c997c3e1f0f2637dd1d575849f0ceefbb4296a5d09a519cd85dfa3016d57d711747501c017fc41357c59bb5dd1cbc504757575282d2d8df46d8c5a985ba2224545163cfef81f99e58e102316b770d54d8a9c9c1cc958b210bd5e1ff146a00e87039d9dd2dda99a9bffc9c7b929c2451a7fd765be7664e0e3dcbe04969d9dcdfe407e181a1ae28d84cd66e363ed0b162c607e7784d0ecddbb37d2f7c060a802db20cc885b98b819710b1337236ed10a274200593696a3b7b717369b2da00b8773b1c664ca4566e6649fe7141414f8cd9b292e2ef6f93acbbb8e2d589c5b61e442a3e21eece281c4f6452a8f2271eebc7c1f8dde25b8e28a91578395daf32887d21b75d5463c408403830e0af614f18f66d5aa3b8633d6a405172d9b7dd5405c6e01201ba5fbfb8f7b9d2bded92e24d21b898b8a2cd06ac763c28464582ca405371d04a3f989c08af2a884d4cefbfefee35e15068483a6bbbb5f72cb9a1258ad5600e4294017ec0a0a0ae27a7304137714237cb2089f287440283518ac562b727272909f9f8fb2b2b2b8598d66e28e03844f095a8f8556b10a65be51515181952b57c6bcc899b847090d0d9ff06ed1bfffdd8b8e8e769f7305835e872d7fd916d3853699b84739b4f0e6da55cf4a5af858ae4be8d5f0495c664c4c3021385f041a61f0d7f92c10c4edf7a4188dd12221be3a37c46aa964b688132252832e2b2b07e79eebb90a2a1e34e16cc41a2c720237e87578bfb129e6e2ea4cdc11a6a8c8c27f2deebf490746389f1ef12470d5c45d980c1c1ca31bf1cae06766e07c05aa1f1426034d83fecf53ebfd4a409f16f40941abef2a2dfe86864f70f9e5b77b1d8fb536255ee2ae4a079a0747f68734e875f83cdb85eb0e8dec3a55e9c0f27330e2eb00c08e1ca0fe5be0b963a1bfffbac037fc7ba0d440f7074d85a0e21f493ffaf5eb5fc1bdf7fec1eb782ced0bf510776132f07c16d0ee0afd0f091021148e0332f78fece63e3303e95a60dd57a18bb23019b8c1002c4e05b6f502f77e19fc35e8200be53ee8400ff5b3957862984cb9983dfb02ac58f193a02cbc5c43d78a8a0a54565646bdc03dc44d4579ec54e0ae4061326019360c25e3801c1d1124109cb80d7a1d6ed2b9706e2260d5bbaf01042e2ae135a624929f458caf6bd1f703e0af21fc79821168e1f0efe4f92cf7fb7fe408de7a77e5076f24aad2a57f469329179f7cb425604bee2b82120b2142cd8e1c705222f0e70a54a50395699e221412ec00b9c140c424c513dd8159afaa74f9d74ac6f9764b0c7a1d36a7913fa250d062e484e66b70520219a474505892c93d178e0bee89419f32720369e1c2f9a8ad7d24b08b01a8a9a9c3cf7eb6caeb782c4c30353b72bc27949d43a13d42473306bd0ed34fbbf8a718e0b6fe14b9c145dd41b90105480f2ae140a09fb7783812e9eb29f3f4d30f60d9b29be53f4c4459d9afb173e72eafe3454516bcf5d67b513bc164a1c028422cd692e127aad4fc45f8b4937bd2f87afab6b4ec08d8ff76f60f223bab54f249b06cd9322c5ebc7874885b890910f5e3439d442a7d3fb1027d7a00ee0122f73b0cc5ff369baf937c2d5a5730f90dc2befcd540a94a071ef45f4fd32fcf1d863ea80000079849444154679147ac123c9f15fa7b0b9347f67b290cf342649fd385a6e130ee73c77c1b07bbfd106e2dff5dc0d79e393307ab56dd21f9da6d3f5d0cb3d91c751e4002e09e848cf48f519936f21baa4a278fd8c523ac815f984ca23fe9dad07fae1b0ca1ff4c55e9c08e5c624d832594f784c2ce9dbb505bfb7ec0e7af5ebd44b23f509fd385db6e0bdc870f179ac264703b86ef379859b97002258c1084120bae4a970ebd051a0293bb174a20911b6148537c8d601691e8bdd0096228f16dfab408e6f718aafb65d0ebe0e8d8ad487830dadc13cd676670f48fd8f4adffc59ba727c987ba80e0c35672e1c44043893404572211ce04c860d9dc237f4ff4a9e50b7f02a5933ba9df4b3021513a3076e406f73e80fc5d80d0a25cc1860757afde88356bfee4753cda96e7355df9ee09e5485602e305e1a40cf06f0da9951587fd02790255a5bb63d952f8fa7b48c5c381d0168a00e0fdf737c9a6fd4a316ddaf5925bdca269f5928502238838364e9f3e7460483d31fc3d390379fa4a6132e5a2adedb580cff7153d696868888a5df78a8adba01f7972d0d39380b5ce915f47897b8905a416725eed0bcdff5eb5ea0eac5ebd24e0f3e5dc13613fa0489260d0eb140903eec8019f97112a85c9244a32d2eb00e41a4f4ff27f9e1c4f4f1a59d4225c110f71e8efde2f438feb3ff3f416b4b6066ef6e5a22776fb21ecdebd3be21e41c2e634f9c958a054a5139faf79848b253718c8ff238d71d389aa551fdafb0d7a1dacfad007d98e1cf0792ab1449fd385471ffdbf41bde7cf7f7e58f2f8d37f5807a3d1185181f313ca6026227261b360f3aee975c4597cc1f88dbeb21201ff910e29bf97de47b0110b1ab9a1d19750f2d077e4049e2846517a1536d8c9a55cee49a42797bcb8fd454a7c85bb2881fe310d7a1d56ea5db20b3581c6860b93fdaf88fa120a4df1f585af9f49188694caef083645d6924cc292c1c6c63f330377762827f0a2220b3ef86073c0e7fbca3d89e4e4921777a8bb5d84a1b358cfe110af64fada3d2395fbcd5f27802790bfa887afbf87701249d709428d92c811acf596dbb963b55ab16eddbac8881b2c1418118402150e0e3a30c4e2a6f9e6be72cd955ca708363408c8c7be23b5b181893b46910a0102cae6e1bff8e21a94972f08f87cb98dc5910a0d3271336409c57acb4d2ed7ae5d8bd2d2d2b00a9c899be19360adb7dcca6524f24e7c8a7ba4a5cc0229633652822def16e942f1b14628d65b6ee532dcd69b15c2f481bfba8900e0701c85c37154f6755f834fcd62f34a12acf5960b0d86db7a3371472152ed4c00efc1263570d478328562bde576cd87736187893b8e11b72e117667100e8c409e20c1c6bd01f9d0a0c3e1084b617b266e860772ad4aee5b764bd065d9e44283e1b2de51296ea96649a1305a6a6b47337225d9c261bdbd8acf537c4da67cb5ad036267a2e48f407b6cfaeaab492bb18a192d032f92d69bc5b9a30ca9f0ab544835968ada47ca7a4795b80d7a1dd23232255fcbc8488156eb3b669e93139a25cccece0ee97d421c0e4750e79f3c791c5d5d5f4bbe76ead4717477f77b1defe9ee0a382d593c48c403443838d47e8ac82deca86dbd5517b79460333327877cbdaeae2323bd259f042320397c0d523172bf8bcccc1f60ec58cfc1acd7eb919aea99272c1c54e201231c2481fe5c62574ce8721514b80748b04f0a29ebad76c66054596e46f088b7790907cb8409c99838d19df02e7c42d141f1cd37dd181820e987d470043bc085ad4fa4e61ffdfdc7b161c356afe34cdc0c55103e5d842e9f7040e8f57a389d4efe89409f044a3cdd00f597e399b81901419f10e2b9cfa953c743ea521c8ea578266e46440847e9b504ffa73018ca52515111969a824cdc8cb0525464095fe214a2d02d319972030a17969494781d73381c686ff7de29dbd575c463d5d46ab506742fa74e1d6739e00a61d0ebf0d9fe2fc2923405001a835ec7cdbaa050f24529f188292e2e0ef8c30a0a0aa2a60268b8181a1a0ad97834363606757e7d7dbdec6b0d0d0da1de46d0d0488c380523dc1b85357bf7ee0dfa4d46a3910b7645ce66b3c1e97406fd59912698c10b0029292951dde14b48525212d7dfef5e0975381ce8ecece4bf170e967d9f36f98d8818f43a145f7e052c963978f7dd9dfc13afa8c882679f7d21ecbf178dd56af5b22ce24738435d0c7a1de49e9e724c98900c8b654e50efd1ebf528282808ea3d42e8c0351a8ddcd2a5551e1b810d7a1d6eab204534b7546f449fd3059329172b56fc2662fd2aa3d2e766442f26532e9e7cf269a4a5a569dadadab8f2f27200eec29f7d4e170c7a1dee7d6039eeb9e79e88baa14cdc8c90a0197d62814783a8294cdc8c9010f69fece9e9e16a6b6bb172e5cab045420281899b1132d1deff9d2de23042a6bcbc1c6d6d6d516b1c7d741b8f4ee4220b393939b29b0e0a0a0aa0d7fbaf441fa938fc4862e14a136cc8b6b3b313d3a64d53f18e4227ac6e495191c523a34cbc482416612cc58c19d147c8e2162e5f0b452a142813272392f0e2163eee858f78a158a3a1fd1a831128dafefefea8884932184a93c084cd885758289011b7307133e216266e46dcc2c4cd885b98b819710b1337236e61e266c42d4cdc8cb885899b11b7307133e216266e46dcc2c4cd885b98b819710b1337236e61e266c42d4cdc8cb885899b11b7307133e216266e46dcf2ff014aec27be8fe3b5c70000000049454e44ae426082</data>
+ </image>
+</images>
+<tabstops>
+ <tabstop>m_editUsername</tabstop>
+ <tabstop>m_editPassword</tabstop>
+ <tabstop>m_textDetails</tabstop>
+ <tabstop>m_listFi</tabstop>
+ <tabstop>m_listAccount</tabstop>
+</tabstops>
+<layoutdefaults spacing="6" margin="11"/>
+</UI>
diff --git a/kmymoney2/plugins/ofximport/dialogs/konlinebankingsetupwizard.cpp b/kmymoney2/plugins/ofximport/dialogs/konlinebankingsetupwizard.cpp
new file mode 100644
index 0000000..d24f9a4
--- /dev/null
+++ b/kmymoney2/plugins/ofximport/dialogs/konlinebankingsetupwizard.cpp
@@ -0,0 +1,445 @@
+/***************************************************************************
+ konlinebankingsetupwizard.cpp
+ -------------------
+ begin : Sat Jan 7 2006
+ copyright : (C) 2006 by Ace Jones
+ email : acejones@users.sourceforge.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. *
+ * *
+ ***************************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+// ----------------------------------------------------------------------------
+// QT Includes
+
+#include <qtextbrowser.h>
+#include <qlineedit.h>
+#include <qlabel.h>
+#include <qlayout.h>
+#include <qregexp.h>
+#include <qcheckbox.h>
+#include <qtabwidget.h>
+
+// ----------------------------------------------------------------------------
+// KDE Includes
+
+#include <klocale.h>
+#include <kdebug.h>
+#include <kmessagebox.h>
+#include <kstandarddirs.h>
+#include <kprogress.h>
+#include <kapplication.h>
+#include <klistview.h>
+#include <klistviewsearchline.h>
+#include <kcombobox.h>
+#include <kurlrequester.h>
+
+// ----------------------------------------------------------------------------
+// Project Includes
+
+#include "konlinebankingsetupwizard.h"
+#include <../ofxpartner.h>
+#include <mymoneyofxconnector.h>
+
+class KOnlineBankingSetupWizard::Private
+{
+public:
+ QFile m_fpTrace;
+ QTextStream m_trace;
+};
+
+KOnlineBankingSetupWizard::KOnlineBankingSetupWizard(QWidget *parent, const char *name):
+ KOnlineBankingSetupDecl(parent,name),
+ d(new Private),
+ m_fDone(false),
+ m_fInit(false),
+ m_appId(0)
+{
+ m_appId = new OfxAppVersion(m_applicationCombo, "");
+ m_headerVersion = new OfxHeaderVersion(m_headerVersionCombo, "");
+
+ // fill the list view with banks
+ KProgressDialog* dlg = new KProgressDialog(this, 0, i18n("Loading banklist"), i18n("Getting list of banks from http://moneycentral.msn.com/\nThis may take some time depending on the available bandwidth."), true);
+ dlg->setAllowCancel(false);
+ // force to show immediately as the call to OfxPartner::BankNames()
+ // does not call the processEvents() loop
+ dlg->setMinimumDuration(0);
+ kapp->processEvents();
+
+ tabLayout->insertWidget(0, new KListViewSearchLineWidget(m_listFi, tab, 0));
+
+ OfxPartner::setDirectory(locateLocal("appdata", ""));
+ QStringList banks = OfxPartner::BankNames();
+ QStringList::const_iterator it_bank = banks.begin();
+ while (it_bank != banks.end())
+ {
+ new KListViewItem( m_listFi, (*it_bank));
+ ++it_bank;
+ }
+ m_fInit = true;
+ delete dlg;
+}
+
+KOnlineBankingSetupWizard::~KOnlineBankingSetupWizard()
+{
+ delete m_appId;
+ delete d;
+}
+
+void KOnlineBankingSetupWizard::next(void)
+{
+ bool ok = true;
+
+ switch (indexOf(currentPage()))
+ {
+ case 0:
+ ok = finishFiPage();
+ break;
+ case 1:
+ ok = finishLoginPage();
+ break;
+ case 2:
+ m_fDone = ok = finishAccountPage();
+ break;
+ }
+
+ if (ok)
+ KOnlineBankingSetupDecl::next();
+
+ setFinishEnabled(currentPage(), m_fDone );
+}
+
+bool KOnlineBankingSetupWizard::finishFiPage(void)
+{
+ bool result = false;
+
+ m_bankInfo.clear();
+ OfxFiServiceInfo info;
+
+ if(m_selectionTab->currentPageIndex() == 0) {
+
+ // Get the fipids for the selected bank
+ QListViewItem* item = m_listFi->currentItem();
+ if ( item )
+ {
+ QString bank = item->text(0);
+ m_textDetails->clear();
+ m_textDetails->append(QString("<p>Details for %1:</p>").arg(bank));
+ QStringList fipids = OfxPartner::FipidForBank(bank);
+ QStringList::const_iterator it_fipid = fipids.begin();
+ while ( it_fipid != fipids.end() )
+ {
+ // For each fipid, get the connection details
+ info = OfxPartner::ServiceInfo(*it_fipid);
+
+ // Print them to the text browser
+ QString message = QString("<p>Fipid: %1<br>").arg(*it_fipid);
+
+ // If the bank supports retrieving statements
+ if ( info.accountlist )
+ {
+ m_bankInfo.push_back(info);
+
+ message += QString("URL: %1<br>Org: %2<br>Fid: %3<br>").arg(info.url,info.org,info.fid);
+ if ( info.statements )
+ message += i18n("Supports online statements<br>");
+ if ( info.investments )
+ message += i18n("Supports investments<br>");
+ if ( info.billpay )
+ message += i18n("Supports bill payment (but not supported by KMyMoney yet)<br>");
+ }
+ else
+ {
+ message += i18n("Does not support online banking</p>");
+ }
+ m_textDetails->append(message);
+
+ ++it_fipid;
+ }
+ result = true;
+ }
+ else
+ // error! No current item
+ KMessageBox::sorry(this,i18n("Please choose a bank."));
+
+ } else { // manual entry of values
+ if(m_fid->text().isEmpty()
+ || m_url->url().isEmpty()
+ || m_bankName->text().isEmpty()) {
+ KMessageBox::sorry(this,i18n("Please fill all fields with values."));
+ }
+
+ m_textDetails->clear();
+ m_textDetails->append(QString("<p>Details for %1:</p>").arg(m_bankName->text()));
+
+ memset(&info, 0, sizeof(OfxFiServiceInfo));
+ strncpy(info.fid, m_fid->text().data(), OFX_FID_LENGTH-1);
+ strncpy(info.org, m_bankName->text().latin1(), OFX_ORG_LENGTH-1);
+ strncpy(info.url, m_url->url().data(), OFX_URL_LENGTH-1);
+ info.accountlist = 1;
+ info.statements = 1;
+ info.billpay = 1;
+ info.investments = 1;
+
+ m_bankInfo.push_back(info);
+
+ QString message;
+ message += QString("URL: %1<br>Org: %2<br>Fid: %3<br>").arg(info.url,info.org,info.fid);
+ if ( info.statements )
+ message += i18n("Supports online statements<br>");
+ if ( info.investments )
+ message += i18n("Supports investments<br>");
+ if ( info.billpay )
+ message += i18n("Supports bill payment (but not supported by KMyMoney yet)<br>");
+ m_textDetails->append(message);
+ result = true;
+ }
+ return result;
+}
+
+bool KOnlineBankingSetupWizard::finishLoginPage(void)
+{
+ bool result = true;
+
+ QString username = m_editUsername->text();
+ QString password = m_editPassword->text();
+
+ m_listAccount->clear();
+
+ // Process an account request for each fipid
+ m_it_info = m_bankInfo.begin();
+ while ( m_it_info != m_bankInfo.end() )
+ {
+ OfxFiLogin fi;
+ memset(&fi,0,sizeof(OfxFiLogin));
+ strncpy(fi.fid,(*m_it_info).fid,OFX_FID_LENGTH-1);
+ strncpy(fi.org,(*m_it_info).org,OFX_ORG_LENGTH-1);
+ strncpy(fi.userid,username.latin1(),OFX_USERID_LENGTH-1);
+ strncpy(fi.userpass,password.latin1(),OFX_USERPASS_LENGTH-1);
+
+#if LIBOFX_IS_VERSION(0,9,0)
+ // pretend we're Quicken 2008
+ // http://ofxblog.wordpress.com/2007/06/06/ofx-appid-and-appver-for-intuit-products/
+ // http://ofxblog.wordpress.com/2007/06/06/ofx-appid-and-appver-for-microsoft-money/
+ QString appId = m_appId->appId();
+ QRegExp exp("(.*):(.*)");
+ if(exp.search(appId) != -1) {
+ strncpy(fi.appid, exp.cap(1).latin1(), OFX_APPID_LENGTH-1);
+ strncpy(fi.appver, exp.cap(2).latin1(), OFX_APPVER_LENGTH-1);
+ } else {
+ strncpy(fi.appid, "QWIN", OFX_APPID_LENGTH-1);
+ strncpy(fi.appver, "1700", OFX_APPVER_LENGTH-1);
+ }
+
+ QString hver = m_headerVersion->headerVersion();
+ strncpy(fi.header_version, hver.latin1(), OFX_HEADERVERSION_LENGTH-1);
+#endif
+
+ // who owns this memory?!?!
+ char* request = libofx_request_accountinfo( &fi );
+
+ KURL filename(QString("%1response.ofx").arg(locateLocal("appdata", "")));
+ QByteArray req;
+ req.setRawData(request, strlen(request));
+ OfxHttpsRequest("POST", (*m_it_info).url, req, QMap<QString, QString>(), filename, true);
+ req.resetRawData(request, strlen(request));
+
+ LibofxContextPtr ctx = libofx_get_new_context();
+ Q_CHECK_PTR(ctx);
+
+ ofx_set_account_cb(ctx, ofxAccountCallback, this);
+ ofx_set_status_cb(ctx, ofxStatusCallback, this);
+ // Add resulting accounts to the account list
+ libofx_proc_file(ctx, filename.path(), AUTODETECT);
+ libofx_free_context(ctx);
+
+ ++m_it_info;
+ }
+
+ if ( ! m_listAccount->childCount() )
+ {
+ KMessageBox::sorry(this,i18n("No suitable accounts were found at this bank."));
+ result = false;
+ }
+ return result;
+}
+
+bool KOnlineBankingSetupWizard::finishAccountPage(void)
+{
+ bool result = true;
+
+ if ( ! m_listAccount->currentItem() )
+ {
+ KMessageBox::sorry(this,i18n("Please choose an account"));
+ result = false;
+ }
+
+ return result;
+}
+
+int KOnlineBankingSetupWizard::ofxAccountCallback(struct OfxAccountData data, void * pv)
+{
+ KOnlineBankingSetupWizard* pthis = reinterpret_cast<KOnlineBankingSetupWizard*>(pv);
+ // Put the account info in the view
+
+ MyMoneyKeyValueContainer kvps;
+
+ if ( data.account_type_valid )
+ {
+ QString type;
+ switch ( data.account_type )
+ {
+ case OfxAccountData::OFX_CHECKING: /**< A standard checking account */
+ type = "CHECKING";
+ break;
+ case OfxAccountData::OFX_SAVINGS: /**< A standard savings account */
+ type = "SAVINGS";
+ break;
+ case OfxAccountData::OFX_MONEYMRKT: /**< A money market account */
+ type = "MONEY MARKET";
+ break;
+ case OfxAccountData::OFX_CREDITLINE: /**< A line of credit */
+ type = "CREDIT LINE";
+ break;
+ case OfxAccountData::OFX_CMA: /**< Cash Management Account */
+ type = "CMA";
+ break;
+ case OfxAccountData::OFX_CREDITCARD: /**< A credit card account */
+ type = "CREDIT CARD";
+ break;
+ case OfxAccountData::OFX_INVESTMENT: /**< An investment account */
+ type = "INVESTMENT";
+ break;
+ default:
+ break;
+ }
+ kvps.setValue("type",type);
+ }
+
+ if ( data.bank_id_valid )
+ kvps.setValue("bankid",data.bank_id);
+
+ if ( data.broker_id_valid )
+ kvps.setValue("bankid",data.broker_id);
+
+ if ( data.branch_id_valid )
+ kvps.setValue("branchid",data.branch_id);
+
+ if ( data.account_number_valid )
+ kvps.setValue("accountid",data.account_number);
+
+ if ( data.account_id_valid )
+ kvps.setValue("uniqueId",data.account_id);
+
+ kvps.setValue("username",pthis->m_editUsername->text());
+ kvps.setValue("password",pthis->m_editPassword->text());
+
+ kvps.setValue("url",(*(pthis->m_it_info)).url);
+ kvps.setValue("fid",(*(pthis->m_it_info)).fid);
+ kvps.setValue("org",(*(pthis->m_it_info)).org);
+ kvps.setValue("fipid","");
+ QListViewItem* item = pthis->m_listFi->currentItem();
+ if ( item )
+ kvps.setValue("bankname",item->text(0));
+
+ // I removed the bankid here, because for some users it
+ // was not possible to setup the automatic account matching
+ // because the bankid was left empty here as well during
+ // the statement download. In case we don't have it, we
+ // simply use it blank. (ipwizard 2009-06-21)
+ if(/* !kvps.value("bankid").isEmpty()
+ && */ !kvps.value("uniqueId").isEmpty()) {
+
+ kvps.setValue("kmmofx-acc-ref", QString("%1-%2").arg(kvps.value("bankid"), kvps.value("uniqueId")));
+ } else {
+ qDebug("Cannot setup kmmofx-acc-ref for '%s'", kvps.value("bankname").data());
+ }
+ kvps.setValue("protocol","OFX");
+
+ new ListViewItem( pthis->m_listAccount, kvps );
+
+ return 0;
+}
+
+int KOnlineBankingSetupWizard::ofxStatusCallback(struct OfxStatusData data, void * pv)
+{
+ KOnlineBankingSetupWizard* pthis = reinterpret_cast<KOnlineBankingSetupWizard*>(pv);
+
+ QString message;
+
+ if(data.code_valid==true)
+ {
+ message += QString("#%1 %2: \"%3\"\n").arg(data.code).arg(data.name,data.description);
+ }
+
+ if(data.server_message_valid==true){
+ message += i18n("Server message: %1\n").arg(data.server_message);
+ }
+
+ if(data.severity_valid==true){
+ switch(data.severity){
+ case OfxStatusData::INFO :
+ break;
+ case OfxStatusData::WARN :
+ KMessageBox::detailedError( pthis, i18n("Your bank returned warnings when signing on"), i18n("WARNING %1").arg(message) );
+ break;
+ case OfxStatusData::ERROR :
+ KMessageBox::detailedError( pthis, i18n("Error signing onto your bank"), i18n("ERROR %1").arg(message) );
+ break;
+ default:
+ break;
+ }
+ }
+ return 0;
+}
+
+bool KOnlineBankingSetupWizard::chosenSettings( MyMoneyKeyValueContainer& settings )
+{
+ bool result = false;;
+
+ if ( m_fDone )
+ {
+ QListViewItem* qitem = m_listAccount->currentItem();
+ ListViewItem* item = dynamic_cast<ListViewItem*>(qitem);
+ if ( item )
+ {
+ settings = *item;
+ settings.deletePair("appId");
+ settings.deletePair("kmmofx-headerVersion");
+ QString appId = m_appId->appId();
+ if(!appId.isEmpty())
+ settings.setValue("appId", appId);
+ QString hVer = m_headerVersion->headerVersion();
+ if(!hVer.isEmpty())
+ settings.setValue("kmmofx-headerVersion", hVer);
+ result = true;
+ }
+ }
+
+ return result;
+}
+
+KOnlineBankingSetupWizard::ListViewItem::ListViewItem( QListView* parent, const MyMoneyKeyValueContainer& kvps ):
+ MyMoneyKeyValueContainer( kvps ), QListViewItem( parent )
+{
+ setText( 0, value("accountid") );
+ setText( 1, value("type") );
+ setText( 2, value("bankid") );
+ setText( 3, value("branchid") );
+}
+
+void KOnlineBankingSetupWizard::ListViewItem::x(void) {}
+
+#include "konlinebankingsetupwizard.moc"
+
+// vim:cin:si:ai:et:ts=2:sw=2:
diff --git a/kmymoney2/plugins/ofximport/dialogs/konlinebankingsetupwizard.h b/kmymoney2/plugins/ofximport/dialogs/konlinebankingsetupwizard.h
new file mode 100644
index 0000000..65a89de
--- /dev/null
+++ b/kmymoney2/plugins/ofximport/dialogs/konlinebankingsetupwizard.h
@@ -0,0 +1,106 @@
+/***************************************************************************
+ konlinebankingsetupwizard.h
+ -------------------
+ begin : Sat Jan 7 2006
+ copyright : (C) 2006 by Ace Jones
+ email : acejones@users.sourceforge.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. *
+ * *
+ ***************************************************************************/
+
+#ifndef KONLINEBANKINGSETUPWIZARD_H
+#define KONLINEBANKINGSETUPWIZARD_H
+
+// ----------------------------------------------------------------------------
+// Library Includes
+
+#include <libofx/libofx.h>
+
+// ----------------------------------------------------------------------------
+// QT Includes
+
+#include <qwidget.h>
+#include <qvaluelist.h>
+#include <qlistview.h>
+
+// ----------------------------------------------------------------------------
+// KDE Includes
+
+// ----------------------------------------------------------------------------
+// Project Includes
+
+#include "konlinebankingsetupdecl.h"
+#include <kmymoney/mymoneykeyvaluecontainer.h>
+class OfxAppVersion;
+class OfxHeaderVersion;
+
+/**
+ * @author Ace Jones
+ */
+
+/**
+ * This class implementes a wizard for setting up an existing account
+ * with online banking.
+ *
+ * The user is asked to choose his bank from the supported bank, and
+ * his account.
+ *
+ * Currently works only with OFX Direct Connect, but I imagined that
+ * other protocols could be included here. To accomodate this, we'd
+ * add another page at the start of the wizard to ask which protocol
+ * they wanted.
+ *
+ */
+class KOnlineBankingSetupWizard : public KOnlineBankingSetupDecl
+{
+ Q_OBJECT
+public:
+ class ListViewItem: public MyMoneyKeyValueContainer, public QListViewItem
+ {
+ public:
+ ListViewItem( QListView* parent, const MyMoneyKeyValueContainer& kvps );
+ virtual void x(void);
+ };
+
+ KOnlineBankingSetupWizard(QWidget *parent=0, const char *name=0);
+ ~KOnlineBankingSetupWizard();
+
+ bool chosenSettings( MyMoneyKeyValueContainer& settings );
+
+ bool isInit(void) const { return m_fInit; }
+
+public slots:
+ void next();
+
+protected:
+ bool finishAccountPage(void);
+ bool finishLoginPage(void);
+ bool finishFiPage(void);
+ bool post(const char* request, const char* url,const char* filename);
+
+ static int ofxAccountCallback(struct OfxAccountData data, void * pv);
+ static int ofxStatusCallback(struct OfxStatusData data, void * pv);
+
+private:
+ /// \internal d-pointer class.
+ class Private;
+ /// \internal d-pointer instance.
+ Private* const d;
+
+ QValueList<OfxFiServiceInfo> m_bankInfo;
+ QValueList<OfxFiServiceInfo>::const_iterator m_it_info;
+ bool m_fDone;
+ bool m_fInit;
+ OfxAppVersion* m_appId;
+ OfxHeaderVersion* m_headerVersion;
+};
+
+#endif
+// vim:cin:si:ai:et:ts=2:sw=2:
diff --git a/kmymoney2/plugins/ofximport/dialogs/konlinebankingstatus.cpp b/kmymoney2/plugins/ofximport/dialogs/konlinebankingstatus.cpp
new file mode 100644
index 0000000..6e5cef9
--- /dev/null
+++ b/kmymoney2/plugins/ofximport/dialogs/konlinebankingstatus.cpp
@@ -0,0 +1,112 @@
+/***************************************************************************
+ konlinebankingstatus.cpp
+ -------------------
+ begin : Wed Apr 16 2008
+ copyright : (C) 2008 by Thomas Baumgart
+ email : ipwizard@users.sourceforge.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. *
+ * *
+ ***************************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+
+// ----------------------------------------------------------------------------
+// System Includes
+
+// ----------------------------------------------------------------------------
+// QT Includes
+
+#include <qlabel.h>
+#include <qpushbutton.h>
+#include <qradiobutton.h>
+#include <qspinbox.h>
+#include <qdatetimeedit.h>
+
+// ----------------------------------------------------------------------------
+// KDE Includes
+
+#include <klocale.h>
+#include <kled.h>
+#include <kcombobox.h>
+
+// ----------------------------------------------------------------------------
+// Project Includes
+
+#include "konlinebankingstatus.h"
+#include <kmymoney/mymoneykeyvaluecontainer.h>
+#include <kmymoney/mymoneyaccount.h>
+#include <libofx/libofx.h>
+#include "mymoneyofxconnector.h"
+
+KOnlineBankingStatus::KOnlineBankingStatus(const MyMoneyAccount& acc, QWidget *parent, const char *name) :
+ KOnlineBankingStatusDecl(parent,name),
+ m_appId(0)
+{
+ m_ledOnlineStatus->off();
+
+ // Set up online banking settings if applicable
+ MyMoneyKeyValueContainer settings = acc.onlineBankingSettings();
+ m_textOnlineStatus->setText(i18n("Enabled & configured"));
+ m_ledOnlineStatus->on();
+
+ QString account = settings.value("accountid");
+ QString bank = settings.value("bankname");
+ QString bankid = QString("%1 %2").arg(settings.value("bankid")).arg(settings.value("branchid"));
+ if ( bankid.length() > 1 )
+ bank += QString(" (%1)").arg(bankid);
+ m_textBank->setText(bank);
+ m_textOnlineAccount->setText(account);
+
+ m_appId = new OfxAppVersion(m_applicationCombo, settings.value("appId"));
+ m_headerVersion = new OfxHeaderVersion(m_headerVersionCombo, settings.value("kmmofx-headerVersion"));
+
+ int numDays = 60;
+ QString snumDays = settings.value("kmmofx-numRequestDays");
+ if (!snumDays.isEmpty())
+ numDays = snumDays.toInt();
+ m_numdaysSpin->setValue(numDays);
+ m_todayRB->setChecked(settings.value("kmmofx-todayMinus").isEmpty() || settings.value("kmmofx-todayMinus").toInt() != 0);
+ m_lastUpdateRB->setChecked(!settings.value("kmmofx-lastUpdate").isEmpty() && settings.value("kmmofx-lastUpdate").toInt() != 0);
+ m_lastUpdateTXT->setText(acc.value("lastImportedTransactionDate"));
+ m_pickDateRB->setChecked(!settings.value("kmmofx-pickDate").isEmpty() && settings.value("kmmofx-pickDate").toInt() != 0);
+ QString specificDate = settings.value("kmmofx-specificDate");
+ if (!specificDate.isEmpty())
+ m_specificDate->setDate(QDate::fromString(specificDate));
+ else
+ m_specificDate->setDate(QDate::currentDate());
+ m_specificDate->setMaxValue(QDate::currentDate());
+ m_payeeidRB->setChecked(settings.value("kmmofx-preferPayeeid").isEmpty() || settings.value("kmmofx-preferPayeeid").toInt() != 0);
+ m_nameRB->setChecked(!settings.value("kmmofx-preferName").isEmpty() && settings.value("kmmofx-preferName").toInt() != 0);
+}
+
+KOnlineBankingStatus::~KOnlineBankingStatus()
+{
+ delete m_appId;
+}
+
+const QString& KOnlineBankingStatus::appId(void) const
+{
+ if(m_appId)
+ return m_appId->appId();
+ return QString::null;
+}
+
+QString KOnlineBankingStatus::headerVersion(void) const
+{
+ if(m_headerVersion)
+ return m_headerVersion->headerVersion();
+ return QString::null;
+}
+
+#include "konlinebankingstatus.moc"
+
diff --git a/kmymoney2/plugins/ofximport/dialogs/konlinebankingstatus.h b/kmymoney2/plugins/ofximport/dialogs/konlinebankingstatus.h
new file mode 100644
index 0000000..bbd62ea
--- /dev/null
+++ b/kmymoney2/plugins/ofximport/dialogs/konlinebankingstatus.h
@@ -0,0 +1,58 @@
+/***************************************************************************
+ konlinebankingstatus.h
+ -------------------
+ begin : Wed Apr 16 2008
+ copyright : (C) 2008 by Thomas Baumgart
+ email : ipwizard@users.sourceforge.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. *
+ * *
+ ***************************************************************************/
+
+#ifndef KONLINEBANKINGSTATUS_H
+#define KONLINEBANKINGSTATUS_H
+
+// ----------------------------------------------------------------------------
+// Library Includes
+
+// ----------------------------------------------------------------------------
+// QT Includes
+
+#include <qwidget.h>
+
+// ----------------------------------------------------------------------------
+// KDE Includes
+
+// ----------------------------------------------------------------------------
+// Project Includes
+
+#include "konlinebankingstatusdecl.h"
+class MyMoneyAccount;
+class OfxAppVersion;
+class OfxHeaderVersion;
+
+/**
+ * @author Thomas Baumgart
+ */
+
+class KOnlineBankingStatus : public KOnlineBankingStatusDecl
+{
+ Q_OBJECT
+public:
+ KOnlineBankingStatus(const MyMoneyAccount& acc, QWidget *parent=0, const char *name=0);
+ ~KOnlineBankingStatus();
+ const QString& appId(void) const;
+ QString headerVersion(void) const;
+private:
+ OfxAppVersion* m_appId;
+ OfxHeaderVersion* m_headerVersion;
+};
+
+#endif
+// vim:cin:si:ai:et:ts=2:sw=2:
diff --git a/kmymoney2/plugins/ofximport/dialogs/konlinebankingstatusdecl.ui b/kmymoney2/plugins/ofximport/dialogs/konlinebankingstatusdecl.ui
new file mode 100644
index 0000000..f76f9e4
--- /dev/null
+++ b/kmymoney2/plugins/ofximport/dialogs/konlinebankingstatusdecl.ui
@@ -0,0 +1,483 @@
+<!DOCTYPE UI><UI version="3.3" stdsetdef="1">
+<class>KOnlineBankingStatusDecl</class>
+<widget class="QWidget">
+ <property name="name">
+ <cstring>KOnlineBankingStatusDecl</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>568</width>
+ <height>529</height>
+ </rect>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QGroupBox">
+ <property name="name">
+ <cstring>groupBox1</cstring>
+ </property>
+ <property name="title">
+ <string>Account Details</string>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLabel" row="1" column="1">
+ <property name="name">
+ <cstring>m_textBank</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>1</hsizetype>
+ <vsizetype>0</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="font">
+ <font>
+ <bold>1</bold>
+ </font>
+ </property>
+ <property name="text">
+ <string>&amp;lt;Not configured&amp;gt;</string>
+ </property>
+ </widget>
+ <widget class="QLabel" row="1" column="0">
+ <property name="name">
+ <cstring>textLabel2</cstring>
+ </property>
+ <property name="text">
+ <string>BANK/BROKER:</string>
+ </property>
+ </widget>
+ <widget class="QLabel" row="2" column="1">
+ <property name="name">
+ <cstring>m_textOnlineAccount</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>1</hsizetype>
+ <vsizetype>0</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="font">
+ <font>
+ <bold>1</bold>
+ </font>
+ </property>
+ <property name="text">
+ <string>&amp;lt;Not configured&amp;gt;</string>
+ </property>
+ </widget>
+ <widget class="QLayoutWidget" row="0" column="1">
+ <property name="name">
+ <cstring>layout5</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="KLed">
+ <property name="name">
+ <cstring>m_ledOnlineStatus</cstring>
+ </property>
+ <property name="state">
+ <enum>Off</enum>
+ </property>
+ </widget>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>m_textOnlineStatus</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>0</hsizetype>
+ <vsizetype>4</vsizetype>
+ <horstretch>10</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text">
+ <string>Unavailable</string>
+ </property>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>spacer4</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>41</width>
+ <height>21</height>
+ </size>
+ </property>
+ </spacer>
+ </hbox>
+ </widget>
+ <widget class="QLabel" row="2" column="0">
+ <property name="name">
+ <cstring>textLabel3</cstring>
+ </property>
+ <property name="text">
+ <string>ACCOUNT:</string>
+ </property>
+ </widget>
+ <widget class="QLabel" row="0" column="0">
+ <property name="name">
+ <cstring>textLabel1</cstring>
+ </property>
+ <property name="text">
+ <string>STATUS:</string>
+ </property>
+ </widget>
+ </grid>
+ </widget>
+ <widget class="QGroupBox">
+ <property name="name">
+ <cstring>groupBox2</cstring>
+ </property>
+ <property name="title">
+ <string>OFX Details</string>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout8</cstring>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLabel" row="1" column="0">
+ <property name="name">
+ <cstring>textLabel1_3</cstring>
+ </property>
+ <property name="text">
+ <string>Header Version</string>
+ </property>
+ </widget>
+ <widget class="KComboBox" row="0" column="1">
+ <property name="name">
+ <cstring>m_applicationCombo</cstring>
+ </property>
+ </widget>
+ <spacer row="0" column="2">
+ <property name="name">
+ <cstring>spacer4_2</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>150</width>
+ <height>21</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="KComboBox" row="1" column="1">
+ <property name="name">
+ <cstring>m_headerVersionCombo</cstring>
+ </property>
+ </widget>
+ <widget class="QLabel" row="0" column="0">
+ <property name="name">
+ <cstring>textLabel1_2</cstring>
+ </property>
+ <property name="text">
+ <string>Identify as</string>
+ </property>
+ </widget>
+ </grid>
+ </widget>
+ <widget class="QButtonGroup">
+ <property name="name">
+ <cstring>buttonGroup2</cstring>
+ </property>
+ <property name="margin">
+ <number>0</number>
+ </property>
+ <property name="midLineWidth">
+ <number>0</number>
+ </property>
+ <property name="title">
+ <string>Start date of import</string>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout17</cstring>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout8</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QRadioButton">
+ <property name="name">
+ <cstring>m_todayRB</cstring>
+ </property>
+ <property name="text">
+ <string>To&amp;day minus</string>
+ </property>
+ <property name="checked">
+ <bool>true</bool>
+ </property>
+ </widget>
+ <widget class="QSpinBox">
+ <property name="name">
+ <cstring>m_numdaysSpin</cstring>
+ </property>
+ <property name="maxValue">
+ <number>180</number>
+ </property>
+ </widget>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>textLabel2_2</cstring>
+ </property>
+ <property name="text">
+ <string>days</string>
+ </property>
+ </widget>
+ </hbox>
+ </widget>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout16</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QRadioButton">
+ <property name="name">
+ <cstring>m_lastUpdateRB</cstring>
+ </property>
+ <property name="text">
+ <string>Last &amp;update</string>
+ </property>
+ </widget>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>m_lastUpdateTXT</cstring>
+ </property>
+ <property name="text">
+ <string></string>
+ </property>
+ </widget>
+ </hbox>
+ </widget>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout7</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QRadioButton">
+ <property name="name">
+ <cstring>m_pickDateRB</cstring>
+ </property>
+ <property name="text">
+ <string>Pi&amp;ck date</string>
+ </property>
+ </widget>
+ <widget class="QDateEdit">
+ <property name="name">
+ <cstring>m_specificDate</cstring>
+ </property>
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ <property name="order">
+ <enum>YMD</enum>
+ </property>
+ <property name="date">
+ <date>
+ <year>2000</year>
+ <month>1</month>
+ <day>1</day>
+ </date>
+ </property>
+ </widget>
+ </hbox>
+ </widget>
+ </vbox>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>spacer10</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>41</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </hbox>
+ </widget>
+ <widget class="QGroupBox">
+ <property name="name">
+ <cstring>groupBox3</cstring>
+ </property>
+ <property name="title">
+ <string>Name is derived from</string>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout11</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QButtonGroup">
+ <property name="name">
+ <cstring>buttonGroup1</cstring>
+ </property>
+ <property name="frameShape">
+ <enum>NoFrame</enum>
+ </property>
+ <property name="title">
+ <string></string>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>0</number>
+ </property>
+ <property name="spacing">
+ <number>1</number>
+ </property>
+ <widget class="QRadioButton">
+ <property name="name">
+ <cstring>m_payeeidRB</cstring>
+ </property>
+ <property name="text">
+ <string>P&amp;AYEEID</string>
+ </property>
+ <property name="checked">
+ <bool>true</bool>
+ </property>
+ </widget>
+ <widget class="QRadioButton">
+ <property name="name">
+ <cstring>m_nameRB</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;NAME</string>
+ </property>
+ </widget>
+ </vbox>
+ </widget>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>textLabel3_2</cstring>
+ </property>
+ <property name="text">
+ <string>field if both are present in download</string>
+ </property>
+ </widget>
+ </hbox>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>spacer11_2</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>31</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </hbox>
+ </widget>
+ </vbox>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>spacer11</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Vertical</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>20</width>
+ <height>50</height>
+ </size>
+ </property>
+ </spacer>
+ </vbox>
+</widget>
+<connections>
+ <connection>
+ <sender>m_pickDateRB</sender>
+ <signal>toggled(bool)</signal>
+ <receiver>m_specificDate</receiver>
+ <slot>setEnabled(bool)</slot>
+ </connection>
+ <connection>
+ <sender>m_todayRB</sender>
+ <signal>toggled(bool)</signal>
+ <receiver>m_numdaysSpin</receiver>
+ <slot>setEnabled(bool)</slot>
+ </connection>
+</connections>
+<layoutdefaults spacing="6" margin="11"/>
+</UI>
diff --git a/kmymoney2/plugins/ofximport/dialogs/mymoneyofxconnector.cpp b/kmymoney2/plugins/ofximport/dialogs/mymoneyofxconnector.cpp
new file mode 100644
index 0000000..6e841bb
--- /dev/null
+++ b/kmymoney2/plugins/ofximport/dialogs/mymoneyofxconnector.cpp
@@ -0,0 +1,725 @@
+/***************************************************************************
+ mymoneyofxconnector.cpp
+ -------------------
+ begin : Sat Nov 13 2004
+ copyright : (C) 2002 by Ace Jones
+ email : acejones@users.sourceforge.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. *
+ * *
+ ***************************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+// ----------------------------------------------------------------------------
+// System Includes
+
+#include <libofx/libofx.h>
+
+// ----------------------------------------------------------------------------
+// QT Includes
+
+#include <qdatetime.h>
+#include <qregexp.h>
+
+// ----------------------------------------------------------------------------
+// KDE Includes
+
+#include <klocale.h>
+#include <kdebug.h>
+#include <kcombobox.h>
+
+// ----------------------------------------------------------------------------
+// Project Includes
+
+#include <kmymoney/mymoneyfile.h>
+#include <kmymoney/mymoneyaccount.h>
+#include <kmymoney/mymoneyinstitution.h>
+#include <kmymoney/mymoneykeyvaluecontainer.h>
+#include "mymoneyofxconnector.h"
+
+OfxHeaderVersion::OfxHeaderVersion(KComboBox* combo, const QString& headerVersion) :
+ m_combo(combo)
+{
+ combo->clear();
+ combo->insertItem("102");
+ combo->insertItem("103");
+
+ if(!headerVersion.isEmpty()) {
+ combo->setCurrentItem(headerVersion);
+ } else {
+ combo->setCurrentItem("102");
+ }
+
+#if ! LIBOFX_IS_VERSION(0,9,0)
+ // This feature does not work with libOFX < 0.9 so
+ // we just make disable the button in this case
+ combo->setDisabled(true);
+#endif
+}
+
+QString OfxHeaderVersion::headerVersion(void) const
+{
+ return m_combo->currentText();
+}
+
+OfxAppVersion::OfxAppVersion(KComboBox* combo, const QString& appId) :
+ m_combo(combo)
+{
+// http://ofxblog.wordpress.com/2007/06/06/ofx-appid-and-appver-for-intuit-products/
+// http://ofxblog.wordpress.com/2007/06/06/ofx-appid-and-appver-for-microsoft-money/
+
+ // Quicken
+ m_appMap[i18n("Quicken Windows 2003")] = "QWIN:1200";
+ m_appMap[i18n("Quicken Windows 2004")] = "QWIN:1300";
+ m_appMap[i18n("Quicken Windows 2005")] = "QWIN:1400";
+ m_appMap[i18n("Quicken Windows 2006")] = "QWIN:1500";
+ m_appMap[i18n("Quicken Windows 2007")] = "QWIN:1600";
+ m_appMap[i18n("Quicken Windows 2008")] = "QWIN:1700";
+
+ // MS-Money
+ m_appMap[i18n("MS-Money 2003")] = "Money:1100";
+ m_appMap[i18n("MS-Money 2004")] = "Money:1200";
+ m_appMap[i18n("MS-Money 2005")] = "Money:1400";
+ m_appMap[i18n("MS-Money 2006")] = "Money:1500";
+ m_appMap[i18n("MS-Money 2007")] = "Money:1600";
+ m_appMap[i18n("MS-Money Plus")] = "Money:1700";
+
+ // KMyMoney
+ m_appMap["KMyMoney"] = "KMyMoney:1000";
+
+ combo->clear();
+ combo->insertStringList(m_appMap.keys());
+
+ QMap<QString, QString>::const_iterator it_a;
+ for(it_a = m_appMap.begin(); it_a != m_appMap.end(); ++it_a) {
+ if(*it_a == appId)
+ break;
+ }
+
+ if(it_a != m_appMap.end()) {
+ combo->setCurrentItem(it_a.key());
+ } else {
+ combo->setCurrentItem(i18n("Quicken Windows 2008"));
+ }
+
+#if ! LIBOFX_IS_VERSION(0,9,0)
+ // This feature does not work with libOFX < 0.9 so
+ // we just make disable the button in this case
+ combo->setDisabled(true);
+#endif
+}
+
+const QString& OfxAppVersion::appId(void) const
+{
+ static QString defaultAppId("QWIN:1700");
+
+ QString app = m_combo->currentText();
+ if(m_appMap[app] != defaultAppId)
+ return m_appMap[app];
+ return QString::null;
+}
+
+MyMoneyOfxConnector::MyMoneyOfxConnector(const MyMoneyAccount& _account):
+ m_account(_account)
+{
+ m_fiSettings = m_account.onlineBankingSettings();
+}
+
+QString MyMoneyOfxConnector::iban(void) const { return m_fiSettings.value("bankid"); }
+QString MyMoneyOfxConnector::fiorg(void) const { return m_fiSettings.value("org"); }
+QString MyMoneyOfxConnector::fiid(void) const { return m_fiSettings.value("fid"); }
+QString MyMoneyOfxConnector::username(void) const { return m_fiSettings.value("username"); }
+QString MyMoneyOfxConnector::password(void) const { return m_fiSettings.value("password"); }
+QString MyMoneyOfxConnector::accountnum(void) const { return m_fiSettings.value("accountid"); }
+QString MyMoneyOfxConnector::url(void) const { return m_fiSettings.value("url"); }
+
+QDate MyMoneyOfxConnector::statementStartDate(void) const {
+ if ((m_fiSettings.value("kmmofx-todayMinus").toInt() != 0) && !m_fiSettings.value("kmmofx-numRequestDays").isEmpty())
+ {
+ return QDate::currentDate().addDays(-m_fiSettings.value("kmmofx-numRequestDays").toInt());
+ }
+ else if ((m_fiSettings.value("kmmofx-lastUpdate").toInt() != 0) && !m_account.value("lastImportedTransactionDate").isEmpty())
+ {
+ return QDate::fromString(m_account.value("lastImportedTransactionDate"), Qt::ISODate);
+ }
+ else if ((m_fiSettings.value("kmmofx-pickDate").toInt() != 0) && !m_fiSettings.value("kmmofx-specificDate").isEmpty())
+ {
+ return QDate::fromString(m_fiSettings.value("kmmofx-specificDate"));
+ }
+ return QDate::currentDate().addMonths(-2);
+}
+
+#if LIBOFX_IS_VERSION(0,9,0)
+OfxAccountData::AccountType MyMoneyOfxConnector::accounttype(void) const
+{
+ OfxAccountData::AccountType result = OfxAccountData::OFX_CHECKING;
+
+ QString type = m_account.onlineBankingSettings()["type"];
+ if(type == "CHECKING")
+ result = OfxAccountData::OFX_CHECKING;
+ else if(type == "SAVINGS")
+ result = OfxAccountData::OFX_SAVINGS;
+ else if(type == "MONEY MARKET")
+ result = OfxAccountData::OFX_MONEYMRKT;
+ else if(type == "CREDIT LINE")
+ result = OfxAccountData::OFX_CREDITLINE;
+ else if(type == "CMA")
+ result = OfxAccountData::OFX_CMA;
+ else if(type == "CREDIT CARD")
+ result = OfxAccountData::OFX_CREDITCARD;
+ else if(type == "INVESTMENT")
+ result = OfxAccountData::OFX_INVESTMENT;
+ else {
+ switch( m_account.accountType()) {
+ case MyMoneyAccount::Investment:
+ result = OfxAccountData::OFX_INVESTMENT;
+ break;
+ case MyMoneyAccount::CreditCard:
+ result = OfxAccountData::OFX_CREDITCARD;
+ break;
+ case MyMoneyAccount::Savings:
+ result = OfxAccountData::OFX_SAVINGS;
+ break;
+ default:
+ break;
+ }
+ }
+
+ // This is a bit of a personalized hack. Sometimes we may want to override the
+ // ofx type for an account. For now, I will stash it in the notes!
+
+ QRegExp rexp("OFXTYPE:([A-Z]*)");
+ if ( rexp.search(m_account.description()) != -1 )
+ {
+ QString override = rexp.cap(1);
+ kdDebug(2) << "MyMoneyOfxConnector::accounttype() overriding to " << result << endl;
+
+ if ( override == "BANK" )
+ result = OfxAccountData::OFX_CHECKING;
+ else if ( override == "CC" )
+ result = OfxAccountData::OFX_CREDITCARD;
+ else if ( override == "INV" )
+ result = OfxAccountData::OFX_INVESTMENT;
+ else if ( override == "MONEYMARKET")
+ result = OfxAccountData::OFX_MONEYMRKT;
+ }
+
+ return result;
+}
+#else
+AccountType MyMoneyOfxConnector::accounttype(void) const
+{
+ AccountType result = OFX_BANK_ACCOUNT;
+
+ switch( m_account.accountType() )
+ {
+ case MyMoneyAccount::Investment:
+ result = OFX_INVEST_ACCOUNT;
+ break;
+ case MyMoneyAccount::CreditCard:
+ result = OFX_CREDITCARD_ACCOUNT;
+ break;
+ default:
+ break;
+ }
+
+ // This is a bit of a personalized hack. Sometimes we may want to override the
+ // ofx type for an account. For now, I will stash it in the notes!
+
+ QRegExp rexp("OFXTYPE:([A-Z]*)");
+ if ( rexp.search(m_account.description()) != -1 )
+ {
+ QString override = rexp.cap(1);
+ kdDebug(2) << "MyMoneyOfxConnector::accounttype() overriding to " << result << endl;
+
+ if ( override == "BANK" )
+ result = OFX_BANK_ACCOUNT;
+ else if ( override == "CC" )
+ result = OFX_CREDITCARD_ACCOUNT;
+ else if ( override == "INV" )
+ result = OFX_INVEST_ACCOUNT;
+#if 0 // money market is not supported by 0.8.x
+ else if ( override == "MONEYMARKET")
+ result = OFX_MONEYMRKT;
+#endif
+ }
+
+ return result;
+}
+#endif
+
+void MyMoneyOfxConnector::initRequest(OfxFiLogin* fi) const
+{
+ memset(fi,0,sizeof(OfxFiLogin));
+ strncpy(fi->fid, fiid().latin1(), OFX_FID_LENGTH-1);
+ strncpy(fi->org, fiorg().latin1(), OFX_ORG_LENGTH-1);
+ strncpy(fi->userid, username().latin1(), OFX_USERID_LENGTH-1);
+ strncpy(fi->userpass, password().latin1(), OFX_USERPASS_LENGTH-1);
+
+#if LIBOFX_IS_VERSION(0,9,0)
+ // If we don't know better, we pretend to be Quicken 2008
+ // http://ofxblog.wordpress.com/2007/06/06/ofx-appid-and-appver-for-intuit-products/
+ // http://ofxblog.wordpress.com/2007/06/06/ofx-appid-and-appver-for-microsoft-money/
+ QString appId = m_account.onlineBankingSettings().value("appId");
+ QRegExp exp("(.*):(.*)");
+ if(exp.search(appId) != -1) {
+ strncpy(fi->appid, exp.cap(1).latin1(), OFX_APPID_LENGTH-1);
+ strncpy(fi->appver, exp.cap(2).latin1(), OFX_APPVER_LENGTH-1);
+ } else {
+ strncpy(fi->appid, "QWIN", OFX_APPID_LENGTH-1);
+ strncpy(fi->appver, "1700", OFX_APPVER_LENGTH-1);
+ }
+
+ QString headerVersion = m_account.onlineBankingSettings().value("kmmofx-headerVersion");
+ if(!headerVersion.isEmpty()) {
+ strncpy(fi->header_version, headerVersion.latin1(), OFX_HEADERVERSION_LENGTH-1);
+ }
+#endif
+}
+
+const QByteArray MyMoneyOfxConnector::statementRequest(void) const
+{
+ OfxFiLogin fi;
+ initRequest(&fi);
+
+#if LIBOFX_IS_VERSION(0,9,0)
+ OfxAccountData account;
+ memset(&account,0,sizeof(OfxAccountData));
+
+ if(iban().latin1() != 0) {
+ strncpy(account.bank_id,iban().latin1(),OFX_BANKID_LENGTH-1);
+ strncpy(account.broker_id,iban().latin1(),OFX_BROKERID_LENGTH-1);
+ }
+ strncpy(account.account_number,accountnum().latin1(),OFX_ACCTID_LENGTH-1);
+ account.account_type = accounttype();
+#else
+ OfxAccountInfo account;
+ memset(&account,0,sizeof(OfxAccountInfo));
+
+ if(iban().latin1() != 0) {
+ strncpy(account.bankid,iban().latin1(),OFX_BANKID_LENGTH-1);
+ strncpy(account.brokerid,iban().latin1(),OFX_BROKERID_LENGTH-1);
+ }
+ strncpy(account.accountid,accountnum().latin1(),OFX_ACCOUNT_ID_LENGTH-1);
+ account.type = accounttype();
+#endif
+
+ char* szrequest = libofx_request_statement( &fi, &account, QDateTime(statementStartDate()).toTime_t() );
+ QString request = szrequest;
+ // remove the trailing zero
+ QByteArray result = request.utf8();
+ result.truncate(result.size()-1);
+ free(szrequest);
+
+ QString msg(result);
+ return result;
+}
+
+#if 0
+// this code is not used anymore. The logic is now
+// contained in KOnlineBankingSetupWizard::finishLoginPage(void)
+const QByteArray MyMoneyOfxConnector::accountInfoRequest(void) const
+{
+ OfxFiLogin fi;
+ initRequest(&fi);
+
+ char* szrequest = libofx_request_accountinfo( &fi );
+ QString request = szrequest;
+ // remove the trailing zero
+ QByteArray result = request.utf8();
+ result.truncate(result.size()-1);
+ free(szrequest);
+
+ return result;
+}
+#endif
+
+#if 0
+
+MyMoneyOfxConnector::Tag MyMoneyOfxConnector::message(const QString& _msgType, const QString& _trnType, const Tag& _request)
+{
+ return Tag(_msgType+"MSGSRQV1")
+ .subtag(Tag(_trnType+"TRNRQ")
+ .element("TRNUID",uuid())
+ .element("CLTCOOKIE","1")
+ .subtag(_request));
+}
+
+MyMoneyOfxConnector::Tag MyMoneyOfxConnector::investmentRequest(void) const
+{
+ QString dtnow_string = QDateTime::currentDateTime().toString(Qt::ISODate).remove(QRegExp("[^0-9]"));
+ QString dtstart_string = _dtstart.toString(Qt::ISODate).remove(QRegExp("[^0-9]"));
+
+ return message("INVSTMT","INVSTMT",Tag("INVSTMTRQ")
+ .subtag(Tag("INVACCTFROM").element("BROKERID", fiorg()).element("ACCTID", accountnum()))
+ .subtag(Tag("INCTRAN").element("DTSTART",dtstart_string).element("INCLUDE","Y"))
+ .element("INCOO","Y")
+ .subtag(Tag("INCPOS").element("DTASOF", dtnow_string).element("INCLUDE","Y"))
+ .element("INCBAL","Y"));
+}
+
+MyMoneyOfxConnector::Tag MyMoneyOfxConnector::bankStatementRequest(const QDate& _dtstart) const
+{
+ QString dtstart_string = _dtstart.toString(Qt::ISODate).remove(QRegExp("[^0-9]"));
+
+ return message("BANK","STMT",Tag("STMTRQ")
+ .subtag(Tag("BANKACCTFROM").element("BANKID", iban()).element("ACCTID", accountnum()).element("ACCTTYPE", "CHECKING"))
+ .subtag(Tag("INCTRAN").element("DTSTART",dtstart_string).element("INCLUDE","Y")));
+}
+
+MyMoneyOfxConnector::Tag MyMoneyOfxConnector::creditCardRequest(const QDate& _dtstart) const
+{
+ QString dtstart_string = _dtstart.toString(Qt::ISODate).remove(QRegExp("[^0-9]"));
+
+ return message("CREDITCARD","CCSTMT",Tag("CCSTMTRQ")
+ .subtag(Tag("CCACCTFROM").element("ACCTID",accountnum()))
+ .subtag(Tag("INCTRAN").element("DTSTART",dtstart_string).element("INCLUDE","Y")));
+}
+
+MyMoneyOfxConnector::Tag MyMoneyOfxConnector::signOn(void) const
+{
+ QString dtnow_string = QDateTime::currentDateTime().toString(Qt::ISODate).remove(QRegExp("[^0-9]"));
+
+ Tag fi("FI");
+ fi.element("ORG",fiorg());
+ if ( !fiid().isEmpty() )
+ fi.element("FID",fiid());
+
+ return Tag("SIGNONMSGSRQV1")
+ .subtag(Tag("SONRQ")
+ .element("DTCLIENT",dtnow_string)
+ .element("USERID",username())
+ .element("USERPASS",password())
+ .element("LANGUAGE","ENG")
+ .subtag(fi)
+ .element("APPID","QWIN")
+ .element("APPVER","1100"));
+}
+
+QString MyMoneyOfxConnector::header(void)
+{
+ return QString("OFXHEADER:100\r\n"
+ "DATA:OFXSGML\r\n"
+ "VERSION:102\r\n"
+ "SECURITY:NONE\r\n"
+ "ENCODING:USASCII\r\n"
+ "CHARSET:1252\r\n"
+ "COMPRESSION:NONE\r\n"
+ "OLDFILEUID:NONE\r\n"
+ "NEWFILEUID:%1\r\n"
+ "\r\n").arg(uuid());
+}
+
+QString MyMoneyOfxConnector::uuid(void)
+{
+ static int id = 1;
+ return QDateTime::currentDateTime().toString("yyyyMMdd-hhmmsszzz-") + QString::number(id++);
+}
+
+//
+// Methods to provide RESPONSES to OFX requests. This has no real use in
+// KMyMoney, but it's included for the purposes of unit testing. This way, I
+// can create a MyMoneyAccount, write it to an OFX file, import that OFX file,
+// and check that everything made it through the importer.
+//
+// It's also a far-off dream to write an OFX server using KMyMoney as a
+// backend. It really should not be that hard, and it would fill a void in
+// the open source software community.
+//
+
+const QByteArray MyMoneyOfxConnector::statementResponse(const QDate& _dtstart) const
+{
+ QString request;
+
+ if ( accounttype()=="CC" )
+ request = header() + Tag("OFX").subtag(signOnResponse()).subtag(creditCardStatementResponse(_dtstart));
+ else if ( accounttype()=="INV" )
+ request = header() + Tag("OFX").subtag(signOnResponse()).data(investmentStatementResponse(_dtstart));
+ else
+ request = header() + Tag("OFX").subtag(signOnResponse()).subtag(bankStatementResponse(_dtstart));
+
+ // remove the trailing zero
+ QByteArray result = request.utf8();
+ result.truncate(result.size()-1);
+
+ return result;
+}
+
+MyMoneyOfxConnector::Tag MyMoneyOfxConnector::signOnResponse(void) const
+{
+ QString dtnow_string = QDateTime::currentDateTime().toString(Qt::ISODate).remove(QRegExp("[^0-9]"));
+
+ Tag sonrs("SONRS");
+ sonrs
+ .subtag(Tag("STATUS")
+ .element("CODE","0")
+ .element("SEVERITY","INFO")
+ .element("MESSAGE","The operation succeeded.")
+ )
+ .element("DTSERVER",dtnow_string)
+ .element("LANGUAGE","ENG");
+
+ Tag fi("FI");
+ if ( !fiorg().isEmpty() )
+ fi.element("ORG",fiorg());
+ if ( !fiid().isEmpty() )
+ fi.element("FID",fiid());
+
+ if ( !fi.isEmpty() )
+ sonrs.subtag(fi);
+
+ return Tag("SIGNONMSGSRSV1").subtag(sonrs);
+}
+
+MyMoneyOfxConnector::Tag MyMoneyOfxConnector::messageResponse(const QString& _msgType, const QString& _trnType, const Tag& _response)
+{
+ return Tag(_msgType+"MSGSRSV1")
+ .subtag(Tag(_trnType+"TRNRS")
+ .element("TRNUID",uuid())
+ .subtag(Tag("STATUS").element("CODE","0").element("SEVERITY","INFO"))
+ .element("CLTCOOKIE","1")
+ .subtag(_response));
+}
+
+MyMoneyOfxConnector::Tag MyMoneyOfxConnector::bankStatementResponse(const QDate& _dtstart) const
+{
+ MyMoneyFile* file = MyMoneyFile::instance();
+
+ QString dtstart_string = _dtstart.toString(Qt::ISODate).remove(QRegExp("[^0-9]"));
+ QString dtnow_string = QDateTime::currentDateTime().toString(Qt::ISODate).remove(QRegExp("[^0-9]"));
+
+ QString transactionlist;
+
+ MyMoneyTransactionFilter filter;
+ filter.setDateFilter(_dtstart,QDate::currentDate());
+ filter.addAccount(m_account.id());
+ QValueList<MyMoneyTransaction> transactions = file->transactionList(filter);
+ QValueList<MyMoneyTransaction>::const_iterator it_transaction = transactions.begin();
+ while ( it_transaction != transactions.end() )
+ {
+ transactionlist += transaction( *it_transaction );
+ ++it_transaction;
+ }
+
+ return messageResponse("BANK","STMT",Tag("STMTRS")
+ .element("CURDEF","USD")
+ .subtag(Tag("BANKACCTFROM").element("BANKID", iban()).element("ACCTID", accountnum()).element("ACCTTYPE", "CHECKING"))
+ .subtag(Tag("BANKTRANLIST").element("DTSTART",dtstart_string).element("DTEND",dtnow_string).data(transactionlist))
+ .subtag(Tag("LEDGERBAL").element("BALAMT",file->balance(m_account.id()).formatMoney(QString(),2)).element("DTASOF",dtnow_string )));
+}
+
+MyMoneyOfxConnector::Tag MyMoneyOfxConnector::creditCardStatementResponse(const QDate& _dtstart) const
+{
+ MyMoneyFile* file = MyMoneyFile::instance();
+
+ QString dtstart_string = _dtstart.toString(Qt::ISODate).remove(QRegExp("[^0-9]"));
+ QString dtnow_string = QDateTime::currentDateTime().toString(Qt::ISODate).remove(QRegExp("[^0-9]"));
+
+ QString transactionlist;
+
+ MyMoneyTransactionFilter filter;
+ filter.setDateFilter(_dtstart,QDate::currentDate());
+ filter.addAccount(m_account.id());
+ QValueList<MyMoneyTransaction> transactions = file->transactionList(filter);
+ QValueList<MyMoneyTransaction>::const_iterator it_transaction = transactions.begin();
+ while ( it_transaction != transactions.end() )
+ {
+ transactionlist += transaction( *it_transaction );
+ ++it_transaction;
+ }
+
+ return messageResponse("CREDITCARD","CCSTMT",Tag("CCSTMTRS")
+ .element("CURDEF","USD")
+ .subtag(Tag("CCACCTFROM").element("ACCTID", accountnum()))
+ .subtag(Tag("BANKTRANLIST").element("DTSTART",dtstart_string).element("DTEND",dtnow_string).data(transactionlist))
+ .subtag(Tag("LEDGERBAL").element("BALAMT",file->balance(m_account.id()).formatMoney(QString(),2)).element("DTASOF",dtnow_string )));
+}
+
+QString MyMoneyOfxConnector::investmentStatementResponse(const QDate& _dtstart) const
+{
+ MyMoneyFile* file = MyMoneyFile::instance();
+
+ QString dtstart_string = _dtstart.toString(Qt::ISODate).remove(QRegExp("[^0-9]"));
+ QString dtnow_string = QDateTime::currentDateTime().toString(Qt::ISODate).remove(QRegExp("[^0-9]"));
+
+ QString transactionlist;
+
+ MyMoneyTransactionFilter filter;
+ filter.setDateFilter(_dtstart,QDate::currentDate());
+ filter.addAccount(m_account.id());
+ filter.addAccount(m_account.accountList());
+ QValueList<MyMoneyTransaction> transactions = file->transactionList(filter);
+ QValueList<MyMoneyTransaction>::const_iterator it_transaction = transactions.begin();
+ while ( it_transaction != transactions.end() )
+ {
+ transactionlist += investmentTransaction( *it_transaction );
+ ++it_transaction;
+ }
+
+ Tag securitylist("SECLIST");
+ QCStringList accountids = m_account.accountList();
+ QCStringList::const_iterator it_accountid = accountids.begin();
+ while ( it_accountid != accountids.end() )
+ {
+ MyMoneySecurity equity = file->security(file->account(*it_accountid).currencyId());
+
+ securitylist.subtag(Tag("STOCKINFO")
+ .subtag(Tag("SECINFO")
+ .subtag(Tag("SECID")
+ .element("UNIQUEID",equity.id())
+ .element("UNIQUEIDTYPE","KMYMONEY"))
+ .element("SECNAME",equity.name())
+ .element("TICKER",equity.tradingSymbol())
+ .element("FIID",equity.id())));
+
+ ++it_accountid;
+ }
+
+ return messageResponse("INVSTMT","INVSTMT",Tag("INVSTMTRS")
+ .element("DTASOF", dtstart_string)
+ .element("CURDEF","USD")
+ .subtag(Tag("INVACCTFROM").element("BROKERID", fiorg()).element("ACCTID", accountnum()))
+ .subtag(Tag("INVTRANLIST").element("DTSTART",dtstart_string).element("DTEND",dtnow_string).data(transactionlist))
+ )
+ + Tag("SECLISTMSGSRSV1").subtag(securitylist);
+}
+
+MyMoneyOfxConnector::Tag MyMoneyOfxConnector::transaction(const MyMoneyTransaction& _t) const
+{
+ // This method creates a transaction tag using ONLY the elements that importer uses
+
+ MyMoneyFile* file = MyMoneyFile::instance();
+
+ //Use this version for bank/cc transactions
+ MyMoneySplit s = _t.splitByAccount( m_account.id(), true );
+
+ //TODO (Ace) Write "investmentTransaction()"...
+ //Use this version for inv transactions
+ //MyMoneySplit s = _t.splitByAccount( m_account.accountList(), true );
+
+ Tag result ("STMTTRN");
+
+ result
+ // This is a temporary hack. I don't use the trntype field in importing at all,
+ // but libofx requires it to be there in order to import the file.
+ .element("TRNTYPE","DEBIT")
+ .element("DTPOSTED",_t.postDate().toString(Qt::ISODate).remove(QRegExp("[^0-9]")))
+ .element("TRNAMT",s.value().formatMoney(QString(),2));
+
+ if ( ! _t.bankID().isEmpty() )
+ result.element("FITID",_t.bankID());
+ else
+ result.element("FITID",_t.id());
+
+ if ( ! s.number().isEmpty() )
+ result.element("CHECKNUM",s.number());
+
+ if ( ! s.payeeId().isEmpty() )
+ result.element("NAME",file->payee(s.payeeId()).name());
+
+ if ( ! _t.memo().isEmpty() )
+ result.element("MEMO",_t.memo());
+
+ return result;
+}
+
+MyMoneyOfxConnector::Tag MyMoneyOfxConnector::investmentTransaction(const MyMoneyTransaction& _t) const
+{
+ MyMoneyFile* file = MyMoneyFile::instance();
+
+ //Use this version for inv transactions
+ MyMoneySplit s = _t.splitByAccount( m_account.accountList(), true );
+
+ QCString stockid = file->account(s.accountId()).currencyId();
+
+ Tag invtran("INVTRAN");
+ invtran.element("FITID",_t.id()).element("DTTRADE",_t.postDate().toString(Qt::ISODate).remove(QRegExp("[^0-9]")));
+ if ( !_t.memo().isEmpty() )
+ invtran.element("MEMO",_t.memo());
+
+ if ( s.action() == MyMoneySplit::ActionBuyShares )
+ {
+ if ( s.shares().isNegative() )
+ {
+ return Tag("SELLSTOCK")
+ .subtag(Tag("INVSELL")
+ .subtag(invtran)
+ .subtag(Tag("SECID").element("UNIQUEID",stockid).element("UNIQUEIDTYPE","KMYMONEY"))
+ .element("UNITS",QString(((s.shares())).formatMoney(QString(),2)).remove(QRegExp("[^0-9.\\-]")))
+ .element("UNITPRICE",QString((s.value()/s.shares()).formatMoney(QString(),2)).remove(QRegExp("[^0-9.]")))
+ .element("TOTAL",QString((-s.value()).formatMoney(QString(),2)).remove(QRegExp("[^0-9.\\-]")))
+ .element("SUBACCTSEC","CASH")
+ .element("SUBACCTFUND","CASH"))
+ .element("SELLTYPE","SELL");
+ }
+ else
+ {
+ return Tag("BUYSTOCK")
+ .subtag(Tag("INVBUY")
+ .subtag(invtran)
+ .subtag(Tag("SECID").element("UNIQUEID",stockid).element("UNIQUEIDTYPE","KMYMONEY"))
+ .element("UNITS",QString((s.shares()).formatMoney(QString(),2)).remove(QRegExp("[^0-9.\\-]")))
+ .element("UNITPRICE",QString((s.value()/s.shares()).formatMoney(QString(),2)).remove(QRegExp("[^0-9.]")))
+ .element("TOTAL",QString((-(s.value())).formatMoney(QString(),2)).remove(QRegExp("[^0-9.\\-]")))
+ .element("SUBACCTSEC","CASH")
+ .element("SUBACCTFUND","CASH"))
+ .element("BUYTYPE","BUY");
+ }
+ }
+ else if ( s.action() == MyMoneySplit::ActionReinvestDividend )
+ {
+ // Should the TOTAL tag really be negative for a REINVEST? That's very strange, but
+ // it's what they look like coming from my bank, and I can't find any information to refute it.
+
+ return Tag("REINVEST")
+ .subtag(invtran)
+ .subtag(Tag("SECID").element("UNIQUEID",stockid).element("UNIQUEIDTYPE","KMYMONEY"))
+ .element("INCOMETYPE","DIV")
+ .element("TOTAL",QString((-s.value()).formatMoney(QString(),2)).remove(QRegExp("[^0-9.\\-]")))
+ .element("SUBACCTSEC","CASH")
+ .element("UNITS",QString((s.shares()).formatMoney(QString(),2)).remove(QRegExp("[^0-9.\\-]")))
+ .element("UNITPRICE",QString((s.value()/s.shares()).formatMoney(QString(),2)).remove(QRegExp("[^0-9.]")));
+ }
+ else if ( s.action() == MyMoneySplit::ActionDividend )
+ {
+ // find the split with the category, which has the actual amount of the dividend
+ QValueList<MyMoneySplit> splits = _t.splits();
+ QValueList<MyMoneySplit>::const_iterator it_split = splits.begin();
+ bool found = false;
+ while( it_split != splits.end() )
+ {
+ QCString accid = (*it_split).accountId();
+ MyMoneyAccount acc = file->account(accid);
+ if ( acc.accountType() == MyMoneyAccount::Income || acc.accountType() == MyMoneyAccount::Expense )
+ {
+ found = true;
+ break;
+ }
+ ++it_split;
+ }
+
+ if ( found )
+ return Tag("INCOME")
+ .subtag(invtran)
+ .subtag(Tag("SECID").element("UNIQUEID",stockid).element("UNIQUEIDTYPE","KMYMONEY"))
+ .element("INCOMETYPE","DIV")
+ .element("TOTAL",QString((-(*it_split).value()).formatMoney(QString(),2)).remove(QRegExp("[^0-9\\.\\-]")))
+ .element("SUBACCTSEC","CASH")
+ .element("SUBACCTFUND","CASH");
+ else
+ return Tag("ERROR").element("DETAILS","Unable to determine the amount of this income transaction.");
+ }
+
+ //FIXME: Do something useful with these errors
+ return Tag("ERROR").element("DETAILS","This transaction contains an unsupported action type");
+}
+#endif
diff --git a/kmymoney2/plugins/ofximport/dialogs/mymoneyofxconnector.h b/kmymoney2/plugins/ofximport/dialogs/mymoneyofxconnector.h
new file mode 100644
index 0000000..1091b15
--- /dev/null
+++ b/kmymoney2/plugins/ofximport/dialogs/mymoneyofxconnector.h
@@ -0,0 +1,128 @@
+/***************************************************************************
+ mymoneyofxconnector.cpp
+ -------------------
+ begin : Sat Nov 13 2004
+ copyright : (C) 2002 by Ace Jones
+ email : acejones@users.sourceforge.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. *
+ * *
+ ***************************************************************************/
+
+#ifndef MYMONEYOFXCONNECTOR_H
+#define MYMONEYOFXCONNECTOR_H
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+
+// ----------------------------------------------------------------------------
+// Library Includes
+
+#include <libofx/libofx.h>
+
+// if OFX has a major version number defined, we'll take it
+// if not, we assume 0.8.3. 0.8.3 was the last version w/o version number info
+#ifdef LIBOFX_MAJOR_VERSION
+ #define LIBOFX_VERSION KDE_MAKE_VERSION(LIBOFX_MAJOR_VERSION, LIBOFX_MINOR_VERSION, LIBOFX_MICRO_VERSION)
+#else
+ #define LIBOFX_VERSION KDE_MAKE_VERSION(0,8,3)
+#endif
+#define LIBOFX_IS_VERSION(a,b,c) (LIBOFX_VERSION >= KDE_MAKE_VERSION(a,b,c))
+
+// ----------------------------------------------------------------------------
+// QT Includes
+
+class QDate;
+
+// ----------------------------------------------------------------------------
+// KDE Includes
+class KComboBox;
+
+// ----------------------------------------------------------------------------
+// Project Includes
+
+#include <kmymoney/mymoneykeyvaluecontainer.h>
+
+class MyMoneyAccount;
+class MyMoneyInstitution;
+class MyMoneyTransaction;
+
+/**
+ * @author Thomas Baumgart
+ */
+class OfxAppVersion
+{
+public:
+ OfxAppVersion(KComboBox* combo, const QString& appId);
+ /**
+ * This method returns the currently selected application id
+ * as a colon separated value consisting of the application
+ * and version (eg. "QWIN:1700"). If current value is the
+ * default, an empty string is returned.
+ */
+ const QString& appId(void) const;
+
+private:
+ QMap<QString, QString> m_appMap;
+ KComboBox* m_combo;
+};
+
+/**
+ * @author Thomas Baumgart
+ */
+class OfxHeaderVersion
+{
+public:
+ OfxHeaderVersion(KComboBox* combo, const QString& headerVersion);
+ QString headerVersion(void) const;
+
+private:
+ KComboBox* m_combo;
+};
+
+/**
+@author ace jones
+*/
+class MyMoneyOfxConnector
+{
+public:
+ MyMoneyOfxConnector(const MyMoneyAccount& _account);
+ QString url(void) const;
+
+ /**
+ * Constructs the request for a statement. The first date
+ * for which transactions will be requested is determined
+ * by statementStartDate()
+ */
+ const QByteArray statementRequest(void) const;
+ const QByteArray statementResponse(const QDate& _dtstart) const;
+
+private:
+ void initRequest(OfxFiLogin* fi) const;
+ QDate statementStartDate(void) const;
+ QString iban(void) const;
+ QString fiorg(void) const;
+ QString fiid(void) const;
+ QString username(void) const;
+ QString password(void) const;
+ QString accountnum(void) const;
+#if LIBOFX_IS_VERSION(0,9,0)
+ OfxAccountData::AccountType accounttype(void) const;
+#else
+ AccountType accounttype(void) const;
+#endif
+
+private:
+ const MyMoneyAccount& m_account;
+ MyMoneyKeyValueContainer m_fiSettings;
+};
+
+#endif // OFXCONNECTOR_H
diff --git a/kmymoney2/plugins/ofximport/kmm_ofximport.desktop b/kmymoney2/plugins/ofximport/kmm_ofximport.desktop
new file mode 100644
index 0000000..32ff003
--- /dev/null
+++ b/kmymoney2/plugins/ofximport/kmm_ofximport.desktop
@@ -0,0 +1,12 @@
+[Desktop Entry]
+Name=KMyMoney OFX
+Comment=Add OFX importing to KMyMoney
+ServiceTypes=KMyMoneyPlugin
+Type=Service
+Icon=connect_creating
+X-KDE-Library=kmm_ofximport
+X-KDE-PluginInfo-Name=KMyMoney OFX
+X-KDE-PluginInfo-License=GPL
+X-KDE-PluginInfo-EnabledByDefault=true
+X-KDE-PluginInfo-Author=Ace Jones,Thomas Baumgart
+X-KDE-PluginInfo-Email=acejones@users.sourceforge.net,ipwizard@users.sourceforge.net
diff --git a/kmymoney2/plugins/ofximport/kmm_ofximport.rc b/kmymoney2/plugins/ofximport/kmm_ofximport.rc
new file mode 100644
index 0000000..7254470
--- /dev/null
+++ b/kmymoney2/plugins/ofximport/kmm_ofximport.rc
@@ -0,0 +1,10 @@
+<!DOCTYPE kpartgui>
+<kpartgui name="kmymoneyplugin-ofximporter" version="2">
+ <MenuBar>
+ <Menu name="file">
+ <Menu name="import" append="import_merge">
+ <Action name="file_import_ofx" />
+ </Menu>
+ </Menu>
+ </MenuBar>
+</kpartgui>
diff --git a/kmymoney2/plugins/ofximport/ofximporterplugin.cpp b/kmymoney2/plugins/ofximport/ofximporterplugin.cpp
new file mode 100644
index 0000000..21a6466
--- /dev/null
+++ b/kmymoney2/plugins/ofximport/ofximporterplugin.cpp
@@ -0,0 +1,688 @@
+/***************************************************************************
+ ofxiimporterplugin.cpp
+ -------------------
+ begin : Sat Jan 01 2005
+ copyright : (C) 2005 by Ace Jones
+ email : Ace Jones <acejones@users.sourceforge.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. *
+ * *
+ ***************************************************************************/
+
+// ----------------------------------------------------------------------------
+// QT Includes
+
+#include <qfile.h>
+#include <qtextstream.h>
+#include <qradiobutton.h>
+#include <qspinbox.h>
+#include <qdatetimeedit.h>
+
+// ----------------------------------------------------------------------------
+// KDE Includes
+
+#include <kgenericfactory.h>
+#include <kdebug.h>
+#include <kfile.h>
+#include <kurl.h>
+#include <kaction.h>
+#include <kmessagebox.h>
+
+// ----------------------------------------------------------------------------
+// Project Includes
+
+#include "ofximporterplugin.h"
+#include "konlinebankingstatus.h"
+#include "konlinebankingsetupwizard.h"
+#include "kofxdirectconnectdlg.h"
+
+K_EXPORT_COMPONENT_FACTORY( kmm_ofximport,
+ KGenericFactory<OfxImporterPlugin>( "kmm_ofximport" ) )
+
+OfxImporterPlugin::OfxImporterPlugin(QObject *parent, const char *name, const QStringList&) :
+ KMyMoneyPlugin::Plugin( parent, name ),
+ KMyMoneyPlugin::ImporterPlugin(),
+ m_valid( false )
+{
+ setInstance(KGenericFactory<OfxImporterPlugin>::instance());
+ setXMLFile("kmm_ofximport.rc");
+ createActions();
+}
+
+OfxImporterPlugin::~OfxImporterPlugin()
+{
+}
+
+void OfxImporterPlugin::createActions(void)
+{
+ new KAction(i18n("OFX..."), "", 0, this, SLOT(slotImportFile()), actionCollection(), "file_import_ofx");
+}
+
+void OfxImporterPlugin::slotImportFile(void)
+{
+ KURL url = importInterface()->selectFile(i18n("OFX import file selection"),
+ "",
+ "*.ofx *.qfx *.ofc|OFX files (*.ofx, *.qfx, *.ofc)\n*.*|All files (*.*)",
+ static_cast<KFile::Mode>(KFile::File | KFile::ExistingOnly));
+ if(url.isValid()) {
+ if ( isMyFormat(url.path()) ) {
+ slotImportFile(url.path());
+ } else {
+ KMessageBox::error( 0, i18n("Unable to import %1 using the OFX importer plugin. This file is not the correct format.").arg(url.prettyURL(0, KURL::StripFileProtocol)), i18n("Incorrect format"));
+ }
+
+ }
+}
+
+QString OfxImporterPlugin::formatName(void) const
+{
+ return "OFX";
+}
+
+QString OfxImporterPlugin::formatFilenameFilter(void) const
+{
+ return "*.ofx *.qfx *.ofc";
+}
+
+
+bool OfxImporterPlugin::isMyFormat( const QString& filename ) const
+{
+ // filename is considered an Ofx file if it contains
+ // the tag "<OFX>" or "<OFC>" in the first 20 lines
+ // which contain some data.
+ bool result = false;
+
+ QFile f( filename );
+ if ( f.open( IO_ReadOnly ) )
+ {
+ QTextStream ts( &f );
+
+ int lineCount = 20;
+ while ( !ts.atEnd() && !result && lineCount != 0)
+ {
+ // get a line of data and remove all unnecessary whitepace chars
+ QString line = ts.readLine().simplifyWhiteSpace();
+ if ( line.contains("<OFX>",false)
+ || line.contains("<OFC>",false) )
+ result = true;
+ // count only lines that contains some non white space chars
+ if(!line.isEmpty())
+ lineCount--;
+ }
+ f.close();
+ }
+
+ return result;
+}
+
+bool OfxImporterPlugin::import( const QString& filename )
+{
+ m_fatalerror = i18n("Unable to parse file");
+ m_valid = false;
+ m_errors.clear();
+ m_warnings.clear();
+ m_infos.clear();
+
+ m_statementlist.clear();
+ m_securitylist.clear();
+
+ QCString filename_deep( filename.utf8() );
+
+ LibofxContextPtr ctx = libofx_get_new_context();
+ Q_CHECK_PTR(ctx);
+
+ ofx_set_transaction_cb(ctx, ofxTransactionCallback, this);
+ ofx_set_statement_cb(ctx, ofxStatementCallback, this);
+ ofx_set_account_cb(ctx, ofxAccountCallback, this);
+ ofx_set_security_cb(ctx, ofxSecurityCallback, this);
+ ofx_set_status_cb(ctx, ofxStatusCallback, this);
+ libofx_proc_file(ctx, filename_deep, AUTODETECT);
+ libofx_free_context(ctx);
+
+ if ( m_valid )
+ {
+ m_fatalerror = QString();
+ m_valid = storeStatements(m_statementlist);
+ }
+ return m_valid;
+}
+
+QString OfxImporterPlugin::lastError(void) const
+{
+ if(m_errors.count() == 0)
+ return m_fatalerror;
+ return m_errors.join("<p>");
+}
+
+/* __________________________________________________________________________
+ * AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ *
+ * Static callbacks for LibOFX
+ *
+ * YYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYY
+ */
+
+int OfxImporterPlugin::ofxTransactionCallback(struct OfxTransactionData data, void * pv)
+{
+// kdDebug(2) << __func__ << endl;
+
+ OfxImporterPlugin* pofx = reinterpret_cast<OfxImporterPlugin*>(pv);
+ MyMoneyStatement& s = pofx->back();
+
+ MyMoneyStatement::Transaction t;
+
+ if(data.date_posted_valid==true)
+ {
+ QDateTime dt;
+ dt.setTime_t(data.date_posted, Qt::UTC);
+ t.m_datePosted = dt.date();
+ }
+ else if(data.date_initiated_valid==true)
+ {
+ QDateTime dt;
+ dt.setTime_t(data.date_initiated, Qt::UTC);
+ t.m_datePosted = dt.date();
+ }
+
+ if(data.amount_valid==true)
+ {
+ t.m_amount = MyMoneyMoney(data.amount, 1000);
+ // if this is an investment statement, reverse the sign. not sure
+ // why this is needed, so I suppose it's a bit of a hack for the moment.
+ if (data.invtransactiontype_valid==true)
+ t.m_amount = -t.m_amount;
+ }
+
+ if(data.check_number_valid==true)
+ {
+ t.m_strNumber = data.check_number;
+ }
+
+ if(data.fi_id_valid==true)
+ {
+ t.m_strBankID = QString("ID ") + data.fi_id;
+ }
+ else if(data.reference_number_valid==true)
+ {
+ t.m_strBankID = QString("REF ") + data.reference_number;
+ }
+ // Decide whether to import NAME or PAYEEID if both are present in the download
+ if (pofx->m_preferName) {
+ if(data.name_valid==true)
+ {
+ t.m_strPayee = data.name;
+ }
+ else if(data.payee_id_valid==true)
+ {
+ t.m_strPayee = data.payee_id;
+ }
+ }
+ else {
+ if(data.payee_id_valid==true)
+ {
+ t.m_strPayee = data.payee_id;
+ }
+ else if(data.name_valid==true)
+ {
+ t.m_strPayee = data.name;
+ }
+ }
+ if(data.memo_valid==true){
+ t.m_strMemo = data.memo;
+ }
+
+ // If the payee or memo fields are blank, set them to
+ // the other one which is NOT blank. (acejones)
+ if ( t.m_strPayee.isEmpty() )
+ {
+ // But we only create a payee for non-investment transactions (ipwizard)
+ if ( ! t.m_strMemo.isEmpty() && data.invtransactiontype_valid == false)
+ t.m_strPayee = t.m_strMemo;
+ }
+ else
+ {
+ if ( t.m_strMemo.isEmpty() )
+ t.m_strMemo = t.m_strPayee;
+ }
+
+ if(data.security_data_valid==true)
+ {
+ struct OfxSecurityData* secdata = data.security_data_ptr;
+
+ if(secdata->ticker_valid==true){
+ t.m_strSymbol = secdata->ticker;
+ }
+
+ if(secdata->secname_valid==true){
+ t.m_strSecurity = secdata->secname;
+ }
+ }
+
+ t.m_shares = MyMoneyMoney();
+ if(data.units_valid==true)
+ {
+ t.m_shares = MyMoneyMoney(data.units, 100000).reduce();
+ }
+
+ t.m_price = MyMoneyMoney();
+ if(data.unitprice_valid == true)
+ {
+ t.m_price = MyMoneyMoney(data.unitprice, 100000).reduce();
+ }
+
+ t.m_fees = MyMoneyMoney();
+ if(data.fees_valid==true)
+ {
+ t.m_fees += MyMoneyMoney(data.fees, 1000).reduce();
+ }
+
+ if(data.commission_valid==true)
+ {
+ t.m_fees += MyMoneyMoney(data.commission, 1000).reduce();
+ }
+
+ bool unhandledtype = false;
+ QString type;
+
+ if(data.invtransactiontype_valid==true)
+ {
+ switch (data.invtransactiontype)
+ {
+ case OFX_BUYDEBT:
+ case OFX_BUYMF:
+ case OFX_BUYOPT:
+ case OFX_BUYOTHER:
+ case OFX_BUYSTOCK:
+ t.m_eAction = MyMoneyStatement::Transaction::eaBuy;
+ break;
+ case OFX_REINVEST:
+ t.m_eAction = MyMoneyStatement::Transaction::eaReinvestDividend;
+ break;
+ case OFX_SELLDEBT:
+ case OFX_SELLMF:
+ case OFX_SELLOPT:
+ case OFX_SELLOTHER:
+ case OFX_SELLSTOCK:
+ t.m_eAction = MyMoneyStatement::Transaction::eaSell;
+ break;
+ case OFX_INCOME:
+ t.m_eAction = MyMoneyStatement::Transaction::eaCashDividend;
+ // NOTE: With CashDividend, the amount of the dividend should
+ // be in data.amount. Since I've never seen an OFX file with
+ // cash dividends, this is an assumption on my part. (acejones)
+ break;
+
+ //
+ // These types are all not handled. We will generate a warning for them.
+ //
+ case OFX_CLOSUREOPT:
+ unhandledtype = true;
+ type = "CLOSUREOPT (Close a position for an option)";
+ break;
+ case OFX_INVEXPENSE:
+ unhandledtype = true;
+ type = "INVEXPENSE (Misc investment expense that is associated with a specific security)";
+ break;
+ case OFX_JRNLFUND:
+ unhandledtype = true;
+ type = "JRNLFUND (Journaling cash holdings between subaccounts within the same investment account)";
+ break;
+ case OFX_MARGININTEREST:
+ unhandledtype = true;
+ type = "MARGININTEREST (Margin interest expense)";
+ break;
+ case OFX_RETOFCAP:
+ unhandledtype = true;
+ type = "RETOFCAP (Return of capital)";
+ break;
+ case OFX_SPLIT:
+ unhandledtype = true;
+ type = "SPLIT (Stock or mutial fund split)";
+ break;
+ case OFX_TRANSFER:
+ unhandledtype = true;
+ type = "TRANSFER (Transfer holdings in and out of the investment account)";
+ break;
+ default:
+ unhandledtype = true;
+ type = QString("UNKNOWN %1").arg(data.invtransactiontype);
+ break;
+ }
+ }
+ else
+ t.m_eAction = MyMoneyStatement::Transaction::eaNone;
+
+ // In the case of investment transactions, the 'total' is supposed to the total amount
+ // of the transaction. units * unitprice +/- commission. Easy, right? Sadly, it seems
+ // some ofx creators do not follow this in all circumstances. Therefore, we have to double-
+ // check the total here and adjust it if it's wrong.
+
+#if 0
+ // Even more sadly, this logic is BROKEN. It consistently results in bogus total
+ // values, because of rounding errors in the price. A more through solution would
+ // be to test if the comission alone is causing a discrepency, and adjust in that case.
+
+ if(data.invtransactiontype_valid==true && data.unitprice_valid)
+ {
+ double proper_total = t.m_dShares * data.unitprice + t.m_moneyFees;
+ if ( proper_total != t.m_moneyAmount )
+ {
+ pofx->addWarning(QString("Transaction %1 has an incorrect total of %2. Using calculated total of %3 instead.").arg(t.m_strBankID).arg(t.m_moneyAmount).arg(proper_total));
+ t.m_moneyAmount = proper_total;
+ }
+ }
+#endif
+
+ if ( unhandledtype )
+ pofx->addWarning(QString("Transaction %1 has an unsupported type (%2).").arg(t.m_strBankID,type));
+ else
+ s.m_listTransactions += t;
+
+// kdDebug(2) << __func__ << "return 0 " << endl;
+
+ return 0;
+}
+
+int OfxImporterPlugin::ofxStatementCallback(struct OfxStatementData data, void* pv)
+{
+// kdDebug(2) << __func__ << endl;
+
+ OfxImporterPlugin* pofx = reinterpret_cast<OfxImporterPlugin*>(pv);
+ MyMoneyStatement& s = pofx->back();
+
+ pofx->setValid();
+
+ if(data.currency_valid==true)
+ {
+ s.m_strCurrency = data.currency;
+ }
+ if(data.account_id_valid==true)
+ {
+ s.m_strAccountNumber = data.account_id;
+ }
+
+ if(data.date_start_valid==true)
+ {
+ QDateTime dt;
+ dt.setTime_t(data.date_start, Qt::UTC);
+ s.m_dateBegin = dt.date();
+ }
+
+ if(data.date_end_valid==true)
+ {
+ QDateTime dt;
+ dt.setTime_t(data.date_end, Qt::UTC);
+ s.m_dateEnd = dt.date();
+ }
+
+ if(data.ledger_balance_valid==true)
+ {
+ s.m_closingBalance = MyMoneyMoney(data.ledger_balance);
+ }
+
+// kdDebug(2) << __func__ << " return 0" << endl;
+
+ return 0;
+}
+
+int OfxImporterPlugin::ofxAccountCallback(struct OfxAccountData data, void * pv)
+{
+// kdDebug(2) << __func__ << endl;
+
+ OfxImporterPlugin* pofx = reinterpret_cast<OfxImporterPlugin*>(pv);
+ pofx->addnew();
+ MyMoneyStatement& s = pofx->back();
+
+ // Having any account at all makes an ofx statement valid
+ pofx->m_valid = true;
+
+ if(data.account_id_valid==true)
+ {
+ s.m_strAccountName = data.account_name;
+ s.m_strAccountNumber = data.account_id;
+ }
+ if(data.bank_id_valid == true)
+ {
+ s.m_strRoutingNumber = data.bank_id;
+ }
+ if(data.broker_id_valid == true)
+ {
+ s.m_strRoutingNumber = data.broker_id;
+ }
+ if(data.currency_valid==true)
+ {
+ s.m_strCurrency = data.currency;
+ }
+
+ if(data.account_type_valid==true)
+ {
+ switch(data.account_type)
+ {
+ case OfxAccountData::OFX_CHECKING : s.m_eType = MyMoneyStatement::etCheckings;
+ break;
+ case OfxAccountData::OFX_SAVINGS : s.m_eType = MyMoneyStatement::etSavings;
+ break;
+ case OfxAccountData::OFX_MONEYMRKT : s.m_eType = MyMoneyStatement::etInvestment;
+ break;
+ case OfxAccountData::OFX_CREDITLINE : s.m_eType = MyMoneyStatement::etCreditCard;
+ break;
+ case OfxAccountData::OFX_CMA : s.m_eType = MyMoneyStatement::etCreditCard;
+ break;
+ case OfxAccountData::OFX_CREDITCARD : s.m_eType = MyMoneyStatement::etCreditCard;
+ break;
+ case OfxAccountData::OFX_INVESTMENT : s.m_eType = MyMoneyStatement::etInvestment;
+ break;
+ }
+ }
+
+ // ask KMyMoney for an account id
+ s.m_accountId = pofx->account("kmmofx-acc-ref", QString("%1-%2").arg(s.m_strRoutingNumber, s.m_strAccountNumber)).id();
+
+ // copy over the securities
+ s.m_listSecurities = pofx->m_securitylist;
+
+// kdDebug(2) << __func__ << " return 0" << endl;
+
+ return 0;
+}
+
+int OfxImporterPlugin::ofxSecurityCallback(struct OfxSecurityData data, void* pv)
+{
+ // kdDebug(2) << __func__ << endl;
+
+ OfxImporterPlugin* pofx = reinterpret_cast<OfxImporterPlugin*>(pv);
+ MyMoneyStatement::Security sec;
+
+ if(data.unique_id_valid==true){
+ sec.m_strId = data.unique_id;
+ }
+ if(data.secname_valid==true){
+ sec.m_strName = data.secname;
+ }
+ if(data.ticker_valid==true){
+ sec.m_strSymbol = data.ticker;
+ }
+
+ pofx->m_securitylist += sec;
+
+ return 0;
+}
+
+int OfxImporterPlugin::ofxStatusCallback(struct OfxStatusData data, void * pv)
+{
+// kdDebug(2) << __func__ << endl;
+
+ OfxImporterPlugin* pofx = reinterpret_cast<OfxImporterPlugin*>(pv);
+ QString message;
+
+ // if we got this far, we know we were able to parse the file.
+ // so if it fails after here it can only because there were no actual
+ // accounts in the file!
+ pofx->m_fatalerror = "No accounts found.";
+
+ if(data.ofx_element_name_valid==true)
+ message.prepend(QString("%1: ").arg(data.ofx_element_name));
+
+ if(data.code_valid==true)
+ message += QString("%1 (Code %2): %3").arg(data.name).arg(data.code).arg(data.description);
+
+ if(data.server_message_valid==true)
+ message += QString(" (%1)").arg(data.server_message);
+
+ if(data.severity_valid==true){
+ switch(data.severity){
+ case OfxStatusData::INFO:
+ pofx->addInfo( message );
+ break;
+ case OfxStatusData::ERROR:
+ pofx->addError( message );
+ break;
+ case OfxStatusData::WARN:
+ pofx->addWarning( message );
+ break;
+ default:
+ pofx->addWarning( message );
+ pofx->addWarning( "Previous message was an unknown type. 'WARNING' was assumed.");
+ break;
+ }
+ }
+
+// kdDebug(2) << __func__ << " return 0 " << endl;
+
+ return 0;
+}
+
+bool OfxImporterPlugin::importStatement(const MyMoneyStatement& s)
+{
+ qDebug("OfxImporterPlugin::importStatement start");
+ return statementInterface()->import(s);
+}
+
+const MyMoneyAccount& OfxImporterPlugin::account(const QString& key, const QString& value) const
+{
+ return statementInterface()->account(key, value);
+}
+
+void OfxImporterPlugin::protocols(QStringList& protocolList) const
+{
+ protocolList.clear();
+ protocolList << "OFX";
+}
+
+QWidget* OfxImporterPlugin::accountConfigTab(const MyMoneyAccount& acc, QString& name)
+{
+ name = i18n("Online settings");
+ m_statusDlg = new KOnlineBankingStatus(acc, 0, 0);
+ return m_statusDlg;
+}
+
+MyMoneyKeyValueContainer OfxImporterPlugin::onlineBankingSettings(const MyMoneyKeyValueContainer& current)
+{
+ MyMoneyKeyValueContainer kvp(current);
+ // keep the provider name in sync with the one found in kmm_ofximport.desktop
+ kvp["provider"] = "KMyMoney OFX";
+ if(m_statusDlg) {
+ kvp.deletePair("appId");
+ kvp.deletePair("kmmofx-headerVersion");
+ if(!m_statusDlg->appId().isEmpty())
+ kvp.setValue("appId", m_statusDlg->appId());
+ kvp.setValue("kmmofx-headerVersion", m_statusDlg->headerVersion());
+ kvp.setValue("kmmofx-numRequestDays", QString::number(m_statusDlg->m_numdaysSpin->value()));
+ kvp.setValue("kmmofx-todayMinus", QString::number(m_statusDlg->m_todayRB->isChecked()));
+ kvp.setValue("kmmofx-lastUpdate", QString::number(m_statusDlg->m_lastUpdateRB->isChecked()));
+ kvp.setValue("kmmofx-pickDate", QString::number(m_statusDlg->m_pickDateRB->isChecked()));
+ kvp.setValue("kmmofx-specificDate", m_statusDlg->m_specificDate->date().toString());
+ kvp.setValue("kmmofx-preferPayeeid", QString::number(m_statusDlg->m_payeeidRB->isChecked()));
+ kvp.setValue("kmmofx-preferName", QString::number(m_statusDlg->m_nameRB->isChecked()));
+ }
+ return kvp;
+}
+
+bool OfxImporterPlugin::mapAccount(const MyMoneyAccount& acc, MyMoneyKeyValueContainer& settings)
+{
+ Q_UNUSED(acc);
+
+ bool rc = false;
+ KOnlineBankingSetupWizard wiz(0, "onlinebankingsetup");
+ if(wiz.isInit()) {
+ if(wiz.exec() == QDialog::Accepted) {
+ rc = wiz.chosenSettings( settings );
+ }
+ }
+
+ return rc;
+}
+
+bool OfxImporterPlugin::updateAccount(const MyMoneyAccount& acc, bool moreAccounts)
+{
+ Q_UNUSED(moreAccounts);
+
+ try {
+ if(!acc.id().isEmpty()) {
+ // Save the value of preferName to be used by ofxTransactionCallback
+ m_preferName = acc.onlineBankingSettings().value("kmmofx-preferName").toInt() != 0;
+ KOfxDirectConnectDlg dlg(acc);
+
+ connect(&dlg, SIGNAL(statementReady(const QString&)),
+ this, SLOT(slotImportFile(const QString&)));
+
+ dlg.init();
+ dlg.exec();
+ }
+ } catch (MyMoneyException *e) {
+ KMessageBox::information(0 ,i18n("Error connecting to bank: %1").arg(e->what()));
+ delete e;
+ }
+
+ return false;
+}
+
+void OfxImporterPlugin::slotImportFile(const QString& url)
+{
+
+ if(!import(url)) {
+ KMessageBox::error( 0, QString("<qt>%1</qt>").arg(i18n("Unable to import %1 using the OFX importer plugin. The plugin returned the following error:<p>%2").arg(url, lastError())), i18n("Importing error"));
+ }
+}
+
+bool OfxImporterPlugin::storeStatements(QValueList<MyMoneyStatement>& statements)
+{
+ bool hasstatements = (statements.count() > 0);
+ bool ok = true;
+ bool abort = false;
+
+ // FIXME Deal with warnings/errors coming back from plugins
+ /*if ( ofx.errors().count() )
+ {
+ if ( KMessageBox::warningContinueCancelList(this,i18n("The following errors were returned from your bank"),ofx.errors(),i18n("OFX Errors")) == KMessageBox::Cancel )
+ abort = true;
+ }
+
+ if ( ofx.warnings().count() )
+ {
+ if ( KMessageBox::warningContinueCancelList(this,i18n("The following warnings were returned from your bank"),ofx.warnings(),i18n("OFX Warnings"),KStdGuiItem::cont(),"ofxwarnings") == KMessageBox::Cancel )
+ abort = true;
+ }*/
+
+ qDebug("OfxImporterPlugin::storeStatements() with %d statements called", static_cast<int>(statements.count()));
+ QValueList<MyMoneyStatement>::const_iterator it_s = statements.begin();
+ while ( it_s != statements.end() && !abort ) {
+ ok = ok && importStatement((*it_s));
+ ++it_s;
+ }
+
+ if ( hasstatements && !ok ) {
+ KMessageBox::error( 0, i18n("Importing process terminated unexpectedly."), i18n("Failed to import all statements."));
+ }
+
+ return ( !hasstatements || ok );
+}
+
+#include "ofximporterplugin.moc"
+// vim:cin:si:ai:et:ts=2:sw=2:
diff --git a/kmymoney2/plugins/ofximport/ofximporterplugin.h b/kmymoney2/plugins/ofximport/ofximporterplugin.h
new file mode 100644
index 0000000..b665439
--- /dev/null
+++ b/kmymoney2/plugins/ofximport/ofximporterplugin.h
@@ -0,0 +1,145 @@
+/***************************************************************************
+ ofxiimporterplugin.h
+ -------------------
+ begin : Sat Jan 01 2005
+ copyright : (C) 2005 by Ace Jones
+ email : Ace Jones <acejones@users.sourceforge.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. *
+ * *
+ ***************************************************************************/
+
+#ifndef OFXIMPORTERPLUGIN_H
+#define OFXIMPORTERPLUGIN_H
+
+// ----------------------------------------------------------------------------
+// KDE Includes
+
+// ----------------------------------------------------------------------------
+// QT Includes
+
+#include <qstringlist.h>
+
+// ----------------------------------------------------------------------------
+// Library Includes
+
+#include <libofx/libofx.h>
+
+// ----------------------------------------------------------------------------
+// Project Includes
+
+#include "../kmymoneyplugin.h"
+class KOnlineBankingStatus;
+
+/**
+@author Ace Jones
+*/
+class OfxImporterPlugin : public KMyMoneyPlugin::Plugin, public KMyMoneyPlugin::ImporterPlugin, public KMyMoneyPlugin::OnlinePlugin
+{
+Q_OBJECT
+public:
+ OfxImporterPlugin(QObject *parent = 0, const char *name = 0, const QStringList& = QStringList());
+
+ ~OfxImporterPlugin();
+
+ /**
+ * This method returns the english-language name of the format
+ * this plugin imports, e.g. "OFX"
+ *
+ * @return QString Name of the format
+ */
+ virtual QString formatName(void) const;
+
+ /**
+ * This method returns the filename filter suitable for passing to
+ * KFileDialog::setFilter(), e.g. "*.ofx *.qfx" which describes how
+ * files of this format are likely to be named in the file system
+ *
+ * @return QString Filename filter string
+ */
+ virtual QString formatFilenameFilter(void) const;
+
+ /**
+ * This method returns whether this plugin is able to import
+ * a particular file.
+ *
+ * @param filename Fully-qualified pathname to a file
+ *
+ * @return bool Whether the indicated file is importable by this plugin
+ */
+ virtual bool isMyFormat( const QString& filename ) const;
+
+ /**
+ * Import a file
+ *
+ * @param filename File to import
+ *
+ * @return bool Whether the import was successful.
+ */
+ virtual bool import( const QString& filename );
+
+ /**
+ * Returns the error result of the last import
+ *
+ * @return QString English-language name of the error encountered in the
+ * last import, or QString() if it was successful.
+ *
+ */
+ virtual QString lastError(void) const;
+
+ QWidget* accountConfigTab(const MyMoneyAccount& acc, QString& name);
+
+ MyMoneyKeyValueContainer onlineBankingSettings(const MyMoneyKeyValueContainer& current);
+
+ const MyMoneyAccount& account(const QString& key, const QString& value) const;
+
+ void protocols(QStringList& protocolList) const;
+
+ bool mapAccount(const MyMoneyAccount& acc, MyMoneyKeyValueContainer& settings);
+ bool updateAccount(const MyMoneyAccount& acc, bool moreAccounts);
+
+protected slots:
+ void slotImportFile(void);
+ void slotImportFile(const QString& url);
+
+protected:
+ void createActions(void);
+ void addnew(void) { m_statementlist.push_back(MyMoneyStatement()); }
+ MyMoneyStatement& back(void) { return m_statementlist.back(); }
+ bool isValid(void) const { return m_valid; }
+ void setValid(void) { m_valid = true; }
+ void addInfo(const QString& _msg ) { m_infos+=_msg; }
+ void addWarning(const QString& _msg ) { m_warnings+=_msg; }
+ void addError(const QString& _msg ) { m_errors+=_msg; }
+ const QStringList& infos(void) const { return m_infos; }
+ const QStringList& warnings(void) const { return m_warnings; }
+ const QStringList& errors(void) const { return m_errors; }
+ bool storeStatements(QValueList<MyMoneyStatement>& statements);
+ bool importStatement(const MyMoneyStatement& s);
+
+
+ static int ofxTransactionCallback( struct OfxTransactionData, void* );
+ static int ofxStatementCallback( struct OfxStatementData, void* );
+ static int ofxAccountCallback( struct OfxAccountData, void* );
+ static int ofxStatusCallback( struct OfxStatusData, void* );
+ static int ofxSecurityCallback( struct OfxSecurityData, void* );
+
+private:
+ bool m_valid;
+ bool m_preferName;
+ QValueList<MyMoneyStatement> m_statementlist;
+ QValueList<MyMoneyStatement::Security> m_securitylist;
+ QString m_fatalerror;
+ QStringList m_infos;
+ QStringList m_warnings;
+ QStringList m_errors;
+ KOnlineBankingStatus* m_statusDlg;
+};
+
+#endif
diff --git a/kmymoney2/plugins/ofximport/ofxpartner.cpp b/kmymoney2/plugins/ofximport/ofxpartner.cpp
new file mode 100644
index 0000000..d36fbb2
--- /dev/null
+++ b/kmymoney2/plugins/ofximport/ofxpartner.cpp
@@ -0,0 +1,429 @@
+/***************************************************************************
+ ofxpartner.cpp
+ ----------
+ begin : Fri Jan 23 2009
+ copyright : (C) 2009 by Thomas Baumgart
+ email : Thomas Baumgart <ipwizard@users.sourceforge.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. *
+ * *
+ ***************************************************************************/
+
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+// ----------------------------------------------------------------------------
+// QT Includes
+
+#include <qdatetime.h>
+#include <qeventloop.h>
+#include <qfileinfo.h>
+#include <qvaluelist.h>
+#include <qapplication.h>
+#include <qdom.h>
+#include <qregexp.h>
+#include <qdir.h>
+#include <qtextstream.h>
+
+// ----------------------------------------------------------------------------
+// KDE Includes
+
+
+#include <kio/job.h>
+#include <klocale.h>
+#include <kmessagebox.h>
+
+// ----------------------------------------------------------------------------
+// Project Includes
+
+#include "ofxpartner.h"
+
+namespace OfxPartner
+{
+bool post(const QString& request, const QMap<QString, QString>& attr, const KURL& url, const KURL& filename);
+bool get(const QString& request, const QMap<QString, QString>& attr, const KURL& url, const KURL& filename);
+
+const QString kBankFilename = "ofx-bank-index.xml";
+const QString kCcFilename = "ofx-cc-index.xml";
+const QString kInvFilename = "ofx-inv-index.xml";
+
+#define VER "9"
+
+static QString directory;
+
+void setDirectory(const QString& dir)
+{
+ directory = dir;
+}
+
+bool needReload(const QFileInfo& i)
+{
+ return ((!i.isReadable())
+ || (i.lastModified().addDays(7) < QDateTime::currentDateTime())
+ || (i.size() < 1024));
+}
+
+void ValidateIndexCache(void)
+{
+ // TODO (Ace) Check whether these files exist and are recent enough before getting them again
+
+ struct stat filestats;
+ KURL fname;
+
+ QMap<QString, QString> attr;
+ attr["content-type"] = "application/x-www-form-urlencoded";
+ attr["accept"] = "*/*";
+
+ fname = directory + kBankFilename;
+ QFileInfo i(fname.path());
+ if(needReload(i))
+ post("T=1&S=*&R=1&O=0&TEST=0", attr, KURL("http://moneycentral.msn.com/money/2005/mnynet/service/ols/filist.aspx?SKU=3&VER=" VER), fname);
+
+ fname = directory + kCcFilename;
+ i = QFileInfo(fname.path());
+ if(needReload(i))
+ post("T=2&S=*&R=1&O=0&TEST=0", attr, KURL("http://moneycentral.msn.com/money/2005/mnynet/service/ols/filist.aspx?SKU=3&VER=" VER) ,fname);
+
+ fname = directory + kInvFilename;
+ i = QFileInfo(fname.path());
+ if(needReload(i))
+ post("T=3&S=*&R=1&O=0&TEST=0", attr, KURL("http://moneycentral.msn.com/money/2005/mnynet/service/ols/filist.aspx?SKU=3&VER=" VER), fname);
+}
+
+static void ParseFile(QMap<QString, QString>& result, const QString& fileName, const QString& bankName)
+{
+ QFile f(fileName);
+ if(f.open(IO_ReadOnly)) {
+ QTextStream stream(&f);
+ stream.setEncoding(QTextStream::Unicode);
+ QString msg;
+ int errl, errc;
+ QDomDocument doc;
+ if(doc.setContent(stream.read(), &msg, &errl, &errc)) {
+ QDomNodeList olist = doc.elementsByTagName("prov");
+ for(int i = 0; i < olist.count(); ++i) {
+ QDomNode onode = olist.item(i);
+ if(onode.isElement()) {
+ bool collectGuid = false;
+ QDomElement elo = onode.toElement();
+ QDomNodeList ilist = onode.childNodes();
+ for(int j = 0; j < ilist.count(); ++j) {
+ QDomNode inode = ilist.item(j);
+ QDomElement el = inode.toElement();
+ if(el.tagName() == "name") {
+ if(bankName.isEmpty())
+ result[el.text()] = QString();
+ else if(el.text() == bankName) {
+ collectGuid = true;
+ }
+ }
+ if(el.tagName() == "guid" && collectGuid) {
+ result[el.text()] = QString();
+ }
+ }
+ }
+ }
+ }
+ f.close();
+ }
+}
+
+QValueList<QString> BankNames(void)
+{
+ QMap<QString, QString> result;
+
+ // Make sure the index files are up to date
+ ValidateIndexCache();
+
+ ParseFile(result, directory + kBankFilename, QString());
+ ParseFile(result, directory + kCcFilename, QString());
+ ParseFile(result, directory + kInvFilename, QString());
+
+ // Add Innovision
+ result["Innovision"] = QString();
+
+ return result.keys();
+}
+
+QValueList<QString> FipidForBank(const QString& bank)
+{
+ QMap<QString, QString> result;
+
+ ParseFile(result, directory + kBankFilename, bank);
+ ParseFile(result, directory + kCcFilename, bank);
+ ParseFile(result, directory + kInvFilename, bank);
+
+ // the fipid for Innovision is 1.
+ if ( bank == "Innovision" )
+ result["1"] = QString();
+
+ return result.keys();
+}
+
+QString extractNodeText(QDomElement& node, const QString& name)
+{
+ QString res;
+ QRegExp exp("([^/]+)/?([^/].*)?");
+ if(exp.search(name) != -1) {
+ QDomNodeList olist = node.elementsByTagName(exp.cap(1));
+ if(olist.count()) {
+ QDomNode onode = olist.item(0);
+ if(onode.isElement()) {
+ QDomElement elo = onode.toElement();
+ if(exp.cap(2).isEmpty()) {
+ res = elo.text();
+ } else {
+ res = extractNodeText(elo, exp.cap(2));
+ }
+ }
+ }
+ }
+ return res;
+}
+
+QString extractNodeText(QDomDocument& doc, const QString& name)
+{
+ QString res;
+ QRegExp exp("([^/]+)/?([^/].*)?");
+ if(exp.search(name) != -1) {
+ QDomNodeList olist = doc.elementsByTagName(exp.cap(1));
+ if(olist.count()) {
+ QDomNode onode = olist.item(0);
+ if(onode.isElement()) {
+ QDomElement elo = onode.toElement();
+ if(exp.cap(2).isEmpty()) {
+ res = elo.text();
+ } else {
+ res = extractNodeText(elo, exp.cap(2));
+ }
+ }
+ }
+ }
+ return res;
+}
+
+OfxFiServiceInfo ServiceInfo(const QString& fipid)
+{
+ OfxFiServiceInfo result;
+ memset(&result, 0, sizeof(OfxFiServiceInfo));
+
+ // Hard-coded values for Innovision test server
+ if ( fipid == "1" )
+ {
+ strncpy(result.fid,"00000",OFX_FID_LENGTH-1);
+ strncpy(result.org,"ReferenceFI",OFX_ORG_LENGTH-1);
+ strncpy(result.url,"http://ofx.innovision.com",OFX_URL_LENGTH-1);
+ result.accountlist = 1;
+ result.statements = 1;
+ result.billpay = 1;
+ result.investments = 1;
+
+ return result;
+ }
+
+ QMap<QString, QString> attr;
+ attr["content-type"] = "application/x-www-form-urlencoded";
+ attr["accept"] = "*/*";
+
+ KURL guidFile(QString("%1fipid-%2.xml").arg(directory).arg(fipid));
+
+ // Apparently at some point in time, for VER=6 msn returned an online URL
+ // to a static error page (http://moneycentral.msn.com/cust404.htm).
+ // Increasing to VER=9 solved the problem. This may happen again in the
+ // future.
+ QFileInfo i(guidFile.path());
+ if(!i.isReadable() || i.lastModified().addDays(7) < QDateTime::currentDateTime())
+ get("", attr, KURL(QString("http://moneycentral.msn.com/money/2005/mnynet/service/olsvcupd/OnlSvcBrandInfo.aspx?MSNGUID=&GUID=%1&SKU=3&VER=" VER).arg(fipid)), guidFile);
+
+ QFile f(guidFile.path());
+ if(f.open(IO_ReadOnly)) {
+ QTextStream stream(&f);
+ stream.setEncoding(QTextStream::Unicode);
+ QString msg;
+ int errl, errc;
+ QDomDocument doc;
+ if(doc.setContent(stream.read(), &msg, &errl, &errc)) {
+ QString fid = extractNodeText(doc, "ProviderSettings/FID");
+ QString org = extractNodeText(doc, "ProviderSettings/Org");
+ QString url = extractNodeText(doc, "ProviderSettings/ProviderURL");
+ strncpy(result.fid, fid.latin1(), OFX_FID_LENGTH-1);
+ strncpy(result.org, org.latin1(), OFX_ORG_LENGTH-1);
+ strncpy(result.url, url.latin1(), OFX_URL_LENGTH-1);
+ result.accountlist = (extractNodeText(doc, "ProviderSettings/AcctListAvail") == "1");
+ result.statements = (extractNodeText(doc, "BankingCapabilities/Bank") == "1");
+ result.billpay= (extractNodeText(doc, "BillPayCapabilities/Pay") == "1");
+ result.investments= (extractNodeText(doc, "InvestmentCapabilities/BrkStmt") == "1");
+ }
+ }
+
+ return result;
+}
+
+bool get(const QString& request, const QMap<QString, QString>& attr, const KURL& url, const KURL& filename)
+{
+ QByteArray req(0);
+ OfxHttpRequest job("GET", url, req, attr, filename, true);
+
+ return job.error() == QHttp::NoError;
+}
+
+bool post(const QString& request, const QMap<QString, QString>& attr, const KURL& url, const KURL& filename)
+{
+ QByteArray req;
+ req.fill(0, request.length()+1);
+ req.duplicate(request.ascii(), request.length());
+
+ OfxHttpRequest job("POST", url, req, attr, filename, true);
+ return job.error() == QHttp::NoError;
+}
+
+} // namespace OfxPartner
+
+class OfxHttpsRequest::Private
+{
+public:
+ QFile m_fpTrace;
+};
+
+OfxHttpsRequest::OfxHttpsRequest(const QString& type, const KURL &url, const QByteArray &postData, const QMap<QString, QString>& metaData, const KURL& dst, bool showProgressInfo) :
+ d(new Private),
+ m_dst(dst)
+{
+ QDir homeDir(QDir::home());
+ if(homeDir.exists("ofxlog.txt")) {
+ d->m_fpTrace.setName(QString("%1/ofxlog.txt").arg(QDir::homeDirPath()));
+ d->m_fpTrace.open(IO_WriteOnly | IO_Append);
+ }
+
+ m_job = KIO::http_post(url, postData, showProgressInfo);
+ m_job->addMetaData("content-type", "Content-type: application/x-ofx" );
+
+ if(d->m_fpTrace.isOpen()) {
+ QTextStream ts(&d->m_fpTrace);
+ ts << "url: " << url.prettyURL() << "\n";
+ ts << "request:\n" << QString(postData) << "\n" << "response:\n";
+ }
+
+ connect(m_job,SIGNAL(result(KIO::Job*)),this,SLOT(slotOfxFinished(KIO::Job*)));
+ connect(m_job,SIGNAL(data(KIO::Job*, const QByteArray&)),this,SLOT(slotOfxData(KIO::Job*,const QByteArray&)));
+ connect(m_job,SIGNAL(connected(KIO::Job*)),this,SLOT(slotOfxConnected(KIO::Job*)));
+
+ qApp->enter_loop();
+}
+
+OfxHttpsRequest::~OfxHttpsRequest()
+{
+ if(d->m_fpTrace.isOpen()) {
+ d->m_fpTrace.close();
+ }
+}
+
+void OfxHttpsRequest::slotOfxConnected(KIO::Job*)
+{
+ m_file.setName(m_dst.path());
+ m_file.open(IO_WriteOnly);
+}
+
+void OfxHttpsRequest::slotOfxData(KIO::Job*,const QByteArray& _ba)
+{
+ if(m_file.isOpen()) {
+ QTextStream ts(&m_file);
+ ts << QString(_ba);
+
+ if(d->m_fpTrace.isOpen()) {
+ d->m_fpTrace.writeBlock(_ba, _ba.size());
+ }
+
+
+ }
+}
+
+void OfxHttpsRequest::slotOfxFinished(KIO::Job* /* e */)
+{
+ if(m_file.isOpen()) {
+ m_file.close();
+ if(d->m_fpTrace.isOpen()) {
+ d->m_fpTrace.writeBlock("\nCompleted\n\n\n\n", 14);
+ }
+ }
+
+ int error = m_job->error();
+ if ( error ) {
+ m_job->showErrorDialog();
+ unlink(m_dst.path());
+
+ } else if ( m_job->isErrorPage() ) {
+ QString details;
+ QFile f( m_dst.path() );
+ if ( f.open( IO_ReadOnly ) ) {
+ QTextStream stream( &f );
+ QString line;
+ while ( !stream.atEnd() ) {
+ details += stream.readLine(); // line of text excluding '\n'
+ }
+ f.close();
+ }
+ KMessageBox::detailedSorry( 0, i18n("The HTTP request failed."), details, i18n("Failed") );
+ unlink(m_dst.path());
+ }
+
+ qApp->exit_loop();
+}
+
+
+
+OfxHttpRequest::OfxHttpRequest(const QString& type, const KURL &url, const QByteArray &postData, const QMap<QString, QString>& metaData, const KURL& dst, bool showProgressInfo)
+{
+ QFile f(dst.path());
+ m_error = QHttp::NoError;
+ QString errorMsg;
+ if(f.open(IO_WriteOnly)) {
+ m_job = new QHttp(url.host());
+ QHttpRequestHeader header(type, url.encodedPathAndQuery());
+ header.setValue("Host", url.host());
+ QMap<QString, QString>::const_iterator it;
+ for(it = metaData.begin(); it != metaData.end(); ++it) {
+ header.setValue(it.key(), *it);
+ }
+
+ m_job->request(header, postData, &f);
+
+ connect(m_job, SIGNAL(requestFinished(int, bool)),
+ this, SLOT(slotOfxFinished(int, bool)));
+
+ qApp->enter_loop();
+
+ if(m_error != QHttp::NoError)
+ errorMsg = m_job->errorString();
+
+ delete m_job;
+ } else {
+ m_error = QHttp::Aborted;
+ errorMsg = i18n("Cannot open file %1 for writing").arg(dst.path());
+ }
+
+ if(m_error != QHttp::NoError) {
+ KMessageBox::error(0, errorMsg, i18n("OFX setup error"));
+ unlink(dst.path());
+ }
+}
+
+void OfxHttpRequest::slotOfxFinished(int, bool rc)
+{
+ if(rc) {
+ m_error = m_job->error();
+ }
+ qApp->exit_loop();
+}
+
+#include "ofxpartner.moc"
+
+// vim:cin:si:ai:et:ts=2:sw=2:
diff --git a/kmymoney2/plugins/ofximport/ofxpartner.h b/kmymoney2/plugins/ofximport/ofxpartner.h
new file mode 100644
index 0000000..e624282
--- /dev/null
+++ b/kmymoney2/plugins/ofximport/ofxpartner.h
@@ -0,0 +1,102 @@
+/***************************************************************************
+ ofxpartner.h
+ ----------
+ begin : Fri Jan 23 2009
+ copyright : (C) 2009 by Thomas Baumgart
+ email : Thomas Baumgart <ipwizard@users.sourceforge.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. *
+ * *
+ ***************************************************************************/
+
+#ifndef OFXPARTNER_H
+#define OFXPARTNER_H
+
+// ----------------------------------------------------------------------------
+// QT Includes
+
+
+#include <qobject.h>
+#include <qhttp.h>
+
+// ----------------------------------------------------------------------------
+// KDE Includes
+
+#include <kurl.h>
+namespace KIO
+{
+ class Job;
+ class TransferJob;
+}
+
+// ----------------------------------------------------------------------------
+// Project Includes
+
+#include <libofx/libofx.h>
+
+namespace OfxPartner
+{
+ /**
+ * setup the directory where the files will be stored.
+ * @a dir must end with a '/' and must exist. Call this
+ * before any other of the functions of OfxPartner. The
+ * default will be to store the files in the current
+ * directory.
+ */
+ void setDirectory(const QString& dir);
+
+ void ValidateIndexCache(void);
+ OfxFiServiceInfo ServiceInfo(const QString& fipid);
+ QValueList<QString> BankNames(void);
+ QValueList<QString> FipidForBank(const QString& bank);
+
+}
+
+class OfxHttpRequest : public QObject
+{
+ Q_OBJECT
+public:
+ OfxHttpRequest(const QString& method, const KURL &url, const QByteArray &postData, const QMap<QString, QString>& metaData, const KURL& dst, bool showProgressInfo=true);
+ virtual ~OfxHttpRequest() {}
+
+ QHttp::Error error(void) const { return m_error; }
+
+protected slots:
+ void slotOfxFinished(int, bool);
+
+private:
+ QHttp* m_job;
+ KURL m_dst;
+ QHttp::Error m_error;
+
+};
+
+class OfxHttpsRequest : public QObject
+{
+Q_OBJECT
+public:
+ OfxHttpsRequest(const QString& method, const KURL &url, const QByteArray &postData, const QMap<QString, QString>& metaData, const KURL& dst, bool showProgressInfo=true);
+ virtual ~OfxHttpsRequest();
+
+ QHttp::Error error(void) const { return m_error; }
+
+protected slots:
+ void slotOfxFinished(KIO::Job*);
+ void slotOfxData(KIO::Job*,const QByteArray&);
+ void slotOfxConnected(KIO::Job*);
+
+private:
+ class Private;
+ Private* d;
+ KURL m_dst;
+ QFile m_file;
+ QHttp::Error m_error;
+ KIO::TransferJob* m_job;
+};
+#endif // OFXPARTNER_H
diff --git a/kmymoney2/plugins/pluginloader.cpp b/kmymoney2/plugins/pluginloader.cpp
new file mode 100644
index 0000000..0201337
--- /dev/null
+++ b/kmymoney2/plugins/pluginloader.cpp
@@ -0,0 +1,163 @@
+/***************************************************************************
+ pluginloader.cpp
+ -------------------
+ begin : Thu Feb 12 2009
+ copyright : (C) 2009 Cristian Onet
+ email : onet.cristian@gmail.com
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * 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. *
+ * *
+ ***************************************************************************/
+
+// ----------------------------------------------------------------------------
+// QT Includes
+
+#include <qstringlist.h>
+#include <qcheckbox.h>
+#include <qlayout.h>
+
+// ----------------------------------------------------------------------------
+// KDE Includes
+
+#include <ktrader.h>
+#include <kparts/componentfactory.h>
+#include <kdebug.h>
+#include <kdialog.h>
+#include <kconfig.h>
+#include <kpluginselector.h>
+#include <klocale.h>
+
+// ----------------------------------------------------------------------------
+// Project Includes
+
+#include "kmymoneyplugin.h"
+#include "pluginloader.h"
+
+namespace KMyMoneyPlugin {
+
+//---------------------------------------------------------------------
+//
+// PluginLoader
+//
+//---------------------------------------------------------------------
+static PluginLoader* s_instance = 0;
+
+typedef QMap<QString, Plugin*> PluginsMap;
+
+struct PluginLoader::Private
+{
+ QObject* m_parent;
+ KPluginInfo::List m_pluginList;
+ KPluginSelector* m_pluginSelector;
+ PluginsMap m_loadedPlugins;
+};
+
+PluginLoader::PluginLoader(QObject* parent)
+{
+ Q_ASSERT( s_instance == 0 );
+ s_instance = this;
+
+ d = new Private;
+
+ d->m_parent = parent;
+
+ KTrader::OfferList offers = KTrader::self()->query("KMyMoneyPlugin");
+ d->m_pluginList = KPluginInfo::fromServices(offers);
+
+ d->m_pluginSelector = new KPluginSelector(NULL);
+ d->m_pluginSelector->setShowEmptyConfigPage(false);
+ d->m_pluginSelector->addPlugins(d->m_pluginList);
+ d->m_pluginSelector->load();
+
+ connect(d->m_pluginSelector, SIGNAL(changed(bool)), this, SLOT(changed()));
+ connect(d->m_pluginSelector, SIGNAL(configCommitted(const QCString &)), this, SLOT(changedConfigOfPlugin(const QCString &)));
+}
+
+PluginLoader::~PluginLoader()
+{
+ delete d;
+}
+
+void PluginLoader::loadPlugins()
+{
+ for( KPluginInfo::List::Iterator it = d->m_pluginList.begin(); it != d->m_pluginList.end(); ++it )
+ loadPlugin( *it );
+}
+
+void PluginLoader::loadPlugin(KPluginInfo* info)
+{
+ if (info->isPluginEnabled()) {
+ Plugin* plugin = getPluginFromInfo(info);
+
+ if (!plugin) {
+ // the plugin is enabled but it is not loaded
+ KService::Ptr service = info->service();
+ int error = 0;
+ Plugin* plugin = KParts::ComponentFactory
+ ::createInstanceFromService<Plugin>(service, d->m_parent, info->name().utf8(), QStringList(), &error);
+ if (plugin) {
+ kdDebug() << "KMyMoneyPlugin::PluginLoader: Loaded plugin " << plugin->name() << endl;
+ d->m_loadedPlugins.insert(info->name(), plugin);
+ emit PluginLoader::instance()->plug(info);
+ }
+ else {
+ kdWarning() << "KMyMoneyPlugin::PluginLoader:: createInstanceFromService returned 0 for "
+ << info->name()
+ << " with error number "
+ << error << endl;
+ if (error == KParts::ComponentFactory::ErrNoLibrary)
+ kdWarning() << "KLibLoader says: "
+ << KLibLoader::self()->lastErrorMessage() << endl;
+ }
+ }
+ }
+ else {
+ if (getPluginFromInfo(info) != NULL) {
+ // everybody interested should say goodbye to the plugin
+ emit PluginLoader::instance()->unplug(info);
+ d->m_loadedPlugins.erase(info->name());
+ }
+ }
+}
+
+void PluginLoader::changed()
+{
+ loadPlugins();
+}
+
+void PluginLoader::changedConfigOfPlugin(const QCString & name)
+{
+ PluginsMap::iterator itPlugin = d->m_loadedPlugins.find(QString(name));
+ if (itPlugin != d->m_loadedPlugins.end())
+ configChanged(*itPlugin);
+}
+
+Plugin* PluginLoader::getPluginFromInfo(KPluginInfo* info)
+{
+ PluginsMap::iterator itPlugin = d->m_loadedPlugins.find(info->name());
+ if (itPlugin != d->m_loadedPlugins.end())
+ return *itPlugin;
+ else
+ return NULL;
+}
+
+PluginLoader* PluginLoader::instance()
+{
+ Q_ASSERT( s_instance != 0);
+ return s_instance;
+}
+
+KPluginSelector* PluginLoader::pluginSelectorWidget()
+{
+ return d->m_pluginSelector;
+}
+
+} // namespace
+
+#include "pluginloader.moc"
diff --git a/kmymoney2/plugins/pluginloader.h b/kmymoney2/plugins/pluginloader.h
new file mode 100644
index 0000000..4d0c500
--- /dev/null
+++ b/kmymoney2/plugins/pluginloader.h
@@ -0,0 +1,76 @@
+/***************************************************************************
+ pluginloader.h
+ -------------------
+ begin : Thu Feb 12 2009
+ copyright : (C) 2009 Cristian Onet
+ email : onet.cristian@gmail.com
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * 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. *
+ * *
+ ***************************************************************************/
+
+#ifndef PLUGINLOADER_H
+#define PLUGINLOADER_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+// ----------------------------------------------------------------------------
+// QT Includes
+
+#include <qwidget.h>
+#include <qscrollview.h>
+
+// ----------------------------------------------------------------------------
+// KDE Includes
+#include <kplugininfo.h>
+
+// ----------------------------------------------------------------------------
+// Project Includes
+
+#include <kmymoney/export.h>
+
+class KPluginSelector;
+
+namespace KMyMoneyPlugin
+{
+ class Plugin;
+
+ class KMYMONEY_EXPORT PluginLoader : public QObject
+ {
+ Q_OBJECT
+ public:
+ PluginLoader(QObject* parent);
+ virtual ~PluginLoader();
+ static PluginLoader* instance();
+
+ void loadPlugins();
+ Plugin* getPluginFromInfo(KPluginInfo*);
+ KPluginSelector* pluginSelectorWidget();
+
+ private:
+ void loadPlugin(KPluginInfo*);
+
+ signals:
+ void plug(KPluginInfo*);
+ void unplug(KPluginInfo*);
+ void configChanged(Plugin*); // consfiguration of the plugin has changed not the enabled/disabled state
+
+ private slots:
+ void changed();
+ void changedConfigOfPlugin( const QCString & );
+
+ private:
+ struct Private;
+ Private* d;
+ };
+}
+
+#endif /* PLUGINLOADER_H */
diff --git a/kmymoney2/plugins/statementinterface.cpp b/kmymoney2/plugins/statementinterface.cpp
new file mode 100644
index 0000000..753db2e
--- /dev/null
+++ b/kmymoney2/plugins/statementinterface.cpp
@@ -0,0 +1,34 @@
+/***************************************************************************
+ statementinterface.cpp
+ -------------------
+ begin : Wed Jan 5 2005
+ copyright : (C) 2005 Thomas Baumgart
+ email : ipwizard@users.sourceforge.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. *
+ * *
+ ***************************************************************************/
+
+// ----------------------------------------------------------------------------
+// QT Includes
+
+// ----------------------------------------------------------------------------
+// KDE Includes
+
+// ----------------------------------------------------------------------------
+// Project Includes
+
+#include "statementinterface.h"
+
+KMyMoneyPlugin::StatementInterface::StatementInterface(QObject* parent, const char* name) :
+ QObject(parent, name)
+{
+}
+
+#include "statementinterface.moc"
diff --git a/kmymoney2/plugins/statementinterface.h b/kmymoney2/plugins/statementinterface.h
new file mode 100644
index 0000000..a3a31d1
--- /dev/null
+++ b/kmymoney2/plugins/statementinterface.h
@@ -0,0 +1,72 @@
+/***************************************************************************
+ statementinterface.h
+ -------------------
+ begin : Wed Jan 5 2005
+ copyright : (C) 2005 Thomas Baumgart
+ email : ipwizard@users.sourceforge.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. *
+ * *
+ ***************************************************************************/
+
+#ifndef STATEMENTINTERFACE_H
+#define STATEMENTINTERFACE_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+// ----------------------------------------------------------------------------
+// QT Includes
+
+#include <qobject.h>
+
+// ----------------------------------------------------------------------------
+// KDE Includes
+
+// ----------------------------------------------------------------------------
+// Project Includes
+
+#include <kmymoney/mymoneystatement.h>
+#include <kmymoney/mymoneyaccount.h>
+#include <kmymoney/export.h>
+
+namespace KMyMoneyPlugin {
+
+/**
+ * This abstract class represents the interface to import statements
+ * into the KMyMoney application
+ */
+class KMYMONEY_EXPORT StatementInterface : public QObject {
+ Q_OBJECT
+
+public:
+ StatementInterface(QObject* parent, const char* name = 0);
+ ~StatementInterface() {}
+
+ /**
+ * This method imports a MyMoneyStatement into the engine
+ */
+ virtual bool import(const MyMoneyStatement& s) = 0;
+
+ /**
+ * This method returns the account for a given @a key - @a value pair.
+ * If the account is not found in the list of accounts, MyMoneyAccount()
+ * is returned.
+ */
+ virtual const MyMoneyAccount& account(const QString& key, const QString& value) const = 0;
+
+ /**
+ */
+ virtual void setAccountOnlineParameters(const MyMoneyAccount& acc, const MyMoneyKeyValueContainer& kvps) const = 0;
+
+};
+
+}; // namespace
+#endif
diff --git a/kmymoney2/plugins/viewinterface.cpp b/kmymoney2/plugins/viewinterface.cpp
new file mode 100644
index 0000000..4db12f1
--- /dev/null
+++ b/kmymoney2/plugins/viewinterface.cpp
@@ -0,0 +1,34 @@
+/***************************************************************************
+ viewinterface.cpp
+ -------------------
+ begin : Wed Jan 5 2005
+ copyright : (C) 2005 Thomas Baumgart
+ email : ipwizard@users.sourceforge.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. *
+ * *
+ ***************************************************************************/
+
+// ----------------------------------------------------------------------------
+// QT Includes
+
+// ----------------------------------------------------------------------------
+// KDE Includes
+
+// ----------------------------------------------------------------------------
+// Project Includes
+
+#include "viewinterface.h"
+
+KMyMoneyPlugin::ViewInterface::ViewInterface(QObject* parent, const char* name) :
+ QObject(parent, name)
+{
+}
+
+#include "viewinterface.moc"
diff --git a/kmymoney2/plugins/viewinterface.h b/kmymoney2/plugins/viewinterface.h
new file mode 100644
index 0000000..d7c7424
--- /dev/null
+++ b/kmymoney2/plugins/viewinterface.h
@@ -0,0 +1,123 @@
+/***************************************************************************
+ viewinterface.h
+ -------------------
+ begin : Wed Jan 5 2005
+ copyright : (C) 2005 Thomas Baumgart
+ email : ipwizard@users.sourceforge.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. *
+ * *
+ ***************************************************************************/
+
+#ifndef VIEWINTERFACE_H
+#define VIEWINTERFACE_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+// ----------------------------------------------------------------------------
+// QT Includes
+
+#include <qobject.h>
+#include <qstring.h>
+#include <qpixmap.h>
+class QFrame;
+
+// ----------------------------------------------------------------------------
+// KDE Includes
+
+class KPopupMenu;
+
+// ----------------------------------------------------------------------------
+// Project Includes
+
+#include <kmymoney/mymoneyaccount.h>
+#include <kmymoney/mymoneyinstitution.h>
+#include <kmymoney/export.h>
+class KMyMoneyViewBase;
+namespace KMyMoneyRegister {
+ class SelectedTransactions;
+};
+
+namespace KMyMoneyPlugin {
+
+/**
+ * This abstract class represents the ViewInterface to
+ * add new view pages to the JanusWidget of KMyMoney. It
+ * also gives access to the account context menu.
+ */
+class KMYMONEY_EXPORT ViewInterface : public QObject {
+ Q_OBJECT
+
+public:
+ ViewInterface(QObject* parent, const char* name = 0);
+ ~ViewInterface() {}
+
+ /**
+ * This method creates a new page in the application.
+ * See KJanusWidget::addPage() for details.
+ */
+ virtual KMyMoneyViewBase* addPage(const QString& item, const QString& icon) = 0;
+
+ /**
+ * This method adds a widget to the layout of the view
+ * created with addPage()
+ *
+ * @param view pointer to view widget
+ * @param w widget to be added to @p page
+ */
+ virtual void addWidget(KMyMoneyViewBase* view, QWidget* w) = 0;
+
+signals:
+ /**
+ * This signal is emitted when a new account has been selected by
+ * the GUI. If no account is selected or the selection is removed,
+ * @a account is identical to MyMoneyAccount(). This signal is used
+ * by plugins to get information about changes.
+ */
+ void accountSelected(const MyMoneyAccount& acc);
+
+ /**
+ * This signal is emitted when a transaction/list of transactions has been selected by
+ * the GUI. If no transaction is selected or the selection is removed,
+ * @p transactions is identical to an empty QValueList. This signal is used
+ * by plugins to get information about changes.
+ */
+ void transactionsSelected(const KMyMoneyRegister::SelectedTransactions& transactions);
+
+ /**
+ * This signal is emitted when a new institution has been selected by
+ * the GUI. If no institution is selected or the selection is removed,
+ * @a institution is identical to MyMoneyInstitution(). This signal is used
+ * by plugins to get information about changes.
+ */
+ void institutionSelected(const MyMoneyInstitution& institution);
+
+ /**
+ * This signal is emitted when an account has been successfully reconciled
+ * and all transactions are updated in the engine. It can be used by plugins
+ * to create reconciliation reports.
+ *
+ * @param account the account data
+ * @param date the reconciliation date as provided through the dialog
+ * @param startingBalance the starting balance as provided through the dialog
+ * @param endingBalance the ending balance as provided through the dialog
+ * @param transactionList reference to QValueList of QPair containing all
+ * transaction/split pairs processed by the reconciliation.
+ */
+ void accountReconciled(const MyMoneyAccount& account, const QDate& date, const MyMoneyMoney& startingBalance, const MyMoneyMoney& endingBalance, const QValueList<QPair<MyMoneyTransaction, MyMoneySplit> >& transactionList);
+
+
+ void viewStateChanged(bool);
+ void kmmFilePlugin(unsigned int);
+};
+
+}; // namespace
+#endif