|
/***************************************************************************
|
|
$RCSfile$
|
|
-------------------
|
|
cvs : $Id$
|
|
begin : Mon Mar 01 2004
|
|
copyright : (C) 2004 by Martin Preuss
|
|
email : martin@libchipcard.de
|
|
|
|
***************************************************************************
|
|
* Please see toplevel file COPYING for license details *
|
|
***************************************************************************/
|
|
|
|
#ifdef HAVE_CONFIG_H
|
|
# include <config.h>
|
|
#endif
|
|
|
|
/* don't warn about our own deprecated functions */
|
|
#define AQBANKING_NOWARN_DEPRECATED
|
|
|
|
|
|
#include "banking_p.h"
|
|
#include "provider_l.h"
|
|
#include "imexporter_l.h"
|
|
#include "bankinfoplugin_l.h"
|
|
#include "cryptmanager_l.h"
|
|
#include "i18n_l.h"
|
|
#include "country_l.h"
|
|
#include "wcb_l.h"
|
|
#include "userfns_l.h"
|
|
|
|
/* TODO: includes for distrib functions, soon to be removed */
|
|
#include "jobgettransactions_l.h"
|
|
#include "jobgetbalance_l.h"
|
|
#include "jobgetstandingorders_l.h"
|
|
#include "jobgetdatedtransfers_l.h"
|
|
|
|
#include <gwenhywfar/version.h>
|
|
#include <gwenhywfar/gwenhywfar.h>
|
|
#include <gwenhywfar/debug.h>
|
|
#include <gwenhywfar/misc.h>
|
|
#include <gwenhywfar/directory.h>
|
|
#include <gwenhywfar/libloader.h>
|
|
#include <gwenhywfar/bio_file.h>
|
|
#include <gwenhywfar/text.h>
|
|
#include <gwenhywfar/md.h>
|
|
#include <gwenhywfar/xml.h>
|
|
#include <gwenhywfar/pathmanager.h>
|
|
|
|
#include <stdlib.h>
|
|
#include <assert.h>
|
|
#include <string.h>
|
|
#include <unistd.h>
|
|
#include <sys/types.h>
|
|
#include <sys/stat.h>
|
|
#include <fcntl.h>
|
|
#include <unistd.h>
|
|
#include <errno.h>
|
|
#include <ctype.h>
|
|
|
|
/* includes for high level API */
|
|
#include "jobgetbalance.h"
|
|
#include "jobgettransactions.h"
|
|
#include "jobgetstandingorders.h"
|
|
#include "jobsingletransfer.h"
|
|
#include "jobsingledebitnote.h"
|
|
#include "jobeutransfer.h"
|
|
#include "jobgetdatedtransfers.h"
|
|
|
|
|
|
#ifdef OS_WIN32
|
|
# define ftruncate chsize
|
|
# define DIRSEP "\\"
|
|
#else
|
|
# define DIRSEP "/"
|
|
#endif
|
|
|
|
#undef AB_Banking_new
|
|
|
|
|
|
GWEN_INHERIT_FUNCTIONS(AB_BANKING)
|
|
|
|
#include <aqbanking/error.h>
|
|
|
|
|
|
AB_BANKING *AB_Banking_new(const char *appName, const char *dname){
|
|
return AB_Banking_newExtended(appName, dname, 0);
|
|
}
|
|
|
|
|
|
|
|
void AB_Banking__GetConfigFileNameAndDataDir(AB_BANKING *ab,
|
|
const char *dname) {
|
|
GWEN_BUFFER *buf;
|
|
char home[256];
|
|
|
|
if (GWEN_Directory_GetHomeDirectory(home, sizeof(home))) {
|
|
DBG_ERROR(AQBANKING_LOGDOMAIN,
|
|
"Could not determine home directory, aborting.");
|
|
abort();
|
|
}
|
|
|
|
buf=GWEN_Buffer_new(0, 256, 0, 1);
|
|
|
|
if (dname) {
|
|
/* determine config file name */
|
|
GWEN_Buffer_AppendString(buf, dname);
|
|
GWEN_Buffer_AppendString(buf, DIRSEP AB_BANKING_CONFIGFILE);
|
|
ab->configFile=strdup(GWEN_Buffer_GetStart(buf));
|
|
/* setup data dir */
|
|
ab->dataDir=strdup(dname);
|
|
}
|
|
else {
|
|
GWEN_TYPE_UINT32 pos;
|
|
FILE *f;
|
|
const char *s;
|
|
|
|
/* determine config directory */
|
|
s=getenv("AQBANKING_HOME");
|
|
if (s && !*s)
|
|
s=0;
|
|
if (s)
|
|
GWEN_Buffer_AppendString(buf, s);
|
|
else
|
|
GWEN_Buffer_AppendString(buf, home);
|
|
GWEN_Buffer_AppendString(buf, DIRSEP);
|
|
pos=GWEN_Buffer_GetPos(buf);
|
|
GWEN_Buffer_AppendString(buf, AB_BANKING_USERDATADIR);
|
|
/* as we are at it: store default data dir */
|
|
ab->dataDir=strdup(GWEN_Buffer_GetStart(buf));
|
|
|
|
/* first try new default file */
|
|
GWEN_Buffer_AppendString(buf, DIRSEP AB_BANKING_CONFIGFILE);
|
|
f=fopen(GWEN_Buffer_GetStart(buf), "r");
|
|
if (f) {
|
|
fclose(f);
|
|
ab->configFile=strdup(GWEN_Buffer_GetStart(buf));
|
|
}
|
|
else {
|
|
/* try old default file */
|
|
GWEN_Buffer_Crop(buf, 0, pos);
|
|
GWEN_Buffer_AppendString(buf, AB_BANKING_OLD_CONFIGFILE);
|
|
f=fopen(GWEN_Buffer_GetStart(buf), "r");
|
|
if (f) {
|
|
fclose(f);
|
|
ab->configFile=strdup(GWEN_Buffer_GetStart(buf));
|
|
/* New file did not exist, if the old file exists we will move it
|
|
* upon AB_Banking_Fini(). */
|
|
}
|
|
else {
|
|
/* file not found, create new default file later */
|
|
GWEN_Buffer_Crop(buf, 0, pos);
|
|
GWEN_Buffer_AppendString(buf,
|
|
AB_BANKING_USERDATADIR DIRSEP
|
|
AB_BANKING_CONFIGFILE);
|
|
ab->configFile=strdup(GWEN_Buffer_GetStart(buf));
|
|
}
|
|
}
|
|
}
|
|
GWEN_Buffer_free(buf);
|
|
}
|
|
|
|
|
|
|
|
|
|
AB_BANKING *AB_Banking_newExtended(const char *appName,
|
|
const char *dname,
|
|
GWEN_TYPE_UINT32 extensions){
|
|
AB_BANKING *ab;
|
|
GWEN_BUFFER *nbuf;
|
|
char buffer[256];
|
|
GWEN_ERRORCODE err;
|
|
|
|
assert(appName);
|
|
err=GWEN_Init();
|
|
if (!GWEN_Error_IsOk(err)) {
|
|
DBG_ERROR_ERR(AQBANKING_LOGDOMAIN, err);
|
|
abort();
|
|
}
|
|
DBG_INFO(AQBANKING_LOGDOMAIN,
|
|
"Application \"%s\" compiled with extensions %08x",
|
|
appName, extensions);
|
|
|
|
nbuf=GWEN_Buffer_new(0, 256, 0, 1);
|
|
if (GWEN_Text_EscapeToBufferTolerant(appName, nbuf)) {
|
|
DBG_ERROR(AQBANKING_LOGDOMAIN,
|
|
"Bad application name, aborting.");
|
|
GWEN_Buffer_free(nbuf);
|
|
abort();
|
|
}
|
|
else {
|
|
char *s;
|
|
|
|
s=GWEN_Buffer_GetStart(nbuf);
|
|
while(*s) {
|
|
*s=tolower(*s);
|
|
s++;
|
|
}
|
|
}
|
|
|
|
GWEN_NEW_OBJECT(AB_BANKING, ab);
|
|
GWEN_INHERIT_INIT(AB_BANKING, ab);
|
|
ab->providers=AB_Provider_List_new();
|
|
ab->imexporters=AB_ImExporter_List_new();
|
|
ab->bankInfoPlugins=AB_BankInfoPlugin_List_new();
|
|
ab->users=AB_User_List_new();
|
|
ab->accounts=AB_Account_List_new();
|
|
ab->enqueuedJobs=AB_Job_List_new();
|
|
ab->appEscName=strdup(GWEN_Buffer_GetStart(nbuf));
|
|
ab->appName=strdup(appName);
|
|
ab->activeProviders=GWEN_StringList_new();
|
|
GWEN_StringList_SetSenseCase(ab->activeProviders, 0);
|
|
ab->data=GWEN_DB_Group_new("BankingData");
|
|
ab->pinList=AB_Pin_List_new();
|
|
ab->pinCacheEnabled=0;
|
|
GWEN_Buffer_free(nbuf);
|
|
|
|
AB_Banking__GetConfigFileNameAndDataDir(ab, dname);
|
|
|
|
ab->dbTempConfig=GWEN_DB_Group_new("tmpConfig");
|
|
|
|
DBG_INFO(AQBANKING_LOGDOMAIN, "Registering callbacks");
|
|
ab->waitCallback=AB_WaitCallback_new(ab, AB_BANKING_WCB_GENERIC);
|
|
if (GWEN_WaitCallback_Register(ab->waitCallback)) {
|
|
DBG_ERROR(AQBANKING_LOGDOMAIN,
|
|
"Internal error: Could not register callback.");
|
|
abort();
|
|
}
|
|
|
|
ab->appExtensions=extensions;
|
|
|
|
if (getcwd(buffer, sizeof(buffer)-1)==0) {
|
|
DBG_ERROR(AQBANKING_LOGDOMAIN,
|
|
"getcwd: %s", strerror(errno));
|
|
}
|
|
else {
|
|
struct stat st;
|
|
|
|
if (stat(buffer, &st)) {
|
|
DBG_ERROR(AQBANKING_LOGDOMAIN,
|
|
"stat(%s): %s", buffer, strerror(errno));
|
|
}
|
|
else {
|
|
ab->startFolder=strdup(buffer);
|
|
}
|
|
}
|
|
|
|
return ab;
|
|
}
|
|
|
|
|
|
|
|
void AB_Banking_free(AB_BANKING *ab){
|
|
if (ab) {
|
|
DBG_INFO(AQBANKING_LOGDOMAIN, "Destroying AB_BANKING");
|
|
|
|
#if 0
|
|
/* This might be enabled to help application programmers to keep
|
|
track of the callbacks that they might have forgotten. */
|
|
if (!ab->messageBoxFn) DBG_WARN(AQBANKING_LOGDOMAIN, "AB_BANKING_MESSAGEBOX_FN messageBoxFn was not set during this usage of AB_BANKING.");
|
|
if (!ab->inputBoxFn) DBG_WARN(AQBANKING_LOGDOMAIN, "AB_BANKING_INPUTBOX_FN inputBoxFn was not set during this usage of AB_BANKING.");
|
|
if (!ab->showBoxFn) DBG_WARN(AQBANKING_LOGDOMAIN, "AB_BANKING_SHOWBOX_FN showBoxFn was not set during this usage of AB_BANKING.");
|
|
if (!ab->hideBoxFn) DBG_WARN(AQBANKING_LOGDOMAIN, "AB_BANKING_HIDEBOX_FN hideBoxFn was not set during this usage of AB_BANKING.");
|
|
if (!ab->progressStartFn) DBG_WARN(AQBANKING_LOGDOMAIN, "AB_BANKING_PROGRESS_START_FN progressStartFn was not set during this usage of AB_BANKING.");
|
|
if (!ab->progressAdvanceFn) DBG_WARN(AQBANKING_LOGDOMAIN, "AB_BANKING_PROGRESS_ADVANCE_FN progressAdvanceFn was not set during this usage of AB_BANKING.");
|
|
if (!ab->progressLogFn) DBG_WARN(AQBANKING_LOGDOMAIN, "AB_BANKING_PROGRESS_LOG_FN progressLogFn was not set during this usage of AB_BANKING.");
|
|
if (!ab->progressEndFn) DBG_WARN(AQBANKING_LOGDOMAIN, "AB_BANKING_PROGRESS_END_FN progressEndFn was not set during this usage of AB_BANKING.");
|
|
if (!ab->printFn) DBG_WARN(AQBANKING_LOGDOMAIN, "AB_BANKING_PRINT_FN printFn was not set during this usage of AB_BANKING.");
|
|
if (!ab->getPinFn) DBG_WARN(AQBANKING_LOGDOMAIN, "AB_BANKING_GETPIN_FN getPinFn was not set during this usage of AB_BANKING.");
|
|
if (!ab->setPinStatusFn) DBG_WARN(AQBANKING_LOGDOMAIN, "AB_BANKING_SETPINSTATUS_FN setPinStatusFn was not set during this usage of AB_BANKING.");
|
|
if (!ab->getTanFn) DBG_WARN(AQBANKING_LOGDOMAIN, "AB_BANKING_GETTAN_FN getTanFn was not set during this usage of AB_BANKING.");
|
|
if (!ab->setTanStatusFn) DBG_WARN(AQBANKING_LOGDOMAIN, "AB_BANKING_SETTANSTATUS_FN setTanStatusFn was not set during this usage of AB_BANKING.");
|
|
#endif
|
|
|
|
GWEN_INHERIT_FINI(AB_BANKING, ab);
|
|
|
|
GWEN_WaitCallback_Unregister(ab->waitCallback);
|
|
GWEN_WaitCallback_free(ab->waitCallback);
|
|
|
|
AB_Job_List_free(ab->enqueuedJobs);
|
|
AB_Account_List_free(ab->accounts);
|
|
AB_User_List_free(ab->users);
|
|
AB_Provider_List_free(ab->providers);
|
|
AB_BankInfoPlugin_List_free(ab->bankInfoPlugins);
|
|
AB_ImExporter_List_free(ab->imexporters);
|
|
GWEN_StringList_free(ab->activeProviders);
|
|
GWEN_DB_Group_free(ab->data);
|
|
AB_Pin_List_free(ab->pinList);
|
|
GWEN_DB_Group_free(ab->dbTempConfig);
|
|
free(ab->startFolder);
|
|
free(ab->appName);
|
|
free(ab->appEscName);
|
|
free(ab->configFile);
|
|
free(ab->dataDir);
|
|
GWEN_FREE_OBJECT(ab);
|
|
GWEN_Fini();
|
|
}
|
|
}
|
|
|
|
|
|
|
|
AB_JOB_LIST2 *AB_Banking_GetEnqueuedJobs(const AB_BANKING *ab){
|
|
AB_JOB_LIST2 *jl;
|
|
AB_JOB *j;
|
|
|
|
assert(ab);
|
|
if (AB_Job_List_GetCount(ab->enqueuedJobs)==0) {
|
|
DBG_INFO(AQBANKING_LOGDOMAIN, "No jobs");
|
|
return 0;
|
|
}
|
|
|
|
jl=AB_Job_List2_new();
|
|
j=AB_Job_List_First(ab->enqueuedJobs);
|
|
assert(j);
|
|
while(j) {
|
|
AB_Job_List2_PushBack(jl, j);
|
|
j=AB_Job_List_Next(j);
|
|
} /* while */
|
|
|
|
return jl;
|
|
}
|
|
|
|
|
|
|
|
GWEN_TYPE_UINT32 AB_Banking_GetUniqueId(AB_BANKING *ab){
|
|
GWEN_BUFFER *nbuf;
|
|
GWEN_TYPE_UINT32 uniqueId;
|
|
int fd;
|
|
|
|
assert(ab);
|
|
uniqueId=0;
|
|
nbuf=GWEN_Buffer_new(0, 256, 0, 1);
|
|
if (AB_Banking_GetUserDataDir(ab, nbuf)) {
|
|
DBG_INFO(AQBANKING_LOGDOMAIN, "here");
|
|
GWEN_Buffer_free(nbuf);
|
|
return 0;
|
|
}
|
|
GWEN_Buffer_AppendString(nbuf, DIRSEP "uniqueid");
|
|
|
|
fd=AB_Banking__OpenFile(GWEN_Buffer_GetStart(nbuf), 1);
|
|
if (fd!=-1) {
|
|
GWEN_BUFFEREDIO *bio;
|
|
char buffer[256];
|
|
GWEN_ERRORCODE err;
|
|
unsigned long int i;
|
|
|
|
buffer[0]=0;
|
|
bio=GWEN_BufferedIO_File_new(fd);
|
|
GWEN_BufferedIO_SubFlags(bio, GWEN_BUFFEREDIO_FLAGS_CLOSE);
|
|
GWEN_BufferedIO_SetReadBuffer(bio, 0, 256);
|
|
if (!GWEN_BufferedIO_CheckEOF(bio)) {
|
|
err=GWEN_BufferedIO_ReadLine(bio, buffer, sizeof(buffer)-1);
|
|
if (!GWEN_Error_IsOk(err)) {
|
|
DBG_ERROR_ERR(AQBANKING_LOGDOMAIN, err);
|
|
GWEN_BufferedIO_free(bio);
|
|
AB_Banking__CloseFile(fd);
|
|
GWEN_Buffer_free(nbuf);
|
|
return 0;
|
|
}
|
|
if (strlen(buffer)) {
|
|
if (1!=sscanf(buffer, "%lu", &i)) {
|
|
DBG_ERROR(AQBANKING_LOGDOMAIN,
|
|
"Bad value in file (%s)",
|
|
buffer);
|
|
GWEN_BufferedIO_free(bio);
|
|
AB_Banking__CloseFile(fd);
|
|
GWEN_Buffer_free(nbuf);
|
|
return 0;
|
|
}
|
|
}
|
|
else
|
|
i=0;
|
|
}
|
|
else {
|
|
DBG_INFO(AQBANKING_LOGDOMAIN, "File is empty");
|
|
i=0;
|
|
}
|
|
GWEN_BufferedIO_free(bio);
|
|
|
|
uniqueId=++i;
|
|
buffer[0]=0;
|
|
snprintf(buffer, sizeof(buffer)-1, "%lu", i);
|
|
if (ftruncate(fd, 0)) {
|
|
DBG_ERROR(AQBANKING_LOGDOMAIN,
|
|
"ftruncate(%s, 0): %s",
|
|
GWEN_Buffer_GetStart(nbuf), strerror(errno));
|
|
GWEN_BufferedIO_free(bio);
|
|
return 0;
|
|
}
|
|
if (lseek(fd, 0, SEEK_SET)) {
|
|
DBG_ERROR(AQBANKING_LOGDOMAIN,
|
|
"lseek(%s, 0): %s",
|
|
GWEN_Buffer_GetStart(nbuf), strerror(errno));
|
|
GWEN_BufferedIO_free(bio);
|
|
return 0;
|
|
}
|
|
|
|
bio=GWEN_BufferedIO_File_new(fd);
|
|
GWEN_BufferedIO_SubFlags(bio, GWEN_BUFFEREDIO_FLAGS_CLOSE);
|
|
GWEN_BufferedIO_SetWriteBuffer(bio, 0, 256);
|
|
err=GWEN_BufferedIO_WriteLine(bio, buffer);
|
|
if (!GWEN_Error_IsOk(err)) {
|
|
DBG_ERROR_ERR(AQBANKING_LOGDOMAIN, err);
|
|
GWEN_BufferedIO_free(bio);
|
|
AB_Banking__CloseFile(fd);
|
|
GWEN_Buffer_free(nbuf);
|
|
return 0;
|
|
}
|
|
err=GWEN_BufferedIO_Flush(bio);
|
|
if (!GWEN_Error_IsOk(err)) {
|
|
DBG_ERROR_ERR(AQBANKING_LOGDOMAIN, err);
|
|
GWEN_BufferedIO_free(bio);
|
|
AB_Banking__CloseFile(fd);
|
|
GWEN_Buffer_free(nbuf);
|
|
return 0;
|
|
}
|
|
}
|
|
else {
|
|
DBG_INFO(AQBANKING_LOGDOMAIN, "Could not open file.");
|
|
uniqueId=1;
|
|
}
|
|
|
|
if (AB_Banking__CloseFile(fd)) {
|
|
DBG_INFO(AQBANKING_LOGDOMAIN,
|
|
"Error closing file \"%s\"",
|
|
GWEN_Buffer_GetStart(nbuf));
|
|
uniqueId=0;
|
|
}
|
|
|
|
GWEN_Buffer_free(nbuf);
|
|
return uniqueId;
|
|
}
|
|
|
|
|
|
|
|
const char *AB_Banking_GetAppName(const AB_BANKING *ab){
|
|
assert(ab);
|
|
return ab->appName;
|
|
}
|
|
|
|
|
|
|
|
const char *AB_Banking_GetEscapedAppName(const AB_BANKING *ab){
|
|
assert(ab);
|
|
return ab->appEscName;
|
|
}
|
|
|
|
|
|
int AB_Banking___LoadData(AB_BANKING *ab,
|
|
const char *prefix,
|
|
const char *name) {
|
|
GWEN_BUFFER *pbuf;
|
|
GWEN_DB_NODE *db;
|
|
|
|
assert(ab);
|
|
pbuf=GWEN_Buffer_new(0, 256, 0, 1);
|
|
if (AB_Banking_GetUserDataDir(ab, pbuf)) {
|
|
DBG_ERROR(AQBANKING_LOGDOMAIN, "Could not get user data dir");
|
|
GWEN_Buffer_free(pbuf);
|
|
return AB_ERROR_GENERIC;
|
|
}
|
|
GWEN_Buffer_AppendString(pbuf, DIRSEP);
|
|
GWEN_Buffer_AppendString(pbuf, prefix);
|
|
GWEN_Buffer_AppendString(pbuf, DIRSEP);
|
|
GWEN_Buffer_AppendString(pbuf, name);
|
|
GWEN_Buffer_AppendString(pbuf, DIRSEP "settings.conf");
|
|
|
|
db=GWEN_DB_GetGroup(ab->data, GWEN_DB_FLAGS_DEFAULT,
|
|
"external");
|
|
assert(db);
|
|
db=GWEN_DB_GetGroup(db, GWEN_DB_FLAGS_DEFAULT, prefix);
|
|
assert(db);
|
|
db=GWEN_DB_GetGroup(db, GWEN_DB_FLAGS_DEFAULT, name);
|
|
assert(db);
|
|
DBG_INFO(AQBANKING_LOGDOMAIN,
|
|
"Reading file \"%s\"", GWEN_Buffer_GetStart(pbuf));
|
|
if (GWEN_DB_ReadFile(db, GWEN_Buffer_GetStart(pbuf),
|
|
GWEN_DB_FLAGS_DEFAULT |
|
|
GWEN_PATH_FLAGS_CREATE_GROUP |
|
|
GWEN_DB_FLAGS_LOCKFILE)) {
|
|
DBG_INFO(AQBANKING_LOGDOMAIN,
|
|
"Could not load config file \"%s\", creating it later",
|
|
GWEN_Buffer_GetStart(pbuf));
|
|
GWEN_Buffer_free(pbuf);
|
|
return 0;
|
|
}
|
|
GWEN_Buffer_free(pbuf);
|
|
|
|
/* sucessfully read */
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
int AB_Banking___SaveData(AB_BANKING *ab,
|
|
const char *prefix,
|
|
const char *name) {
|
|
GWEN_BUFFER *pbuf;
|
|
GWEN_BUFFER *rpbuf;
|
|
GWEN_DB_NODE *db;
|
|
|
|
assert(ab);
|
|
db=GWEN_DB_GetGroup(ab->data, GWEN_PATH_FLAGS_NAMEMUSTEXIST,
|
|
"external");
|
|
if (!db)
|
|
return 0;
|
|
db=GWEN_DB_GetGroup(db, GWEN_PATH_FLAGS_NAMEMUSTEXIST, prefix);
|
|
if (!db)
|
|
return 0;
|
|
db=GWEN_DB_GetGroup(db, GWEN_PATH_FLAGS_NAMEMUSTEXIST, name);
|
|
if (!db)
|
|
return 0;
|
|
|
|
pbuf=GWEN_Buffer_new(0, 256, 0, 1);
|
|
if (AB_Banking_GetUserDataDir(ab, pbuf)) {
|
|
DBG_ERROR(AQBANKING_LOGDOMAIN, "Could not get user data dir");
|
|
GWEN_Buffer_free(pbuf);
|
|
return AB_ERROR_GENERIC;
|
|
}
|
|
GWEN_Buffer_AppendString(pbuf, DIRSEP);
|
|
GWEN_Buffer_AppendString(pbuf, prefix);
|
|
GWEN_Buffer_AppendString(pbuf, DIRSEP);
|
|
GWEN_Buffer_AppendString(pbuf, name);
|
|
GWEN_Buffer_AppendString(pbuf, DIRSEP "settings.conf");
|
|
|
|
|
|
DBG_INFO(AQBANKING_LOGDOMAIN,
|
|
"Writing file \"%s\"", GWEN_Buffer_GetStart(pbuf));
|
|
if (GWEN_Directory_GetPath(GWEN_Buffer_GetStart(pbuf),
|
|
GWEN_PATH_FLAGS_VARIABLE)) {
|
|
DBG_ERROR(AQBANKING_LOGDOMAIN,
|
|
"Path \"%s\" is not available",
|
|
GWEN_Buffer_GetStart(pbuf));
|
|
GWEN_Buffer_free(pbuf);
|
|
return AB_ERROR_GENERIC;
|
|
}
|
|
rpbuf=GWEN_Buffer_new(0, GWEN_Buffer_GetUsedBytes(pbuf)+4, 0, 1);
|
|
GWEN_Buffer_AppendBuffer(rpbuf, pbuf);
|
|
GWEN_Buffer_AppendString(pbuf, ".tmp");
|
|
if (GWEN_DB_WriteFile(db, GWEN_Buffer_GetStart(pbuf),
|
|
GWEN_DB_FLAGS_DEFAULT |
|
|
GWEN_DB_FLAGS_LOCKFILE)) {
|
|
DBG_INFO(AQBANKING_LOGDOMAIN,
|
|
"Could not save app config file \"%s\"",
|
|
GWEN_Buffer_GetStart(pbuf));
|
|
GWEN_Buffer_free(rpbuf);
|
|
GWEN_Buffer_free(pbuf);
|
|
return AB_ERROR_GENERIC;
|
|
}
|
|
#ifdef OS_WIN32
|
|
if (unlink(GWEN_Buffer_GetStart(rpbuf))) {
|
|
DBG_ERROR(AQBANKING_LOGDOMAIN,
|
|
"Could not delete old file \"%s\": %s",
|
|
GWEN_Buffer_GetStart(rpbuf),
|
|
strerror(errno));
|
|
GWEN_Buffer_free(rpbuf);
|
|
GWEN_Buffer_free(pbuf);
|
|
return AB_ERROR_GENERIC;
|
|
}
|
|
#endif
|
|
if (rename(GWEN_Buffer_GetStart(pbuf),
|
|
GWEN_Buffer_GetStart(rpbuf))) {
|
|
DBG_ERROR(AQBANKING_LOGDOMAIN,
|
|
"Could not rename file to \"%s\": %s",
|
|
GWEN_Buffer_GetStart(rpbuf),
|
|
strerror(errno));
|
|
GWEN_Buffer_free(rpbuf);
|
|
GWEN_Buffer_free(pbuf);
|
|
return AB_ERROR_GENERIC;
|
|
}
|
|
GWEN_Buffer_free(rpbuf);
|
|
GWEN_Buffer_free(pbuf);
|
|
|
|
/* sucessfully written */
|
|
return 0;
|
|
}
|
|
|
|
|
|
|
|
int AB_Banking__LoadData(AB_BANKING *ab,
|
|
const char *prefix,
|
|
const char *name) {
|
|
GWEN_BUFFER *pbuf;
|
|
int rv;
|
|
|
|
pbuf=GWEN_Buffer_new(0, 256, 0, 1);
|
|
if (GWEN_Text_EscapeToBuffer(name, pbuf)) {
|
|
DBG_ERROR(AQBANKING_LOGDOMAIN,
|
|
"Error escaping string, aborting (%s).", name);
|
|
GWEN_Buffer_free(pbuf);
|
|
abort();
|
|
}
|
|
|
|
rv=AB_Banking___LoadData(ab, prefix, GWEN_Buffer_GetStart(pbuf));
|
|
GWEN_Buffer_free(pbuf);
|
|
return rv;
|
|
}
|
|
|
|
|
|
|
|
int AB_Banking__SaveData(AB_BANKING *ab,
|
|
const char *prefix,
|
|
const char *name) {
|
|
GWEN_BUFFER *pbuf;
|
|
int rv;
|
|
|
|
pbuf=GWEN_Buffer_new(0, 256, 0, 1);
|
|
if (GWEN_Text_EscapeToBuffer(name, pbuf)) {
|
|
DBG_ERROR(AQBANKING_LOGDOMAIN,
|
|
"Error escaping string, aborting (%s).", name);
|
|
GWEN_Buffer_free(pbuf);
|
|
abort();
|
|
}
|
|
|
|
rv=AB_Banking___SaveData(ab, prefix, GWEN_Buffer_GetStart(pbuf));
|
|
GWEN_Buffer_free(pbuf);
|
|
return rv;
|
|
}
|
|
|
|
|
|
|
|
int AB_Banking__SaveExternalData(AB_BANKING *ab) {
|
|
GWEN_DB_NODE *db;
|
|
|
|
db=GWEN_DB_GetGroup(ab->data, GWEN_PATH_FLAGS_NAMEMUSTEXIST, "external");
|
|
if (!db)
|
|
return 0;
|
|
db=GWEN_DB_GetFirstGroup(db);
|
|
while(db) {
|
|
const char *prefix;
|
|
GWEN_DB_NODE *dbName;
|
|
|
|
prefix=GWEN_DB_GroupName(db);
|
|
dbName=GWEN_DB_GetFirstGroup(db);
|
|
while(dbName) {
|
|
int rv;
|
|
|
|
rv=AB_Banking__SaveData(ab, prefix, GWEN_DB_GroupName(dbName));
|
|
if (rv)
|
|
return rv;
|
|
dbName=GWEN_DB_GetNextGroup(dbName);
|
|
}
|
|
db=GWEN_DB_GetNextGroup(db);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
|
|
int AB_Banking__LoadAppData(AB_BANKING *ab) {
|
|
return AB_Banking__LoadData(ab, "apps", ab->appEscName);
|
|
}
|
|
|
|
|
|
|
|
int AB_Banking__LoadSharedData(AB_BANKING *ab, const char *name) {
|
|
return AB_Banking__LoadData(ab, "shared", name);
|
|
}
|
|
|
|
|
|
|
|
int AB_Banking__SaveSharedData(AB_BANKING *ab, const char *name) {
|
|
return AB_Banking__SaveData(ab, "shared", name);
|
|
}
|
|
|
|
|
|
|
|
GWEN_DB_NODE *AB_Banking_GetAppData(AB_BANKING *ab) {
|
|
GWEN_DB_NODE *db;
|
|
GWEN_DB_NODE *dbT;
|
|
|
|
assert(ab);
|
|
assert(ab->appEscName);
|
|
db=GWEN_DB_GetGroup(ab->data, GWEN_DB_FLAGS_DEFAULT,
|
|
"external/apps");
|
|
assert(db);
|
|
|
|
dbT=GWEN_DB_GetGroup(db, GWEN_PATH_FLAGS_NAMEMUSTEXIST,
|
|
ab->appEscName);
|
|
if (!dbT) {
|
|
if (AB_Banking__LoadAppData(ab)) {
|
|
DBG_ERROR(AQBANKING_LOGDOMAIN, "Could not load app data file");
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
dbT=GWEN_DB_GetGroup(db, GWEN_DB_FLAGS_DEFAULT,
|
|
ab->appEscName);
|
|
assert(dbT);
|
|
return dbT;
|
|
}
|
|
|
|
|
|
|
|
GWEN_DB_NODE *AB_Banking_GetSharedData(AB_BANKING *ab, const char *name) {
|
|
GWEN_DB_NODE *db;
|
|
GWEN_DB_NODE *dbT;
|
|
|
|
assert(ab);
|
|
db=GWEN_DB_GetGroup(ab->data, GWEN_DB_FLAGS_DEFAULT,
|
|
"external/shared");
|
|
assert(db);
|
|
|
|
dbT=GWEN_DB_GetGroup(db, GWEN_PATH_FLAGS_NAMEMUSTEXIST, name);
|
|
if (!dbT) {
|
|
if (AB_Banking__LoadSharedData(ab, name)) {
|
|
DBG_ERROR(AQBANKING_LOGDOMAIN, "Could not load app data file");
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
dbT=GWEN_DB_GetGroup(db, GWEN_DB_FLAGS_DEFAULT, name);
|
|
assert(dbT);
|
|
return dbT;
|
|
}
|
|
|
|
|
|
|
|
|
|
GWEN_DB_NODE *AB_Banking_GetProviderData(AB_BANKING *ab,
|
|
AB_PROVIDER *pro) {
|
|
GWEN_DB_NODE *db;
|
|
GWEN_DB_NODE *dbT;
|
|
|
|
assert(ab);
|
|
assert(pro);
|
|
|
|
db=GWEN_DB_GetGroup(ab->data, GWEN_DB_FLAGS_DEFAULT,
|
|
"banking/backends");
|
|
assert(db);
|
|
dbT=GWEN_DB_GetGroup(db, GWEN_PATH_FLAGS_NAMEMUSTEXIST,
|
|
AB_Provider_GetEscapedName(pro));
|
|
if (!dbT && ab->lastVersion < ((1<<24) | (8<<16) | (1<<8) | 3)) {
|
|
int rv;
|
|
|
|
/* load separate file for older releases */
|
|
rv=AB_Banking__LoadOldProviderData(ab, AB_Provider_GetEscapedName(pro));
|
|
if (rv) {
|
|
DBG_ERROR(AQBANKING_LOGDOMAIN,
|
|
"Could not load settings for backend \"%s\"",
|
|
AB_Provider_GetName(pro));
|
|
abort();
|
|
}
|
|
}
|
|
|
|
dbT=GWEN_DB_GetGroup(db, GWEN_DB_FLAGS_DEFAULT,
|
|
AB_Provider_GetEscapedName(pro));
|
|
assert(dbT);
|
|
return dbT;
|
|
}
|
|
|
|
|
|
|
|
void AB_Banking_SetMessageBoxFn(AB_BANKING *ab,
|
|
AB_BANKING_MESSAGEBOX_FN f){
|
|
assert(ab);
|
|
ab->messageBoxFn=f;
|
|
}
|
|
|
|
|
|
|
|
void AB_Banking_SetInputBoxFn(AB_BANKING *ab,
|
|
AB_BANKING_INPUTBOX_FN f){
|
|
assert(ab);
|
|
ab->inputBoxFn=f;
|
|
}
|
|
|
|
|
|
|
|
void AB_Banking_SetShowBoxFn(AB_BANKING *ab,
|
|
AB_BANKING_SHOWBOX_FN f){
|
|
assert(ab);
|
|
ab->showBoxFn=f;
|
|
}
|
|
|
|
|
|
|
|
void AB_Banking_SetHideBoxFn(AB_BANKING *ab,
|
|
AB_BANKING_HIDEBOX_FN f){
|
|
assert(ab);
|
|
ab->hideBoxFn=f;
|
|
}
|
|
|
|
|
|
|
|
void AB_Banking_SetProgressStartFn(AB_BANKING *ab,
|
|
AB_BANKING_PROGRESS_START_FN f){
|
|
assert(ab);
|
|
ab->progressStartFn=f;
|
|
}
|
|
|
|
|
|
|
|
void AB_Banking_SetProgressAdvanceFn(AB_BANKING *ab,
|
|
AB_BANKING_PROGRESS_ADVANCE_FN f){
|
|
assert(ab);
|
|
ab->progressAdvanceFn=f;
|
|
}
|
|
|
|
|
|
|
|
void AB_Banking_SetProgressLogFn(AB_BANKING *ab,
|
|
AB_BANKING_PROGRESS_LOG_FN f){
|
|
assert(ab);
|
|
ab->progressLogFn=f;
|
|
}
|
|
|
|
|
|
|
|
void AB_Banking_SetProgressEndFn(AB_BANKING *ab,
|
|
AB_BANKING_PROGRESS_END_FN f){
|
|
assert(ab);
|
|
ab->progressEndFn=f;
|
|
}
|
|
|
|
|
|
|
|
void AB_Banking_SetPrintFn(AB_BANKING *ab,
|
|
AB_BANKING_PRINT_FN f){
|
|
assert(ab);
|
|
ab->printFn=f;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
int AB_Banking_MessageBox(AB_BANKING *ab,
|
|
GWEN_TYPE_UINT32 flags,
|
|
const char *title,
|
|
const char *text,
|
|
const char *b1,
|
|
const char *b2,
|
|
const char *b3){
|
|
assert(ab);
|
|
if (ab->messageBoxFn) {
|
|
return ab->messageBoxFn(ab, flags, title, text, b1, b2, b3);
|
|
}
|
|
DBG_INFO(AQBANKING_LOGDOMAIN, "No messageBox function set");
|
|
return 0;
|
|
}
|
|
|
|
|
|
|
|
int AB_Banking_InputBox(AB_BANKING *ab,
|
|
GWEN_TYPE_UINT32 flags,
|
|
const char *title,
|
|
const char *text,
|
|
char *buffer,
|
|
int minLen,
|
|
int maxLen){
|
|
assert(ab);
|
|
if (ab->inputBoxFn) {
|
|
return ab->inputBoxFn(ab, flags, title, text, buffer, minLen, maxLen);
|
|
}
|
|
DBG_ERROR(AQBANKING_LOGDOMAIN, "No inputBox function set");
|
|
return AB_ERROR_NOFN;
|
|
}
|
|
|
|
|
|
|
|
GWEN_TYPE_UINT32 AB_Banking_ShowBox(AB_BANKING *ab,
|
|
GWEN_TYPE_UINT32 flags,
|
|
const char *title,
|
|
const char *text){
|
|
assert(ab);
|
|
if (ab->showBoxFn) {
|
|
return ab->showBoxFn(ab, flags, title, text);
|
|
}
|
|
DBG_INFO(AQBANKING_LOGDOMAIN, "No showBox function set");
|
|
return 0;
|
|
}
|
|
|
|
|
|
|
|
void AB_Banking_HideBox(AB_BANKING *ab, GWEN_TYPE_UINT32 id){
|
|
assert(ab);
|
|
if (ab->hideBoxFn) {
|
|
ab->hideBoxFn(ab, id);
|
|
return;
|
|
}
|
|
DBG_INFO(AQBANKING_LOGDOMAIN, "No hideBox function set");
|
|
}
|
|
|
|
|
|
|
|
GWEN_TYPE_UINT32 AB_Banking_ProgressStart(AB_BANKING *ab,
|
|
const char *title,
|
|
const char *text,
|
|
GWEN_TYPE_UINT32 total){
|
|
assert(ab);
|
|
if (ab->progressStartFn) {
|
|
GWEN_TYPE_UINT32 pid;
|
|
|
|
if (ab->progressNestingLevel>0) {
|
|
/* nesting, check whether the application supports it */
|
|
if (!(ab->appExtensions & AB_BANKING_EXTENSION_NESTING_PROGRESS)) {
|
|
/* nope, app doesn't support nesting, return currently active
|
|
* progress id */
|
|
GWEN_WaitCallback_Enter(AB_BANKING_WCB_GENERIC);
|
|
ab->progressNestingLevel++;
|
|
return ab->lastProgressId;
|
|
}
|
|
}
|
|
|
|
pid=ab->progressStartFn(ab, title, text, total);
|
|
if (pid) {
|
|
GWEN_WaitCallback_Enter(AB_BANKING_WCB_GENERIC);
|
|
ab->progressNestingLevel++;
|
|
ab->lastProgressId=pid;
|
|
}
|
|
else {
|
|
DBG_INFO(AQBANKING_LOGDOMAIN, "here");
|
|
ab->lastProgressId=0;
|
|
}
|
|
return pid;
|
|
}
|
|
else {
|
|
DBG_DEBUG(AQBANKING_LOGDOMAIN, "No progressStart function set");
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
int AB_Banking_ProgressAdvance(AB_BANKING *ab,
|
|
GWEN_TYPE_UINT32 id,
|
|
GWEN_TYPE_UINT32 progress){
|
|
assert(ab);
|
|
if (ab->progressAdvanceFn) {
|
|
return ab->progressAdvanceFn(ab, id, progress);
|
|
}
|
|
DBG_INFO(AQBANKING_LOGDOMAIN, "No progressAdvance function set");
|
|
return 0;
|
|
}
|
|
|
|
|
|
|
|
int AB_Banking_ProgressLog(AB_BANKING *ab,
|
|
GWEN_TYPE_UINT32 id,
|
|
AB_BANKING_LOGLEVEL level,
|
|
const char *text){
|
|
assert(ab);
|
|
if (ab->progressLogFn)
|
|
return ab->progressLogFn(ab, id, level, text);
|
|
DBG_INFO(AQBANKING_LOGDOMAIN, "No progressLog function set");
|
|
return 0;
|
|
}
|
|
|
|
|
|
|
|
int AB_Banking_ProgressEnd(AB_BANKING *ab, GWEN_TYPE_UINT32 id){
|
|
|
|
assert(ab);
|
|
if (ab->progressNestingLevel)
|
|
GWEN_WaitCallback_Leave();
|
|
|
|
if (ab->progressEndFn) {
|
|
if (ab->progressNestingLevel<1) {
|
|
DBG_ERROR(AQBANKING_LOGDOMAIN, "No progress context open");
|
|
return AB_ERROR_INVALID;
|
|
}
|
|
else {
|
|
int rv;
|
|
|
|
if (!(ab->appExtensions & AB_BANKING_EXTENSION_NESTING_PROGRESS)) {
|
|
/* app does not support nesting progress */
|
|
if ((ab->progressNestingLevel)>1) {
|
|
/* just count down the nesting level and return */
|
|
ab->progressNestingLevel--;
|
|
return 0;
|
|
}
|
|
}
|
|
rv=ab->progressEndFn(ab, id);
|
|
if (rv==0) {
|
|
ab->progressNestingLevel--;
|
|
}
|
|
ab->lastProgressId=0;
|
|
return rv;
|
|
}
|
|
}
|
|
else {
|
|
DBG_INFO(AQBANKING_LOGDOMAIN, "No progressEnd function set");
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
int AB_Banking_Print(AB_BANKING *ab,
|
|
const char *docTitle,
|
|
const char *docType,
|
|
const char *descr,
|
|
const char *text){
|
|
assert(ab);
|
|
if (ab->printFn) {
|
|
return ab->printFn(ab, docTitle, docType, descr, text);
|
|
}
|
|
DBG_INFO(AQBANKING_LOGDOMAIN, "No print function set");
|
|
return AB_ERROR_NOT_SUPPORTED;
|
|
}
|
|
|
|
|
|
|
|
|
|
int AB_Banking_InitProvider(AB_BANKING *ab, AB_PROVIDER *pro) {
|
|
return AB_Provider_Init(pro);
|
|
}
|
|
|
|
|
|
|
|
int AB_Banking_FiniProvider(AB_BANKING *ab, AB_PROVIDER *pro) {
|
|
int rv;
|
|
|
|
rv=AB_Provider_Fini(pro);
|
|
if (rv) {
|
|
DBG_INFO(AQBANKING_LOGDOMAIN, "Error deinit backend (%d)", rv);
|
|
}
|
|
return rv;
|
|
}
|
|
|
|
|
|
|
|
AB_PROVIDER *AB_Banking_FindProvider(AB_BANKING *ab, const char *name) {
|
|
AB_PROVIDER *pro;
|
|
|
|
assert(ab);
|
|
assert(name);
|
|
pro=AB_Provider_List_First(ab->providers);
|
|
while(pro) {
|
|
if (strcasecmp(AB_Provider_GetName(pro), name)==0)
|
|
break;
|
|
pro=AB_Provider_List_Next(pro);
|
|
} /* while */
|
|
|
|
return pro;
|
|
}
|
|
|
|
|
|
|
|
AB_PROVIDER *AB_Banking_GetProvider(AB_BANKING *ab, const char *name) {
|
|
AB_PROVIDER *pro;
|
|
|
|
assert(ab);
|
|
assert(name);
|
|
pro=AB_Banking_FindProvider(ab, name);
|
|
if (pro)
|
|
return pro;
|
|
pro=AB_Banking__LoadProviderPlugin(ab, name);
|
|
if (pro) {
|
|
if (AB_Banking_InitProvider(ab, pro)) {
|
|
DBG_ERROR(AQBANKING_LOGDOMAIN, "Could not init provider \"%s\"", name);
|
|
AB_Provider_free(pro);
|
|
return 0;
|
|
}
|
|
AB_Provider_List_Add(pro, ab->providers);
|
|
}
|
|
|
|
return pro;
|
|
}
|
|
|
|
|
|
|
|
AB_ACCOUNT_LIST2 *AB_Banking_GetAccounts(const AB_BANKING *ab){
|
|
AB_ACCOUNT_LIST2 *al;
|
|
AB_ACCOUNT *a;
|
|
|
|
assert(ab);
|
|
if (AB_Account_List_GetCount(ab->accounts)==0) {
|
|
DBG_INFO(AQBANKING_LOGDOMAIN, "No accounts");
|
|
return 0;
|
|
}
|
|
al=AB_Account_List2_new();
|
|
a=AB_Account_List_First(ab->accounts);
|
|
assert(a);
|
|
while(a) {
|
|
AB_Account_List2_PushBack(al, a);
|
|
a=AB_Account_List_Next(a);
|
|
} /* while */
|
|
|
|
return al;
|
|
}
|
|
|
|
|
|
|
|
AB_ACCOUNT *AB_Banking_GetAccount(const AB_BANKING *ab,
|
|
GWEN_TYPE_UINT32 uniqueId){
|
|
AB_ACCOUNT *a;
|
|
|
|
assert(ab);
|
|
if (AB_Account_List_GetCount(ab->accounts)==0) {
|
|
DBG_INFO(AQBANKING_LOGDOMAIN, "No accounts");
|
|
return 0;
|
|
}
|
|
a=AB_Account_List_First(ab->accounts);
|
|
assert(a);
|
|
while(a) {
|
|
if (AB_Account_GetUniqueId(a)==uniqueId)
|
|
break;
|
|
a=AB_Account_List_Next(a);
|
|
} /* while */
|
|
|
|
return a;
|
|
}
|
|
|
|
|
|
|
|
AB_ACCOUNT *AB_Banking_FindAccount(const AB_BANKING *ab,
|
|
const char *backendName,
|
|
const char *country,
|
|
const char *bankId,
|
|
const char *accountId) {
|
|
AB_ACCOUNT *a;
|
|
|
|
assert(ab);
|
|
if (AB_Account_List_GetCount(ab->accounts)==0) {
|
|
DBG_INFO(AQBANKING_LOGDOMAIN, "No accounts");
|
|
return 0;
|
|
}
|
|
a=AB_Account_List_First(ab->accounts);
|
|
assert(a);
|
|
|
|
if (!backendName) backendName="*";
|
|
if (!country) country="*";
|
|
if (!bankId) bankId="*";
|
|
if (!accountId) accountId="*";
|
|
|
|
while(a) {
|
|
const char *lbackendName;
|
|
/*const char *lcountry;
|
|
const char *lbankId;
|
|
const char *laccountId;*/
|
|
|
|
lbackendName=AB_Account_GetBackendName(a);
|
|
if (!lbackendName) {
|
|
DBG_ERROR(AQBANKING_LOGDOMAIN,
|
|
"Account: %s/%s/%s: No backend\n",
|
|
AB_Account_GetCountry(a),
|
|
AB_Account_GetBankCode(a),
|
|
AB_Account_GetAccountNumber(a));
|
|
abort();
|
|
}
|
|
|
|
if ((-1!=GWEN_Text_ComparePattern(lbackendName,
|
|
backendName, 0)) &&
|
|
(-1!=GWEN_Text_ComparePattern(AB_Account_GetCountry(a),
|
|
country, 0)) &&
|
|
(-1!=GWEN_Text_ComparePattern(AB_Account_GetBankCode(a),
|
|
bankId, 0)) &&
|
|
(-1!=GWEN_Text_ComparePattern(AB_Account_GetAccountNumber(a),
|
|
accountId, 0)))
|
|
break;
|
|
a=AB_Account_List_Next(a);
|
|
} /* while */
|
|
|
|
return a;
|
|
}
|
|
|
|
|
|
|
|
AB_ACCOUNT_LIST2 *AB_Banking_FindAccounts(const AB_BANKING *ab,
|
|
const char *backendName,
|
|
const char *country,
|
|
const char *bankId,
|
|
const char *accountId) {
|
|
AB_ACCOUNT_LIST2 *al;
|
|
AB_ACCOUNT *a;
|
|
|
|
assert(ab);
|
|
if (AB_Account_List_GetCount(ab->accounts)==0) {
|
|
DBG_INFO(AQBANKING_LOGDOMAIN, "No accounts");
|
|
return 0;
|
|
}
|
|
al=AB_Account_List2_new();
|
|
a=AB_Account_List_First(ab->accounts);
|
|
assert(a);
|
|
|
|
if (!backendName) backendName="*";
|
|
if (!country) country="*";
|
|
if (!bankId) bankId="*";
|
|
if (!accountId) accountId="*";
|
|
|
|
while(a) {
|
|
const char *lbackendName;
|
|
/*const char *lcountry;
|
|
const char *lbankId;
|
|
const char *laccountId;*/
|
|
|
|
lbackendName=AB_Account_GetBackendName(a);
|
|
if (!lbackendName) {
|
|
DBG_ERROR(AQBANKING_LOGDOMAIN,
|
|
"Account: %s/%s/%s: No backend\n",
|
|
AB_Account_GetCountry(a),
|
|
AB_Account_GetBankCode(a),
|
|
AB_Account_GetAccountNumber(a));
|
|
abort();
|
|
}
|
|
|
|
if ((-1!=GWEN_Text_ComparePattern(AB_Account_GetBackendName(a),
|
|
backendName, 0)) &&
|
|
(-1!=GWEN_Text_ComparePattern(AB_Account_GetCountry(a),
|
|
country, 0)) &&
|
|
(-1!=GWEN_Text_ComparePattern(AB_Account_GetBankCode(a),
|
|
bankId, 0)) &&
|
|
(-1!=GWEN_Text_ComparePattern(AB_Account_GetAccountNumber(a),
|
|
accountId, 0)))
|
|
AB_Account_List2_PushBack(al, a);
|
|
a=AB_Account_List_Next(a);
|
|
} /* while */
|
|
|
|
if (AB_Account_List2_GetSize(al)==0) {
|
|
AB_Account_List2_free(al);
|
|
return 0;
|
|
}
|
|
|
|
return al;
|
|
}
|
|
|
|
|
|
|
|
AB_USER_LIST2 *AB_Banking_GetUsers(const AB_BANKING *ab){
|
|
AB_USER_LIST2 *ul;
|
|
AB_USER *u;
|
|
|
|
assert(ab);
|
|
if (AB_User_List_GetCount(ab->users)==0) {
|
|
DBG_INFO(AQBANKING_LOGDOMAIN, "No users");
|
|
return 0;
|
|
}
|
|
ul=AB_User_List2_new();
|
|
u=AB_User_List_First(ab->users);
|
|
assert(u);
|
|
while(u) {
|
|
AB_User_List2_PushBack(ul, u);
|
|
u=AB_User_List_Next(u);
|
|
} /* while */
|
|
|
|
return ul;
|
|
}
|
|
|
|
|
|
|
|
AB_USER *AB_Banking_GetUser(const AB_BANKING *ab, GWEN_TYPE_UINT32 uniqueId){
|
|
AB_USER *u;
|
|
|
|
assert(ab);
|
|
if (AB_User_List_GetCount(ab->users)==0) {
|
|
DBG_INFO(AQBANKING_LOGDOMAIN, "No users");
|
|
return 0;
|
|
}
|
|
u=AB_User_List_First(ab->users);
|
|
assert(u);
|
|
while(u) {
|
|
if (AB_User_GetUniqueId(u)==uniqueId)
|
|
break;
|
|
u=AB_User_List_Next(u);
|
|
} /* while */
|
|
|
|
return u;
|
|
}
|
|
|
|
|
|
|
|
AB_USER *AB_Banking_FindUser(const AB_BANKING *ab,
|
|
const char *backendName,
|
|
const char *country,
|
|
const char *bankId,
|
|
const char *userId,
|
|
const char *customerId) {
|
|
AB_USER *u;
|
|
|
|
assert(ab);
|
|
if (AB_User_List_GetCount(ab->users)==0) {
|
|
DBG_INFO(AQBANKING_LOGDOMAIN, "No users");
|
|
return 0;
|
|
}
|
|
u=AB_User_List_First(ab->users);
|
|
assert(u);
|
|
|
|
if (!backendName) backendName="*";
|
|
if (!country) country="*";
|
|
if (!bankId) bankId="*";
|
|
if (!userId) userId="*";
|
|
if (!customerId) customerId="*";
|
|
|
|
while(u) {
|
|
const char *lCountry;
|
|
const char *lBankCode;
|
|
const char *lUserId;
|
|
const char *lCustomerId;
|
|
|
|
lCountry=AB_User_GetCountry(u);
|
|
if (!lCountry)
|
|
lCountry="";
|
|
lBankCode=AB_User_GetBankCode(u);
|
|
if (!lBankCode)
|
|
lBankCode="";
|
|
lUserId=AB_User_GetUserId(u);
|
|
if (!lUserId)
|
|
lUserId="";
|
|
lCustomerId=AB_User_GetCustomerId(u);
|
|
if (!lCustomerId)
|
|
lCustomerId="";
|
|
|
|
if ((-1!=GWEN_Text_ComparePattern(AB_User_GetBackendName(u),
|
|
backendName, 0)) &&
|
|
(-1!=GWEN_Text_ComparePattern(lCountry,
|
|
country, 0)) &&
|
|
(-1!=GWEN_Text_ComparePattern(lBankCode,
|
|
bankId, 0)) &&
|
|
(-1!=GWEN_Text_ComparePattern(lUserId,
|
|
userId, 0)) &&
|
|
(-1!=GWEN_Text_ComparePattern(lCustomerId,
|
|
customerId, 0)))
|
|
break;
|
|
u=AB_User_List_Next(u);
|
|
} /* while */
|
|
|
|
return u;
|
|
}
|
|
|
|
|
|
|
|
AB_USER_LIST2 *AB_Banking_FindUsers(const AB_BANKING *ab,
|
|
const char *backendName,
|
|
const char *country,
|
|
const char *bankId,
|
|
const char *userId,
|
|
const char *customerId) {
|
|
AB_USER_LIST2 *ul;
|
|
AB_USER *u;
|
|
|
|
assert(ab);
|
|
if (AB_User_List_GetCount(ab->users)==0) {
|
|
DBG_INFO(AQBANKING_LOGDOMAIN, "No users");
|
|
return 0;
|
|
}
|
|
ul=AB_User_List2_new();
|
|
u=AB_User_List_First(ab->users);
|
|
assert(u);
|
|
|
|
if (!backendName) backendName="*";
|
|
if (!country) country="*";
|
|
if (!bankId) bankId="*";
|
|
if (!userId) userId="*";
|
|
if (!customerId) customerId="*";
|
|
|
|
while(u) {
|
|
const char *lCountry;
|
|
const char *lBankCode;
|
|
const char *lUserId;
|
|
const char *lCustomerId;
|
|
|
|
lCountry=AB_User_GetCountry(u);
|
|
if (!lCountry)
|
|
lCountry="";
|
|
lBankCode=AB_User_GetBankCode(u);
|
|
if (!lBankCode)
|
|
lBankCode="";
|
|
lUserId=AB_User_GetUserId(u);
|
|
if (!lUserId)
|
|
lUserId="";
|
|
lCustomerId=AB_User_GetCustomerId(u);
|
|
if (!lCustomerId)
|
|
lCustomerId="";
|
|
|
|
if ((-1!=GWEN_Text_ComparePattern(AB_User_GetBackendName(u),
|
|
backendName, 0)) &&
|
|
(-1!=GWEN_Text_ComparePattern(lCountry,
|
|
country, 0)) &&
|
|
(-1!=GWEN_Text_ComparePattern(lBankCode,
|
|
bankId, 0)) &&
|
|
(-1!=GWEN_Text_ComparePattern(lUserId,
|
|
userId, 0)) &&
|
|
(-1!=GWEN_Text_ComparePattern(lCustomerId,
|
|
customerId, 0))) {
|
|
AB_User_List2_PushBack(ul, u);
|
|
}
|
|
u=AB_User_List_Next(u);
|
|
} /* while */
|
|
|
|
if (AB_User_List2_GetSize(ul)==0) {
|
|
AB_User_List2_free(ul);
|
|
return 0;
|
|
}
|
|
|
|
return ul;
|
|
}
|
|
|
|
|
|
|
|
AB_USER *AB_Banking_CreateUser(AB_BANKING *ab, const char *backendName) {
|
|
AB_USER *u;
|
|
AB_PROVIDER *pro;
|
|
GWEN_TYPE_UINT32 uid;
|
|
int rv;
|
|
|
|
assert(ab);
|
|
pro=AB_Banking_GetProvider(ab, backendName);
|
|
if (!pro) {
|
|
DBG_ERROR(AQBANKING_LOGDOMAIN, "Backend \"%s\" not found", backendName);
|
|
return 0;
|
|
}
|
|
|
|
u=AB_User_new(ab);
|
|
AB_User_SetBackendName(u, AB_Provider_GetName(pro));
|
|
uid=AB_Banking_GetUniqueId(ab);
|
|
assert(uid);
|
|
AB_User_SetUniqueId(u, uid);
|
|
rv=AB_Provider_ExtendUser(pro, u, AB_ProviderExtendMode_Create);
|
|
if (rv) {
|
|
DBG_ERROR(AQBANKING_LOGDOMAIN, "Error extending user (%d)", rv);
|
|
AB_User_free(u);
|
|
return 0;
|
|
}
|
|
|
|
return u;
|
|
}
|
|
|
|
|
|
|
|
int AB_Banking_AddUser(AB_BANKING *ab, AB_USER *u) {
|
|
int rv;
|
|
|
|
assert(ab);
|
|
assert(u);
|
|
rv=AB_Provider_ExtendUser(AB_User_GetProvider(u), u,
|
|
AB_ProviderExtendMode_Add);
|
|
if (rv)
|
|
return rv;
|
|
AB_User_List_Add(u, ab->users);
|
|
return 0;
|
|
}
|
|
|
|
|
|
|
|
AB_ACCOUNT *AB_Banking_CreateAccount(AB_BANKING *ab, const char *backendName){
|
|
AB_ACCOUNT *a;
|
|
AB_PROVIDER *pro;
|
|
int rv;
|
|
GWEN_TYPE_UINT32 uid;
|
|
|
|
assert(ab);
|
|
pro=AB_Banking_GetProvider(ab, backendName);
|
|
if (!pro) {
|
|
DBG_ERROR(AQBANKING_LOGDOMAIN, "Backend \"%s\" not found", backendName);
|
|
return 0;
|
|
}
|
|
|
|
uid=AB_Banking_GetUniqueId(ab);
|
|
assert(uid);
|
|
|
|
a=AB_Account_new(ab, pro);
|
|
AB_Account_SetUniqueId(a, uid);
|
|
rv=AB_Provider_ExtendAccount(pro, a, AB_ProviderExtendMode_Create);
|
|
if (rv) {
|
|
DBG_ERROR(AQBANKING_LOGDOMAIN, "Error extending account (%d)", rv);
|
|
AB_Account_free(a);
|
|
return 0;
|
|
}
|
|
|
|
return a;
|
|
}
|
|
|
|
|
|
|
|
int AB_Banking_AddAccount(AB_BANKING *ab, AB_ACCOUNT *a) {
|
|
int rv;
|
|
|
|
assert(ab);
|
|
assert(a);
|
|
rv=AB_Provider_ExtendAccount(AB_Account_GetProvider(a), a,
|
|
AB_ProviderExtendMode_Add);
|
|
if (rv)
|
|
return rv;
|
|
AB_Account_List_Add(a, ab->accounts);
|
|
return 0;
|
|
}
|
|
|
|
|
|
|
|
GWEN_TYPE_UINT64 AB_Banking__char2uint64(const char *accountId) {
|
|
GWEN_TYPE_UINT64 res=0;
|
|
const char *s;
|
|
|
|
s=accountId;
|
|
while(*s) {
|
|
if (*s<'0' || *s>'9')
|
|
return 0;
|
|
res*=10;
|
|
res+=(*s-'0');
|
|
s++;
|
|
}
|
|
|
|
return res;
|
|
}
|
|
|
|
|
|
|
|
AB_ACCOUNT *AB_Banking_GetAccountByCodeAndNumber(const AB_BANKING *ab,
|
|
const char *bankCode,
|
|
const char *accountId){
|
|
AB_ACCOUNT *a;
|
|
|
|
if ((bankCode == NULL) || (accountId == NULL))
|
|
return NULL;
|
|
assert(ab);
|
|
if (AB_Account_List_GetCount(ab->accounts)==0) {
|
|
DBG_INFO(AQBANKING_LOGDOMAIN, "No accounts");
|
|
return 0;
|
|
}
|
|
a=AB_Account_List_First(ab->accounts);
|
|
assert(a);
|
|
while(a) {
|
|
if (bankCode) {
|
|
if (strcasecmp(AB_Account_GetBankCode(a), bankCode)==0 &&
|
|
strcasecmp(AB_Account_GetAccountNumber(a), accountId)==0)
|
|
break;
|
|
}
|
|
else {
|
|
if (strcasecmp(AB_Account_GetAccountNumber(a), accountId)==0)
|
|
break;
|
|
}
|
|
a=AB_Account_List_Next(a);
|
|
} /* while */
|
|
|
|
if (!a) {
|
|
GWEN_TYPE_UINT64 an;
|
|
|
|
an=AB_Banking__char2uint64(accountId);
|
|
if (an) {
|
|
a=AB_Account_List_First(ab->accounts);
|
|
assert(a);
|
|
while(a) {
|
|
GWEN_TYPE_UINT64 lan;
|
|
|
|
lan=AB_Banking__char2uint64(AB_Account_GetAccountNumber(a));
|
|
if (lan) {
|
|
if (bankCode) {
|
|
if (strcasecmp(AB_Account_GetBankCode(a), bankCode)==0 &&
|
|
an==lan)
|
|
break;
|
|
}
|
|
else {
|
|
if (an==lan)
|
|
break;
|
|
}
|
|
}
|
|
a=AB_Account_List_Next(a);
|
|
} /* while */
|
|
}
|
|
}
|
|
|
|
return a;
|
|
}
|
|
|
|
|
|
|
|
int AB_Banking_Init(AB_BANKING *ab) {
|
|
GWEN_DB_NODE *dbT;
|
|
GWEN_DB_NODE *dbTsrc;
|
|
AB_JOB_LIST2 *jl;
|
|
int i;
|
|
const char *s;
|
|
GWEN_PLUGIN_MANAGER *pm;
|
|
#ifdef LOCAL_INSTALL
|
|
GWEN_BUFFER *buf=0;
|
|
unsigned int pos;
|
|
#endif
|
|
|
|
assert(ab);
|
|
if (ab->isOpen) {
|
|
DBG_ERROR(AQBANKING_LOGDOMAIN, "AqBanking already initialized!");
|
|
return AB_ERROR_INVALID;
|
|
}
|
|
|
|
if (!GWEN_Logger_IsOpen(AQBANKING_LOGDOMAIN)) {
|
|
GWEN_Logger_Open(AQBANKING_LOGDOMAIN,
|
|
"aqbanking", 0,
|
|
GWEN_LoggerTypeConsole,
|
|
GWEN_LoggerFacilityUser);
|
|
}
|
|
|
|
s=getenv("AQBANKING_LOGLEVEL");
|
|
if (s && *s) {
|
|
GWEN_LOGGER_LEVEL ll;
|
|
|
|
ll=GWEN_Logger_Name2Level(s);
|
|
GWEN_Logger_SetLevel(AQBANKING_LOGDOMAIN, ll);
|
|
}
|
|
else
|
|
GWEN_Logger_SetLevel(AQBANKING_LOGDOMAIN, GWEN_LoggerLevelNotice);
|
|
|
|
#ifdef HAVE_I18N
|
|
setlocale(LC_ALL,"");
|
|
s=bindtextdomain(PACKAGE, LOCALEDIR);
|
|
if (s) {
|
|
DBG_DEBUG(AQBANKING_LOGDOMAIN, "Locale bound.");
|
|
bind_textdomain_codeset(PACKAGE, "UTF-8");
|
|
}
|
|
else {
|
|
DBG_ERROR(AQBANKING_LOGDOMAIN, "Error binding locale");
|
|
}
|
|
#endif
|
|
|
|
DBG_INFO(AQBANKING_LOGDOMAIN,
|
|
"AqBanking v"
|
|
AQBANKING_VERSION_FULL_STRING
|
|
" (compiled at "
|
|
COMPILE_DATETIME
|
|
"): initialising");
|
|
|
|
/* define sysconf paths */
|
|
GWEN_PathManager_DefinePath(AB_PM_LIBNAME, AB_PM_SYSCONFDIR);
|
|
#ifdef OS_WIN32
|
|
GWEN_PathManager_AddPathFromWinReg(AB_PM_LIBNAME,
|
|
AB_PM_LIBNAME,
|
|
AB_PM_DATADIR,
|
|
AB_BANKING_REGKEY_PATHS,
|
|
AB_BANKING_REGKEY_SYSCONFDIR);
|
|
#endif
|
|
GWEN_PathManager_AddPath(AB_PM_LIBNAME,
|
|
AB_PM_LIBNAME,
|
|
AB_PM_SYSCONFDIR,
|
|
AQBANKING_SYSCONF_DIR);
|
|
|
|
|
|
/* define data paths */
|
|
GWEN_PathManager_DefinePath(AB_PM_LIBNAME, AB_PM_DATADIR);
|
|
#ifdef OS_WIN32
|
|
GWEN_PathManager_AddPathFromWinReg(AB_PM_LIBNAME,
|
|
AB_PM_LIBNAME,
|
|
AB_PM_DATADIR,
|
|
AB_BANKING_REGKEY_PATHS,
|
|
AB_BANKING_REGKEY_DATADIR);
|
|
#endif
|
|
GWEN_PathManager_AddPath(AB_PM_LIBNAME,
|
|
AB_PM_LIBNAME,
|
|
AB_PM_DATADIR,
|
|
AQBANKING_DATA_DIR);
|
|
|
|
#ifdef LOCAL_INSTALL
|
|
buf=GWEN_Buffer_new(0, 256, 0, 1);
|
|
if (ab->startFolder) {
|
|
GWEN_Buffer_AppendString(buf, ab->startFolder);
|
|
GWEN_Buffer_AppendString(buf, DIRSEP);
|
|
}
|
|
pos=GWEN_Buffer_GetPos(buf);
|
|
|
|
/* add local sysconf dir */
|
|
GWEN_Buffer_AppendString(buf, "etc");
|
|
GWEN_PathManager_InsertPath(AB_PM_LIBNAME,
|
|
AB_PM_LIBNAME,
|
|
AB_PM_SYSCONFDIR,
|
|
GWEN_Buffer_GetStart(buf));
|
|
GWEN_Buffer_Crop(buf, 0, pos);
|
|
|
|
/* add local data dir */
|
|
GWEN_Buffer_AppendString(buf, "share" DIRSEP "aqbanking");
|
|
GWEN_PathManager_InsertPath(AB_PM_LIBNAME,
|
|
AB_PM_LIBNAME,
|
|
AB_PM_DATADIR,
|
|
GWEN_Buffer_GetStart(buf));
|
|
GWEN_Buffer_Crop(buf, 0, pos);
|
|
|
|
/* add local plugin paths */
|
|
/* Watch out: need to use "lib64" on x64 */
|
|
GWEN_Buffer_AppendString(buf, "lib" DIRSEP "aqbanking" DIRSEP
|
|
"plugins" DIRSEP
|
|
AQBANKING_SO_EFFECTIVE_STR DIRSEP);
|
|
pos=GWEN_Buffer_GetPos(buf);
|
|
|
|
#endif
|
|
|
|
|
|
/* create bankinfo plugin manager */
|
|
DBG_INFO(AQBANKING_LOGDOMAIN, "Registering bankinfo plugin manager");
|
|
pm=GWEN_PluginManager_new("bankinfo");
|
|
|
|
#ifdef LOCAL_INSTALL
|
|
GWEN_Buffer_AppendString(buf, "bankinfo");
|
|
GWEN_PluginManager_AddPath(pm, GWEN_Buffer_GetStart(buf));
|
|
GWEN_Buffer_Crop(buf, 0, pos);
|
|
#endif
|
|
GWEN_PluginManager_AddPathFromWinReg(pm,
|
|
AB_BANKING_REGKEY_PATHS,
|
|
AB_BANKING_REGKEY_BANKINFODIR);
|
|
GWEN_PluginManager_AddPath(pm,
|
|
AQBANKING_PLUGINS
|
|
DIRSEP
|
|
AB_BANKINFO_PLUGIN_FOLDER);
|
|
if (GWEN_PluginManager_Register(pm)) {
|
|
DBG_ERROR(AQBANKING_LOGDOMAIN,
|
|
"Could not register bankinfo plugin manager");
|
|
#ifdef LOCAL_INSTALL
|
|
GWEN_Buffer_free(buf);
|
|
#endif
|
|
return AB_ERROR_GENERIC;
|
|
}
|
|
ab->pluginManagerBankInfo=pm;
|
|
|
|
|
|
/* create provider plugin manager */
|
|
DBG_INFO(AQBANKING_LOGDOMAIN, "Registering provider plugin manager");
|
|
pm=GWEN_PluginManager_new("provider");
|
|
#ifdef LOCAL_INSTALL
|
|
GWEN_Buffer_AppendString(buf, "provider");
|
|
GWEN_PluginManager_AddPath(pm, GWEN_Buffer_GetStart(buf));
|
|
GWEN_Buffer_Crop(buf, 0, pos);
|
|
#endif
|
|
GWEN_PluginManager_AddPathFromWinReg(pm,
|
|
AB_BANKING_REGKEY_PATHS,
|
|
AB_BANKING_REGKEY_PROVIDERDIR);
|
|
GWEN_PluginManager_AddPath(pm,
|
|
AQBANKING_PLUGINS
|
|
DIRSEP
|
|
AB_PROVIDER_FOLDER);
|
|
if (GWEN_PluginManager_Register(pm)) {
|
|
DBG_ERROR(AQBANKING_LOGDOMAIN,
|
|
"Could not register provider plugin manager");
|
|
#ifdef LOCAL_INSTALL
|
|
GWEN_Buffer_free(buf);
|
|
#endif
|
|
return AB_ERROR_GENERIC;
|
|
}
|
|
ab->pluginManagerProvider=pm;
|
|
|
|
/* create imexporters plugin manager */
|
|
DBG_INFO(AQBANKING_LOGDOMAIN, "Registering imexporters plugin manager");
|
|
pm=GWEN_PluginManager_new("imexporters");
|
|
#ifdef LOCAL_INSTALL
|
|
GWEN_Buffer_AppendString(buf, "imexporters");
|
|
GWEN_PluginManager_AddPath(pm, GWEN_Buffer_GetStart(buf));
|
|
GWEN_Buffer_Crop(buf, 0, pos);
|
|
#endif
|
|
GWEN_PluginManager_AddPathFromWinReg(pm,
|
|
AB_BANKING_REGKEY_PATHS,
|
|
AB_BANKING_REGKEY_IMPORTERDIR);
|
|
GWEN_PluginManager_AddPath(pm,
|
|
AQBANKING_PLUGINS
|
|
DIRSEP
|
|
AB_IMEXPORTER_FOLDER);
|
|
if (GWEN_PluginManager_Register(pm)) {
|
|
DBG_ERROR(AQBANKING_LOGDOMAIN,
|
|
"Could not register imexporters plugin manager");
|
|
#ifdef LOCAL_INSTALL
|
|
GWEN_Buffer_free(buf);
|
|
#endif
|
|
return AB_ERROR_GENERIC;
|
|
}
|
|
ab->pluginManagerImExporter=pm;
|
|
|
|
|
|
/* create crypt plugin manager */
|
|
DBG_INFO(AQBANKING_LOGDOMAIN, "Registering crypttoken plugin manager");
|
|
pm=AB_CryptManager_new(ab);
|
|
#ifdef LOCAL_INSTALL
|
|
GWEN_Buffer_Reset(buf);
|
|
if (ab->startFolder) {
|
|
GWEN_Buffer_AppendString(buf, ab->startFolder);
|
|
GWEN_Buffer_AppendString(buf, DIRSEP);
|
|
}
|
|
/* Watch out: need to use "lib64" on x64 */
|
|
GWEN_Buffer_AppendString(buf, "lib" DIRSEP "gwenhywfar" DIRSEP
|
|
"plugin" DIRSEP
|
|
GWENHYWFAR_SO_EFFECTIVE_STR DIRSEP);
|
|
pos=GWEN_Buffer_GetPos(buf);
|
|
GWEN_Buffer_AppendString(buf, "crypttoken");
|
|
GWEN_PluginManager_AddPath(pm, GWEN_Buffer_GetStart(buf));
|
|
GWEN_Buffer_Crop(buf, 0, pos);
|
|
#endif
|
|
|
|
if (1) { /* this "if" is just to have local vars in the next block */
|
|
GWEN_BUFFER *ctbuf;
|
|
|
|
/* add path from gwen since all crypt token plugins are installed there */
|
|
ctbuf=GWEN_Buffer_new(0, 256, 0, 1);
|
|
GWEN_GetPluginPath(ctbuf);
|
|
GWEN_Buffer_AppendString(ctbuf, DIRSEP);
|
|
GWEN_Buffer_AppendString(ctbuf, "crypttoken");
|
|
GWEN_PluginManager_AddPath(pm,
|
|
GWEN_Buffer_GetStart(ctbuf));
|
|
GWEN_Buffer_free(ctbuf);
|
|
}
|
|
if (GWEN_PluginManager_Register(pm)) {
|
|
DBG_ERROR(AQBANKING_LOGDOMAIN,
|
|
"Could not register crypttoken plugin manager");
|
|
#ifdef LOCAL_INSTALL
|
|
GWEN_Buffer_free(buf);
|
|
#endif
|
|
return AB_ERROR_GENERIC;
|
|
}
|
|
ab->pluginManagerCryptToken=pm;
|
|
|
|
|
|
/* add local path for DBIO plugins if in local installation mode */
|
|
#ifdef LOCAL_INSTALL
|
|
pm=GWEN_PluginManager_FindPluginManager("dbio");
|
|
if (pm) {
|
|
GWEN_Buffer_AppendString(buf, "dbio");
|
|
GWEN_PluginManager_InsertPath(pm, GWEN_Buffer_GetStart(buf));
|
|
GWEN_Buffer_Crop(buf, 0, pos);
|
|
}
|
|
#endif
|
|
|
|
#ifdef LOCAL_INSTALL
|
|
GWEN_Buffer_free(buf);
|
|
#endif
|
|
|
|
/* read config file */
|
|
if (access(ab->configFile, F_OK)) {
|
|
DBG_NOTICE(AQBANKING_LOGDOMAIN,
|
|
"Configuration file \"%s\" does not exist, "
|
|
"will create it later.", ab->configFile);
|
|
/* Check whether directory for configuration file exists; if
|
|
it does not exist, it is created here. */
|
|
if (GWEN_Directory_GetPath(ab->dataDir,
|
|
GWEN_PATH_FLAGS_CHECKROOT)) {
|
|
DBG_ERROR(AQBANKING_LOGDOMAIN,
|
|
"Data folder \"%s\" could not be created.",
|
|
ab->dataDir);
|
|
return AB_ERROR_NOT_FOUND;
|
|
}
|
|
} else {
|
|
|
|
/* Configuration file exists, so read it now. */
|
|
dbT=GWEN_DB_Group_new("banking");
|
|
assert(dbT);
|
|
if (GWEN_DB_ReadFile(dbT, ab->configFile,
|
|
GWEN_DB_FLAGS_DEFAULT |
|
|
GWEN_PATH_FLAGS_CREATE_GROUP |
|
|
GWEN_DB_FLAGS_LOCKFILE)) {
|
|
GWEN_DB_Group_free(dbT);
|
|
return AB_ERROR_BAD_CONFIG_FILE;
|
|
}
|
|
|
|
ab->lastVersion=GWEN_DB_GetIntValue(dbT, "lastVersion", 0, 0);
|
|
|
|
/* store data as new "banking" group within global configuration DB */
|
|
GWEN_DB_DeleteGroup(ab->data, "banking");
|
|
GWEN_DB_AddGroup(ab->data, dbT);
|
|
|
|
/* read active providers */
|
|
for (i=0; ; i++) {
|
|
const char *p;
|
|
|
|
p=GWEN_DB_GetCharValue(ab->data, "banking/activeProviders", i, 0);
|
|
if (!p)
|
|
break;
|
|
GWEN_StringList_AppendString(ab->activeProviders, p, 0, 1);
|
|
}
|
|
|
|
|
|
ab->alwaysAskForCert=GWEN_DB_GetIntValue(ab->data,
|
|
"banking/alwaysAskForCert", 0, 0);
|
|
ab->pinCacheEnabled=0;
|
|
|
|
/* init active providers */
|
|
if (GWEN_StringList_Count(ab->activeProviders)) {
|
|
GWEN_STRINGLISTENTRY *se;
|
|
|
|
se=GWEN_StringList_FirstEntry(ab->activeProviders);
|
|
assert(se);
|
|
while(se) {
|
|
const char *p;
|
|
AB_PROVIDER *pro;
|
|
|
|
p=GWEN_StringListEntry_Data(se);
|
|
assert(p);
|
|
|
|
pro=AB_Banking_GetProvider(ab, p);
|
|
if (!pro) {
|
|
DBG_WARN(AQBANKING_LOGDOMAIN,
|
|
"Error loading/initializing backend \"%s\"", p);
|
|
}
|
|
se=GWEN_StringListEntry_Next(se);
|
|
} /* while */
|
|
}
|
|
|
|
/* read users */
|
|
dbTsrc=GWEN_DB_GetGroup(dbT, GWEN_PATH_FLAGS_NAMEMUSTEXIST, "users");
|
|
if (dbTsrc) {
|
|
GWEN_DB_NODE *dbU;
|
|
|
|
dbU=GWEN_DB_FindFirstGroup(dbTsrc, "user");
|
|
while(dbU) {
|
|
AB_USER *u;
|
|
|
|
u=AB_User_fromDb(ab, dbU);
|
|
if (u) {
|
|
const char *s;
|
|
AB_PROVIDER *pro;
|
|
|
|
s=AB_User_GetBackendName(u);
|
|
assert(s && *s);
|
|
pro=AB_Banking_GetProvider(ab, s);
|
|
if (!pro) {
|
|
DBG_WARN(AQBANKING_LOGDOMAIN, "Provider \"%s\" not found", s);
|
|
}
|
|
else {
|
|
int rv;
|
|
|
|
rv=AB_Provider_ExtendUser(pro, u, AB_ProviderExtendMode_Extend);
|
|
if (rv) {
|
|
DBG_INFO(AQBANKING_LOGDOMAIN, "here");
|
|
AB_User_free(u);
|
|
}
|
|
else {
|
|
DBG_DEBUG(AQBANKING_LOGDOMAIN, "Adding user");
|
|
AB_User_List_Add(u, ab->users);
|
|
}
|
|
}
|
|
}
|
|
dbU=GWEN_DB_FindNextGroup(dbU, "user");
|
|
} /* while */
|
|
} /* if users */
|
|
|
|
|
|
/* read accounts */
|
|
dbTsrc=GWEN_DB_GetGroup(dbT, GWEN_PATH_FLAGS_NAMEMUSTEXIST, "accounts");
|
|
if (dbTsrc) {
|
|
GWEN_DB_NODE *dbA;
|
|
|
|
dbA=GWEN_DB_FindFirstGroup(dbTsrc, "account");
|
|
while(dbA) {
|
|
AB_ACCOUNT *a;
|
|
|
|
a=AB_Account_fromDb(ab, dbA);
|
|
if (a) {
|
|
int rv;
|
|
|
|
rv=AB_Provider_ExtendAccount(AB_Account_GetProvider(a), a,
|
|
AB_ProviderExtendMode_Extend);
|
|
if (rv) {
|
|
DBG_INFO(AQBANKING_LOGDOMAIN, "here");
|
|
}
|
|
else {
|
|
DBG_DEBUG(AQBANKING_LOGDOMAIN, "Adding account");
|
|
AB_Account_List_Add(a, ab->accounts);
|
|
}
|
|
}
|
|
dbA=GWEN_DB_FindNextGroup(dbA, "account");
|
|
} /* while */
|
|
} /* if accounts */
|
|
|
|
|
|
/* update active providers if necessary */
|
|
if (AB_Provider_List_GetCount(ab->providers) &&
|
|
ab->lastVersion <
|
|
((AQBANKING_VERSION_MAJOR<<24) |
|
|
(AQBANKING_VERSION_MINOR<<16) |
|
|
(AQBANKING_VERSION_PATCHLEVEL<<8) |
|
|
AQBANKING_VERSION_BUILD)) {
|
|
AB_PROVIDER *pro;
|
|
|
|
pro=AB_Provider_List_First(ab->providers);
|
|
while(pro) {
|
|
int rv;
|
|
|
|
rv=AB_Provider_Update(pro, ab->lastVersion,
|
|
((AQBANKING_VERSION_MAJOR<<24) |
|
|
(AQBANKING_VERSION_MINOR<<16) |
|
|
(AQBANKING_VERSION_PATCHLEVEL<<8) |
|
|
AQBANKING_VERSION_BUILD));
|
|
if (rv) {
|
|
DBG_ERROR(AQBANKING_LOGDOMAIN,
|
|
"Could not update provider \"%s\"",
|
|
AB_Provider_GetName(pro));
|
|
return rv;
|
|
}
|
|
|
|
pro=AB_Provider_List_Next(pro);
|
|
} /* while */
|
|
}
|
|
|
|
|
|
/* read jobs */
|
|
jl=AB_Banking__LoadJobsAs(ab, "todo");
|
|
if (jl) {
|
|
AB_JOB_LIST2_ITERATOR *it;
|
|
AB_JOB *j;
|
|
|
|
AB_Job_List_free(ab->enqueuedJobs);
|
|
ab->enqueuedJobs=AB_Job_List_new();
|
|
|
|
it=AB_Job_List2_First(jl);
|
|
assert(it);
|
|
j=AB_Job_List2Iterator_Data(it);
|
|
assert(j);
|
|
while(j) {
|
|
if (AB_Job_CheckAvailability(j)) {
|
|
DBG_INFO(AQBANKING_LOGDOMAIN, "Job not available, ignoring");
|
|
}
|
|
else
|
|
AB_Job_List_Add(j, ab->enqueuedJobs);
|
|
j=AB_Job_List2Iterator_Next(it);
|
|
} /* while */
|
|
AB_Job_List2Iterator_free(it);
|
|
AB_Job_List2_free(jl);
|
|
}
|
|
|
|
} /* if (access(ab->configFile, F_OK)) */
|
|
|
|
ab->isOpen=1;
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
|
|
|
|
int AB_Banking_Fini(AB_BANKING *ab) {
|
|
int rv;
|
|
AB_PROVIDER *pro;
|
|
|
|
assert(ab);
|
|
|
|
if (!ab->isOpen) {
|
|
DBG_ERROR(AQBANKING_LOGDOMAIN, "AqBanking not initialized!");
|
|
return AB_ERROR_INVALID;
|
|
}
|
|
|
|
/* deinit all providers */
|
|
pro=AB_Provider_List_First(ab->providers);
|
|
while(pro) {
|
|
while (AB_Provider_IsInit(pro)) {
|
|
rv=AB_Banking_FiniProvider(ab, pro);
|
|
if (rv) {
|
|
DBG_WARN(AQBANKING_LOGDOMAIN,
|
|
"Error deinitializing backend \"%s\"",
|
|
AB_Provider_GetName(pro));
|
|
break;
|
|
}
|
|
}
|
|
pro=AB_Provider_List_Next(pro);
|
|
} /* while */
|
|
|
|
rv=AB_Banking_Save(ab);
|
|
if (rv) {
|
|
DBG_INFO(AQBANKING_LOGDOMAIN, "here (%d)", rv);
|
|
return rv;
|
|
}
|
|
|
|
AB_Job_List_Clear(ab->enqueuedJobs);
|
|
AB_Account_List_Clear(ab->accounts);
|
|
AB_User_List_Clear(ab->users);
|
|
AB_Provider_List_Clear(ab->providers);
|
|
|
|
/* unregister and unload crypt token plugin manager */
|
|
if (ab->pluginManagerCryptToken) {
|
|
if (GWEN_PluginManager_Unregister(ab->pluginManagerCryptToken)) {
|
|
DBG_ERROR(AQBANKING_LOGDOMAIN,
|
|
"Could not unregister crypt token plugin manager");
|
|
}
|
|
GWEN_PluginManager_free(ab->pluginManagerCryptToken);
|
|
ab->pluginManagerCryptToken=0;
|
|
}
|
|
|
|
/* unregister and unload provider plugin manager */
|
|
if (ab->pluginManagerProvider) {
|
|
if (GWEN_PluginManager_Unregister(ab->pluginManagerProvider)) {
|
|
DBG_ERROR(AQBANKING_LOGDOMAIN,
|
|
"Could not unregister provider plugin manager");
|
|
}
|
|
GWEN_PluginManager_free(ab->pluginManagerProvider);
|
|
ab->pluginManagerProvider=0;
|
|
}
|
|
|
|
/* unregister and unload bankinfo plugin manager */
|
|
if (ab->pluginManagerBankInfo) {
|
|
if (GWEN_PluginManager_Unregister(ab->pluginManagerBankInfo)) {
|
|
DBG_ERROR(AQBANKING_LOGDOMAIN,
|
|
"Could not unregister bankinfo plugin manager");
|
|
}
|
|
GWEN_PluginManager_free(ab->pluginManagerBankInfo);
|
|
ab->pluginManagerBankInfo=0;
|
|
}
|
|
|
|
/* unregister and unload imexporters plugin manager */
|
|
if (ab->pluginManagerImExporter) {
|
|
if (GWEN_PluginManager_Unregister(ab->pluginManagerImExporter)) {
|
|
DBG_ERROR(AQBANKING_LOGDOMAIN,
|
|
"Could not unregister imexporter plugin manager");
|
|
}
|
|
GWEN_PluginManager_free(ab->pluginManagerImExporter);
|
|
ab->pluginManagerImExporter=0;
|
|
}
|
|
|
|
/* unregister and unload pkgdata plugin manager */
|
|
if (ab->pluginManagerPkgdatadir) {
|
|
/*
|
|
if (GWEN_PluginManager_Unregister(ab->pluginManagerPkgdatadir)) {
|
|
DBG_ERROR(AQBANKING_LOGDOMAIN,
|
|
"Could not unregister aqbanking_datadir plugin manager");
|
|
}*/
|
|
GWEN_PluginManager_free(ab->pluginManagerPkgdatadir);
|
|
ab->pluginManagerPkgdatadir=0;
|
|
}
|
|
|
|
GWEN_PathManager_UndefinePath(AB_PM_LIBNAME, AB_PM_DATADIR);
|
|
GWEN_PathManager_UndefinePath(AB_PM_LIBNAME, AB_PM_SYSCONFDIR);
|
|
|
|
GWEN_DB_ClearGroup(ab->data, 0);
|
|
GWEN_Logger_Close(AQBANKING_LOGDOMAIN);
|
|
|
|
ab->isOpen=0;
|
|
return 0;
|
|
}
|
|
|
|
|
|
|
|
int AB_Banking_Save(AB_BANKING *ab) {
|
|
GWEN_DB_NODE *db;
|
|
GWEN_DB_NODE *dbT;
|
|
AB_ACCOUNT *a;
|
|
AB_USER *u;
|
|
AB_JOB *j;
|
|
int rv;
|
|
int rvExternal;
|
|
GWEN_BUFFER *rpbuf;
|
|
|
|
assert(ab);
|
|
|
|
db=GWEN_DB_Group_new("config");
|
|
assert(db);
|
|
|
|
GWEN_DB_SetIntValue(db, GWEN_DB_FLAGS_OVERWRITE_VARS,
|
|
"lastVersion",
|
|
(AQBANKING_VERSION_MAJOR<<24) |
|
|
(AQBANKING_VERSION_MINOR<<16) |
|
|
(AQBANKING_VERSION_PATCHLEVEL<<8) |
|
|
AQBANKING_VERSION_BUILD);
|
|
|
|
/* save bad pins */
|
|
rv=AB_Banking__SaveBadPins(ab);
|
|
if (rv) {
|
|
DBG_WARN(AQBANKING_LOGDOMAIN, "Could not save bad pins");
|
|
}
|
|
|
|
/* save list of active backends */
|
|
if (GWEN_StringList_Count(ab->activeProviders)) {
|
|
GWEN_STRINGLISTENTRY *se;
|
|
|
|
se=GWEN_StringList_FirstEntry(ab->activeProviders);
|
|
assert(se);
|
|
while(se) {
|
|
const char *p;
|
|
|
|
p=GWEN_StringListEntry_Data(se);
|
|
assert(p);
|
|
GWEN_DB_SetCharValue(db, GWEN_DB_FLAGS_DEFAULT,
|
|
"activeProviders", p);
|
|
|
|
se=GWEN_StringListEntry_Next(se);
|
|
} /* while */
|
|
}
|
|
|
|
/* store some vars */
|
|
GWEN_DB_SetIntValue(db, GWEN_DB_FLAGS_OVERWRITE_VARS,
|
|
"alwaysAskForCert",
|
|
ab->alwaysAskForCert);
|
|
|
|
/* save users */
|
|
u=AB_User_List_First(ab->users);
|
|
while(u) {
|
|
GWEN_DB_NODE *dbTdst;
|
|
int rv;
|
|
AB_PROVIDER *pro;
|
|
|
|
/* let provider store not yet stored data */
|
|
pro=AB_User_GetProvider(u);
|
|
if (pro) {
|
|
rv=AB_Provider_ExtendUser(pro, u, AB_ProviderExtendMode_Save);
|
|
if (rv) {
|
|
DBG_WARN(AQBANKING_LOGDOMAIN, "Error extending user (%d)", rv);
|
|
}
|
|
}
|
|
else {
|
|
DBG_WARN(AQBANKING_LOGDOMAIN, "No provider for user \"%08x\"",
|
|
AB_User_GetUniqueId(u));
|
|
}
|
|
|
|
/* store user data */
|
|
dbTdst=GWEN_DB_GetGroup(db,
|
|
GWEN_DB_FLAGS_DEFAULT |
|
|
GWEN_PATH_FLAGS_CREATE_GROUP,
|
|
"users/user");
|
|
assert(dbTdst);
|
|
rv=AB_User_toDb(u, dbTdst);
|
|
if (rv) {
|
|
DBG_ERROR(AQBANKING_LOGDOMAIN, "Error saving user \"%08x\"",
|
|
AB_User_GetUniqueId(u));
|
|
GWEN_DB_Group_free(db);
|
|
return rv;
|
|
}
|
|
u=AB_User_List_Next(u);
|
|
} /* while */
|
|
|
|
/* save accounts */
|
|
a=AB_Account_List_First(ab->accounts);
|
|
while(a) {
|
|
GWEN_DB_NODE *dbTdst;
|
|
int rv;
|
|
AB_PROVIDER *pro;
|
|
|
|
/* let provider store not yet stored data */
|
|
pro=AB_Account_GetProvider(a);
|
|
if (pro) {
|
|
rv=AB_Provider_ExtendAccount(pro, a, AB_ProviderExtendMode_Save);
|
|
if (rv) {
|
|
DBG_WARN(AQBANKING_LOGDOMAIN, "Error extending account (%d)", rv);
|
|
}
|
|
}
|
|
|
|
dbTdst=GWEN_DB_GetGroup(db,
|
|
GWEN_DB_FLAGS_DEFAULT |
|
|
GWEN_PATH_FLAGS_CREATE_GROUP,
|
|
"accounts/account");
|
|
assert(dbTdst);
|
|
rv=AB_Account_toDb(a, dbTdst);
|
|
if (rv) {
|
|
DBG_ERROR(AQBANKING_LOGDOMAIN, "Error saving account \"%08x\"",
|
|
AB_Account_GetUniqueId(a));
|
|
GWEN_DB_Group_free(db);
|
|
return rv;
|
|
}
|
|
a=AB_Account_List_Next(a);
|
|
} /* while */
|
|
|
|
/* store bad pins */
|
|
dbT=GWEN_DB_GetGroup(ab->data,
|
|
GWEN_PATH_FLAGS_NAMEMUSTEXIST,
|
|
"banking/pins");
|
|
if (dbT) {
|
|
GWEN_DB_NODE *dbTdst;
|
|
|
|
dbTdst=GWEN_DB_GetGroup(db,
|
|
GWEN_DB_FLAGS_DEFAULT,
|
|
"pins");
|
|
GWEN_DB_AddGroupChildren(dbTdst, dbT);
|
|
}
|
|
|
|
/* store certificates */
|
|
dbT=GWEN_DB_GetGroup(ab->data,
|
|
GWEN_PATH_FLAGS_NAMEMUSTEXIST,
|
|
"banking/certificates");
|
|
if (dbT) {
|
|
GWEN_DB_NODE *dbTdst;
|
|
|
|
dbTdst=GWEN_DB_GetGroup(db,
|
|
GWEN_DB_FLAGS_DEFAULT,
|
|
"certificates");
|
|
GWEN_DB_AddGroupChildren(dbTdst, dbT);
|
|
}
|
|
|
|
/* store backends */
|
|
dbT=GWEN_DB_GetGroup(ab->data,
|
|
GWEN_PATH_FLAGS_NAMEMUSTEXIST,
|
|
"banking/backends");
|
|
if (dbT) {
|
|
GWEN_DB_NODE *dbTdst;
|
|
|
|
dbTdst=GWEN_DB_GetGroup(db,
|
|
GWEN_DB_FLAGS_DEFAULT,
|
|
"backends");
|
|
GWEN_DB_AddGroupChildren(dbTdst, dbT);
|
|
}
|
|
|
|
/* save enqueued jobs */
|
|
j=AB_Job_List_First(ab->enqueuedJobs);
|
|
while(j) {
|
|
if (AB_Banking__SaveJobAs(ab, j, "todo")) {
|
|
DBG_INFO(AQBANKING_LOGDOMAIN, "Error saving job, ignoring");
|
|
}
|
|
j=AB_Job_List_Next(j);
|
|
} /* while */
|
|
|
|
/* store external data */
|
|
rvExternal=AB_Banking__SaveExternalData(ab);
|
|
|
|
/* write config file. TODO: make backups */
|
|
rpbuf=GWEN_Buffer_new(0, strlen(ab->configFile)+4, 0, 1);
|
|
GWEN_Buffer_AppendString(rpbuf, ab->configFile);
|
|
GWEN_Buffer_AppendString(rpbuf, ".tmp");
|
|
if (GWEN_DB_WriteFile(db, GWEN_Buffer_GetStart(rpbuf),
|
|
GWEN_DB_FLAGS_DEFAULT|GWEN_DB_FLAGS_LOCKFILE)) {
|
|
DBG_INFO(AQBANKING_LOGDOMAIN,
|
|
"Could not save app config file \"%s\"",
|
|
ab->configFile);
|
|
GWEN_Buffer_free(rpbuf);
|
|
GWEN_DB_Group_free(db);
|
|
return AB_ERROR_GENERIC;
|
|
}
|
|
#ifdef OS_WIN32
|
|
if (unlink(ab->configFile)) {
|
|
DBG_ERROR(AQBANKING_LOGDOMAIN,
|
|
"Could not delete old file \"%s\": %s",
|
|
ab->configFile,
|
|
strerror(errno));
|
|
GWEN_Buffer_free(rpbuf);
|
|
GWEN_DB_Group_free(db);
|
|
return AB_ERROR_GENERIC;
|
|
}
|
|
#endif
|
|
if (rename(GWEN_Buffer_GetStart(rpbuf), ab->configFile)) {
|
|
DBG_ERROR(AQBANKING_LOGDOMAIN,
|
|
"Could not rename file to \"%s\": %s",
|
|
ab->configFile,
|
|
strerror(errno));
|
|
GWEN_Buffer_free(rpbuf);
|
|
GWEN_DB_Group_free(db);
|
|
return AB_ERROR_GENERIC;
|
|
}
|
|
GWEN_Buffer_free(rpbuf);
|
|
GWEN_DB_Group_free(db);
|
|
|
|
if (rvExternal) {
|
|
DBG_ERROR(AQBANKING_LOGDOMAIN, "Could not save external configuration");
|
|
return rvExternal;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
GWEN_PLUGIN_DESCRIPTION_LIST2 *AB_Banking_GetProviderDescrs(AB_BANKING *ab){
|
|
GWEN_PLUGIN_DESCRIPTION_LIST2 *l;
|
|
|
|
l=GWEN_LoadPluginDescrs(AQBANKING_PLUGINS DIRSEP "providers");
|
|
if (l) {
|
|
GWEN_PLUGIN_DESCRIPTION_LIST2_ITERATOR *it;
|
|
GWEN_PLUGIN_DESCRIPTION *pd;
|
|
|
|
it=GWEN_PluginDescription_List2_First(l);
|
|
assert(it);
|
|
pd=GWEN_PluginDescription_List2Iterator_Data(it);
|
|
assert(pd);
|
|
while(pd) {
|
|
if (GWEN_StringList_HasString(ab->activeProviders,
|
|
GWEN_PluginDescription_GetName(pd)))
|
|
GWEN_PluginDescription_SetIsActive(pd, 1);
|
|
else
|
|
GWEN_PluginDescription_SetIsActive(pd, 0);
|
|
pd=GWEN_PluginDescription_List2Iterator_Next(it);
|
|
}
|
|
GWEN_PluginDescription_List2Iterator_free(it);
|
|
}
|
|
|
|
return l;
|
|
}
|
|
|
|
|
|
|
|
GWEN_PLUGIN_DESCRIPTION_LIST2 *AB_Banking_GetWizardDescrs(AB_BANKING *ab){
|
|
GWEN_PLUGIN_DESCRIPTION_LIST2 *wdl;
|
|
|
|
wdl=GWEN_LoadPluginDescrs(AQBANKING_PLUGINS
|
|
DIRSEP
|
|
AB_WIZARD_FOLDER);
|
|
return wdl;
|
|
}
|
|
|
|
|
|
|
|
GWEN_PLUGIN_DESCRIPTION_LIST2 *AB_Banking_GetDebuggerDescrs(AB_BANKING *ab,
|
|
const char *pn){
|
|
GWEN_BUFFER *pbuf;
|
|
GWEN_PLUGIN_DESCRIPTION_LIST2 *wdl;
|
|
|
|
pbuf=GWEN_Buffer_new(0, 256, 0, 1);
|
|
GWEN_Buffer_AppendString(pbuf,
|
|
AQBANKING_PLUGINS
|
|
DIRSEP
|
|
AB_PROVIDER_DEBUGGER_FOLDER
|
|
DIRSEP);
|
|
GWEN_Buffer_AppendString(pbuf, pn);
|
|
|
|
wdl=GWEN_LoadPluginDescrs(GWEN_Buffer_GetStart(pbuf));
|
|
|
|
GWEN_Buffer_free(pbuf);
|
|
return wdl;
|
|
}
|
|
|
|
|
|
|
|
GWEN_PLUGIN_DESCRIPTION_LIST2 *AB_Banking_GetImExporterDescrs(AB_BANKING *ab){
|
|
GWEN_PLUGIN_DESCRIPTION_LIST2 *l;
|
|
|
|
l=GWEN_LoadPluginDescrs(AQBANKING_PLUGINS DIRSEP "imexporters");
|
|
return l;
|
|
}
|
|
|
|
|
|
|
|
int AB_Banking_EnqueueJob(AB_BANKING *ab, AB_JOB *j){
|
|
int rv;
|
|
AB_JOB_STATUS jst;
|
|
|
|
assert(ab);
|
|
assert(j);
|
|
rv=AB_Job_CheckAvailability(j);
|
|
if (rv) {
|
|
DBG_ERROR(AQBANKING_LOGDOMAIN, "Job is not available, refusing to enqueue.");
|
|
AB_Job_Log(j, AB_Banking_LogLevelError, "aqbanking",
|
|
"Job is not available with the backend, not enqueueing");
|
|
return rv;
|
|
}
|
|
jst=AB_Job_GetStatus(j);
|
|
if (jst==AB_Job_StatusFinished ||
|
|
jst==AB_Job_StatusError ||
|
|
jst==AB_Job_StatusEnqueued) {
|
|
DBG_ERROR(AQBANKING_LOGDOMAIN,
|
|
"Job has already been enqueued or even finished, "
|
|
"not enqueueing it");
|
|
AB_Job_Log(j, AB_Banking_LogLevelError, "aqbanking",
|
|
"Job has already been enqueued or finished, "
|
|
"not enqueueing");
|
|
return AB_ERROR_INVALID;
|
|
}
|
|
|
|
/* adapt status if necessary */
|
|
if (jst!=AB_Job_StatusEnqueued &&
|
|
jst!=AB_Job_StatusPending)
|
|
AB_Job_SetStatus(j, AB_Job_StatusEnqueued);
|
|
|
|
/* really enqueue the job */
|
|
if (AB_Job_GetJobId(j)==0)
|
|
AB_Job_SetUniqueId(j, AB_Banking_GetUniqueId(ab));
|
|
AB_Job_Attach(j);
|
|
AB_Job_List_Add(j, ab->enqueuedJobs);
|
|
AB_Banking__SaveJobAs(ab, j, "todo");
|
|
|
|
/* unlink it from whatever previous list it belonged to */
|
|
switch(jst) {
|
|
case AB_Job_StatusPending:
|
|
AB_Banking__UnlinkJobAs(ab, j, "pending"); break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
/* done */
|
|
return 0;
|
|
}
|
|
|
|
|
|
|
|
int AB_Banking_DequeueJob(AB_BANKING *ab, AB_JOB *j){
|
|
int rv;
|
|
AB_JOB_STATUS jst;
|
|
|
|
assert(ab);
|
|
assert(j);
|
|
jst=AB_Job_GetStatus(j);
|
|
if (jst==AB_Job_StatusEnqueued) {
|
|
AB_Job_SetStatus(j, AB_Job_StatusNew);
|
|
AB_Job_List_Del(j);
|
|
}
|
|
rv=AB_Banking__UnlinkJobAs(ab, j, "todo");
|
|
AB_Job_free(j);
|
|
return rv;
|
|
}
|
|
|
|
|
|
|
|
int AB_Banking_EnqueuePendingJobs(AB_BANKING *ab, int mineOnly){
|
|
AB_JOB_LIST2 *jl;
|
|
int errorCount;
|
|
int successCount;
|
|
|
|
errorCount=successCount=0;
|
|
jl=AB_Banking_GetPendingJobs(ab);
|
|
if (jl) {
|
|
AB_JOB *j;
|
|
AB_JOB_LIST2_ITERATOR *it;
|
|
|
|
it=AB_Job_List2_First(jl);
|
|
assert(it);
|
|
|
|
j=AB_Job_List2Iterator_Data(it);
|
|
assert(j);
|
|
while(j) {
|
|
int doit;
|
|
|
|
if (!mineOnly)
|
|
doit=1;
|
|
else
|
|
doit=(strcasecmp(AB_Job_GetCreatedBy(j), ab->appName)==0);
|
|
if (doit) {
|
|
if (AB_Banking_EnqueueJob(ab, j)) {
|
|
DBG_ERROR(AQBANKING_LOGDOMAIN,
|
|
"Error enqueueing job %d",
|
|
AB_Job_GetJobId(j));
|
|
errorCount++;
|
|
}
|
|
else
|
|
successCount++;
|
|
}
|
|
j=AB_Job_List2Iterator_Next(it);
|
|
} /* while */
|
|
AB_Job_List2Iterator_free(it);
|
|
AB_Job_List2_FreeAll(jl);
|
|
} /* if pending jobs */
|
|
|
|
if (!errorCount)
|
|
return 0;
|
|
if (errorCount)
|
|
/* all attempts resulted in errors */
|
|
return AB_ERROR_GENERIC;
|
|
return 0;
|
|
}
|
|
|
|
|
|
|
|
int AB_Banking_ExecutionProgress(AB_BANKING *ab, GWEN_TYPE_UINT32 pid) {
|
|
if (!ab->currentJobs)
|
|
return 0;
|
|
else {
|
|
AB_JOB_LIST2_ITERATOR *jit;
|
|
GWEN_TYPE_UINT32 count=0;
|
|
|
|
jit=AB_Job_List2_First(ab->currentJobs);
|
|
if (jit) {
|
|
AB_JOB *j;
|
|
|
|
j=AB_Job_List2Iterator_Data(jit);
|
|
while(j) {
|
|
AB_JOB_STATUS jst;
|
|
|
|
jst=AB_Job_GetStatus(j);
|
|
if (jst==AB_Job_StatusFinished ||
|
|
jst==AB_Job_StatusPending ||
|
|
jst==AB_Job_StatusError)
|
|
count++;
|
|
j=AB_Job_List2Iterator_Next(jit);
|
|
} /* while */
|
|
AB_Job_List2Iterator_free(jit);
|
|
}
|
|
return AB_Banking_ProgressAdvance(ab, pid, count);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
int AB_Banking__ExecuteQueue(AB_BANKING *ab,
|
|
AB_JOB_LIST2 *jl,
|
|
AB_IMEXPORTER_CONTEXT *ctx,
|
|
GWEN_TYPE_UINT32 pid){
|
|
AB_PROVIDER *pro;
|
|
int succ;
|
|
|
|
assert(ab);
|
|
pro=AB_Provider_List_First(ab->providers);
|
|
succ=0;
|
|
|
|
ab->currentJobs=jl;
|
|
|
|
while(pro) {
|
|
AB_JOB_LIST2_ITERATOR *jit;
|
|
int jobs=0;
|
|
int rv;
|
|
|
|
jit=AB_Job_List2_First(jl);
|
|
if (jit) {
|
|
AB_JOB *j;
|
|
|
|
j=AB_Job_List2Iterator_Data(jit);
|
|
while(j) {
|
|
AB_JOB_STATUS jst;
|
|
|
|
jst=AB_Job_GetStatus(j);
|
|
DBG_INFO(AQBANKING_LOGDOMAIN, "Checking job...");
|
|
if (jst==AB_Job_StatusEnqueued ||
|
|
jst==AB_Job_StatusPending) {
|
|
AB_ACCOUNT *a;
|
|
|
|
a=AB_Job_GetAccount(j);
|
|
assert(a);
|
|
if (AB_Account_GetProvider(a)==pro) {
|
|
DBG_INFO(AQBANKING_LOGDOMAIN, "Same provider, adding job");
|
|
/* same provider, add job */
|
|
AB_Job_Log(j, AB_Banking_LogLevelInfo, "aqbanking",
|
|
"Adding job to backend");
|
|
rv=AB_Provider_AddJob(pro, j);
|
|
if (rv) {
|
|
DBG_ERROR(AQBANKING_LOGDOMAIN, "Could not add job (%d)", rv);
|
|
AB_Job_SetStatus(j, AB_Job_StatusError);
|
|
AB_Job_SetResultText(j, "Refused by backend");
|
|
AB_Job_Log(j, AB_Banking_LogLevelError, "aqbanking",
|
|
"Adding job: Refused by backend");
|
|
}
|
|
else {
|
|
jobs++;
|
|
if (AB_Job_GetStatus(j)!=AB_Job_StatusPending) {
|
|
AB_Job_SetStatus(j, AB_Job_StatusSent);
|
|
AB_Banking__SaveJobAs(ab, j, "sent");
|
|
AB_Banking__UnlinkJobAs(ab, j, "todo");
|
|
}
|
|
else {
|
|
AB_Banking__SaveJobAs(ab, j, "sent");
|
|
AB_Banking__UnlinkJobAs(ab, j, "todo");
|
|
}
|
|
}
|
|
}
|
|
} /* if job enqueued */
|
|
else {
|
|
DBG_DEBUG(AQBANKING_LOGDOMAIN,
|
|
"Job %08x in queue with status \"%s\"",
|
|
AB_Job_GetJobId(j),
|
|
AB_Job_Status2Char(AB_Job_GetStatus(j)));
|
|
}
|
|
j=AB_Job_List2Iterator_Next(jit);
|
|
} /* while */
|
|
AB_Job_List2Iterator_free(jit);
|
|
}
|
|
|
|
if (jobs) {
|
|
DBG_INFO(AQBANKING_LOGDOMAIN, "Letting backend \"%s\" work",
|
|
AB_Provider_GetName(pro));
|
|
rv=AB_Provider_Execute(pro, ctx);
|
|
if (rv) {
|
|
int lrv;
|
|
|
|
if (rv==AB_ERROR_USER_ABORT) {
|
|
DBG_INFO(AQBANKING_LOGDOMAIN, "Aborted by user");
|
|
ab->currentJobs=0;
|
|
return rv;
|
|
}
|
|
DBG_NOTICE(AQBANKING_LOGDOMAIN, "Error executing backend's queue");
|
|
lrv=AB_Banking_MessageBox(ab,
|
|
AB_BANKING_MSG_FLAGS_TYPE_ERROR |
|
|
AB_BANKING_MSG_FLAGS_CONFIRM_B1 |
|
|
AB_BANKING_MSG_FLAGS_SEVERITY_NORMAL,
|
|
I18N("Error"),
|
|
I18N("Error executing backend's queue.\n"
|
|
"What shall we do?"),
|
|
I18N("Continue"), I18N("Abort"), 0);
|
|
if (lrv!=1) {
|
|
DBG_INFO(AQBANKING_LOGDOMAIN, "Aborted by user");
|
|
ab->currentJobs=0;
|
|
return AB_ERROR_USER_ABORT;
|
|
}
|
|
}
|
|
else {
|
|
rv=AB_Banking_ExecutionProgress(ab, pid);
|
|
if (rv==AB_ERROR_USER_ABORT) {
|
|
DBG_INFO(AQBANKING_LOGDOMAIN, "Aborted by user");
|
|
ab->currentJobs=0;
|
|
return rv;
|
|
}
|
|
succ++;
|
|
}
|
|
} /* if jobs in backend's queue */
|
|
|
|
pro=AB_Provider_List_Next(pro);
|
|
} /* while */
|
|
ab->currentJobs=0;
|
|
|
|
if (!succ) {
|
|
DBG_ERROR(AQBANKING_LOGDOMAIN, "Not a single job successfully executed");
|
|
return AB_ERROR_GENERIC;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
|
|
int AB_Banking_ExecuteQueue(AB_BANKING *ab){
|
|
AB_IMEXPORTER_CONTEXT *ctx;
|
|
int rv;
|
|
AB_JOB_LIST2 *jl2;
|
|
|
|
jl2=AB_Banking_GetEnqueuedJobs(ab);
|
|
if (!jl2) {
|
|
DBG_INFO(AQBANKING_LOGDOMAIN, "No jobs enqueued");
|
|
return 0;
|
|
}
|
|
|
|
ctx=AB_ImExporterContext_new();
|
|
rv=AB_Banking_ExecuteJobListWithCtx(ab, jl2, ctx);
|
|
AB_Banking__DistribContextAmongJobs(ctx, jl2);
|
|
AB_ImExporterContext_free(ctx);
|
|
AB_Job_List2_FreeAll(jl2);
|
|
|
|
return rv;
|
|
}
|
|
|
|
|
|
|
|
int AB_Banking_ExecuteQueueWithCtx(AB_BANKING *ab,
|
|
AB_IMEXPORTER_CONTEXT *ctx) {
|
|
AB_JOB_LIST2 *jl2;
|
|
int rv;
|
|
|
|
jl2=AB_Banking_GetEnqueuedJobs(ab);
|
|
if (!jl2) {
|
|
DBG_INFO(AQBANKING_LOGDOMAIN, "No jobs enqueued");
|
|
return 0;
|
|
}
|
|
|
|
rv=AB_Banking_ExecuteJobListWithCtx(ab, jl2, ctx);
|
|
AB_Job_List2_FreeAll(jl2);
|
|
if (rv) {
|
|
DBG_INFO(AQBANKING_LOGDOMAIN, "here (%d)", rv);
|
|
return rv;
|
|
}
|
|
|
|
#if 0
|
|
if (1) {
|
|
GWEN_DB_NODE *dbTest;
|
|
|
|
dbTest=GWEN_DB_Group_new("ctx");
|
|
AB_ImExporterContext_toDb(ctx, dbTest);
|
|
GWEN_DB_WriteFile(dbTest, "/tmp/queue.ctx", GWEN_DB_FLAGS_DEFAULT);
|
|
GWEN_DB_Group_free(dbTest);
|
|
}
|
|
#endif
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
|
|
int AB_Banking_ExecuteJobListWithCtx(AB_BANKING *ab, AB_JOB_LIST2 *jl2,
|
|
AB_IMEXPORTER_CONTEXT *ctx){
|
|
int rv;
|
|
GWEN_TYPE_UINT32 pid;
|
|
AB_JOB_LIST2_ITERATOR *jit;
|
|
AB_PROVIDER *pro=0;
|
|
|
|
assert(ab);
|
|
|
|
DBG_DEBUG(AQBANKING_LOGDOMAIN, "Attaching to jobs, dequeing them");
|
|
jit=AB_Job_List2_First(jl2);
|
|
if (jit) {
|
|
AB_JOB *j;
|
|
|
|
j=AB_Job_List2Iterator_Data(jit);
|
|
while(j) {
|
|
/* attach to job in case the queue is the only owner of the job
|
|
* we will free the job later */
|
|
AB_Job_Attach(j);
|
|
AB_Job_List_Del(j);
|
|
j=AB_Job_List2Iterator_Next(jit);
|
|
} /* while */
|
|
AB_Job_List2Iterator_free(jit);
|
|
}
|
|
|
|
/* clear temporarily accepted certificates */
|
|
GWEN_DB_ClearGroup(ab->dbTempConfig, "certificates");
|
|
|
|
/* execute jobs */
|
|
pid=AB_Banking_ProgressStart(ab,
|
|
I18N("Executing Jobs"),
|
|
I18N("Now the jobs are send via their "
|
|
"backends to the credit institutes."),
|
|
AB_Job_List2_GetSize(jl2));
|
|
rv=AB_Banking__ExecuteQueue(ab, jl2, ctx, pid);
|
|
if (rv) {
|
|
DBG_INFO(AQBANKING_LOGDOMAIN, "here (%d)", rv);
|
|
}
|
|
AB_Banking_ProgressEnd(ab, pid);
|
|
|
|
/* clear temporarily accepted certificates again */
|
|
GWEN_DB_ClearGroup(ab->dbTempConfig, "certificates");
|
|
|
|
/* clear queue */
|
|
jit=AB_Job_List2_First(jl2);
|
|
if (jit) {
|
|
AB_JOB *j;
|
|
|
|
j=AB_Job_List2Iterator_Data(jit);
|
|
while(j) {
|
|
switch(AB_Job_GetStatus(j)) {
|
|
case AB_Job_StatusEnqueued:
|
|
/* job still enqueued, so it has never been sent */
|
|
AB_Job_SetStatus(j, AB_Job_StatusError);
|
|
AB_Job_SetResultText(j, "Job has never been sent");
|
|
AB_Job_Log(j, AB_Banking_LogLevelError, "aqbanking",
|
|
"Job has never been sent");
|
|
if (AB_Banking__SaveJobAs(ab, j, "finished")) {
|
|
DBG_ERROR(AQBANKING_LOGDOMAIN, "Could not save job as \"finished\"");
|
|
}
|
|
AB_Banking__UnlinkJobAs(ab, j, "sent");
|
|
break;
|
|
|
|
case AB_Job_StatusPending:
|
|
AB_Job_Log(j, AB_Banking_LogLevelNotice, "aqbanking",
|
|
"Job is still pending");
|
|
if (AB_Banking__SaveJobAs(ab, j, "pending")) {
|
|
DBG_ERROR(AQBANKING_LOGDOMAIN, "Could not save job as \"pending\"");
|
|
}
|
|
AB_Banking__UnlinkJobAs(ab, j, "sent");
|
|
break;
|
|
|
|
case AB_Job_StatusSent:
|
|
case AB_Job_StatusFinished:
|
|
case AB_Job_StatusError:
|
|
default:
|
|
AB_Job_Log(j, AB_Banking_LogLevelInfo, "aqbanking",
|
|
"Job finished");
|
|
if (AB_Banking__SaveJobAs(ab, j, "finished")) {
|
|
DBG_ERROR(AQBANKING_LOGDOMAIN, "Could not save job as \"finished\"");
|
|
}
|
|
AB_Banking__UnlinkJobAs(ab, j, "sent");
|
|
break;
|
|
}
|
|
|
|
/* we attached some lines ago, so we must now free */
|
|
AB_Job_free(j);
|
|
|
|
j=AB_Job_List2Iterator_Next(jit);
|
|
} /* while */
|
|
AB_Job_List2Iterator_free(jit);
|
|
}
|
|
|
|
/* reset all provider queues, this makes sure no job remains in any queue */
|
|
pro=AB_Provider_List_First(ab->providers);
|
|
while(pro) {
|
|
int lrv;
|
|
|
|
lrv=AB_Provider_ResetQueue(pro);
|
|
if (lrv) {
|
|
DBG_INFO(AQBANKING_LOGDOMAIN, "Error resetting providers queue (%d)",
|
|
lrv);
|
|
}
|
|
pro=AB_Provider_List_Next(pro);
|
|
} /* while */
|
|
|
|
|
|
if (!AB_Banking_GetPinCacheEnabled(ab)) {
|
|
/* If pin caching was disabled, then delete all PINs */
|
|
AB_Pin_List_Clear(ab->pinList);
|
|
}
|
|
|
|
return rv;
|
|
}
|
|
|
|
|
|
|
|
int AB_Banking_ExecuteJobList(AB_BANKING *ab, AB_JOB_LIST2 *jl2){
|
|
AB_IMEXPORTER_CONTEXT *ctx;
|
|
int rv;
|
|
|
|
ctx=AB_ImExporterContext_new();
|
|
rv=AB_Banking_ExecuteJobListWithCtx(ab, jl2, ctx);
|
|
/* distribute context accross jobs in list */
|
|
AB_Banking__DistribContextAmongJobs(ctx, jl2);
|
|
AB_ImExporterContext_free(ctx);
|
|
return rv;
|
|
}
|
|
|
|
|
|
|
|
AB_IMEXPORTER_ACCOUNTINFO*
|
|
AB_Banking__FindAccountInfo(AB_IMEXPORTER_CONTEXT *ctx,
|
|
const AB_ACCOUNT *a) {
|
|
const char *bankId;
|
|
const char *accountNr;
|
|
const char *accountName;
|
|
|
|
bankId=AB_Account_GetBankCode(a);
|
|
accountNr=AB_Account_GetAccountNumber(a);
|
|
accountName=AB_Account_GetAccountName(a);
|
|
|
|
if (bankId || accountNr || accountName) {
|
|
AB_IMEXPORTER_ACCOUNTINFO *ai;
|
|
AB_IMEXPORTER_ACCOUNTINFO *aiFound=0;
|
|
|
|
ai=AB_ImExporterContext_GetFirstAccountInfo(ctx);
|
|
while(ai) {
|
|
const char *s1;
|
|
const char *s2;
|
|
const char *s3;
|
|
|
|
s1=AB_ImExporterAccountInfo_GetBankCode(ai);
|
|
s2=AB_ImExporterAccountInfo_GetAccountNumber(ai);
|
|
s3=AB_ImExporterAccountInfo_GetAccountName(ai);
|
|
if (s1 || s2 || s3) {
|
|
int match=1;
|
|
|
|
if ((s2 && accountNr)) {
|
|
/* account number is given in both, maybe bank code, too */
|
|
if (strcasecmp(s2, accountNr)!=0)
|
|
/* mismatch of account number */
|
|
match=0;
|
|
if (match && s1 && bankId) {
|
|
if (strcasecmp(s1, bankId)!=0)
|
|
/* mismatch of bank code */
|
|
match=0;
|
|
}
|
|
}
|
|
else if (s3 && accountName) {
|
|
/* account name is given in both */
|
|
if (strcasecmp(s3, accountName)!=0)
|
|
/* mismatch of account name */
|
|
match=0;
|
|
}
|
|
else {
|
|
/* could not match anything */
|
|
match=0;
|
|
}
|
|
|
|
if (match) {
|
|
if (aiFound) {
|
|
DBG_ERROR(AQBANKING_LOGDOMAIN,
|
|
"Ambiguous account specification");
|
|
return 0;
|
|
}
|
|
aiFound=ai;
|
|
} /* if no mismatch */
|
|
} /* if any argument is given in account info */
|
|
ai=AB_ImExporterContext_GetNextAccountInfo(ctx);
|
|
} /* while */
|
|
return aiFound;
|
|
} /* if there is anything in the account to cmp against */
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
|
|
void AB_Banking__DistribContextAmongJobs(AB_IMEXPORTER_CONTEXT *ctx,
|
|
AB_JOB_LIST2 *jl2){
|
|
AB_JOB_LIST2_ITERATOR *jit;
|
|
|
|
jit=AB_Job_List2_First(jl2);
|
|
if (jit) {
|
|
AB_JOB *j;
|
|
|
|
j=AB_Job_List2Iterator_Data(jit);
|
|
assert(j);
|
|
while(j) {
|
|
AB_JOB_STATUS jst;
|
|
|
|
jst=AB_Job_GetStatus(j);
|
|
if (jst==AB_Job_StatusFinished ||
|
|
jst==AB_Job_StatusPending) {
|
|
switch(AB_Job_GetType(j)) {
|
|
case AB_Job_TypeGetBalance: {
|
|
AB_ACCOUNT *a;
|
|
AB_IMEXPORTER_ACCOUNTINFO *ai;
|
|
|
|
a=AB_Job_GetAccount(j);
|
|
assert(a);
|
|
ai=AB_Banking__FindAccountInfo(ctx, a);
|
|
if (ai) {
|
|
AB_ACCOUNT_STATUS *ast;
|
|
|
|
ast=AB_ImExporterAccountInfo_GetFirstAccountStatus(ai);
|
|
if (ast) {
|
|
while(ast) {
|
|
AB_JobGetBalance_SetAccountStatus(j, AB_AccountStatus_dup(ast));
|
|
ast=AB_ImExporterAccountInfo_GetNextAccountStatus(ai);
|
|
}
|
|
}
|
|
} /* if ai */
|
|
break;
|
|
}
|
|
case AB_Job_TypeGetTransactions: {
|
|
AB_ACCOUNT *a;
|
|
AB_IMEXPORTER_ACCOUNTINFO *ai;
|
|
|
|
a=AB_Job_GetAccount(j);
|
|
assert(a);
|
|
ai=AB_Banking__FindAccountInfo(ctx, a);
|
|
if (ai) {
|
|
AB_ACCOUNT_STATUS *ast;
|
|
const AB_TRANSACTION *t;
|
|
|
|
ast=AB_ImExporterAccountInfo_GetFirstAccountStatus(ai);
|
|
if (ast) {
|
|
AB_ACCOUNT_STATUS_LIST2 *asl;
|
|
|
|
asl=AB_AccountStatus_List2_new();
|
|
while(ast) {
|
|
AB_AccountStatus_List2_PushBack(asl,
|
|
AB_AccountStatus_dup(ast));
|
|
ast=AB_ImExporterAccountInfo_GetNextAccountStatus(ai);
|
|
}
|
|
AB_JobGetTransactions_SetAccountStatusList(j, asl);
|
|
}
|
|
|
|
t=AB_ImExporterAccountInfo_GetFirstTransaction(ai);
|
|
if (t) {
|
|
AB_TRANSACTION_LIST2 *tl;
|
|
|
|
tl=AB_Transaction_List2_new();
|
|
while(t) {
|
|
AB_Transaction_List2_PushBack(tl,
|
|
AB_Transaction_dup(t));
|
|
t=AB_ImExporterAccountInfo_GetNextTransaction(ai);
|
|
}
|
|
AB_JobGetTransactions_SetTransactions(j, tl);
|
|
}
|
|
} /* if ai */
|
|
break;
|
|
}
|
|
case AB_Job_TypeGetStandingOrders: {
|
|
AB_ACCOUNT *a;
|
|
AB_IMEXPORTER_ACCOUNTINFO *ai;
|
|
|
|
a=AB_Job_GetAccount(j);
|
|
assert(a);
|
|
ai=AB_Banking__FindAccountInfo(ctx, a);
|
|
if (ai) {
|
|
const AB_TRANSACTION *t;
|
|
|
|
t=AB_ImExporterAccountInfo_GetFirstStandingOrder(ai);
|
|
if (t) {
|
|
AB_TRANSACTION_LIST2 *tl;
|
|
|
|
tl=AB_Transaction_List2_new();
|
|
while(t) {
|
|
AB_Transaction_List2_PushBack(tl,
|
|
AB_Transaction_dup(t));
|
|
t=AB_ImExporterAccountInfo_GetNextStandingOrder(ai);
|
|
}
|
|
AB_JobGetStandingOrders_SetStandingOrders(j, tl);
|
|
}
|
|
} /* if ai */
|
|
break;
|
|
}
|
|
case AB_Job_TypeGetDatedTransfers: {
|
|
AB_ACCOUNT *a;
|
|
AB_IMEXPORTER_ACCOUNTINFO *ai;
|
|
|
|
a=AB_Job_GetAccount(j);
|
|
assert(a);
|
|
ai=AB_Banking__FindAccountInfo(ctx, a);
|
|
if (ai) {
|
|
const AB_TRANSACTION *t;
|
|
|
|
t=AB_ImExporterAccountInfo_GetFirstDatedTransfer(ai);
|
|
if (t) {
|
|
AB_TRANSACTION_LIST2 *tl;
|
|
|
|
tl=AB_Transaction_List2_new();
|
|
while(t) {
|
|
AB_Transaction_List2_PushBack(tl,
|
|
AB_Transaction_dup(t));
|
|
t=AB_ImExporterAccountInfo_GetNextDatedTransfer(ai);
|
|
}
|
|
AB_JobGetDatedTransfers_SetDatedTransfers(j, tl);
|
|
}
|
|
} /* if ai */
|
|
break;
|
|
}
|
|
default:
|
|
break;
|
|
}
|
|
} /* if status ok */
|
|
j=AB_Job_List2Iterator_Next(jit);
|
|
}
|
|
|
|
AB_Job_List2Iterator_free(jit);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
int AB_Banking_ActivateProvider(AB_BANKING *ab, const char *pname) {
|
|
AB_PROVIDER *pro;
|
|
|
|
if (GWEN_StringList_HasString(ab->activeProviders, pname)) {
|
|
DBG_INFO(AQBANKING_LOGDOMAIN, "Provider already active");
|
|
return AB_ERROR_FOUND;
|
|
}
|
|
|
|
pro=AB_Banking_GetProvider(ab, pname);
|
|
if (!pro) {
|
|
DBG_ERROR(AQBANKING_LOGDOMAIN,
|
|
"Could not load backend \"%s\"", pname);
|
|
return AB_ERROR_NOT_FOUND;
|
|
}
|
|
|
|
GWEN_StringList_AppendString(ab->activeProviders, pname, 0, 1);
|
|
return 0;
|
|
}
|
|
|
|
|
|
|
|
int AB_Banking_DeactivateProvider(AB_BANKING *ab, const char *pname) {
|
|
AB_ACCOUNT *a;
|
|
AB_USER *u;
|
|
AB_PROVIDER *pro;
|
|
|
|
if (!GWEN_StringList_HasString(ab->activeProviders, pname)) {
|
|
DBG_INFO(AQBANKING_LOGDOMAIN, "Provider not active");
|
|
return AB_ERROR_INVALID;
|
|
}
|
|
|
|
pro=AB_Banking_FindProvider(ab, pname);
|
|
if (pro)
|
|
AB_Banking_FiniProvider(ab, pro);
|
|
|
|
GWEN_StringList_RemoveString(ab->activeProviders, pname);
|
|
|
|
/* delete accounts which use this backend */
|
|
a=AB_Account_List_First(ab->accounts);
|
|
while(a) {
|
|
AB_ACCOUNT *na;
|
|
|
|
na=AB_Account_List_Next(a);
|
|
pro=AB_Account_GetProvider(a);
|
|
assert(pro);
|
|
if (strcasecmp(AB_Provider_GetName(pro), pname)==0) {
|
|
AB_Account_List_Del(a);
|
|
AB_Account_free(a);
|
|
}
|
|
a=na;
|
|
}
|
|
|
|
/* delete users which use this backend */
|
|
u=AB_User_List_First(ab->users);
|
|
while(u) {
|
|
AB_USER *nu;
|
|
const char *s;
|
|
|
|
nu=AB_User_List_Next(u);
|
|
s=AB_User_GetBackendName(u);
|
|
assert(s && *s);
|
|
if (strcasecmp(s, pname)==0) {
|
|
AB_User_List_Del(u);
|
|
AB_User_free(u);
|
|
}
|
|
u=nu;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
|
|
const GWEN_STRINGLIST *AB_Banking_GetActiveProviders(const AB_BANKING *ab) {
|
|
assert(ab);
|
|
if (GWEN_StringList_Count(ab->activeProviders)==0)
|
|
return 0;
|
|
return ab->activeProviders;
|
|
}
|
|
|
|
|
|
|
|
int AB_Banking_GetUserDataDir(const AB_BANKING *ab, GWEN_BUFFER *buf){
|
|
char home[256];
|
|
|
|
assert(ab);
|
|
if (ab->dataDir) {
|
|
GWEN_Buffer_AppendString(buf, ab->dataDir);
|
|
}
|
|
else {
|
|
if (GWEN_Directory_GetHomeDirectory(home, sizeof(home))) {
|
|
DBG_ERROR(AQBANKING_LOGDOMAIN,
|
|
"Could not determine home directory, aborting.");
|
|
return -1;
|
|
}
|
|
GWEN_Buffer_AppendString(buf, home);
|
|
GWEN_Buffer_AppendString(buf, DIRSEP AB_BANKING_USERDATADIR);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
|
|
|
|
int AB_Banking_GetSharedDataDir(const AB_BANKING *ab,
|
|
const char *name,
|
|
GWEN_BUFFER *buf){
|
|
char home[256];
|
|
|
|
assert(ab);
|
|
if (ab->dataDir) {
|
|
GWEN_Buffer_AppendString(buf, ab->dataDir);
|
|
}
|
|
else {
|
|
if (GWEN_Directory_GetHomeDirectory(home, sizeof(home))) {
|
|
DBG_ERROR(AQBANKING_LOGDOMAIN,
|
|
"Could not determine home directory, aborting.");
|
|
return -1;
|
|
}
|
|
GWEN_Buffer_AppendString(buf, home);
|
|
GWEN_Buffer_AppendString(buf, DIRSEP AB_BANKING_USERDATADIR);
|
|
}
|
|
|
|
GWEN_Buffer_AppendString(buf, DIRSEP "shared" DIRSEP);
|
|
if (GWEN_Text_EscapeToBufferTolerant(name, buf)) {
|
|
DBG_ERROR(AQBANKING_LOGDOMAIN,
|
|
"Bad share name, aborting.");
|
|
abort();
|
|
}
|
|
else {
|
|
char *s;
|
|
|
|
s=GWEN_Buffer_GetStart(buf);
|
|
while(*s) {
|
|
*s=tolower(*s);
|
|
s++;
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
|
|
int AB_Banking_GetAppUserDataDir(const AB_BANKING *ab, GWEN_BUFFER *buf){
|
|
int rv;
|
|
|
|
assert(ab->appEscName);
|
|
rv=AB_Banking_GetUserDataDir(ab, buf);
|
|
if (rv)
|
|
return rv;
|
|
GWEN_Buffer_AppendString(buf, DIRSEP "apps" DIRSEP);
|
|
GWEN_Buffer_AppendString(buf, ab->appEscName);
|
|
GWEN_Buffer_AppendString(buf, DIRSEP "data");
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
|
|
int AB_Banking_GetProviderUserDataDir(const AB_BANKING *ab,
|
|
const char *name,
|
|
GWEN_BUFFER *buf){
|
|
int rv;
|
|
|
|
rv=AB_Banking_GetUserDataDir(ab, buf);
|
|
if (rv)
|
|
return rv;
|
|
GWEN_Buffer_AppendString(buf, DIRSEP "backends" DIRSEP);
|
|
GWEN_Buffer_AppendString(buf, name);
|
|
GWEN_Buffer_AppendString(buf, DIRSEP "data");
|
|
return 0;
|
|
}
|
|
|
|
|
|
|
|
int AB_Banking__ReadImExporterProfiles(AB_BANKING *ab,
|
|
const char *path,
|
|
GWEN_DB_NODE *db) {
|
|
GWEN_DIRECTORYDATA *d;
|
|
GWEN_BUFFER *nbuf;
|
|
char nbuffer[64];
|
|
unsigned int pathLen;
|
|
|
|
if (!path)
|
|
path="";
|
|
|
|
/* create path */
|
|
nbuf=GWEN_Buffer_new(0, 256, 0, 1);
|
|
GWEN_Buffer_AppendString(nbuf, path);
|
|
pathLen=GWEN_Buffer_GetUsedBytes(nbuf);
|
|
|
|
d=GWEN_Directory_new();
|
|
if (GWEN_Directory_Open(d, GWEN_Buffer_GetStart(nbuf))) {
|
|
DBG_INFO(AQBANKING_LOGDOMAIN,
|
|
"Path \"%s\" is not available",
|
|
GWEN_Buffer_GetStart(nbuf));
|
|
GWEN_Buffer_free(nbuf);
|
|
GWEN_Directory_free(d);
|
|
return AB_ERROR_NOT_FOUND;
|
|
}
|
|
|
|
while(!GWEN_Directory_Read(d,
|
|
nbuffer,
|
|
sizeof(nbuffer))) {
|
|
if (strcmp(nbuffer, ".") &&
|
|
strcmp(nbuffer, "..")) {
|
|
int nlen;
|
|
|
|
nlen=strlen(nbuffer);
|
|
if (nlen>4) {
|
|
if (strcasecmp(nbuffer+nlen-5, ".conf")==0) {
|
|
struct stat st;
|
|
|
|
GWEN_Buffer_Crop(nbuf, 0, pathLen);
|
|
GWEN_Buffer_SetPos(nbuf, pathLen);
|
|
GWEN_Buffer_AppendString(nbuf, DIRSEP);
|
|
GWEN_Buffer_AppendString(nbuf, nbuffer);
|
|
|
|
if (stat(GWEN_Buffer_GetStart(nbuf), &st)) {
|
|
DBG_ERROR(AQBANKING_LOGDOMAIN, "stat(%s): %s",
|
|
GWEN_Buffer_GetStart(nbuf),
|
|
strerror(errno));
|
|
}
|
|
else {
|
|
if (!S_ISDIR(st.st_mode)) {
|
|
GWEN_DB_NODE *dbT;
|
|
|
|
dbT=GWEN_DB_Group_new("profile");
|
|
if (GWEN_DB_ReadFile(dbT,
|
|
GWEN_Buffer_GetStart(nbuf),
|
|
GWEN_DB_FLAGS_DEFAULT |
|
|
GWEN_PATH_FLAGS_CREATE_GROUP)) {
|
|
DBG_ERROR(AQBANKING_LOGDOMAIN,
|
|
"Could not read file \"%s\"",
|
|
GWEN_Buffer_GetStart(nbuf));
|
|
}
|
|
else {
|
|
const char *s;
|
|
|
|
s=GWEN_DB_GetCharValue(dbT, "name", 0, 0);
|
|
if (!s) {
|
|
DBG_ERROR(AQBANKING_LOGDOMAIN,
|
|
"Bad file \"%s\" (no name)",
|
|
GWEN_Buffer_GetStart(nbuf));
|
|
}
|
|
else {
|
|
GWEN_DB_NODE *dbTarget;
|
|
DBG_INFO(AQBANKING_LOGDOMAIN,
|
|
"File \"%s\" contains profile \"%s\"",
|
|
GWEN_Buffer_GetStart(nbuf), s);
|
|
|
|
dbTarget=GWEN_DB_GetGroup(db,
|
|
GWEN_DB_FLAGS_OVERWRITE_GROUPS,
|
|
s);
|
|
assert(dbTarget);
|
|
GWEN_DB_AddGroupChildren(dbTarget, dbT);
|
|
} /* if name */
|
|
} /* if file successfully read */
|
|
GWEN_DB_Group_free(dbT);
|
|
} /* if !dir */
|
|
} /* if stat was ok */
|
|
} /* if conf */
|
|
} /* if name has more than 4 chars */
|
|
} /* if not "." and not ".." */
|
|
} /* while */
|
|
GWEN_Directory_Close(d);
|
|
GWEN_Directory_free(d);
|
|
GWEN_Buffer_free(nbuf);
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
|
|
GWEN_DB_NODE *AB_Banking_GetImExporterProfiles(AB_BANKING *ab,
|
|
const char *name){
|
|
GWEN_BUFFER *buf;
|
|
GWEN_DB_NODE *db;
|
|
int rv;
|
|
GWEN_STRINGLIST *sl;
|
|
GWEN_STRINGLISTENTRY *sentry;
|
|
|
|
buf=GWEN_Buffer_new(0, 256, 0, 1);
|
|
db=GWEN_DB_Group_new("profiles");
|
|
|
|
sl=AB_Banking_GetGlobalDataDirs(ab);
|
|
assert(sl);
|
|
|
|
sentry=GWEN_StringList_FirstEntry(sl);
|
|
assert(sentry);
|
|
|
|
while(sentry) {
|
|
const char *pkgdatadir;
|
|
|
|
pkgdatadir = GWEN_StringListEntry_Data(sentry);
|
|
assert(pkgdatadir);
|
|
|
|
/* read global profiles */
|
|
GWEN_Buffer_AppendString(buf, pkgdatadir);
|
|
GWEN_Buffer_AppendString(buf, DIRSEP "imexporters" DIRSEP);
|
|
if (GWEN_Text_EscapeToBufferTolerant(name, buf)) {
|
|
DBG_ERROR(AQBANKING_LOGDOMAIN,
|
|
"Bad name for importer/exporter");
|
|
GWEN_StringList_free(sl);
|
|
GWEN_DB_Group_free(db);
|
|
GWEN_Buffer_free(buf);
|
|
return 0;
|
|
}
|
|
GWEN_Buffer_AppendString(buf, DIRSEP "profiles");
|
|
rv=AB_Banking__ReadImExporterProfiles(ab,
|
|
GWEN_Buffer_GetStart(buf),
|
|
db);
|
|
if (rv && rv!=AB_ERROR_NOT_FOUND) {
|
|
DBG_ERROR(AQBANKING_LOGDOMAIN,
|
|
"Error reading global profiles");
|
|
GWEN_StringList_free(sl);
|
|
GWEN_DB_Group_free(db);
|
|
GWEN_Buffer_free(buf);
|
|
return 0;
|
|
}
|
|
GWEN_Buffer_Reset(buf);
|
|
sentry=GWEN_StringListEntry_Next(sentry);
|
|
}
|
|
GWEN_StringList_free(sl);
|
|
|
|
/* read local user profiles */
|
|
if (AB_Banking_GetUserDataDir(ab, buf)) {
|
|
DBG_ERROR(AQBANKING_LOGDOMAIN,
|
|
"Could not get user data dir");
|
|
GWEN_DB_Group_free(db);
|
|
GWEN_Buffer_free(buf);
|
|
return 0;
|
|
}
|
|
GWEN_Buffer_AppendString(buf, DIRSEP "imexporters" DIRSEP);
|
|
if (GWEN_Text_EscapeToBufferTolerant(name, buf)) {
|
|
DBG_ERROR(AQBANKING_LOGDOMAIN,
|
|
"Bad name for importer/exporter");
|
|
GWEN_DB_Group_free(db);
|
|
GWEN_Buffer_free(buf);
|
|
return 0;
|
|
}
|
|
GWEN_Buffer_AppendString(buf, DIRSEP "profiles");
|
|
|
|
rv=AB_Banking__ReadImExporterProfiles(ab,
|
|
GWEN_Buffer_GetStart(buf),
|
|
db);
|
|
if (rv && rv!=AB_ERROR_NOT_FOUND) {
|
|
DBG_ERROR(AQBANKING_LOGDOMAIN,
|
|
"Error reading users profiles");
|
|
GWEN_DB_Group_free(db);
|
|
GWEN_Buffer_free(buf);
|
|
return 0;
|
|
}
|
|
GWEN_Buffer_free(buf);
|
|
|
|
return db;
|
|
}
|
|
|
|
|
|
|
|
|
|
AB_PROVIDER *AB_Banking__LoadProviderPlugin(AB_BANKING *ab,
|
|
const char *modname){
|
|
GWEN_LIBLOADER *ll;
|
|
AB_PROVIDER *pro;
|
|
AB_PROVIDER_FACTORY_FN fn;
|
|
void *p;
|
|
const char *s;
|
|
GWEN_ERRORCODE err;
|
|
GWEN_BUFFER *mbuf;
|
|
GWEN_PLUGIN *pl;
|
|
GWEN_PLUGIN_MANAGER *pm;
|
|
|
|
pm=GWEN_PluginManager_FindPluginManager("provider");
|
|
if (!pm) {
|
|
DBG_ERROR(AQBANKING_LOGDOMAIN,
|
|
"Could not find plugin manager for \"%s\"",
|
|
"provider");
|
|
return 0;
|
|
}
|
|
pl=GWEN_PluginManager_LoadPlugin(pm, modname);
|
|
if (!pl) {
|
|
DBG_ERROR(AQBANKING_LOGDOMAIN,
|
|
"Could not load %s plugin for \"%s\"",
|
|
"provider", modname);
|
|
return 0;
|
|
}
|
|
ll=GWEN_Plugin_GetLibLoader(pl);
|
|
|
|
mbuf=GWEN_Buffer_new(0, 256, 0, 1);
|
|
s=modname;
|
|
while(*s) GWEN_Buffer_AppendByte(mbuf, tolower(*(s++)));
|
|
|
|
/* create name of init function */
|
|
GWEN_Buffer_AppendString(mbuf, "_factory");
|
|
|
|
/* resolve name of factory function */
|
|
err=GWEN_LibLoader_Resolve(ll, GWEN_Buffer_GetStart(mbuf), &p);
|
|
if (!GWEN_Error_IsOk(err)) {
|
|
DBG_ERROR_ERR(AQBANKING_LOGDOMAIN, err);
|
|
GWEN_Buffer_free(mbuf);
|
|
GWEN_Plugin_free(pl);
|
|
return 0;
|
|
}
|
|
GWEN_Buffer_free(mbuf);
|
|
|
|
fn=(AB_PROVIDER_FACTORY_FN)p;
|
|
assert(fn);
|
|
pro=fn(ab);
|
|
if (!pro) {
|
|
DBG_ERROR(AQBANKING_LOGDOMAIN, "Error in plugin: No provider created");
|
|
GWEN_Plugin_free(pl);
|
|
return 0;
|
|
}
|
|
|
|
/* store libloader */
|
|
AB_Provider_SetPlugin(pro, pl);
|
|
|
|
return pro;
|
|
}
|
|
|
|
|
|
|
|
AB_BANKINFO_PLUGIN *AB_Banking__LoadBankInfoPlugin(AB_BANKING *ab,
|
|
const char *modname){
|
|
GWEN_LIBLOADER *ll;
|
|
AB_BANKINFO_PLUGIN *bip;
|
|
AB_BANKINFO_PLUGIN_FACTORY_FN fn;
|
|
void *p;
|
|
const char *s;
|
|
GWEN_ERRORCODE err;
|
|
GWEN_BUFFER *mbuf;
|
|
GWEN_DB_NODE *db;
|
|
GWEN_PLUGIN *pl;
|
|
GWEN_PLUGIN_MANAGER *pm;
|
|
|
|
pm=GWEN_PluginManager_FindPluginManager("bankinfo");
|
|
if (!pm) {
|
|
DBG_ERROR(AQBANKING_LOGDOMAIN,
|
|
"Could not find plugin manager for \"%s\"",
|
|
"bankinfo");
|
|
return 0;
|
|
}
|
|
pl=GWEN_PluginManager_LoadPlugin(pm, modname);
|
|
if (!pl) {
|
|
DBG_ERROR(AQBANKING_LOGDOMAIN,
|
|
"Could not load %s plugin for \"%s\"",
|
|
"bankinfo", modname);
|
|
return 0;
|
|
}
|
|
ll=GWEN_Plugin_GetLibLoader(pl);
|
|
|
|
mbuf=GWEN_Buffer_new(0, 256, 0, 1);
|
|
s=modname;
|
|
while(*s) GWEN_Buffer_AppendByte(mbuf, tolower(*(s++)));
|
|
|
|
/* create name of init function */
|
|
GWEN_Buffer_AppendString(mbuf, "_factory");
|
|
|
|
/* resolve name of factory function */
|
|
err=GWEN_LibLoader_Resolve(ll, GWEN_Buffer_GetStart(mbuf), &p);
|
|
if (!GWEN_Error_IsOk(err)) {
|
|
DBG_ERROR_ERR(AQBANKING_LOGDOMAIN, err);
|
|
GWEN_Buffer_free(mbuf);
|
|
GWEN_Plugin_free(pl);
|
|
return 0;
|
|
}
|
|
GWEN_Buffer_free(mbuf);
|
|
|
|
db=GWEN_DB_GetGroup(ab->data, GWEN_DB_FLAGS_DEFAULT,
|
|
"banking/bankinfoplugins");
|
|
assert(db);
|
|
db=GWEN_DB_GetGroup(ab->data, GWEN_DB_FLAGS_DEFAULT,
|
|
modname);
|
|
assert(db);
|
|
|
|
fn=(AB_BANKINFO_PLUGIN_FACTORY_FN)p;
|
|
assert(fn);
|
|
bip=fn(ab, db);
|
|
if (!bip) {
|
|
DBG_ERROR(AQBANKING_LOGDOMAIN,
|
|
"Error in plugin: No bankinfoplugin created");
|
|
GWEN_Plugin_free(pl);
|
|
return 0;
|
|
}
|
|
|
|
/* store libloader */
|
|
AB_BankInfoPlugin_SetPlugin(bip, pl);
|
|
|
|
return bip;
|
|
}
|
|
|
|
|
|
|
|
AB_BANKINFO_PLUGIN *AB_Banking__GetBankInfoPlugin(AB_BANKING *ab,
|
|
const char *country) {
|
|
AB_BANKINFO_PLUGIN *bip;
|
|
|
|
assert(ab);
|
|
assert(country);
|
|
|
|
bip=AB_BankInfoPlugin_List_First(ab->bankInfoPlugins);
|
|
while(bip) {
|
|
if (strcasecmp(AB_BankInfoPlugin_GetCountry(bip), country)==0)
|
|
return bip;
|
|
bip=AB_BankInfoPlugin_List_Next(bip);
|
|
}
|
|
|
|
bip=AB_Banking__LoadBankInfoPlugin(ab, country);
|
|
if (!bip) {
|
|
DBG_ERROR(AQBANKING_LOGDOMAIN,
|
|
"BankInfo plugin for country \"%s\" not found",
|
|
country);
|
|
return 0;
|
|
}
|
|
AB_BankInfoPlugin_List_Add(bip, ab->bankInfoPlugins);
|
|
return bip;
|
|
}
|
|
|
|
|
|
|
|
AB_BANKINFO *AB_Banking_GetBankInfo(AB_BANKING *ab,
|
|
const char *country,
|
|
const char *branchId,
|
|
const char *bankId){
|
|
AB_BANKINFO_PLUGIN *bip;
|
|
|
|
assert(ab);
|
|
assert(country);
|
|
bip=AB_Banking__GetBankInfoPlugin(ab, country);
|
|
if (!bip) {
|
|
DBG_INFO(AQBANKING_LOGDOMAIN,
|
|
"BankInfo plugin for country \"%s\" not found",
|
|
country);
|
|
return 0;
|
|
}
|
|
|
|
return AB_BankInfoPlugin_GetBankInfo(bip, branchId, bankId);
|
|
}
|
|
|
|
|
|
|
|
int AB_Banking_GetBankInfoByTemplate(AB_BANKING *ab,
|
|
const char *country,
|
|
AB_BANKINFO *tbi,
|
|
AB_BANKINFO_LIST2 *bl){
|
|
AB_BANKINFO_PLUGIN *bip;
|
|
|
|
assert(ab);
|
|
assert(country);
|
|
bip=AB_Banking__GetBankInfoPlugin(ab, country);
|
|
if (!bip) {
|
|
DBG_INFO(AQBANKING_LOGDOMAIN,
|
|
"BankInfo plugin for country \"%s\" not found",
|
|
country);
|
|
return 0;
|
|
}
|
|
|
|
return AB_BankInfoPlugin_GetBankInfoByTemplate(bip, tbi, bl);
|
|
}
|
|
|
|
|
|
|
|
AB_BANKINFO_CHECKRESULT
|
|
AB_Banking_CheckAccount(AB_BANKING *ab,
|
|
const char *country,
|
|
const char *branchId,
|
|
const char *bankId,
|
|
const char *accountId) {
|
|
AB_BANKINFO_PLUGIN *bip;
|
|
|
|
assert(ab);
|
|
assert(country);
|
|
bip=AB_Banking__GetBankInfoPlugin(ab, country);
|
|
if (!bip) {
|
|
DBG_INFO(AQBANKING_LOGDOMAIN,
|
|
"BankInfo plugin for country \"%s\" not found",
|
|
country);
|
|
return AB_BankInfoCheckResult_UnknownResult;
|
|
}
|
|
|
|
return AB_BankInfoPlugin_CheckAccount(bip, branchId, bankId, accountId);
|
|
}
|
|
|
|
|
|
|
|
int AB_Banking__GetDebuggerPath(AB_BANKING *ab,
|
|
const char *backend,
|
|
GWEN_BUFFER *pbuf){
|
|
const char *s;
|
|
|
|
GWEN_Buffer_AppendString(pbuf,
|
|
AQBANKING_PLUGINS
|
|
DIRSEP
|
|
AB_PROVIDER_DEBUGGER_FOLDER
|
|
DIRSEP);
|
|
s=backend;
|
|
while(*s) GWEN_Buffer_AppendByte(pbuf, tolower(*(s++)));
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
|
|
int AB_Banking_FindDebugger(AB_BANKING *ab,
|
|
const char *backend,
|
|
const char *frontends,
|
|
GWEN_BUFFER *pbuf){
|
|
GWEN_PLUGIN_DESCRIPTION_LIST2 *pl;
|
|
char *s;
|
|
char *p;
|
|
|
|
pl=AB_Banking_GetDebuggerDescrs(ab, backend);
|
|
if (!pl) {
|
|
DBG_WARN(AQBANKING_LOGDOMAIN,
|
|
"No debuggers available for backend \"%s\"", backend);
|
|
return -1;
|
|
}
|
|
|
|
if (frontends==0) {
|
|
GWEN_PLUGIN_DESCRIPTION_LIST2_ITERATOR *pit;
|
|
GWEN_PLUGIN_DESCRIPTION *pd;
|
|
const char *name;
|
|
|
|
pit=GWEN_PluginDescription_List2_First(pl);
|
|
assert(pit);
|
|
pd=GWEN_PluginDescription_List2Iterator_Data(pit);
|
|
while(pd) {
|
|
name=GWEN_PluginDescription_GetName(pd);
|
|
if (!name) {
|
|
DBG_WARN(AQBANKING_LOGDOMAIN,
|
|
"Found a plugin description with no name");
|
|
}
|
|
else {
|
|
int rv;
|
|
|
|
rv=AB_Banking__GetDebuggerPath(ab, backend, pbuf);
|
|
if (rv) {
|
|
DBG_INFO(AQBANKING_LOGDOMAIN, "here");
|
|
return rv;
|
|
}
|
|
GWEN_Buffer_AppendString(pbuf, DIRSEP);
|
|
GWEN_Buffer_AppendString(pbuf, name);
|
|
GWEN_PluginDescription_List2Iterator_free(pit);
|
|
GWEN_PluginDescription_List2_freeAll(pl);
|
|
return 0;
|
|
}
|
|
pd=GWEN_PluginDescription_List2Iterator_Next(pit);
|
|
}
|
|
GWEN_PluginDescription_List2Iterator_free(pit);
|
|
} /* if no frontend list */
|
|
|
|
/* check for every given frontend */
|
|
s=strdup(frontends);
|
|
|
|
p=s;
|
|
while(*p) {
|
|
GWEN_PLUGIN_DESCRIPTION_LIST2_ITERATOR *pit;
|
|
GWEN_PLUGIN_DESCRIPTION *pd;
|
|
char *t;
|
|
|
|
t=strchr(p, ';');
|
|
if (t)
|
|
*(t++)=0;
|
|
|
|
DBG_DEBUG(AQBANKING_LOGDOMAIN, "Trying frontend \"%s\"", p);
|
|
|
|
pit=GWEN_PluginDescription_List2_First(pl);
|
|
assert(pit);
|
|
pd=GWEN_PluginDescription_List2Iterator_Data(pit);
|
|
assert(pd);
|
|
while(pd) {
|
|
GWEN_XMLNODE *n;
|
|
const char *fr;
|
|
|
|
n=GWEN_PluginDescription_GetXmlNode(pd);
|
|
assert(n);
|
|
fr=GWEN_XMLNode_GetProperty(n, "frontend", "");
|
|
if (-1!=GWEN_Text_ComparePattern(fr, p, 0)) {
|
|
const char *name;
|
|
|
|
name=GWEN_PluginDescription_GetName(pd);
|
|
if (!name) {
|
|
DBG_WARN(AQBANKING_LOGDOMAIN,
|
|
"Found a plugin description with no name");
|
|
}
|
|
else {
|
|
int rv;
|
|
|
|
rv=AB_Banking__GetDebuggerPath(ab, backend, pbuf);
|
|
if (rv) {
|
|
DBG_INFO(AQBANKING_LOGDOMAIN, "here");
|
|
return rv;
|
|
}
|
|
GWEN_Buffer_AppendString(pbuf, DIRSEP);
|
|
GWEN_Buffer_AppendString(pbuf, name);
|
|
free(s);
|
|
GWEN_PluginDescription_List2Iterator_free(pit);
|
|
GWEN_PluginDescription_List2_freeAll(pl);
|
|
return 0;
|
|
}
|
|
}
|
|
pd=GWEN_PluginDescription_List2Iterator_Next(pit);
|
|
} /* while pd */
|
|
GWEN_PluginDescription_List2Iterator_free(pit);
|
|
|
|
if (!t)
|
|
break;
|
|
p=t;
|
|
} /* while */
|
|
|
|
free(s);
|
|
GWEN_PluginDescription_List2_freeAll(pl);
|
|
DBG_ERROR(AQBANKING_LOGDOMAIN, "No matching debugger found");
|
|
return -1;
|
|
}
|
|
|
|
|
|
|
|
int AB_Banking_FindWizard(AB_BANKING *ab,
|
|
const char *backend,
|
|
const char *frontends,
|
|
GWEN_BUFFER *pbuf){
|
|
GWEN_PLUGIN_DESCRIPTION_LIST2 *pl;
|
|
char *s;
|
|
char *pfront;
|
|
assert(ab);
|
|
assert(pbuf);
|
|
|
|
pl=AB_Banking_GetWizardDescrs(ab);
|
|
if (!pl) {
|
|
DBG_WARN(AQBANKING_LOGDOMAIN,
|
|
"No wizards available.");
|
|
return -1;
|
|
}
|
|
|
|
if (frontends==0) {
|
|
GWEN_PLUGIN_DESCRIPTION_LIST2_ITERATOR *pit;
|
|
GWEN_PLUGIN_DESCRIPTION *pd;
|
|
const char *name;
|
|
|
|
pit=GWEN_PluginDescription_List2_First(pl);
|
|
assert(pit);
|
|
pd=GWEN_PluginDescription_List2Iterator_Data(pit);
|
|
while(pd) {
|
|
name=GWEN_PluginDescription_GetName(pd);
|
|
if (!name) {
|
|
DBG_WARN(AQBANKING_LOGDOMAIN,
|
|
"Found a plugin description with no name.");
|
|
}
|
|
else {
|
|
GWEN_Buffer_AppendString(pbuf,
|
|
AQBANKING_PLUGINS
|
|
DIRSEP
|
|
AB_WIZARD_FOLDER
|
|
DIRSEP);
|
|
GWEN_Buffer_AppendString(pbuf, name);
|
|
GWEN_PluginDescription_List2Iterator_free(pit);
|
|
GWEN_PluginDescription_List2_freeAll(pl);
|
|
return 0;
|
|
}
|
|
pd=GWEN_PluginDescription_List2Iterator_Next(pit);
|
|
}
|
|
GWEN_PluginDescription_List2Iterator_free(pit);
|
|
} /* if no frontend list */
|
|
|
|
/* check for every given frontend */
|
|
s=strdup(frontends);
|
|
|
|
pfront=s;
|
|
while(*pfront) {
|
|
GWEN_PLUGIN_DESCRIPTION_LIST2_ITERATOR *pit;
|
|
GWEN_PLUGIN_DESCRIPTION *pd;
|
|
char *t;
|
|
|
|
t=strchr(pfront, ';');
|
|
if (t)
|
|
*(t++)=0;
|
|
|
|
DBG_DEBUG(AQBANKING_LOGDOMAIN, "Trying frontend \"%s\"", pfront);
|
|
|
|
pit=GWEN_PluginDescription_List2_First(pl);
|
|
assert(pit);
|
|
pd=GWEN_PluginDescription_List2Iterator_Data(pit);
|
|
assert(pd);
|
|
while(pd) {
|
|
GWEN_XMLNODE *n;
|
|
const char *fr;
|
|
|
|
n=GWEN_PluginDescription_GetXmlNode(pd);
|
|
assert(n);
|
|
fr=GWEN_XMLNode_GetProperty(n, "frontend", "");
|
|
if (-1!=GWEN_Text_ComparePattern(fr, pfront, 0)) {
|
|
const char *name;
|
|
|
|
name=GWEN_PluginDescription_GetName(pd);
|
|
if (!name) {
|
|
DBG_WARN(AQBANKING_LOGDOMAIN,
|
|
"Found a plugin description with no name");
|
|
}
|
|
else {
|
|
GWEN_Buffer_AppendString(pbuf,
|
|
AQBANKING_PLUGINS
|
|
DIRSEP
|
|
AB_WIZARD_FOLDER
|
|
DIRSEP);
|
|
GWEN_Buffer_AppendString(pbuf, name);
|
|
free(s);
|
|
GWEN_PluginDescription_List2Iterator_free(pit);
|
|
GWEN_PluginDescription_List2_freeAll(pl);
|
|
return 0;
|
|
}
|
|
}
|
|
pd=GWEN_PluginDescription_List2Iterator_Next(pit);
|
|
} /* while pd */
|
|
GWEN_PluginDescription_List2Iterator_free(pit);
|
|
|
|
if (!t)
|
|
break;
|
|
pfront=t;
|
|
} /* while */
|
|
|
|
free(s);
|
|
GWEN_PluginDescription_List2_freeAll(pl);
|
|
DBG_ERROR(AQBANKING_LOGDOMAIN, "No matching wizard found");
|
|
return -1;
|
|
}
|
|
|
|
|
|
|
|
int AB_Banking_IsProviderActive(AB_BANKING *ab, const char *backend){
|
|
AB_PROVIDER *pro;
|
|
|
|
pro=AB_Banking_FindProvider(ab, backend);
|
|
if (!pro) {
|
|
DBG_ERROR(AQBANKING_LOGDOMAIN, "Provider \"%s\" not found", backend);
|
|
return 0;
|
|
}
|
|
|
|
return AB_Provider_IsInit(pro);
|
|
}
|
|
|
|
|
|
|
|
void AB_Banking__AddJobDir(const AB_BANKING *ab,
|
|
const char *as,
|
|
GWEN_BUFFER *buf) {
|
|
AB_Banking_GetUserDataDir(ab, buf);
|
|
GWEN_Buffer_AppendString(buf, DIRSEP "jobs" DIRSEP);
|
|
GWEN_Buffer_AppendString(buf, as);
|
|
}
|
|
|
|
|
|
|
|
void AB_Banking__AddJobPath(const AB_BANKING *ab,
|
|
const char *as,
|
|
GWEN_TYPE_UINT32 jid,
|
|
GWEN_BUFFER *buf) {
|
|
char buffer[16];
|
|
|
|
AB_Banking__AddJobDir(ab, as, buf);
|
|
GWEN_Buffer_AppendString(buf, DIRSEP);
|
|
snprintf(buffer, sizeof(buffer), "%08lx", (unsigned long)jid);
|
|
GWEN_Buffer_AppendString(buf, buffer);
|
|
GWEN_Buffer_AppendString(buf, ".job");
|
|
}
|
|
|
|
|
|
|
|
int AB_Banking__OpenFile(const char *s, int wr) {
|
|
#ifndef OS_WIN32
|
|
struct flock fl;
|
|
#endif
|
|
int fd;
|
|
|
|
if (wr) {
|
|
if (GWEN_Directory_GetPath(s,
|
|
GWEN_DB_FLAGS_DEFAULT |
|
|
GWEN_PATH_FLAGS_VARIABLE)) {
|
|
DBG_ERROR(AQBANKING_LOGDOMAIN, "Could not create path \"%s\"", s);
|
|
return -1;
|
|
}
|
|
fd=open(s,
|
|
O_RDWR | O_CREAT,
|
|
S_IRUSR | S_IWUSR);
|
|
}
|
|
else {
|
|
fd=open(s, O_RDONLY);
|
|
}
|
|
|
|
if (fd==-1) {
|
|
DBG_ERROR(AQBANKING_LOGDOMAIN, "open(%s): %s", s, strerror(errno));
|
|
return -1;
|
|
}
|
|
|
|
#ifndef OS_WIN32
|
|
/* lock file for reading or writing */
|
|
memset(&fl, 0, sizeof(fl));
|
|
fl.l_type=wr?F_WRLCK:F_RDLCK;
|
|
fl.l_whence=SEEK_SET;
|
|
fl.l_start=0;
|
|
fl.l_len=0;
|
|
if (fcntl(fd, F_SETLKW, &fl)) {
|
|
# ifdef ENOLCK
|
|
if (errno!=ENOLCK) {
|
|
DBG_ERROR(AQBANKING_LOGDOMAIN,
|
|
"fcntl(%s, F_SETLKW): %s", s, strerror(errno));
|
|
close(fd);
|
|
return -1;
|
|
}
|
|
DBG_INFO(AQBANKING_LOGDOMAIN,
|
|
"Advisory locking is not supported at this file location.");
|
|
# else
|
|
DBG_ERROR(AQBANKING_LOGDOMAIN,
|
|
"fcntl(%s, F_SETLKW): %s", s, strerror(errno));
|
|
close(fd);
|
|
return -1;
|
|
# endif
|
|
}
|
|
#endif
|
|
|
|
return fd;
|
|
}
|
|
|
|
|
|
|
|
int AB_Banking__CloseFile(int fd){
|
|
#ifndef OS_WIN32
|
|
struct flock fl;
|
|
#endif
|
|
|
|
if (fd==-1) {
|
|
DBG_ERROR(AQBANKING_LOGDOMAIN, "File is not open");
|
|
return -1;
|
|
}
|
|
|
|
#ifndef OS_WIN32
|
|
/* unlock file */
|
|
memset(&fl, 0, sizeof(fl));
|
|
fl.l_type=F_UNLCK;
|
|
fl.l_whence=SEEK_SET;
|
|
fl.l_start=0;
|
|
fl.l_len=0;
|
|
if (fcntl(fd, F_SETLK, &fl)) {
|
|
DBG_WARN(AQBANKING_LOGDOMAIN, "fcntl(%d, F_SETLK): %s",
|
|
fd, strerror(errno));
|
|
}
|
|
#endif
|
|
|
|
if (close(fd)) {
|
|
DBG_ERROR(AQBANKING_LOGDOMAIN, "close(%d): %s", fd, strerror(errno));
|
|
return -1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
|
|
|
|
int AB_Banking__OpenJobAs(AB_BANKING *ab,
|
|
GWEN_TYPE_UINT32 jid,
|
|
const char *as,
|
|
int wr){
|
|
int fd;
|
|
GWEN_BUFFER *pbuf;
|
|
|
|
pbuf=GWEN_Buffer_new(0, 256, 0, 1);
|
|
AB_Banking__AddJobPath(ab, as, jid, pbuf);
|
|
|
|
fd=AB_Banking__OpenFile(GWEN_Buffer_GetStart(pbuf), wr);
|
|
if (fd!=-1 && wr)
|
|
ftruncate(fd, 0);
|
|
GWEN_Buffer_free(pbuf);
|
|
|
|
return fd;
|
|
}
|
|
|
|
|
|
|
|
int AB_Banking__CloseJob(const AB_BANKING *ab, int fd){
|
|
return AB_Banking__CloseFile(fd);
|
|
}
|
|
|
|
|
|
|
|
AB_JOB *AB_Banking__LoadJobFile(AB_BANKING *ab, const char *s){
|
|
GWEN_DB_NODE *dbJob;
|
|
AB_JOB *j;
|
|
int fd;
|
|
GWEN_BUFFEREDIO *bio;
|
|
|
|
|
|
fd=AB_Banking__OpenFile(s, 0);
|
|
if (fd==-1) {
|
|
return 0;
|
|
}
|
|
|
|
bio=GWEN_BufferedIO_File_new(fd);
|
|
GWEN_BufferedIO_SetReadBuffer(bio, 0, 1024);
|
|
GWEN_BufferedIO_SubFlags(bio, GWEN_BUFFEREDIO_FLAGS_CLOSE);
|
|
|
|
dbJob=GWEN_DB_Group_new("job");
|
|
if (GWEN_DB_ReadFromStream(dbJob, bio,
|
|
GWEN_DB_FLAGS_DEFAULT |
|
|
GWEN_PATH_FLAGS_CREATE_GROUP)) {
|
|
DBG_INFO(AQBANKING_LOGDOMAIN, "Error reading job data");
|
|
GWEN_DB_Group_free(dbJob);
|
|
GWEN_BufferedIO_free(bio);
|
|
AB_Banking__CloseJob(ab, fd);
|
|
return 0;
|
|
}
|
|
|
|
j=AB_Job_fromDb(ab, dbJob);
|
|
GWEN_DB_Group_free(dbJob);
|
|
GWEN_BufferedIO_Close(bio);
|
|
GWEN_BufferedIO_free(bio);
|
|
if (AB_Banking__CloseFile(fd)) {
|
|
DBG_INFO(AQBANKING_LOGDOMAIN, "Error closing job, ignoring");
|
|
}
|
|
return j;
|
|
}
|
|
|
|
|
|
|
|
#if 0 /* FIXME: This function is not used */
|
|
AB_JOB *AB_Banking__LoadJobAs(AB_BANKING *ab,
|
|
GWEN_TYPE_UINT32 jid,
|
|
const char *as){
|
|
GWEN_DB_NODE *dbJob;
|
|
AB_JOB *j;
|
|
int fd;
|
|
GWEN_BUFFEREDIO *bio;
|
|
|
|
|
|
fd=AB_Banking__OpenJobAs(ab, jid, as, 0);
|
|
if (fd==-1) {
|
|
return 0;
|
|
}
|
|
|
|
bio=GWEN_BufferedIO_File_new(fd);
|
|
GWEN_BufferedIO_SetReadBuffer(bio, 0, 1024);
|
|
GWEN_BufferedIO_SubFlags(bio, GWEN_BUFFEREDIO_FLAGS_CLOSE);
|
|
|
|
dbJob=GWEN_DB_Group_new("job");
|
|
if (GWEN_DB_ReadFromStream(dbJob, bio,
|
|
GWEN_DB_FLAGS_DEFAULT |
|
|
GWEN_PATH_FLAGS_CREATE_GROUP)) {
|
|
DBG_INFO(AQBANKING_LOGDOMAIN, "Error reading job data");
|
|
GWEN_DB_Group_free(dbJob);
|
|
GWEN_BufferedIO_free(bio);
|
|
AB_Banking__CloseJob(ab, fd);
|
|
return 0;
|
|
}
|
|
|
|
j=AB_Job_fromDb(ab, dbJob);
|
|
GWEN_DB_Group_free(dbJob);
|
|
GWEN_BufferedIO_Close(bio);
|
|
GWEN_BufferedIO_free(bio);
|
|
if (AB_Banking__CloseJob(ab, fd)) {
|
|
DBG_INFO(AQBANKING_LOGDOMAIN, "Error closing job, ignoring");
|
|
}
|
|
return j;
|
|
}
|
|
#endif
|
|
|
|
|
|
|
|
int AB_Banking__SaveJobAs(AB_BANKING *ab,
|
|
AB_JOB *j,
|
|
const char *as){
|
|
GWEN_DB_NODE *dbJob;
|
|
int fd;
|
|
GWEN_BUFFEREDIO *bio;
|
|
GWEN_ERRORCODE err;
|
|
|
|
dbJob=GWEN_DB_Group_new("job");
|
|
if (AB_Job_toDb(j, dbJob)) {
|
|
DBG_ERROR(AQBANKING_LOGDOMAIN, "Could not store job");
|
|
GWEN_DB_Group_free(dbJob);
|
|
return -1;
|
|
}
|
|
|
|
fd=AB_Banking__OpenJobAs(ab,
|
|
AB_Job_GetJobId(j),
|
|
as, 1);
|
|
if (fd==-1) {
|
|
GWEN_DB_Group_free(dbJob);
|
|
return -1;
|
|
}
|
|
|
|
bio=GWEN_BufferedIO_File_new(fd);
|
|
GWEN_BufferedIO_SetWriteBuffer(bio, 0, 1024);
|
|
GWEN_BufferedIO_SubFlags(bio, GWEN_BUFFEREDIO_FLAGS_CLOSE);
|
|
|
|
if (GWEN_DB_WriteToStream(dbJob, bio,
|
|
GWEN_DB_FLAGS_DEFAULT)) {
|
|
DBG_INFO(AQBANKING_LOGDOMAIN, "Error reading job data");
|
|
GWEN_DB_Group_free(dbJob);
|
|
GWEN_BufferedIO_free(bio);
|
|
AB_Banking__CloseJob(ab, fd);
|
|
return -1;
|
|
}
|
|
|
|
GWEN_DB_Group_free(dbJob);
|
|
err=GWEN_BufferedIO_Flush(bio);
|
|
if (!GWEN_Error_IsOk(err)) {
|
|
DBG_ERROR_ERR(AQBANKING_LOGDOMAIN, err);
|
|
GWEN_BufferedIO_free(bio);
|
|
AB_Banking__CloseJob(ab, fd);
|
|
return -1;
|
|
}
|
|
GWEN_BufferedIO_free(bio);
|
|
if (AB_Banking__CloseJob(ab, fd)) {
|
|
DBG_INFO(AQBANKING_LOGDOMAIN, "Error closing job");
|
|
return -1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
|
|
|
|
int AB_Banking__UnlinkJobAs(AB_BANKING *ab,
|
|
AB_JOB *j,
|
|
const char *as){
|
|
int fd;
|
|
GWEN_BUFFER *pbuf;
|
|
|
|
pbuf=GWEN_Buffer_new(0, 256, 0, 1);
|
|
AB_Banking__AddJobPath(ab, as, AB_Job_GetJobId(j), pbuf);
|
|
|
|
fd=AB_Banking__OpenFile(GWEN_Buffer_GetStart(pbuf), 0);
|
|
if (fd!=-1) {
|
|
#ifdef OS_WIN32
|
|
/* For windows, first close the file, then unlink it */
|
|
AB_Banking__CloseFile(fd);
|
|
if (unlink(GWEN_Buffer_GetStart(pbuf))) {
|
|
DBG_DEBUG(AQBANKING_LOGDOMAIN, "unlink(%s): %s",
|
|
GWEN_Buffer_GetStart(pbuf),
|
|
strerror(errno));
|
|
GWEN_Buffer_free(pbuf);
|
|
return AB_ERROR_GENERIC;
|
|
}
|
|
#else
|
|
if (unlink(GWEN_Buffer_GetStart(pbuf))) {
|
|
DBG_DEBUG(AQBANKING_LOGDOMAIN, "unlink(%s): %s",
|
|
GWEN_Buffer_GetStart(pbuf),
|
|
strerror(errno));
|
|
GWEN_Buffer_free(pbuf);
|
|
AB_Banking__CloseFile(fd);
|
|
return AB_ERROR_GENERIC;
|
|
}
|
|
AB_Banking__CloseFile(fd);
|
|
#endif
|
|
}
|
|
|
|
GWEN_Buffer_free(pbuf);
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
|
|
|
|
AB_JOB_LIST2 *AB_Banking__LoadJobsAs(AB_BANKING *ab, const char *as) {
|
|
GWEN_BUFFER *pbuf;
|
|
AB_JOB_LIST2 *l;
|
|
GWEN_DIRECTORYDATA *d;
|
|
GWEN_TYPE_UINT32 pos;
|
|
|
|
l=AB_Job_List2_new();
|
|
|
|
pbuf=GWEN_Buffer_new(0, 256, 0, 1);
|
|
AB_Banking__AddJobDir(ab, as, pbuf);
|
|
pos=GWEN_Buffer_GetPos(pbuf);
|
|
|
|
d=GWEN_Directory_new();
|
|
if (!GWEN_Directory_Open(d, GWEN_Buffer_GetStart(pbuf))) {
|
|
char nbuffer[256];
|
|
|
|
while(!GWEN_Directory_Read(d, nbuffer, sizeof(nbuffer))) {
|
|
int i;
|
|
|
|
i=strlen(nbuffer);
|
|
if (i>4) {
|
|
if (strcmp(nbuffer+i-4, ".job")==0) {
|
|
AB_JOB *j;
|
|
|
|
GWEN_Buffer_Crop(pbuf, 0, pos);
|
|
GWEN_Buffer_AppendString(pbuf, DIRSEP);
|
|
GWEN_Buffer_AppendString(pbuf, nbuffer);
|
|
|
|
/* job found */
|
|
j=AB_Banking__LoadJobFile(ab, GWEN_Buffer_GetStart(pbuf));
|
|
if (!j) {
|
|
DBG_INFO(AQBANKING_LOGDOMAIN, "Error in job file \"%s\"",
|
|
GWEN_Buffer_GetStart(pbuf));
|
|
}
|
|
else {
|
|
DBG_DEBUG(AQBANKING_LOGDOMAIN, "Adding job \"%s\"", GWEN_Buffer_GetStart(pbuf));
|
|
AB_Job_List2_PushBack(l, j);
|
|
}
|
|
} /* if filename ends in ".job" */
|
|
} /* if filename is long enough */
|
|
} /* while still jobs */
|
|
if (GWEN_Directory_Close(d)) {
|
|
DBG_ERROR(AQBANKING_LOGDOMAIN, "Error closing dir");
|
|
AB_Job_List2_free(l);
|
|
GWEN_Buffer_free(pbuf);
|
|
return 0;
|
|
}
|
|
} /* if open */
|
|
GWEN_Directory_free(d);
|
|
GWEN_Buffer_free(pbuf);
|
|
|
|
if (AB_Job_List2_GetSize(l)==0) {
|
|
AB_Job_List2_free(l);
|
|
return 0;
|
|
}
|
|
|
|
return l;
|
|
}
|
|
|
|
|
|
|
|
AB_JOB_LIST2 *AB_Banking_GetFinishedJobs(AB_BANKING *ab) {
|
|
return AB_Banking__LoadJobsAs(ab, "finished");
|
|
}
|
|
|
|
|
|
|
|
int AB_Banking_DelFinishedJob(AB_BANKING *ab, AB_JOB *j){
|
|
int rv=AB_ERROR_INVALID;
|
|
|
|
assert(ab);
|
|
assert(j);
|
|
/* First check whether this job actually has sane data */
|
|
if (ab->appName && AB_Job_GetCreatedBy(j)) {
|
|
if (strcasecmp(ab->appName, AB_Job_GetCreatedBy(j))==0) {
|
|
rv=AB_Banking__SaveJobAs(ab, j, "archived");
|
|
if (rv) {
|
|
DBG_ERROR(AQBANKING_LOGDOMAIN,
|
|
"Could not store job in archive (%d)", rv);
|
|
return rv;
|
|
}
|
|
rv=AB_Banking__UnlinkJobAs(ab, j, "finished");
|
|
}
|
|
else {
|
|
DBG_WARN(AQBANKING_LOGDOMAIN,
|
|
"Job can only be removed by its creator application");
|
|
}
|
|
}
|
|
return rv;
|
|
}
|
|
|
|
|
|
|
|
AB_JOB_LIST2 *AB_Banking_GetArchivedJobs(AB_BANKING *ab){
|
|
return AB_Banking__LoadJobsAs(ab, "archived");
|
|
}
|
|
|
|
|
|
|
|
int AB_Banking_DelArchivedJob(AB_BANKING *ab, AB_JOB *j){
|
|
int rv=AB_ERROR_INVALID;
|
|
|
|
assert(ab);
|
|
assert(j);
|
|
/* First check whether this job actually has sane data */
|
|
if (ab->appName && AB_Job_GetCreatedBy(j)) {
|
|
if (strcasecmp(ab->appName, AB_Job_GetCreatedBy(j))==0) {
|
|
rv=AB_Banking__UnlinkJobAs(ab, j, "archived");
|
|
}
|
|
else {
|
|
DBG_WARN(AQBANKING_LOGDOMAIN,
|
|
"Job can only be removed by its creator application");
|
|
}
|
|
}
|
|
return rv;
|
|
}
|
|
|
|
|
|
|
|
|
|
AB_JOB_LIST2 *AB_Banking_GetPendingJobs(AB_BANKING *ab) {
|
|
return AB_Banking__LoadJobsAs(ab, "pending");
|
|
}
|
|
|
|
|
|
|
|
int AB_Banking_DelPendingJob(AB_BANKING *ab, AB_JOB *j){
|
|
int rv=AB_ERROR_INVALID;
|
|
|
|
assert(ab);
|
|
assert(j);
|
|
/* First check whether this job actually has sane data */
|
|
if (ab->appName && AB_Job_GetCreatedBy(j)) {
|
|
if (strcasecmp(ab->appName, AB_Job_GetCreatedBy(j))==0) {
|
|
rv=AB_Banking__SaveJobAs(ab, j, "archived");
|
|
if (rv) {
|
|
DBG_ERROR(AQBANKING_LOGDOMAIN,
|
|
"Could not store job in archive (%d)", rv);
|
|
return rv;
|
|
}
|
|
rv=AB_Banking__UnlinkJobAs(ab, j, "pending");
|
|
}
|
|
else {
|
|
DBG_WARN(AQBANKING_LOGDOMAIN, "Job can only be removed by its creator application");
|
|
}
|
|
}
|
|
return rv;
|
|
}
|
|
|
|
|
|
|
|
void *AB_Banking_GetUserData(AB_BANKING *ab) {
|
|
assert(ab);
|
|
return ab->user_data;
|
|
}
|
|
|
|
|
|
void AB_Banking_SetUserData(AB_BANKING *ab, void *user_data) {
|
|
assert(ab);
|
|
ab->user_data = user_data;
|
|
}
|
|
|
|
|
|
|
|
AB_IMEXPORTER *AB_Banking_FindImExporter(AB_BANKING *ab, const char *name) {
|
|
AB_IMEXPORTER *ie;
|
|
|
|
assert(ab);
|
|
assert(name);
|
|
ie=AB_ImExporter_List_First(ab->imexporters);
|
|
while(ie) {
|
|
if (strcasecmp(AB_ImExporter_GetName(ie), name)==0)
|
|
break;
|
|
ie=AB_ImExporter_List_Next(ie);
|
|
} /* while */
|
|
|
|
return ie;
|
|
}
|
|
|
|
|
|
|
|
AB_IMEXPORTER *AB_Banking_GetImExporter(AB_BANKING *ab, const char *name){
|
|
AB_IMEXPORTER *ie;
|
|
|
|
assert(ab);
|
|
assert(name);
|
|
|
|
ie=AB_Banking_FindImExporter(ab, name);
|
|
if (ie)
|
|
return ie;
|
|
ie=AB_Banking__LoadImExporterPlugin(ab, name);
|
|
if (ie) {
|
|
AB_ImExporter_List_Add(ie, ab->imexporters);
|
|
}
|
|
|
|
return ie;
|
|
}
|
|
|
|
|
|
|
|
AB_IMEXPORTER *AB_Banking__LoadImExporterPlugin(AB_BANKING *ab,
|
|
const char *modname){
|
|
GWEN_LIBLOADER *ll;
|
|
AB_IMEXPORTER *ie;
|
|
AB_IMEXPORTER_FACTORY_FN fn;
|
|
void *p;
|
|
const char *s;
|
|
GWEN_ERRORCODE err = 0;
|
|
GWEN_BUFFER *mbuf;
|
|
GWEN_DB_NODE *db;
|
|
GWEN_PLUGIN_MANAGER *pm;
|
|
GWEN_STRINGLISTENTRY *sentry;
|
|
const char *dirpath = 0;
|
|
|
|
mbuf=GWEN_Buffer_new(0, 256, 0, 1);
|
|
s=modname;
|
|
while(*s) GWEN_Buffer_AppendByte(mbuf, tolower(*(s++)));
|
|
modname=GWEN_Buffer_GetStart(mbuf);
|
|
|
|
/* New loading code -- use path list from PluginManager but don't
|
|
use its loading code */
|
|
pm = GWEN_PluginManager_FindPluginManager("imexporters");
|
|
if (!pm) {
|
|
DBG_ERROR(AQBANKING_LOGDOMAIN,
|
|
"Could not find plugin manager for \"%s\"",
|
|
"imexporters");
|
|
return 0;
|
|
}
|
|
|
|
ll = GWEN_LibLoader_new();
|
|
sentry = GWEN_StringList_FirstEntry(GWEN_PluginManager_GetPaths(pm));
|
|
while (sentry) {
|
|
dirpath = GWEN_StringListEntry_Data(sentry);
|
|
assert(dirpath);
|
|
err = GWEN_LibLoader_OpenLibraryWithPath(ll, dirpath, modname);
|
|
if (GWEN_Error_IsOk(err))
|
|
break;
|
|
else {
|
|
/* DBG_INFO_ERR(AQBANKING_LOGDOMAIN, err); */
|
|
}
|
|
sentry = GWEN_StringListEntry_Next(sentry);
|
|
}
|
|
|
|
if (!GWEN_Error_IsOk(err)) {
|
|
DBG_INFO_ERR(AQBANKING_LOGDOMAIN, err);
|
|
DBG_ERROR(AQBANKING_LOGDOMAIN,
|
|
"Could not load provider plugin \"%s\"",
|
|
modname);
|
|
GWEN_Buffer_free(mbuf);
|
|
GWEN_LibLoader_free(ll);
|
|
return 0;
|
|
}
|
|
|
|
/* create name of init function */
|
|
GWEN_Buffer_AppendString(mbuf, "_factory");
|
|
|
|
/* resolve name of factory function */
|
|
err=GWEN_LibLoader_Resolve(ll, GWEN_Buffer_GetStart(mbuf), &p);
|
|
if (!GWEN_Error_IsOk(err)) {
|
|
DBG_ERROR_ERR(AQBANKING_LOGDOMAIN, err);
|
|
GWEN_Buffer_free(mbuf);
|
|
GWEN_LibLoader_CloseLibrary(ll);
|
|
GWEN_LibLoader_free(ll);
|
|
return 0;
|
|
}
|
|
GWEN_Buffer_free(mbuf);
|
|
|
|
db=GWEN_DB_GetGroup(ab->data, GWEN_DB_FLAGS_DEFAULT,
|
|
"banking/imexporters");
|
|
assert(db);
|
|
db=GWEN_DB_GetGroup(ab->data, GWEN_DB_FLAGS_DEFAULT, modname);
|
|
assert(db);
|
|
|
|
fn=(AB_IMEXPORTER_FACTORY_FN)p;
|
|
assert(fn);
|
|
ie=fn(ab, db);
|
|
if (!ie) {
|
|
DBG_ERROR(AQBANKING_LOGDOMAIN,
|
|
"Error in plugin [%s]: No im/exporter created",
|
|
dirpath);
|
|
GWEN_LibLoader_CloseLibrary(ll);
|
|
GWEN_LibLoader_free(ll);
|
|
return 0;
|
|
}
|
|
|
|
/* store libloader */
|
|
AB_ImExporter_SetLibLoader(ie, ll);
|
|
|
|
return ie;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* __________________________________________________________________________
|
|
* AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
|
* High Level API
|
|
* YYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYY
|
|
*/
|
|
|
|
|
|
|
|
AB_ACCOUNT *AB_Banking__GetAccount(AB_BANKING *ab, const char *accountId){
|
|
GWEN_DB_NODE *dbData;
|
|
GWEN_TYPE_UINT32 uniqueId;
|
|
AB_ACCOUNT *a;
|
|
|
|
uniqueId=0;
|
|
dbData=AB_Banking_GetAppData(ab);
|
|
dbData=GWEN_DB_GetGroup(dbData, GWEN_PATH_FLAGS_NAMEMUSTEXIST,
|
|
"banking/aliases");
|
|
if (dbData)
|
|
uniqueId=GWEN_DB_GetIntValue(dbData, accountId, 0, 0);
|
|
if (!uniqueId) {
|
|
/* should not happen anyway */
|
|
DBG_ERROR(AQBANKING_LOGDOMAIN,
|
|
"Account has no unique id. Should not happen");
|
|
return 0;
|
|
}
|
|
|
|
a=AB_Banking_GetAccount(ab, uniqueId);
|
|
if (!a) {
|
|
DBG_ERROR(AQBANKING_LOGDOMAIN, "Account with alias \"%s\" not found",
|
|
accountId);
|
|
return 0;
|
|
}
|
|
|
|
return a;
|
|
}
|
|
|
|
|
|
|
|
AB_ACCOUNT *AB_Banking_GetAccountByAlias(AB_BANKING *ab,
|
|
const char *accountId){
|
|
return AB_Banking__GetAccount(ab, accountId);
|
|
}
|
|
|
|
|
|
|
|
void AB_Banking_SetAccountAlias(AB_BANKING *ab,
|
|
AB_ACCOUNT *a, const char *alias){
|
|
GWEN_DB_NODE *dbData;
|
|
|
|
assert(a);
|
|
assert(alias);
|
|
|
|
dbData=AB_Banking_GetAppData(ab);
|
|
dbData=GWEN_DB_GetGroup(dbData, GWEN_DB_FLAGS_DEFAULT,
|
|
"banking/aliases");
|
|
assert(dbData);
|
|
GWEN_DB_SetIntValue(dbData, GWEN_DB_FLAGS_OVERWRITE_VARS,
|
|
alias,
|
|
AB_Account_GetUniqueId(a));
|
|
}
|
|
|
|
|
|
|
|
int AB_Banking_RequestBalance(AB_BANKING *ab,
|
|
const char *bankCode,
|
|
const char *accountNumber) {
|
|
AB_ACCOUNT *a;
|
|
AB_JOB *j;
|
|
int rv;
|
|
|
|
if (!accountNumber) {
|
|
DBG_ERROR(AQBANKING_LOGDOMAIN,
|
|
"Account number is required");
|
|
return AB_ERROR_INVALID;
|
|
}
|
|
|
|
a=AB_Banking_GetAccountByCodeAndNumber(ab, bankCode, accountNumber);
|
|
if (!a)
|
|
return AB_ERROR_INVALID;
|
|
|
|
/* TODO: check if there already is such a job in the queue */
|
|
|
|
j=AB_JobGetBalance_new(a);
|
|
assert(j);
|
|
rv=AB_Job_CheckAvailability(j);
|
|
if (rv) {
|
|
DBG_ERROR(AQBANKING_LOGDOMAIN,
|
|
"Job not available with the backend for this account (%d)",
|
|
rv);
|
|
AB_Banking_MessageBox(ab,
|
|
AB_BANKING_MSG_FLAGS_TYPE_ERROR |
|
|
AB_BANKING_MSG_FLAGS_SEVERITY_NORMAL,
|
|
I18N("Unsupported Request"),
|
|
I18N("The backend for this banking account "
|
|
"does not support your request."),
|
|
I18N("Dismiss"), 0, 0);
|
|
AB_Job_free(j);
|
|
return AB_ERROR_GENERIC;
|
|
}
|
|
|
|
rv=AB_Banking_EnqueueJob(ab, j);
|
|
if (rv) {
|
|
DBG_ERROR(AQBANKING_LOGDOMAIN,
|
|
"Could not enqueue the job (%d)",
|
|
rv);
|
|
AB_Banking_MessageBox(ab,
|
|
AB_BANKING_MSG_FLAGS_TYPE_ERROR |
|
|
AB_BANKING_MSG_FLAGS_SEVERITY_NORMAL,
|
|
I18N("Queue Error"),
|
|
I18N("Unable to enqueue your request."),
|
|
I18N("Dismiss"), 0, 0);
|
|
AB_Job_free(j);
|
|
return AB_ERROR_GENERIC;
|
|
}
|
|
|
|
DBG_INFO(AQBANKING_LOGDOMAIN,
|
|
"Job successfully enqueued");
|
|
AB_Job_free(j);
|
|
return 0;
|
|
}
|
|
|
|
|
|
|
|
int AB_Banking_RequestTransactions(AB_BANKING *ab,
|
|
const char *bankCode,
|
|
const char *accountNumber,
|
|
const GWEN_TIME *firstDate,
|
|
const GWEN_TIME *lastDate){
|
|
AB_ACCOUNT *a;
|
|
AB_JOB *j;
|
|
int rv;
|
|
|
|
if (!accountNumber) {
|
|
DBG_ERROR(AQBANKING_LOGDOMAIN,
|
|
"Account number is required");
|
|
return AB_ERROR_INVALID;
|
|
}
|
|
|
|
a=AB_Banking_GetAccountByCodeAndNumber(ab, bankCode, accountNumber);
|
|
if (!a)
|
|
return AB_ERROR_INVALID;
|
|
|
|
/* TODO: check if there already is such a job in the queue */
|
|
|
|
j=AB_JobGetTransactions_new(a);
|
|
assert(j);
|
|
rv=AB_Job_CheckAvailability(j);
|
|
if (rv) {
|
|
DBG_ERROR(AQBANKING_LOGDOMAIN,
|
|
"Job not available with the backend for this account (%d)",
|
|
rv);
|
|
AB_Banking_MessageBox(ab,
|
|
AB_BANKING_MSG_FLAGS_TYPE_ERROR |
|
|
AB_BANKING_MSG_FLAGS_SEVERITY_NORMAL,
|
|
I18N("Unsupported Request"),
|
|
I18N("The backend for this banking account "
|
|
"does not support your request."),
|
|
I18N("Dismiss"), 0, 0);
|
|
AB_Job_free(j);
|
|
return AB_ERROR_GENERIC;
|
|
}
|
|
|
|
if (firstDate)
|
|
AB_JobGetTransactions_SetFromTime(j, firstDate);
|
|
if (lastDate)
|
|
AB_JobGetTransactions_SetToTime(j, lastDate);
|
|
|
|
rv=AB_Banking_EnqueueJob(ab, j);
|
|
if (rv) {
|
|
DBG_ERROR(AQBANKING_LOGDOMAIN,
|
|
"Could not enqueue the job (%d)",
|
|
rv);
|
|
AB_Banking_MessageBox(ab,
|
|
AB_BANKING_MSG_FLAGS_TYPE_ERROR |
|
|
AB_BANKING_MSG_FLAGS_SEVERITY_NORMAL,
|
|
I18N("Queue Error"),
|
|
I18N("Unable to enqueue your request."),
|
|
I18N("Dismiss"), 0, 0);
|
|
AB_Job_free(j);
|
|
return AB_ERROR_GENERIC;
|
|
}
|
|
|
|
DBG_INFO(AQBANKING_LOGDOMAIN,
|
|
"Job successfully enqueued");
|
|
AB_Job_free(j);
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
int AB_Banking_RequestStandingOrders(AB_BANKING *ab,
|
|
const char *bankCode,
|
|
const char *accountNumber) {
|
|
AB_ACCOUNT *a;
|
|
AB_JOB *j;
|
|
int rv;
|
|
|
|
if (!accountNumber) {
|
|
DBG_ERROR(AQBANKING_LOGDOMAIN,
|
|
"Account number is required");
|
|
return AB_ERROR_INVALID;
|
|
}
|
|
|
|
a=AB_Banking_GetAccountByCodeAndNumber(ab, bankCode, accountNumber);
|
|
if (!a)
|
|
return AB_ERROR_INVALID;
|
|
|
|
/* TODO: check if there already is such a job in the queue */
|
|
|
|
j=AB_JobGetStandingOrders_new(a);
|
|
assert(j);
|
|
rv=AB_Job_CheckAvailability(j);
|
|
if (rv) {
|
|
DBG_ERROR(AQBANKING_LOGDOMAIN,
|
|
"Job not available with the backend for this account (%d)",
|
|
rv);
|
|
AB_Banking_MessageBox(ab,
|
|
AB_BANKING_MSG_FLAGS_TYPE_ERROR |
|
|
AB_BANKING_MSG_FLAGS_SEVERITY_NORMAL,
|
|
I18N("Unsupported Request"),
|
|
I18N("The backend for this banking account "
|
|
"does not support your request."),
|
|
I18N("Dismiss"), 0, 0);
|
|
AB_Job_free(j);
|
|
return AB_ERROR_GENERIC;
|
|
}
|
|
|
|
rv=AB_Banking_EnqueueJob(ab, j);
|
|
if (rv) {
|
|
DBG_ERROR(AQBANKING_LOGDOMAIN,
|
|
"Could not enqueue the job (%d)",
|
|
rv);
|
|
AB_Banking_MessageBox(ab,
|
|
AB_BANKING_MSG_FLAGS_TYPE_ERROR |
|
|
AB_BANKING_MSG_FLAGS_SEVERITY_NORMAL,
|
|
I18N("Queue Error"),
|
|
I18N("Unable to enqueue your request."),
|
|
I18N("Dismiss"), 0, 0);
|
|
AB_Job_free(j);
|
|
return AB_ERROR_GENERIC;
|
|
}
|
|
|
|
DBG_INFO(AQBANKING_LOGDOMAIN,
|
|
"Job successfully enqueued");
|
|
AB_Job_free(j);
|
|
return 0;
|
|
}
|
|
|
|
|
|
|
|
int AB_Banking_RequestDatedTransfers(AB_BANKING *ab,
|
|
const char *bankCode,
|
|
const char *accountNumber) {
|
|
AB_ACCOUNT *a;
|
|
AB_JOB *j;
|
|
int rv;
|
|
|
|
if (!accountNumber) {
|
|
DBG_ERROR(AQBANKING_LOGDOMAIN,
|
|
"Account number is required");
|
|
return AB_ERROR_INVALID;
|
|
}
|
|
|
|
a=AB_Banking_GetAccountByCodeAndNumber(ab, bankCode, accountNumber);
|
|
if (!a)
|
|
return AB_ERROR_INVALID;
|
|
|
|
/* TODO: check if there already is such a job in the queue */
|
|
|
|
j=AB_JobGetDatedTransfers_new(a);
|
|
assert(j);
|
|
rv=AB_Job_CheckAvailability(j);
|
|
if (rv) {
|
|
DBG_ERROR(AQBANKING_LOGDOMAIN,
|
|
"Job not available with the backend for this account (%d)",
|
|
rv);
|
|
AB_Banking_MessageBox(ab,
|
|
AB_BANKING_MSG_FLAGS_TYPE_ERROR |
|
|
AB_BANKING_MSG_FLAGS_SEVERITY_NORMAL,
|
|
I18N("Unsupported Request"),
|
|
I18N("The backend for this banking account "
|
|
"does not support your request."),
|
|
I18N("Dismiss"), 0, 0);
|
|
AB_Job_free(j);
|
|
return AB_ERROR_GENERIC;
|
|
}
|
|
|
|
rv=AB_Banking_EnqueueJob(ab, j);
|
|
if (rv) {
|
|
DBG_ERROR(AQBANKING_LOGDOMAIN,
|
|
"Could not enqueue the job (%d)",
|
|
rv);
|
|
AB_Banking_MessageBox(ab,
|
|
AB_BANKING_MSG_FLAGS_TYPE_ERROR |
|
|
AB_BANKING_MSG_FLAGS_SEVERITY_NORMAL,
|
|
I18N("Queue Error"),
|
|
I18N("Unable to enqueue your request."),
|
|
I18N("Dismiss"), 0, 0);
|
|
AB_Job_free(j);
|
|
return AB_ERROR_GENERIC;
|
|
}
|
|
|
|
DBG_INFO(AQBANKING_LOGDOMAIN,
|
|
"Job successfully enqueued");
|
|
AB_Job_free(j);
|
|
return 0;
|
|
}
|
|
|
|
|
|
|
|
void AB_Banking_SetGetPinFn(AB_BANKING *ab,
|
|
AB_BANKING_GETPIN_FN f){
|
|
assert(ab);
|
|
ab->getPinFn=f;
|
|
}
|
|
|
|
|
|
|
|
void AB_Banking_SetSetPinStatusFn(AB_BANKING *ab,
|
|
AB_BANKING_SETPINSTATUS_FN f){
|
|
assert(ab);
|
|
ab->setPinStatusFn=f;
|
|
}
|
|
|
|
|
|
|
|
void AB_Banking_SetGetTanFn(AB_BANKING *ab,
|
|
AB_BANKING_GETTAN_FN f){
|
|
assert(ab);
|
|
ab->getTanFn=f;
|
|
}
|
|
|
|
|
|
|
|
void AB_Banking_SetSetTanStatusFn(AB_BANKING *ab,
|
|
AB_BANKING_SETTANSTATUS_FN f){
|
|
assert(ab);
|
|
ab->setTanStatusFn=f;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int AB_Banking__GetPin(AB_BANKING *ab,
|
|
GWEN_TYPE_UINT32 flags,
|
|
const char *token,
|
|
const char *title,
|
|
const char *text,
|
|
char *buffer,
|
|
int minLen,
|
|
int maxLen){
|
|
|
|
assert(ab);
|
|
|
|
if (ab->getPinFn) {
|
|
return ab->getPinFn(ab, flags, token, title, text, buffer,
|
|
minLen, maxLen);
|
|
}
|
|
else {
|
|
return AB_Banking_InputBox(ab,
|
|
flags,
|
|
title,
|
|
text,
|
|
buffer,
|
|
minLen,
|
|
maxLen);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
int AB_Banking_GetPin(AB_BANKING *ab,
|
|
GWEN_TYPE_UINT32 flags,
|
|
const char *token,
|
|
const char *title,
|
|
const char *text,
|
|
char *buffer,
|
|
int minLen,
|
|
int maxLen){
|
|
AB_PIN *p;
|
|
int rv;
|
|
int i;
|
|
|
|
assert(ab);
|
|
assert(token);
|
|
|
|
/* check whether we already know the pin */
|
|
p=AB_Pin_List_First(ab->pinList);
|
|
while(p) {
|
|
const char *s;
|
|
|
|
s=AB_Pin_GetToken(p);
|
|
if (s) {
|
|
if (strcasecmp(s, token)==0) {
|
|
break;
|
|
}
|
|
}
|
|
p=AB_Pin_List_Next(p);
|
|
}
|
|
|
|
if (!p) {
|
|
/* no pin yet, ask program for it */
|
|
DBG_INFO(AQBANKING_LOGDOMAIN,
|
|
"Have no pin for \"%s\", getting it",
|
|
token);
|
|
|
|
rv=AB_Banking__GetPin(ab, flags, token, title, text, buffer,
|
|
minLen, maxLen);
|
|
if (rv)
|
|
return rv;
|
|
p=AB_Pin_new();
|
|
AB_Pin_SetToken(p, token);
|
|
AB_Pin_SetValue(p, buffer);
|
|
AB_Pin_SetHash(p, 0);
|
|
AB_Pin_SetStatus(p, "unknown");
|
|
DBG_DEBUG(AQBANKING_LOGDOMAIN,
|
|
"Adding pin for \"%s\"",
|
|
token);
|
|
AB_Pin_List_Add(p, ab->pinList);
|
|
}
|
|
|
|
for (i=0 ; ; i++) {
|
|
const char *st;
|
|
const char *t;
|
|
int l;
|
|
int doSet;
|
|
|
|
if (i)
|
|
flags|=AB_BANKING_INPUT_FLAGS_RETRY;
|
|
|
|
if (i>AB_BANKING_MAX_PIN_TRY) {
|
|
DBG_ERROR(AQBANKING_LOGDOMAIN,
|
|
"No valid PIN within %d tries, giving up", i);
|
|
AB_Banking_MessageBox(ab,
|
|
AB_BANKING_MSG_FLAGS_TYPE_ERROR |
|
|
AB_BANKING_MSG_FLAGS_SEVERITY_NORMAL,
|
|
I18N("Error"),
|
|
I18N("No valid PIN (tried too often).\n"
|
|
"Aborting."),
|
|
I18N("Dismiss"), 0, 0);
|
|
return AB_ERROR_INVALID;
|
|
}
|
|
|
|
l=strlen(AB_Pin_GetValue(p));
|
|
if (l>=minLen && l<=maxLen) {
|
|
/* check whether PIN is bad */
|
|
if (flags & AB_BANKING_INPUT_FLAGS_CONFIRM) {
|
|
/* got a working pin */
|
|
memmove(buffer, AB_Pin_GetValue(p), l+1);
|
|
/* a confirmed pin is always ok */
|
|
DBG_INFO(AQBANKING_LOGDOMAIN, "Confirmed PIN");
|
|
AB_Pin_SetStatus(p, "ok");
|
|
break;
|
|
}
|
|
AB_Banking__CheckBadPin(ab, p);
|
|
st=AB_Pin_GetStatus(p);
|
|
assert(st);
|
|
DBG_INFO(AQBANKING_LOGDOMAIN, "Pin status: %s", st);
|
|
if (strcasecmp(st, "bad")!=0) {
|
|
/* got a working pin */
|
|
memmove(buffer, AB_Pin_GetValue(p), l+1);
|
|
break;
|
|
}
|
|
DBG_ERROR(AQBANKING_LOGDOMAIN, "Pin is registered as \"bad\"");
|
|
}
|
|
else {
|
|
DBG_ERROR(AQBANKING_LOGDOMAIN, "Pin is too short/long");
|
|
AB_Pin_SetStatus(p, "bad");
|
|
}
|
|
rv=AB_Banking__GetPin(ab, flags, token, title, text, buffer,
|
|
minLen, maxLen);
|
|
if (rv)
|
|
return rv;
|
|
|
|
doSet=0;
|
|
t=AB_Pin_GetValue(p);
|
|
if (t) {
|
|
if (strcmp(buffer, t)!=0)
|
|
doSet=1;
|
|
else {
|
|
int lrv;
|
|
|
|
lrv=AB_Banking_MessageBox(ab,
|
|
AB_BANKING_MSG_FLAGS_TYPE_ERROR |
|
|
AB_BANKING_MSG_FLAGS_CONFIRM_B1 |
|
|
AB_BANKING_MSG_FLAGS_SEVERITY_DANGEROUS,
|
|
I18N("Enforce PIN"),
|
|
I18N(
|
|
"You entered the same PIN twice.\n"
|
|
"The PIN is marked as bad, do you want\n"
|
|
"to use it anyway?"
|
|
"<html>"
|
|
"<p>"
|
|
"You entered the same PIN twice."
|
|
"</p>"
|
|
"<p>"
|
|
"The PIN is marked as <b>bad</b>, "
|
|
"do you want to use it anyway?"
|
|
"</p>"
|
|
"</html>"),
|
|
I18N("Use this"),
|
|
I18N("Re-enter"),
|
|
0);
|
|
if (lrv==1) {
|
|
/* accept this input */
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
doSet=1;
|
|
|
|
if (doSet) {
|
|
AB_Pin_SetValue(p, buffer);
|
|
AB_Pin_SetHash(p, 0);
|
|
AB_Pin_SetStatus(p, "unknown");
|
|
}
|
|
} /* for */
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
|
|
int AB_Banking_SetPinStatus(AB_BANKING *ab,
|
|
const char *token,
|
|
const char *pin,
|
|
AB_BANKING_PINSTATUS status){
|
|
AB_PIN *p;
|
|
const char *s;
|
|
|
|
assert(ab);
|
|
assert(token);
|
|
assert(pin);
|
|
|
|
DBG_DEBUG(AQBANKING_LOGDOMAIN,
|
|
"Setting PIN status for \"%s\" to %d",
|
|
token, status);
|
|
|
|
p=AB_Pin_List_First(ab->pinList);
|
|
while(p) {
|
|
const char *s;
|
|
|
|
s=AB_Pin_GetToken(p);
|
|
if (s) {
|
|
if (strcasecmp(s, token)==0) {
|
|
break;
|
|
}
|
|
}
|
|
p=AB_Pin_List_Next(p);
|
|
}
|
|
|
|
if (!p) {
|
|
/* no pin yet, create it */
|
|
DBG_DEBUG(AQBANKING_LOGDOMAIN, "Pin \"%s\" is new", token);
|
|
p=AB_Pin_new();
|
|
AB_Pin_SetToken(p, token);
|
|
AB_Pin_SetValue(p, pin);
|
|
AB_Pin_SetHash(p, 0);
|
|
AB_Pin_SetStatus(p, "unknown");
|
|
AB_Pin_List_Add(p, ab->pinList);
|
|
}
|
|
|
|
/* we already know the pin, save the status */
|
|
switch(status) {
|
|
case AB_Banking_PinStatusBad: s="bad"; break;
|
|
case AB_Banking_PinStatusOk: s="ok"; break;
|
|
default: s="unknown"; break;
|
|
}
|
|
AB_Pin_SetStatus(p, s);
|
|
|
|
if (ab->setPinStatusFn) {
|
|
return ab->setPinStatusFn(ab, token, pin, status);
|
|
}
|
|
else {
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
void AB_Banking_SetPinCacheEnabled(AB_BANKING *ab, int enabled){
|
|
assert(ab);
|
|
ab->pinCacheEnabled = enabled;
|
|
}
|
|
|
|
|
|
|
|
int AB_Banking_GetPinCacheEnabled(const AB_BANKING *ab){
|
|
assert(ab);
|
|
return ab->pinCacheEnabled;
|
|
}
|
|
|
|
|
|
|
|
int AB_Banking_GetTan(AB_BANKING *ab,
|
|
const char *token,
|
|
const char *title,
|
|
const char *text,
|
|
char *buffer,
|
|
int minLen,
|
|
int maxLen){
|
|
assert(ab);
|
|
if (ab->getTanFn) {
|
|
return ab->getTanFn(ab, token, title, text, buffer,
|
|
minLen, maxLen);
|
|
}
|
|
else {
|
|
return AB_Banking_InputBox(ab,
|
|
AB_BANKING_INPUT_FLAGS_SHOW,
|
|
title,
|
|
text,
|
|
buffer,
|
|
minLen,
|
|
maxLen);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
int AB_Banking_SetTanStatus(AB_BANKING *ab,
|
|
const char *token,
|
|
const char *tan,
|
|
AB_BANKING_TANSTATUS status){
|
|
DBG_NOTICE(AQBANKING_LOGDOMAIN,
|
|
"Setting status of TAN to %d",
|
|
status);
|
|
assert(ab);
|
|
if (ab->setTanStatusFn) {
|
|
return ab->setTanStatusFn(ab, token, tan, status);
|
|
}
|
|
else {
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
int AB_Banking__HashPin(AB_PIN *p) {
|
|
const char *st;
|
|
|
|
st=AB_Pin_GetStatus(p);
|
|
if (st) {
|
|
const char *token;
|
|
const char *value;
|
|
|
|
/* found a bad pin */
|
|
token=AB_Pin_GetToken(p);
|
|
value=AB_Pin_GetValue(p);
|
|
if (token && value) {
|
|
GWEN_BUFFER *buf;
|
|
char hash[21];
|
|
unsigned int bs;
|
|
|
|
buf=GWEN_Buffer_new(0, 256, 0, 1);
|
|
GWEN_Buffer_AppendString(buf, token);
|
|
GWEN_Buffer_AppendByte(buf, '-');
|
|
GWEN_Buffer_AppendString(buf, value);
|
|
bs=sizeof(hash);
|
|
if (GWEN_MD_Hash("RMD160",
|
|
GWEN_Buffer_GetStart(buf),
|
|
GWEN_Buffer_GetUsedBytes(buf),
|
|
hash, &bs)) {
|
|
DBG_ERROR(AQBANKING_LOGDOMAIN,
|
|
"Error on hash");
|
|
GWEN_Buffer_free(buf);
|
|
return AB_ERROR_GENERIC;
|
|
}
|
|
GWEN_Buffer_Reset(buf);
|
|
if (GWEN_Text_ToHexBuffer(hash, bs, buf, 0, 0, 0)) {
|
|
DBG_ERROR(AQBANKING_LOGDOMAIN,
|
|
"Error encoding hash");
|
|
GWEN_Buffer_free(buf);
|
|
return AB_ERROR_GENERIC;
|
|
}
|
|
bs=GWEN_Buffer_GetUsedBytes(buf);
|
|
if (*(GWEN_Buffer_GetStart(buf)+bs-1)=='/')
|
|
/* cut of trailing slash */
|
|
GWEN_Buffer_Crop(buf, 0, bs-1);
|
|
AB_Pin_SetHash(p, GWEN_Buffer_GetStart(buf));
|
|
GWEN_Buffer_free(buf);
|
|
}
|
|
else
|
|
return AB_ERROR_GENERIC;
|
|
}
|
|
else
|
|
return AB_ERROR_GENERIC;
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
|
|
int AB_Banking__SaveBadPins(AB_BANKING *ab) {
|
|
AB_PIN *p;
|
|
GWEN_DB_NODE *dbPins;
|
|
|
|
dbPins=GWEN_DB_GetGroup(ab->data,
|
|
GWEN_DB_FLAGS_DEFAULT,
|
|
"banking/pins");
|
|
assert(dbPins);
|
|
p=AB_Pin_List_First(ab->pinList);
|
|
while(p) {
|
|
const char *st;
|
|
|
|
DBG_INFO(AQBANKING_LOGDOMAIN,
|
|
"Checking pin \"%s\"",
|
|
AB_Pin_GetToken(p));
|
|
st=AB_Pin_GetStatus(p);
|
|
if (st) {
|
|
if (strcasecmp(st, "bad")==0) {
|
|
const char *hash;
|
|
|
|
/* only save bad pins */
|
|
hash=AB_Pin_GetHash(p);
|
|
if (!hash) {
|
|
int rv;
|
|
|
|
rv=AB_Banking__HashPin(p);
|
|
if (rv) {
|
|
return rv;
|
|
}
|
|
hash=AB_Pin_GetHash(p);
|
|
assert(hash);
|
|
} /* if no hash */
|
|
GWEN_DB_SetCharValue(dbPins, GWEN_DB_FLAGS_OVERWRITE_VARS,
|
|
hash, st);
|
|
} /* if pin is bad */
|
|
} /* if status known */
|
|
else {
|
|
DBG_ERROR(AQBANKING_LOGDOMAIN, "No status for pin \"%s\"",
|
|
AB_Pin_GetToken(p));
|
|
}
|
|
p=AB_Pin_List_Next(p);
|
|
} /* while */
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
|
|
int AB_Banking__CheckBadPin(AB_BANKING *ab, AB_PIN *p) {
|
|
GWEN_DB_NODE *dbPins;
|
|
const char *hash;
|
|
const char *st;
|
|
|
|
st=AB_Pin_GetStatus(p);
|
|
if (st) {
|
|
DBG_INFO(AQBANKING_LOGDOMAIN, "Pin status: %s", st);
|
|
if (strcasecmp(st, "ok")==0) {
|
|
/* pin is explicitly marked as "ok", assume it is */
|
|
DBG_INFO(AQBANKING_LOGDOMAIN, "Pin is marked \"ok\"");
|
|
return 0;
|
|
}
|
|
}
|
|
dbPins=GWEN_DB_GetGroup(ab->data,
|
|
GWEN_DB_FLAGS_DEFAULT,
|
|
"banking/pins");
|
|
assert(dbPins);
|
|
|
|
hash=AB_Pin_GetHash(p);
|
|
if (!hash) {
|
|
int rv;
|
|
|
|
rv=AB_Banking__HashPin(p);
|
|
if (rv) {
|
|
return rv;
|
|
}
|
|
hash=AB_Pin_GetHash(p);
|
|
assert(hash);
|
|
} /* if no hash */
|
|
if (!st) {
|
|
DBG_INFO(AQBANKING_LOGDOMAIN, "No status, assuming unknown");
|
|
st="unknown";
|
|
}
|
|
st=GWEN_DB_GetCharValue(dbPins, hash, 0, st);
|
|
DBG_INFO(AQBANKING_LOGDOMAIN, "Saved pin status: %s", st);
|
|
if (strcasecmp(st, "bad")==0) {
|
|
AB_Pin_SetStatus(p, "bad");
|
|
return AB_ERROR_BAD_DATA;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
|
|
GWEN_NL_SSL_ASKADDCERT_RESULT
|
|
AB_Banking_AskAddCert(GWEN_NETLAYER *nl,
|
|
const GWEN_SSLCERTDESCR *cd,
|
|
void *user_data) {
|
|
int rv;
|
|
AB_BANKING *ab;
|
|
GWEN_DB_NODE *pd;
|
|
int isNew;
|
|
int isError;
|
|
int isWarning;
|
|
const char *hash;
|
|
const char *status;
|
|
const char *ipAddr;
|
|
const char *statusOn;
|
|
const char *statusOff;
|
|
char varName[128];
|
|
char dbuffer1[32];
|
|
char dbuffer2[32];
|
|
char buffer[8192];
|
|
const GWEN_TIME *ti;
|
|
const char *unknown;
|
|
const char *commonName;
|
|
const char *organizationName;
|
|
const char *organizationalUnitName;
|
|
const char *countryName;
|
|
const char *localityName;
|
|
const char *stateOrProvinceName;
|
|
|
|
char *msg=I18N_NOOP(
|
|
"The following certificate has been received:\n"
|
|
"Name : %s\n"
|
|
"Organisation: %s\n"
|
|
"Department : %s\n"
|
|
"Country : %s\n"
|
|
"City : %s\n"
|
|
"State : %s\n"
|
|
"Valid after : %s\n"
|
|
"Valid until : %s\n"
|
|
"Hash : %s\n"
|
|
"Status : %s\n"
|
|
"Do you wish to accept this certificate?"
|
|
|
|
"<html>"
|
|
" <p>"
|
|
" The following certificate has been received:"
|
|
" </p>"
|
|
" <table>"
|
|
" <tr><td>Name</td><td>%s</td></tr>"
|
|
" <tr><td>Organisation</td><td>%s</td></tr>"
|
|
" <tr><td>Department</td><td>%s</td></tr>"
|
|
" <tr><td>Country</td><td>%s</td></tr>"
|
|
" <tr><td>City</td><td>%s</td></tr>"
|
|
" <tr><td>State</td><td>%s</td></tr>"
|
|
" <tr><td>Valid after</td><td>%s</td></tr>"
|
|
" <tr><td>Valid until</td><td>%s</td></tr>"
|
|
" <tr><td>Hash</td><td>%s</td></tr>"
|
|
" <tr><td>Status</td><td>%s%s%s</td></tr>"
|
|
" </table>"
|
|
" <p>"
|
|
" Do you wish to accept this certificate?"
|
|
" </p>"
|
|
"</html>"
|
|
);
|
|
|
|
assert(user_data);
|
|
ab=(AB_BANKING*)user_data;
|
|
|
|
pd=GWEN_DB_GetGroup(ab->data, GWEN_DB_FLAGS_DEFAULT, "banking");
|
|
assert(pd);
|
|
|
|
memset(dbuffer1, 0, sizeof(dbuffer1));
|
|
memset(dbuffer2, 0, sizeof(dbuffer2));
|
|
memset(varName, 0, sizeof(varName));
|
|
|
|
isNew=GWEN_SslCertDescr_GetIsNew(cd);
|
|
isError=GWEN_SslCertDescr_GetIsError(cd);
|
|
isWarning=GWEN_SslCertDescr_GetIsWarning(cd);
|
|
|
|
hash=GWEN_SslCertDescr_GetFingerPrint(cd);
|
|
assert(hash);
|
|
status=GWEN_SslCertDescr_GetStatusText(cd);
|
|
ipAddr=GWEN_SslCertDescr_GetIpAddress(cd);
|
|
|
|
if (hash && status && ipAddr) {
|
|
GWEN_BUFFER *dbuf;
|
|
char msgHash[64];
|
|
unsigned int bsize;
|
|
|
|
dbuf=GWEN_Buffer_new(0, 32, 0, 1);
|
|
GWEN_Buffer_AppendString(dbuf, "certificates/");
|
|
GWEN_Buffer_AppendString(dbuf, ipAddr);
|
|
GWEN_Buffer_AppendString(dbuf, "/");
|
|
GWEN_Buffer_AppendString(dbuf, hash);
|
|
GWEN_Buffer_AppendString(dbuf, "/");
|
|
bsize=sizeof(msgHash);
|
|
if (GWEN_MD_Hash("rmd160", status, strlen(status),
|
|
msgHash, &bsize)) {
|
|
DBG_ERROR(AQBANKING_LOGDOMAIN, "Hash algo RMD160 not found");
|
|
abort();
|
|
}
|
|
GWEN_Text_ToHexBuffer(msgHash, bsize, dbuf, 0, 0, 0);
|
|
if (strlen(GWEN_Buffer_GetStart(dbuf))>=sizeof(varName)) {
|
|
DBG_ERROR(AQBANKING_LOGDOMAIN,
|
|
"Uuups, varname buffer is too small (%zd needed)",
|
|
strlen(GWEN_Buffer_GetStart(dbuf)));
|
|
abort();
|
|
}
|
|
strncpy(varName, GWEN_Buffer_GetStart(dbuf),
|
|
sizeof(varName)-1);
|
|
DBG_INFO(AQBANKING_LOGDOMAIN,
|
|
"Certificate path: %s", varName);
|
|
GWEN_Buffer_free(dbuf);
|
|
}
|
|
|
|
if (!ab->alwaysAskForCert && !isNew && varName[0]) {
|
|
const char *result;
|
|
|
|
result=GWEN_DB_GetCharValue(pd, varName, 0, 0);
|
|
if (!result) {
|
|
/* check temporary config */
|
|
result=GWEN_DB_GetCharValue(ab->dbTempConfig, varName, 0, 0);
|
|
}
|
|
if (result) {
|
|
if (strcasecmp(result, "accept")==0) {
|
|
DBG_NOTICE(AQBANKING_LOGDOMAIN,
|
|
"Automatically accepting certificate \"%s\"", hash);
|
|
return GWEN_NetLayerSsl_AskAddCertResult_Perm;
|
|
}
|
|
else if (strcasecmp(result, "temp")==0) {
|
|
DBG_NOTICE(AQBANKING_LOGDOMAIN,
|
|
"Automatically accepting certificate \"%s\"", hash);
|
|
return GWEN_NetLayerSsl_AskAddCertResult_Tmp;
|
|
}
|
|
}
|
|
else
|
|
isNew=1;
|
|
}
|
|
|
|
ti=GWEN_SslCertDescr_GetNotBefore(cd);
|
|
if (ti) {
|
|
GWEN_BUFFER *tbuf;
|
|
|
|
tbuf=GWEN_Buffer_new(0, 32, 0, 1);
|
|
/* TRANSLATORS: This string is used as a template string to
|
|
convert a given time into your local translated timeformat. The
|
|
following characters are accepted in the template string: Y -
|
|
digit of the year, M - digit of the month, D - digit of the day
|
|
of month, h - digit of the hour, m - digit of the minute, s-
|
|
digit of the second. All other characters are left unchanged. */
|
|
if (GWEN_Time_toString(ti, I18N("YYYY/MM/DD hh:mm:ss"), tbuf)) {
|
|
DBG_ERROR(AQBANKING_LOGDOMAIN,
|
|
"Could not convert beforeDate to string");
|
|
abort();
|
|
}
|
|
strncpy(dbuffer1, GWEN_Buffer_GetStart(tbuf), sizeof(dbuffer1)-1);
|
|
GWEN_Buffer_free(tbuf);
|
|
}
|
|
|
|
ti=GWEN_SslCertDescr_GetNotAfter(cd);
|
|
if (ti) {
|
|
GWEN_BUFFER *tbuf;
|
|
|
|
tbuf=GWEN_Buffer_new(0, 32, 0, 1);
|
|
if (GWEN_Time_toString(ti, I18N("YYYY/MM/DD hh:mm:ss"), tbuf)) {
|
|
DBG_ERROR(AQBANKING_LOGDOMAIN,
|
|
"Could not convert untilDate to string");
|
|
abort();
|
|
}
|
|
strncpy(dbuffer2, GWEN_Buffer_GetStart(tbuf), sizeof(dbuffer2)-1);
|
|
GWEN_Buffer_free(tbuf);
|
|
}
|
|
|
|
if (isError) {
|
|
statusOn="<font color=red>";
|
|
statusOff="</font>";
|
|
}
|
|
else if (isWarning) {
|
|
statusOn="<font color=blue>";
|
|
statusOff="</font>";
|
|
}
|
|
else {
|
|
statusOn="<font color=green>";
|
|
statusOff="</font>";
|
|
}
|
|
|
|
unknown=I18N("unknown");
|
|
commonName=GWEN_SslCertDescr_GetCommonName(cd);
|
|
if (!commonName)
|
|
commonName=unknown;
|
|
organizationName=GWEN_SslCertDescr_GetOrganizationName(cd);
|
|
if (!organizationName)
|
|
organizationName=unknown;
|
|
organizationalUnitName=GWEN_SslCertDescr_GetOrganizationalUnitName(cd);
|
|
if (!organizationalUnitName)
|
|
organizationalUnitName=unknown;
|
|
countryName=GWEN_SslCertDescr_GetCountryName(cd);
|
|
if (!countryName)
|
|
countryName=unknown;
|
|
localityName=GWEN_SslCertDescr_GetLocalityName(cd);
|
|
if (!localityName)
|
|
localityName=unknown;
|
|
stateOrProvinceName=GWEN_SslCertDescr_GetStateOrProvinceName(cd);
|
|
if (!stateOrProvinceName)
|
|
stateOrProvinceName=unknown;
|
|
if (!status)
|
|
status=unknown;
|
|
|
|
snprintf(buffer, sizeof(buffer)-1,
|
|
I18N(msg),
|
|
commonName,
|
|
organizationName,
|
|
organizationalUnitName,
|
|
countryName,
|
|
localityName,
|
|
stateOrProvinceName,
|
|
dbuffer1, dbuffer2,
|
|
hash,
|
|
status,
|
|
/* the same again for HTML */
|
|
commonName,
|
|
organizationName,
|
|
organizationalUnitName,
|
|
countryName,
|
|
localityName,
|
|
stateOrProvinceName,
|
|
dbuffer1, dbuffer2,
|
|
hash,
|
|
statusOn,
|
|
status,
|
|
statusOff
|
|
);
|
|
|
|
rv=AB_Banking_MessageBox(ab,
|
|
AB_BANKING_MSG_FLAGS_TYPE_WARN |
|
|
AB_BANKING_MSG_FLAGS_CONFIRM_B1 |
|
|
AB_BANKING_MSG_FLAGS_SEVERITY_DANGEROUS,
|
|
I18N("Certificate Received"),
|
|
buffer,
|
|
I18N("Yes"), I18N("No"), 0);
|
|
if (rv==1) {
|
|
rv=AB_Banking_MessageBox(ab,
|
|
AB_BANKING_MSG_FLAGS_TYPE_WARN |
|
|
AB_BANKING_MSG_FLAGS_CONFIRM_B1 |
|
|
AB_BANKING_MSG_FLAGS_SEVERITY_DANGEROUS,
|
|
I18N("Certificate"),
|
|
I18N(
|
|
"Do you want to accept this certificate permanently?"
|
|
"<html>Do you want to accept this certificate permanently?</html>"),
|
|
I18N("Permanently"),
|
|
I18N("This session only"),
|
|
I18N("Abort"));
|
|
if (rv==1) {
|
|
DBG_NOTICE(AQBANKING_LOGDOMAIN,
|
|
"User accepted certificate permanently");
|
|
if (*varName) {
|
|
GWEN_DB_SetCharValue(pd, GWEN_DB_FLAGS_OVERWRITE_VARS,
|
|
varName, "accept");
|
|
}
|
|
return GWEN_NetLayerSsl_AskAddCertResult_Perm;
|
|
}
|
|
else if (rv==2) {
|
|
DBG_NOTICE(AQBANKING_LOGDOMAIN,
|
|
"User accepted certificate temporarily");
|
|
if (*varName) {
|
|
GWEN_DB_SetCharValue(ab->dbTempConfig,
|
|
GWEN_DB_FLAGS_OVERWRITE_VARS,
|
|
varName, "temp");
|
|
}
|
|
return GWEN_NetLayerSsl_AskAddCertResult_Tmp;
|
|
}
|
|
else {
|
|
DBG_NOTICE(AQBANKING_LOGDOMAIN,
|
|
"User aborted");
|
|
return GWEN_NetLayerSsl_AskAddCertResult_No;
|
|
}
|
|
}
|
|
else {
|
|
DBG_NOTICE(AQBANKING_LOGDOMAIN,
|
|
"User rejected certificate");
|
|
if (*varName) {
|
|
GWEN_DB_DeleteVar(pd, varName);
|
|
GWEN_DB_DeleteVar(ab->dbTempConfig, varName);
|
|
}
|
|
return GWEN_NetLayerSsl_AskAddCertResult_No;
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
int AB_Banking_GetAlwaysAskForCert(const AB_BANKING *ab){
|
|
assert(ab);
|
|
return ab->alwaysAskForCert;
|
|
}
|
|
|
|
|
|
|
|
void AB_Banking_SetAlwaysAskForCert(AB_BANKING *ab, int i){
|
|
assert(ab);
|
|
ab->alwaysAskForCert=i;
|
|
}
|
|
|
|
|
|
|
|
const AB_COUNTRY *AB_Banking_FindCountryByName(AB_BANKING *ab,
|
|
const char *name){
|
|
assert(ab);
|
|
return AB_Country_FindByName(name);
|
|
}
|
|
|
|
|
|
|
|
const AB_COUNTRY *AB_Banking_FindCountryByLocalName(AB_BANKING *ab,
|
|
const char *name){
|
|
assert(ab);
|
|
return AB_Country_FindByLocalName(name);
|
|
}
|
|
|
|
|
|
|
|
const AB_COUNTRY *AB_Banking_FindCountryByCode(AB_BANKING *ab,
|
|
const char *code){
|
|
assert(ab);
|
|
return AB_Country_FindByCode(code);
|
|
}
|
|
|
|
|
|
|
|
const AB_COUNTRY *AB_Banking_FindCountryByNumeric(AB_BANKING *ab,
|
|
int numid){
|
|
assert(ab);
|
|
return AB_Country_FindByNumeric(numid);
|
|
}
|
|
|
|
|
|
|
|
AB_COUNTRY_CONSTLIST2 *AB_Banking_ListCountriesByName(AB_BANKING *ab,
|
|
const char *name){
|
|
assert(ab);
|
|
return AB_Country_ListByName(name);
|
|
}
|
|
|
|
|
|
|
|
AB_COUNTRY_CONSTLIST2 *AB_Banking_ListCountriesByLocalName(AB_BANKING *ab,
|
|
const char *name){
|
|
assert(ab);
|
|
return AB_Country_ListByLocalName(name);
|
|
}
|
|
|
|
|
|
|
|
int AB_Banking__TransformIban(const char *iban, int len,
|
|
char *newIban, int maxLen) {
|
|
int i, j;
|
|
const char *p;
|
|
char *s;
|
|
|
|
assert(iban);
|
|
/* format IBAN */
|
|
i=0;
|
|
j=0;
|
|
p=iban;
|
|
s=newIban;
|
|
while(j<len && i<maxLen) {
|
|
int c;
|
|
|
|
c=toupper(*p);
|
|
if (c!=' ') {
|
|
if (c>='A' && c<='Z') {
|
|
c=10+(c-'A');
|
|
*s='0'+(c/10);
|
|
s++; i++;
|
|
if (i>=maxLen) {
|
|
DBG_ERROR(AQBANKING_LOGDOMAIN, "Bad IBAN (too long)");
|
|
return -1;
|
|
}
|
|
*s='0'+(c%10);
|
|
s++; i++;
|
|
}
|
|
else if (isdigit(c)) {
|
|
*s=c;
|
|
s++; i++;
|
|
}
|
|
else {
|
|
DBG_ERROR(AQBANKING_LOGDOMAIN, "Bad IBAN (bad char)");
|
|
return -1;
|
|
}
|
|
}
|
|
p++;
|
|
j++;
|
|
} /* while */
|
|
if (j<len) {
|
|
DBG_ERROR(AQBANKING_LOGDOMAIN, "Bad IBAN (too long)");
|
|
return -1;
|
|
}
|
|
*s=0;
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
|
|
int AB_Banking_CheckIban(const char *iban) {
|
|
char newIban[256];
|
|
char tmp[10];
|
|
int i;
|
|
unsigned int j;
|
|
const char *p;
|
|
char *s;
|
|
|
|
if (strlen(iban)<5) {
|
|
DBG_ERROR(AQBANKING_LOGDOMAIN, "Bad IBAN (too short)");
|
|
return -1;
|
|
}
|
|
p=iban+4;
|
|
|
|
/* convert IBAN+4 to buffer */
|
|
if (AB_Banking__TransformIban(p, strlen(p),
|
|
newIban, sizeof(newIban)-1)) {
|
|
DBG_INFO(AQBANKING_LOGDOMAIN, "here");
|
|
return -1;
|
|
}
|
|
|
|
/* append country and checksum */
|
|
p=iban;
|
|
s=newIban+strlen(newIban);
|
|
if (AB_Banking__TransformIban(p, 4, s, sizeof(newIban)-strlen(newIban)-1)){
|
|
DBG_INFO(AQBANKING_LOGDOMAIN, "here");
|
|
return -1;
|
|
}
|
|
|
|
/* calculate checksum in 9er steps */
|
|
p=newIban;
|
|
tmp[0]=0;
|
|
j=0;
|
|
while(*p) {
|
|
i=strlen(tmp);
|
|
for (i=strlen(tmp); i<9; i++) {
|
|
if (!*p)
|
|
break;
|
|
tmp[i]=*(p++);
|
|
}
|
|
tmp[i]=0;
|
|
if (1!=sscanf(tmp, "%u", &j)) {
|
|
DBG_ERROR(AQBANKING_LOGDOMAIN, "Bad IBAN (bad char)");
|
|
return -1;
|
|
}
|
|
j=j%97; /* modulo 97 */
|
|
snprintf(tmp, sizeof(tmp), "%u", j);
|
|
} /* while */
|
|
|
|
if (j!=1) {
|
|
DBG_ERROR(AQBANKING_LOGDOMAIN, "Bad IBAN (bad checksum)");
|
|
return 1;
|
|
}
|
|
|
|
DBG_INFO(AQBANKING_LOGDOMAIN, "IBAN is valid");
|
|
return 0;
|
|
}
|
|
|
|
|
|
|
|
GWEN_STRINGLIST *AB_Banking_GetGlobalDataDirs() {
|
|
GWEN_STRINGLIST *sl;
|
|
|
|
sl=GWEN_PathManager_GetPaths(AB_PM_LIBNAME, AB_PM_DATADIR);
|
|
return sl;
|
|
}
|
|
|
|
|
|
|
|
GWEN_STRINGLIST *AB_Banking_GetGlobalSysconfDirs() {
|
|
GWEN_STRINGLIST *sl;
|
|
|
|
sl=GWEN_PathManager_GetPaths(AB_PM_LIBNAME, AB_PM_SYSCONFDIR);
|
|
return sl;
|
|
}
|
|
|
|
|
|
|
|
int AB_Banking__LoadOldProviderData(AB_BANKING *ab, const char *name){
|
|
GWEN_BUFFER *pbuf;
|
|
GWEN_DB_NODE *db;
|
|
|
|
assert(ab);
|
|
pbuf=GWEN_Buffer_new(0, 256, 0, 1);
|
|
|
|
if (AB_Banking_GetUserDataDir(ab, pbuf)) {
|
|
DBG_ERROR(AQBANKING_LOGDOMAIN, "Could not get user data dir");
|
|
GWEN_Buffer_free(pbuf);
|
|
return AB_ERROR_GENERIC;
|
|
}
|
|
GWEN_Buffer_AppendString(pbuf, DIRSEP "backends" DIRSEP);
|
|
GWEN_Buffer_AppendString(pbuf, name);
|
|
GWEN_Buffer_AppendString(pbuf, DIRSEP "settings.conf");
|
|
|
|
db=GWEN_DB_GetGroup(ab->data, GWEN_DB_FLAGS_DEFAULT,
|
|
"banking/backends");
|
|
assert(db);
|
|
db=GWEN_DB_GetGroup(db, GWEN_DB_FLAGS_DEFAULT, name);
|
|
assert(db);
|
|
DBG_INFO(AQBANKING_LOGDOMAIN,
|
|
"Reading file \"%s\"", GWEN_Buffer_GetStart(pbuf));
|
|
if (GWEN_DB_ReadFile(db, GWEN_Buffer_GetStart(pbuf),
|
|
GWEN_DB_FLAGS_DEFAULT |
|
|
GWEN_PATH_FLAGS_CREATE_GROUP |
|
|
GWEN_DB_FLAGS_LOCKFILE)) {
|
|
DBG_INFO(AQBANKING_LOGDOMAIN,
|
|
"Could not load config file \"%s\", creating it later",
|
|
GWEN_Buffer_GetStart(pbuf));
|
|
GWEN_Buffer_free(pbuf);
|
|
return 0;
|
|
}
|
|
GWEN_Buffer_free(pbuf);
|
|
|
|
/* sucessfully read */
|
|
return 0;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|