/* --------------------------------------------------------------- FUNCTION */
int AH_Job_SepaStandingOrdersGet__ReadSto(AH_JOB *j,
					  AB_IMEXPORTER_CONTEXT *ctx,
					  const uint8_t *ptr,
					  uint32_t len,
					  const char *fiId){
  int rv;
  AB_IMEXPORTER_CONTEXT *tmpCtx;
  GWEN_BUFFER *tbuf;
  AB_IMEXPORTER_ACCOUNTINFO *ai;

  tmpCtx=AB_ImExporterContext_new();
  tbuf=GWEN_Buffer_new(0, 256, 0, 1);
  GWEN_Buffer_AppendBytes(tbuf, (const char*) ptr, len);

  rv=AB_Banking_ImportBuffer(AH_Job_GetBankingApi(j),
			     tmpCtx,
			     "sepa",
			     "default",
			     tbuf);
  if (rv<0) {
    DBG_INFO(AQHBCI_LOGDOMAIN, "here (%d)", rv);
    GWEN_Buffer_free(tbuf);
    AB_ImExporterContext_free(tmpCtx);
    return rv;
  }
  GWEN_Buffer_free(tbuf);

  ai=AB_ImExporterContext_GetFirstAccountInfo(tmpCtx);
  if (ai) {
    AB_TRANSACTION *t;

    while( (t=AB_ImExporterAccountInfo_GetFirstTransaction(ai)) ) {
      AB_Transaction_List_Del(t);
      AB_Transaction_SetFiId(t, fiId);
      /* add to real im/exporter context */
      AB_ImExporterContext_AddTransaction(ctx, t);
    }
  }
  AB_ImExporterContext_free(tmpCtx);

  return 0;
}
示例#2
0
static const AB_TRANSACTION *
AB_ImExporterAccountInfo_TransactionsForEach(AB_IMEXPORTER_ACCOUNTINFO *iea,
        const AB_TRANSACTION *
        (* func)(const AB_TRANSACTION *element,
                 void *user_data),
        void* user_data)
{
    const AB_TRANSACTION *it;
    const AB_TRANSACTION *retval;
    g_assert(iea);

    it = AB_ImExporterAccountInfo_GetFirstTransaction (iea);
    while (it)
    {
        retval = func(it, user_data);
        if (retval)
        {
            return retval;
        }
        it = AB_ImExporterAccountInfo_GetNextTransaction (iea);
    }
    return 0;
}
示例#3
0
static PyObject *aqbanking_Account_transactions(aqbanking_Account* self, PyObject *args, PyObject *kwds)
{
	int rv;
	double tmpDateTime = 0;
	const char *bank_code;
	const char *account_no;
#if PY_VERSION_HEX >= 0x03030000
	bank_code = PyUnicode_AsUTF8(self->bank_code);
	account_no = PyUnicode_AsUTF8(self->no);
#else
	PyObject *s = _PyUnicode_AsDefaultEncodedString(self->bank_code, NULL);
	bank_code = PyBytes_AS_STRING(s);
	s = _PyUnicode_AsDefaultEncodedString(self->no, NULL);
	account_no = PyBytes_AS_STRING(s);
#endif
	GWEN_TIME *gwTime;
	const char *dateFrom=NULL, *dateTo=NULL;
	static char *kwlist[] = {"dateFrom", "dateTo", NULL};
	if (! PyArg_ParseTupleAndKeywords(args, kwds, "|ss", kwlist, &dateFrom, &dateTo))
	{
		return NULL;
	}

	AB_ACCOUNT *a;
	AB_JOB *job = 0;
	AB_JOB_LIST2 *jl = 0;
	AB_IMEXPORTER_CONTEXT *ctx = 0;
	AB_IMEXPORTER_ACCOUNTINFO *ai;
	/*aqbanking_Transaction *trans = NULL;*/
	PyObject *transList = PyList_New(0);

	// Valid data set?
	if (self->no == NULL)
	{
		PyErr_SetString(PyExc_AttributeError, "no");
	}
	if (self->bank_code == NULL)
	{
		PyErr_SetString(PyExc_AttributeError, "bank_code");
	}

	// Initialize aqbanking.
	rv = AB_create(self);
	if (rv > 0)
	{
		Py_DECREF(transList);
		return NULL;
	}

	// Let us find the account!
	a = AB_Banking_GetAccountByCodeAndNumber(self->ab, bank_code, account_no);
	if (!a)
	{
		PyErr_SetString(AccountNotFound, "Could not find the given account! ");
		Py_DECREF(transList);
		return NULL;
	}

	// Create job and execute it.
	job = AB_JobGetTransactions_new(a);
	if (dateFrom != NULL)
	{
		gwTime = GWEN_Time_fromString(dateFrom, "YYYYMMDD");
		AB_JobGetTransactions_SetFromTime(job, gwTime);
	}
	if (dateTo != NULL)
	{
		gwTime = GWEN_Time_fromString(dateTo, "YYYYMMDD");
		AB_JobGetTransactions_SetToTime(job, gwTime);
	}
	// Check for availability
	rv = AB_Job_CheckAvailability(job);
	if (rv) {
		PyErr_SetString(ExecutionFailed, "Transaction retrieval is not supported!");
		Py_DECREF(transList);
		return NULL;
	}

	jl = AB_Job_List2_new();
	AB_Job_List2_PushBack(jl, job);
	ctx = AB_ImExporterContext_new();
	rv = AB_Banking_ExecuteJobs(self->ab, jl, ctx);

	if (rv)
	{
		PyErr_SetString(ExecutionFailed, "Could not retrieve transactions!");
		Py_DECREF(transList);
		return NULL;
	}

	// With success. No process the result.
	ai = AB_ImExporterContext_GetFirstAccountInfo (ctx);
	while(ai)
	{
		const AB_TRANSACTION *t;
		
		t = AB_ImExporterAccountInfo_GetFirstTransaction(ai);
		while(t) {
			const AB_VALUE *v;
			AB_TRANSACTION_STATUS state;

			v=AB_Transaction_GetValue(t);
			if (v) {
				const GWEN_STRINGLIST *sl;
				const GWEN_TIME *tdtime;
				const char *purpose;
				const char *remoteName;
				aqbanking_Transaction *trans = (aqbanking_Transaction*) PyObject_CallObject((PyObject *) &aqbanking_TransactionType, NULL);

				/* The purpose (memo field) might contain multiple lines.
				 * Therefore AqBanking stores the purpose in a string list
				 * of which the first entry is used in this tutorial */
				sl = AB_Transaction_GetPurpose(t);
				if (sl)
				{
					purpose = GWEN_StringList_FirstString(sl);
					if (purpose == NULL) {
						purpose = "";
					}
				}
				else
				{
					purpose = "";
				}

#ifdef DEBUGSTDERR
				fprintf(stderr, "[%-10d]: [%-10s/%-10s][%-10s/%-10s] %-32s (%.2f %s)\n",
						AB_Transaction_GetUniqueId(t),
						AB_Transaction_GetRemoteIban(t),
						AB_Transaction_GetRemoteBic(t),
						AB_Transaction_GetRemoteAccountNumber(t),
						AB_Transaction_GetRemoteBankCode(t),
						purpose,
						AB_Value_GetValueAsDouble(v),
						AB_Value_GetCurrency(v)
				);
#endif

				tdtime = AB_Transaction_GetDate(t);
				tmpDateTime = PyLong_AsDouble(PyLong_FromSize_t(GWEN_Time_Seconds(tdtime)));
				trans->date = PyDate_FromTimestamp(Py_BuildValue("(O)", PyFloat_FromDouble(tmpDateTime)));
				tdtime = AB_Transaction_GetValutaDate(t);
				tmpDateTime = PyLong_AsDouble(PyLong_FromSize_t(GWEN_Time_Seconds(tdtime)));
				trans->valutaDate = PyDate_FromTimestamp(Py_BuildValue("(O)", PyFloat_FromDouble(tmpDateTime)));
				trans->purpose = PyUnicode_FromString(purpose);

				// Local user
				if (AB_Transaction_GetLocalAccountNumber(t) == NULL) {
					trans->localAccount = Py_None;
					Py_INCREF(Py_None);
				} else {
					trans->localAccount = PyUnicode_FromString(AB_Transaction_GetLocalAccountNumber(t));
				}
				if (AB_Transaction_GetLocalBankCode(t) == NULL) {
					trans->localBank = Py_None;
					Py_INCREF(Py_None);
				} else {
					trans->localBank = PyUnicode_FromString(AB_Transaction_GetLocalBankCode(t));
				}
				if (AB_Transaction_GetLocalIban(t) == NULL) {
					trans->localIban = Py_None;
					Py_INCREF(Py_None);
				} else {
					trans->localIban = PyUnicode_FromString(AB_Transaction_GetLocalIban(t));
				}
				if (AB_Transaction_GetLocalBic(t) == NULL) {
					trans->localBic = Py_None;
					Py_INCREF(Py_None);
				} else {
					trans->localBic = PyUnicode_FromString(AB_Transaction_GetLocalBic(t));
				}
				if (AB_Transaction_GetLocalName(t) == NULL) {
					trans->localName = Py_None;
					Py_INCREF(Py_None);
				} else {
				        trans->localName = PyUnicode_FromString(AB_Transaction_GetLocalName(t));
				}

				// Remote user
				if (AB_Transaction_GetRemoteAccountNumber(t) == NULL) {
					trans->remoteAccount = Py_None;
					Py_INCREF(Py_None);
				} else {
					trans->remoteAccount = PyUnicode_FromString(AB_Transaction_GetRemoteAccountNumber(t));
				}
				if (AB_Transaction_GetRemoteBankCode(t) == NULL) {
					trans->remoteBank = Py_None;
					Py_INCREF(Py_None);
				} else {
					trans->remoteBank = PyUnicode_FromString(AB_Transaction_GetRemoteBankCode(t));
				}
				if (AB_Transaction_GetRemoteIban(t) == NULL) {
					trans->remoteIban = Py_None;
					Py_INCREF(Py_None);
				} else {
					trans->remoteIban = PyUnicode_FromString(AB_Transaction_GetRemoteIban(t));
				}
				if (AB_Transaction_GetRemoteBic(t) == NULL) {
					trans->remoteBic = Py_None;
					Py_INCREF(Py_None);
				} else {
					trans->remoteBic = PyUnicode_FromString(AB_Transaction_GetRemoteBic(t));
				}
				if (AB_Transaction_GetRemoteName(t) == NULL) {
					trans->remoteName = Py_None;
					Py_INCREF(Py_None);
				} else {
					sl = AB_Transaction_GetRemoteName(t);
					remoteName = GWEN_StringList_FirstString(sl);
					if (remoteName == NULL) {
						trans->remoteName = Py_None;
					} else {
						trans->remoteName = PyUnicode_FromString(remoteName);
					}
				}

				trans->value = PyFloat_FromDouble(AB_Value_GetValueAsDouble(v));
				trans->currency = PyUnicode_FromString("EUR");
				trans->uniqueId = PyLong_FromLong(AB_Transaction_GetUniqueId(t));
				if (AB_Transaction_GetTransactionText(t) == NULL) {
					trans->transactionText = PyUnicode_FromString("");
				} else {
					trans->transactionText = PyUnicode_FromString(AB_Transaction_GetTransactionText(t));
				}
				trans->transactionCode = PyLong_FromLong(AB_Transaction_GetTransactionCode(t));
				trans->textKey = PyLong_FromLong(AB_Transaction_GetTextKey(t));
				trans->textKeyExt = PyLong_FromLong(AB_Transaction_GetTextKeyExt(t));
				if (AB_Transaction_GetMandateId(t) == NULL) {
					trans->sepaMandateId = Py_None;
				} else {
					trans->sepaMandateId = PyUnicode_FromString(AB_Transaction_GetMandateId(t));
				}
				if (AB_Transaction_GetCustomerReference(t) == NULL) {
					trans->customerReference = PyUnicode_FromString("");
				} else {
					trans->customerReference = PyUnicode_FromString(AB_Transaction_GetCustomerReference(t));
				}
				if (AB_Transaction_GetBankReference(t) == NULL) {
					trans->bankReference = PyUnicode_FromString("");
				} else {
					trans->bankReference = PyUnicode_FromString(AB_Transaction_GetBankReference(t));
				}
				if (AB_Transaction_GetEndToEndReference(t) == NULL) {
					trans->endToEndReference = PyUnicode_FromString("");
				} else {
					trans->endToEndReference = PyUnicode_FromString(AB_Transaction_GetEndToEndReference(t));
				}
				trans->state = 0;
				state = AB_Transaction_GetStatus(t);
				switch(state)
				{
					case AB_Transaction_StatusUnknown:
						trans->state = -1;
						break;
					case AB_Transaction_StatusNone:
						trans->state = 0;
						break;
					case AB_Transaction_StatusAccepted:
						trans->state = 1;
						break;
					case AB_Transaction_StatusRejected:
						trans->state = 2;
						break;
					case AB_Transaction_StatusPending:
						trans->state = 4;
						break;
					case AB_Transaction_StatusSending:
						trans->state = 8;
						break;
					case AB_Transaction_StatusAutoReconciled:
						trans->state = 16;
						break;
					case AB_Transaction_StatusManuallyReconciled:
						trans->state = 32;
						break;
					case AB_Transaction_StatusRevoked:
						trans->state = 64;
						break;
					case AB_Transaction_StatusAborted:
						trans->state = 128;
						break;
				}

				PyList_Append(transList, (PyObject *)trans);
				Py_DECREF(trans);
			}
			t = AB_ImExporterAccountInfo_GetNextTransaction(ai);
		} 
		ai = AB_ImExporterContext_GetNextAccountInfo(ctx);
	}

	// Free jobs.
	AB_Job_free(job);
	AB_Job_List2_free(jl);
	AB_ImExporterContext_free(ctx);

	// Exit aqbanking.
	rv = AB_free(self);
	if (rv > 0)
	{
		//Py_XDECREF(trans);
		Py_DECREF(transList);
		return NULL;
	}

	return transList;
}
示例#4
0
static AB_IMEXPORTER_ACCOUNTINFO *
txn_accountinfo_cb(AB_IMEXPORTER_ACCOUNTINFO *element, gpointer user_data)
{
    GncABImExContextImport *data = user_data;
    Account *gnc_acc;

    g_return_val_if_fail(element && data, NULL);

    if (data->awaiting & IGNORE_TRANSACTIONS)
        /* Ignore them */
        return NULL;

    if (!AB_ImExporterAccountInfo_GetFirstTransaction(element))
        /* No transaction found */
        return NULL;
    else
        data->awaiting |= FOUND_TRANSACTIONS;

    if (!(data->awaiting & AWAIT_TRANSACTIONS))
    {
        if (gnc_verify_dialog(data->parent, TRUE, "%s",
                              _("The bank has sent transaction information "
                                "in its response."
                                "\n"
                                "Do you want to import it?")))
        {
            data->awaiting |= AWAIT_TRANSACTIONS;
        }
        else
        {
            data->awaiting |= IGNORE_TRANSACTIONS;
            return NULL;
        }
    }

    /* Lookup the corresponding gnucash account */
    gnc_acc = gnc_ab_accinfo_to_gnc_acc(element);
    if (!gnc_acc) return NULL;
    data->gnc_acc = gnc_acc;

    if (data->execute_txns)
    {
        /* Retrieve the aqbanking account that belongs to this gnucash
         * account */
        data->ab_acc = gnc_ab_get_ab_account(data->api, gnc_acc);
        if (!data->ab_acc)
        {
            gnc_error_dialog(NULL, "%s",
                             _("No Online Banking account found for this "
                               "gnucash account. These transactions will "
                               "not be executed by Online Banking."));
        }
    }
    else
    {
        data->ab_acc = NULL;
    }

    if (!data->generic_importer)
    {
        data->generic_importer = gnc_gen_trans_list_new(data->parent, NULL,
                                 TRUE, 14);
        if (data->execute_txns)
        {
            gnc_gen_trans_list_add_tp_cb(data->generic_importer,
                                         gnc_ab_trans_processed_cb, data);
        }
    }

    /* Iterate through all transactions */
    AB_ImExporterAccountInfo_TransactionsForEach(element, txn_transaction_cb,
            data);

    return NULL;
}
示例#5
0
/* --------------------------------------------------------------- FUNCTION */
int AH_Job_GetTransactions_Process(AH_JOB *j, AB_IMEXPORTER_CONTEXT *ctx)
{
  AH_JOB_GETTRANSACTIONS *aj;
  AB_ACCOUNT *a;
  AB_IMEXPORTER_ACCOUNTINFO *ai;
  GWEN_DB_NODE *dbResponses;
  GWEN_DB_NODE *dbCurr;
  GWEN_BUFFER *tbooked;
  GWEN_BUFFER *tnoted;
  int rv;

  DBG_INFO(AQHBCI_LOGDOMAIN, "Processing JobGetTransactions");

  assert(j);
  aj=GWEN_INHERIT_GETDATA(AH_JOB, AH_JOB_GETTRANSACTIONS, j);
  assert(aj);

  tbooked=GWEN_Buffer_new(0, 1024, 0, 1);
  tnoted=GWEN_Buffer_new(0, 1024, 0, 1);

  dbResponses=AH_Job_GetResponses(j);
  assert(dbResponses);

  /* search for "Transactions" */
  dbCurr=GWEN_DB_GetFirstGroup(dbResponses);
  while (dbCurr) {
    GWEN_DB_NODE *dbXA;

    rv=AH_Job_CheckEncryption(j, dbCurr);
    if (rv) {
      DBG_INFO(AQHBCI_LOGDOMAIN, "Compromised security (encryption)");
      GWEN_Buffer_free(tbooked);
      GWEN_Buffer_free(tnoted);
      AH_Job_SetStatus(j, AH_JobStatusError);
      return rv;
    }
    rv=AH_Job_CheckSignature(j, dbCurr);
    if (rv) {
      DBG_INFO(AQHBCI_LOGDOMAIN, "Compromised security (signature)");
      GWEN_Buffer_free(tbooked);
      GWEN_Buffer_free(tnoted);
      AH_Job_SetStatus(j, AH_JobStatusError);
      return rv;
    }

    dbXA=GWEN_DB_GetGroup(dbCurr, GWEN_PATH_FLAGS_NAMEMUSTEXIST,
                          "data/transactions");
    if (dbXA) {
      const void *p;
      unsigned int bs;

      if (GWEN_Logger_GetLevel(0)>=GWEN_LoggerLevel_Debug)
        GWEN_DB_Dump(dbXA, 2);
      p=GWEN_DB_GetBinValue(dbXA, "booked", 0, 0, 0, &bs);
      if (p && bs)
        GWEN_Buffer_AppendBytes(tbooked, p, bs);
      p=GWEN_DB_GetBinValue(dbXA, "noted", 0, 0, 0, &bs);
      if (p && bs)
        GWEN_Buffer_AppendBytes(tnoted, p, bs);
    } /* if "Transactions" */
    dbCurr=GWEN_DB_GetNextGroup(dbCurr);
  }

  GWEN_Buffer_Rewind(tbooked);
  GWEN_Buffer_Rewind(tnoted);

  /* now the buffers contain data to be parsed by DBIOs */
  a=AH_AccountJob_GetAccount(j);
  assert(a);
  ai=AB_ImExporterContext_GetOrAddAccountInfo(ctx,
                                              AB_Account_GetUniqueId(a),
                                              AB_Account_GetIban(a),
                                              AB_Account_GetBankCode(a),
                                              AB_Account_GetAccountNumber(a),
                                              AB_Account_GetAccountType(a));
  assert(ai);

  /* read booked transactions */
  if (GWEN_Buffer_GetUsedBytes(tbooked)) {
    if (getenv("AQHBCI_LOGBOOKED")) {
      FILE *f;

      f=fopen("/tmp/booked.mt", "w+");
      if (f) {
        if (fwrite(GWEN_Buffer_GetStart(tbooked),
                   GWEN_Buffer_GetUsedBytes(tbooked), 1, f)!=1) {
          DBG_ERROR(AQHBCI_LOGDOMAIN, "fwrite: %s", strerror(errno));
        }
        if (fclose(f)) {
          DBG_ERROR(AQHBCI_LOGDOMAIN, "fclose: %s", strerror(errno));
        }
      }
    }

    if (AH_Job_GetTransactions__ReadTransactions(j,
                                                 ai,
                                                 "SWIFT-MT940",
                                                 AB_Transaction_TypeStatement,
                                                 (const uint8_t *) GWEN_Buffer_GetStart(tbooked),
                                                 GWEN_Buffer_GetUsedBytes(tbooked))) {
      GWEN_Buffer_free(tbooked);
      GWEN_Buffer_free(tnoted);
      DBG_INFO(AQHBCI_LOGDOMAIN, "Error parsing booked transactions");
      AH_Job_SetStatus(j, AH_JobStatusError);
      return -1;
    }
  }

  /* read noted transactions */
  if (GWEN_Buffer_GetUsedBytes(tnoted)) {
    if (getenv("AQHBCI_LOGNOTED")) {
      FILE *f;

      f=fopen("/tmp/noted.mt", "w+");
      if (f) {
        if (fwrite(GWEN_Buffer_GetStart(tnoted),
                   GWEN_Buffer_GetUsedBytes(tnoted), 1, f)!=1) {
          DBG_ERROR(AQHBCI_LOGDOMAIN, "fwrite: %s", strerror(errno));
        }
        if (fclose(f)) {
          DBG_ERROR(AQHBCI_LOGDOMAIN, "fclose: %s", strerror(errno));
        }
      }
    }

    if (AH_Job_GetTransactions__ReadTransactions(j,
                                                 ai,
                                                 "SWIFT-MT942",
                                                 AB_Transaction_TypeNotedStatement,
                                                 (const uint8_t *) GWEN_Buffer_GetStart(tnoted),
                                                 GWEN_Buffer_GetUsedBytes(tnoted))) {
      GWEN_Buffer_free(tbooked);
      GWEN_Buffer_free(tnoted);
      DBG_INFO(AQHBCI_LOGDOMAIN, "Error parsing noted transactions");
      AH_Job_SetStatus(j, AH_JobStatusError);
      return -1;
    }
  }

  if (GWEN_Logger_GetLevel(AQHBCI_LOGDOMAIN)>=GWEN_LoggerLevel_Debug) {
    GWEN_DB_NODE *gn;
    AB_TRANSACTION *ttmp;

    DBG_INFO(AQHBCI_LOGDOMAIN, "*** Dumping transactions *******************");
    ttmp=AB_ImExporterAccountInfo_GetFirstTransaction(ai, 0, 0);
    while (ttmp) {
      DBG_INFO(AQHBCI_LOGDOMAIN, "*** --------------------------------------");
      gn=GWEN_DB_Group_new("transaction");
      AB_Transaction_toDb(ttmp, gn);
      GWEN_DB_Dump(gn, 2);
      GWEN_DB_Group_free(gn);
      ttmp=AB_Transaction_List_Next(ttmp);
    }

    DBG_INFO(AQHBCI_LOGDOMAIN, "*** End dumping transactions ***************");
  }

  GWEN_Buffer_free(tbooked);
  GWEN_Buffer_free(tnoted);
  return 0;
}
示例#6
0
int main(int argc, char **argv)
{
  GWEN_GUI *gui;
  AB_BANKING *ab;
  AB_ACCOUNT_SPEC_LIST *accs=NULL;
  AB_ACCOUNT_SPEC *as;
  AB_IMEXPORTER_ACCOUNTINFO *ai;

  gui=GWEN_Gui_CGui_new();
  GWEN_Gui_SetGui(gui);

  ab=AB_Banking_new("tutorial3", 0, 0);
  AB_Banking_Init(ab);
  fprintf(stderr, "AqBanking successfully initialized.\n");


  /* get the list of known accounts */
  AB_Banking_GetAccountSpecList(ab, &accs);

  /* find a matching account within the given list */
  as=AB_AccountSpec_List_FindFirst(accs,
                                   "aqhbci",                /* backendName */
                                   "de",                    /* country */
                                   "28*",                   /* bankId bank */
                                   "*",                     /* accountNumber */
                                   "*",                     /* subAccountId */
                                   "*",                     /* iban */
                                   "*",                     /* currency */
                                   AB_AccountType_Unknown); /* ty */
  if (as) {
    AB_TRANSACTION_LIST2 *cmdList;
    AB_TRANSACTION *t;
    AB_IMEXPORTER_CONTEXT *ctx;

    cmdList=AB_Transaction_List2_new();

    t=AB_Transaction_new();
    AB_Transaction_SetCommand(t, AB_Transaction_CommandGetTransactions);
    AB_Transaction_SetUniqueAccountId(t, AB_AccountSpec_GetUniqueId(as));

    AB_Transaction_List2_PushBack(cmdList, t);

    ctx=AB_ImExporterContext_new();
    AB_Banking_SendCommands(ab, cmdList, ctx);

    ai=AB_ImExporterContext_GetFirstAccountInfo(ctx);
    while (ai) {
      const AB_TRANSACTION *t;

      t=AB_ImExporterAccountInfo_GetFirstTransaction(ai, 0, 0);
      while (t) {
        const AB_VALUE *v;

        v=AB_Transaction_GetValue(t);
        if (v) {
          const char *purpose;

          purpose=AB_Transaction_GetPurpose(t);
          fprintf(stderr, " %-32s (%.2f %s)\n",
                  purpose,
                  AB_Value_GetValueAsDouble(v),
                  AB_Value_GetCurrency(v));
        }
        t=AB_Transaction_List_Next(t);
      } /* while transactions */
      ai=AB_ImExporterAccountInfo_List_Next(ai);
    } /* while ai */
    AB_ImExporterContext_free(ctx);
  } /* if (as) */

  AB_Banking_Fini(ab);
  AB_Banking_free(ab);

  return 0;
}