/* HomeBank -- Free, easy, personal accounting for everyone.
- * Copyright (C) 1995-2012 Maxime DOYEN
+ * Copyright (C) 1995-2019 Maxime DOYEN
*
* This file is part of HomeBank.
*
extern Currency4217 iso4217cur[];
extern guint n_iso4217cur;
-Currency4217 *iso4217format_get(gchar *code);
/* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */
*max_key = MAX(*max_key, item->key);
}
+static gboolean da_cur_name_grfunc(gpointer key, Currency *item, gchar *name)
+{
+ if( name && item->name )
+ {
+ if(!strcasecmp(name, item->name))
+ return TRUE;
+ }
+ return FALSE;
+}
+
static gboolean da_cur_iso_grfunc(gpointer key, Currency *item, gchar *iso)
{
if( iso && item->iso_code )
DB( g_print("da_cur_append\n") );
/* ensure no duplicate */
- //g_strstrip(item->name);
- if(item->iso_code != NULL)
+ existitem = da_cur_get_by_name( item->name );
+ if( existitem == NULL )
{
- existitem = da_cur_get_by_iso_code( item->iso_code );
- if( existitem == NULL )
- {
- new_key = g_new0(guint32, 1);
- *new_key = da_cur_get_max_key() + 1;
- item->key = *new_key;
- //item->pos = da_cur_length() + 1;
-
- DB( g_print(" -> insert id: %d\n", *new_key) );
+ new_key = g_new0(guint32, 1);
+ *new_key = da_cur_get_max_key() + 1;
+ item->key = *new_key;
+ //item->pos = da_cur_length() + 1;
- g_hash_table_insert(GLOBALS->h_cur, new_key, item);
+ DB( g_print(" -> insert id: %d\n", *new_key) );
- da_cur_initformat(item);
+ g_hash_table_insert(GLOBALS->h_cur, new_key, item);
- return TRUE;
- }
+ da_cur_initformat(item);
-
+ return TRUE;
}
DB( g_print(" -> %s already exist: %d\n", item->iso_code, item->key) );
}
+Currency *
+da_cur_get_by_name(gchar *name)
+{
+ DB( g_print("da_cur_get_by_name\n") );
+
+ return g_hash_table_find(GLOBALS->h_cur, (GHRFunc)da_cur_name_grfunc, name);
+}
+
Currency *
da_cur_get_by_iso_code(gchar *iso_code)
/* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */
+
+gboolean
+currency_is_euro(guint32 key)
+{
+Currency *item;
+gboolean retval = FALSE;
+
+ item = da_cur_get(key);
+ if( item && item->iso_code )
+ {
+ if(!strcasecmp("EUR", item->iso_code))
+ retval = TRUE;
+ }
+ return retval;
+}
+
+
/**
* currency_is_used:
*
DB( g_printf("\n[(currency] found adding %s\n", curfmt->curr_iso_code) );
- //item = da_cur_get_by_iso_code(curfmt->curr_iso_code);
-
item = da_cur_malloc();
//no mem alloc here
//item->key = i;
}
else
{
- item->name = g_strdup("unknow");
+ item->name = g_strdup("unknown");
//item->country = cur.country_name;
item->iso_code = g_strdup("XXX");
item->frac_digits = 2;
}
-
-
-
-static void
-start_element_handler (GMarkupParseContext *context, const gchar *element_name, const gchar **attribute_names,
- const gchar **attribute_values, gpointer user_data, GError **error)
+static gboolean currency_rate_update(gchar *isocode, gdouble rate, guint32 date)
{
-ParseExchangeContext *ctx = user_data;
-gint i;
-
- //DB( g_print("** start element: '%s' iso=%s\n", element_name, ctx->iso) );
-
- ctx->elt_name = element_name;
+gboolean retval = FALSE;
+Currency *cur;
- switch(element_name[0])
+ cur = da_cur_get_by_iso_code (isocode);
+ if(cur)
{
- case 'r':
- {
- if(!strcmp (element_name, "rate"))
- {
- i = 0;
- //DB( g_print(" att='%s' val='%s'\n", attribute_names[i], attribute_values[i]) );
- //we have only 1 attribute id :: store isocode pair
- if(attribute_names[i] != NULL && !strcmp (attribute_names[i], "id"))
- {
- g_stpcpy (ctx->iso, attribute_values[i]);
- }
- }
- }
- break;
+ DB( g_print(" found cur='%s'\n", cur->iso_code) );
+ cur->rate = rate;
+ cur->mdate = date;
+ GLOBALS->changes_count++;
+ retval = TRUE;
}
-}
+ return retval;
+}
-static void
-text_handler(GMarkupParseContext *context, const gchar *text, gsize text_len, gpointer user_data, GError **error)
-{
-ParseExchangeContext *ctx = user_data;
-
- if(text_len == 0)
- return;
-
- //DB( g_print("** text: '%s' %d\n", text, text_len) );
- if(!strcmp (ctx->elt_name, "Rate"))
- {
- ctx->rate = g_ascii_strtod(text, NULL);
- //DB( g_print(" stored '%s' %.2f\n", text, ctx->rate) );
- }
-}
+/* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */
+/* currency API
+ * discontinued see #1730527, #1785210
+ */
+/* real open source fixer API */
+/* DNS should be: https://frankfurter.app
+ * see https://github.com/fixerAPI/fixer/issues/107
+ */
-static void
-end_element_handler (GMarkupParseContext *context, const gchar *element_name, gpointer user_data, GError **error)
+/* old
+** api.fixer.io deprecated since 30/04/2019
+** QS: https://api.fixer.io/latest?base=EUR&symbols=USD,CHF,AUD,CAD,JPY,CNY,GBP
+**
+** test API
+** gchar fixeriojson[] =
+** "{ }";
+** " { \r \"base\" : \"EUR\", \
+** \"date\": \n\r \"2017-12-04\", \
+** \"rates\" \n\n :{\"AUD\":1.5585,\"CAD\":1.5034,\"CHF\":1.1665,\"CNY\":7.8532,\"GBP\":0.87725,\"JPY\":133.91,\"USD\":1.1865 \
+** } }";
+*/
+
+
+static gboolean api_fixerio_parse(const gchar *body, GError **error)
{
-ParseExchangeContext *ctx = user_data;
-Currency *cur;
+gchar *rawjson;
+gchar *p;
+gchar strbuf[48];
+gchar isocode[8];
+gdouble rate;
+guint32 date = GLOBALS->today;
+guint count = 0;
+
+ if(body)
+ {
+ //there is no need of a complex JSON parser here, so let's hack !
+ rawjson = g_strdup(body);
+ hb_string_inline(rawjson);
- DB( g_print("** end element: '%s'\n", element_name) );
+ DB( g_printf("\nbody: '%s'\n", rawjson ) );
- if(!strcmp (element_name, "rate"))
- {
- DB( g_print(" should store here !!\n") );
- DB( g_print(" %s %f\n", ctx->iso, ctx->rate) );
- cur = da_cur_get_by_iso_code (ctx->iso + 3);
- if(cur)
+ //get date
+ p = g_strstr_len(rawjson, -1, "\"date\"");
+ if(p)
{
- DB( g_print(" found cur='%s'\n", cur->iso_code) );
- cur->rate = ctx->rate;
- cur->mdate = GLOBALS->today;
+ strncpy(strbuf, p+8, 10);
+ strbuf[10]='\0';
+ date = hb_date_get_julian(strbuf, PRF_DATEFMT_YMD);
+ DB( g_printf("\n-date: %.10s %d\n", strbuf, date) );
}
-
- //clean all
- ctx->elt_name = NULL;
- *ctx->iso = '\0';
- ctx->rate = 0.0;
- }
-}
-
-
-static GMarkupParser hb_xchange_parser = {
- start_element_handler,
- end_element_handler,
- text_handler,
- NULL,
- NULL //cleanup
-};
-
-static gboolean currency_online_parse(const gchar *buffer, GError **error)
-{
-GMarkupParseContext *context;
-ParseExchangeContext ctx;
-gboolean retval;
+ //get rates
+ p = g_strstr_len(rawjson, -1, "\"rates\"");
+ if(p)
+ {
+ p = p+8;
+ do
+ {
+ p = hb_string_copy_jsonpair(strbuf, p);
+ strncpy(isocode, strbuf, 3);
+ isocode[3]='\0';
+ rate = g_ascii_strtod(strbuf+4, NULL);
+ DB( g_printf("\npair: '%s' '%s' %f\n", strbuf, isocode, rate ) );
+
+ if( currency_rate_update(isocode, rate, date) )
+ count++;
+ }
+ while( p != NULL );
+ }
- memset(&ctx, 0, sizeof(ParseExchangeContext));
- context = g_markup_parse_context_new (&hb_xchange_parser, 0, &ctx, NULL);
+ g_free(rawjson);
- retval = g_markup_parse_context_parse (context, buffer, -1, error);
- //retval = g_markup_parse_context_parse (context, badyahooxml, -1, error);
- g_markup_parse_context_free (context);
+ }
- return retval;
+ return( (count > 0) ? TRUE : FALSE);
}
-static gchar *currency_get_query(void)
+static gchar *api_fixerio_query_build(void)
{
GList *list;
GString *node;
Currency *item;
gint i;
-//http://query.yahooapis.com/v1/public/yql
-//?q=select * from yahoo.finance.xchange where pair in ("EURGBP","EURUSD")
-//&env=store://datatables.org/alltableswithkeys
-
- node = g_string_sized_new(1024);
- g_string_append(node, "http://query.yahooapis.com/v1/public/yql");
- g_string_append(node, "?q=select * from yahoo.finance.xchange where pair in (");
-
base = da_cur_get (GLOBALS->kcur);
+ node = g_string_sized_new(512);
+ //todo: think about encapsulate the API call ourself
+ //todo: let the user choose http / https
+ g_string_append_printf(node, "https://frankfurter.app/latest?base=%s&symbols=", base->iso_code);
+ //g_string_append_printf(node, "https://api.fixer.io/latest?base=%s&symbols=", base->iso_code);
+
list = g_hash_table_get_values(GLOBALS->h_cur);
- i = g_list_length (list) - 1;
-
+ i = g_list_length (list);
while (list != NULL)
{
item = list->data;
- if(item->key != GLOBALS->kcur)
+ if( (item->key != GLOBALS->kcur) && (strlen(item->iso_code) == 3) )
{
- g_string_append_printf(node, "\"%s%s\"", base->iso_code, item->iso_code);
+ g_string_append_printf(node, "%s", item->iso_code);
if(i > 1)
{
g_string_append(node, ",");
}
- i--;
}
+ i--;
list = g_list_next(list);
}
g_list_free(list);
- g_string_append(node, ")&env=store://datatables.org/alltableswithkeys");
-
return g_string_free(node, FALSE);
}
-gboolean currency_sync_online(GError **error)
+/* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */
+
+
+gboolean currency_online_sync(GError **error)
{
SoupSession *session;
SoupMessage *msg;
DB( g_printf("\n[currency] sync online\n") );
- query = currency_get_query();
- DB( g_printf(" - query is '%s'\n", query) );
-
+ query = api_fixerio_query_build();
+ DB( g_printf("query: '%s'\n", query) );
+
+ /*
+ //test API
+ retval = api_fixerio_parse(fixeriojson, error);
+ */
+
session = soup_session_new ();
msg = soup_message_new ("GET", query);
if(msg != NULL)
{
soup_session_send_message (session, msg);
+
DB( g_print("status_code: %d %d\n", msg->status_code, SOUP_STATUS_IS_SUCCESSFUL(msg->status_code) ) );
DB( g_print("reason: %s\n", msg->reason_phrase) );
DB( g_print("datas: %s\n", msg->response_body->data) );
if( SOUP_STATUS_IS_SUCCESSFUL(msg->status_code) == TRUE )
{
- retval = currency_online_parse(msg->response_body->data, error);
+ //#1750426 ignore the retval here (false when no rate was found, as we don't care)
+ api_fixerio_parse(msg->response_body->data, error);
}
else
{
*error = g_error_new_literal(1, msg->status_code, msg->reason_phrase);
retval = FALSE;
}
+
+ g_object_unref(msg);
}
else
{
g_free(query);
+ soup_session_abort (session);
+
+ g_object_unref(session);
+
return retval;
}
/* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */
-
//struct iso_4217_currency iso_4217_currencies[];
/*debug testing
{ "BSD", 2, ".", ",", TRUE, "$", "Bahamian Dollar" },
{ "BTN", 2, ".", ",", TRUE, "Nu.", "Ngultrum" },
{ "BWP", 2, ".", " ", TRUE, "P", "Pula" },
- { "BYR", 0, ",", " ", FALSE, "Br", "Belarussian Ruble" },
+ { "BYN", 0, ",", " ", FALSE, "Br", "Belarussian Ruble" },
+ { "BYR", 0, ",", " ", FALSE, "Br", "Old Belarussian Ruble" },
{ "BZD", 2, ".", ",", TRUE, "$", "Belize Dollar" },
{ "CAD", 2, ",", " ", TRUE, "$", "Canadian Dollar" },
{ "CDF", 2, ",", " ", TRUE, "FC", "Congolese Franc" },