X-Git-Url: https://git.dogcows.com/gitweb?p=chaz%2Fhomebank;a=blobdiff_plain;f=src%2Fhb-xml.c;h=2338e581857133d5402597ec6a0a280fc62ced50;hp=d859c3510c8353ea9e7c6b90967382a2d61d04d0;hb=996fa4ab9f6b836001f8ad0eecbfd3821687fea7;hpb=27f6e3b112df235c8e9afc9911b1f6bce208a001 diff --git a/src/hb-xml.c b/src/hb-xml.c index d859c35..2338e58 100644 --- a/src/hb-xml.c +++ b/src/hb-xml.c @@ -1,5 +1,5 @@ /* HomeBank -- Free, easy, personal accounting for everyone. - * Copyright (C) 1995-2014 Maxime DOYEN + * Copyright (C) 1995-2016 Maxime DOYEN * * This file is part of HomeBank. * @@ -23,6 +23,8 @@ #include "hb-transaction.h" #include "hb-xml.h" +#include "ui-dialogs.h" + /****************************************************************************/ /* Debug macros */ /****************************************************************************/ @@ -38,754 +40,916 @@ extern struct HomeBank *GLOBALS; extern struct Preferences *PREFS; -typedef struct _ParseContext ParseContext; -struct _ParseContext -{ - gdouble version; -}; +/* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */ -static void homebank_upgrade_to_v02(void); -static void homebank_upgrade_to_v03(void); -static void homebank_upgrade_to_v04(void); -static void homebank_upgrade_to_v05(void); -static void homebank_upgrade_lower_v06(void); -static void homebank_upgrade_to_v06(void); -static void homebank_upgrade_to_v07(void); -static void homebank_upgrade_to_v08(void); -static void -start_element_handler (GMarkupParseContext *context, - const gchar *element_name, - const gchar **attribute_names, - const gchar **attribute_values, - gpointer user_data, - GError **error) +// v0.1 to v0.2 : we must change account reference by making a +1 to its index references +static void homebank_upgrade_to_v02(void) { -ParseContext *ctx = user_data; -//GtkUIManager *self = ctx->self; -gint i, j; +GList *lst_acc, *lnk_acc; +GList *list; +GHashTable *h_old_acc; + - //DB( g_print("** start element: %s\n", element_name) ); + DB( g_print("\n[hb-xml] homebank_upgrade_to_v02\n") ); - switch(element_name[0]) + //keep old hashtable with us + h_old_acc = GLOBALS->h_acc; + da_acc_new(); + + lst_acc = g_hash_table_get_values(h_old_acc); + lnk_acc = g_list_first(lst_acc); + while (lnk_acc != NULL) { - //get file version - /* - case 'h': - { - if(!strcmp (element_name, "homebank")) - { - if(!strcmp (attribute_names[0], "v" )) - { - version = g_ascii_strtod(attribute_values[0], NULL); - DB( g_print(" version %f\n", version) ); - } + Account *acc = lnk_acc->data; - } - } - */ + acc->key++; + acc->pos++; + da_acc_insert (acc); - case 'a': + list = g_queue_peek_head_link(acc->txn_queue); + while (list != NULL) { - if(!strcmp (element_name, "account")) - { - Account *entry = da_acc_malloc(); + Transaction *entry = list->data; + entry->kacc++; + entry->kxferacc++; + list = g_list_next(list); + } + lnk_acc = g_list_next(lnk_acc); + } + g_list_free(lst_acc); - for (i = 0; attribute_names[i] != NULL; i++) - { - //DB( g_print(" att=%s val=%s\n", attribute_names[i], attribute_values[i]) ); - - if(!strcmp (attribute_names[i], "key" )) { entry->key = atoi(attribute_values[i]); } - else if(!strcmp (attribute_names[i], "flags" )) { entry->flags = atoi(attribute_values[i]); } - else if(!strcmp (attribute_names[i], "pos" )) { entry->pos = atoi(attribute_values[i]); } - else if(!strcmp (attribute_names[i], "type" )) { entry->type = atoi(attribute_values[i]); } - //else if(!strcmp (attribute_names[i], "curr" )) { entry->kcur = atoi(attribute_values[i]); } - else if(!strcmp (attribute_names[i], "name" )) { if(strcmp(attribute_values[i],"(null)") && attribute_values[i] != NULL) entry->name = g_strdup(attribute_values[i]); } - else if(!strcmp (attribute_names[i], "number" )) { if(strcmp(attribute_values[i],"(null)") && attribute_values[i] != NULL) entry->number = g_strdup(attribute_values[i]); } - else if(!strcmp (attribute_names[i], "bankname")) { if(strcmp(attribute_values[i],"(null)") && attribute_values[i] != NULL) entry->bankname = g_strdup(attribute_values[i]); } - else if(!strcmp (attribute_names[i], "initial" )) { entry->initial = g_ascii_strtod(attribute_values[i], NULL); } - else if(!strcmp (attribute_names[i], "minimum" )) { entry->minimum = g_ascii_strtod(attribute_values[i], NULL); } - else if(!strcmp (attribute_names[i], "cheque1" )) { entry->cheque1 = atoi(attribute_values[i]); } - else if(!strcmp (attribute_names[i], "cheque2" )) { entry->cheque2 = atoi(attribute_values[i]); } + //we loose some small memory here + g_hash_table_steal_all(h_old_acc); - } + list = g_list_first(GLOBALS->arc_list); + while (list != NULL) + { + Archive *entry = list->data; + entry->kacc++; + entry->kxferacc++; + list = g_list_next(list); + } +} - //version upgrade: type was added in 0.2 - //todo: for stock account - /* - if(version <= 0.1) - { - entry->type = ACC_TYPE_BANK; - DB( g_print(" acctype forced to BANK\n") ); - } - */ +// v0.2 to v0.3 : we must assume categories exists : bugs 303886, 303738 +static void homebank_upgrade_to_v03(void) +{ +GList *lst_acc, *lnk_acc; +GList *list; - DB( g_print(" version %f\n", ctx->version) ); + DB( g_print("\n[hb-xml] homebank_upgrade_to_v03\n") ); - //upgrade to v0.2 file - // we must change account reference by making a +1 to its index references - if( ctx->version == 0.1 ) - { - entry->key++; - entry->pos = entry->key; - } + lst_acc = g_hash_table_get_values(GLOBALS->h_acc); + lnk_acc = g_list_first(lst_acc); + while (lnk_acc != NULL) + { + Account *acc = lnk_acc->data; - //all attribute loaded: append - da_acc_insert(entry); - } + list = g_queue_peek_head_link(acc->txn_queue); + while (list != NULL) + { + Transaction *entry = list->data; - //assign - else if(!strcmp (element_name, "asg")) - { - Assign *entry = da_asg_malloc(); - gint exact = 0; + da_transaction_consistency(entry); + list = g_list_next(list); + } + lnk_acc = g_list_next(lnk_acc); + } + g_list_free(lst_acc); - for (i = 0; attribute_names[i] != NULL; i++) - { - //DB( g_print(" att=%s val=%s\n", attribute_names[i], attribute_values[i]) ); - - if(!strcmp (attribute_names[i], "key" )) { entry->key = atoi(attribute_values[i]); } - else if(!strcmp (attribute_names[i], "flags" )) { entry->flags = atoi(attribute_values[i]); } - else if(!strcmp (attribute_names[i], "field" )) { entry->field = atoi(attribute_values[i]); } - else if(!strcmp (attribute_names[i], "name" )) { if(strcmp(attribute_values[i],"(null)") && attribute_values[i] != NULL) entry->name = g_strdup(attribute_values[i]); } - else if(!strcmp (attribute_names[i], "payee" )) { entry->kpay = atoi(attribute_values[i]); } - else if(!strcmp (attribute_names[i], "category")) { entry->kcat = atoi(attribute_values[i]); } - //else if(!strcmp (attribute_names[i], "paymode" )) { entry->paymode = atoi(attribute_values[i]); } - // prior v08 - else if(!strcmp (attribute_names[i], "exact" )) { exact = atoi(attribute_values[i]); } - } - /* in v08 exact moved to flag */ - if( ctx->version <= 0.7) - { - entry->flags = (ASGF_DOCAT|ASGF_DOPAY); - if( exact > 0 ) - entry->flags |= ASGF_EXACT; - } + list = g_list_first(GLOBALS->arc_list); + while (list != NULL) + { + Archive *entry = list->data; - //all attribute loaded: append - da_asg_append(entry); + da_archive_consistency(entry); + list = g_list_next(list); + } +} - } +static void homebank_upgrade_to_v04(void) +{ + DB( g_print("\n[hb-xml] homebank_upgrade_to_v04\n") ); - } - break; + GLOBALS->arc_list = da_archive_sort(GLOBALS->arc_list); +} - case 'p': - { - if(!strcmp (element_name, "pay")) - { - Payee *entry = da_pay_malloc(); - for (i = 0; attribute_names[i] != NULL; i++) - { - //DB( g_print(" att=%s val=%s\n", attribute_names[i], attribute_values[i]) ); +// v0.4 to v0.5 : +// we must assume kxferacc exists in archives for internal xfer : bug 528923 +// if not, delete automation from the archive +static void homebank_upgrade_to_v05(void) +{ +GList *list; - if(!strcmp (attribute_names[i], "key" )) { entry->key = atoi(attribute_values[i]); } - //else if(!strcmp (attribute_names[i], "flags")) { entry->flags = atoi(attribute_values[i]); } - else if(!strcmp (attribute_names[i], "name" )) { entry->name = g_strdup(attribute_values[i]); } - } + DB( g_print("\n[hb-xml] homebank_upgrade_to_v05\n") ); - //all attribute loaded: append - da_pay_insert(entry); + list = g_list_first(GLOBALS->arc_list); + while (list != NULL) + { + Archive *entry = list->data; - } - else if(!strcmp (element_name, "properties")) - { - for (i = 0; attribute_names[i] != NULL; i++) - { - if(!strcmp (attribute_names[i], "title" )) { g_free(GLOBALS->owner); GLOBALS->owner = g_strdup(attribute_values[i]); } - //else if(!strcmp (attribute_names[i], "curr" )) { GLOBALS->kcur = atoi(attribute_values[i]); } - else if(!strcmp (attribute_names[i], "car_category")) { GLOBALS->vehicle_category = atoi(attribute_values[i]); } - else if(!strcmp (attribute_names[i], "auto_smode" )) { GLOBALS->auto_smode = atoi(attribute_values[i]); } - else if(!strcmp (attribute_names[i], "auto_weekday")) { GLOBALS->auto_weekday = atoi(attribute_values[i]); } - else if(!strcmp (attribute_names[i], "auto_nbdays" )) { GLOBALS->auto_nbdays = atoi(attribute_values[i]); } - } - } - } - break; + da_archive_consistency(entry); + list = g_list_next(list); + } +} - case 'c': - { - if(!strcmp (element_name, "cat")) - { - Category *entry = da_cat_malloc(); - gboolean budget; - for (i = 0; attribute_names[i] != NULL; i++) - { - //DB( g_print(" att=%s val=%s\n", attribute_names[i], attribute_values[i]) ); +// v0.5 to v0.6 : we must change kxferacc to 0 on non Xfer transactions +//#677351 +static void homebank_upgrade_to_v06(void) +{ +GList *lst_acc, *lnk_acc; +GList *list; - if(!strcmp (attribute_names[i], "key" )) { entry->key = atoi(attribute_values[i]); } - else if(!strcmp (attribute_names[i], "parent")) { entry->parent = atoi(attribute_values[i]); } - else if(!strcmp (attribute_names[i], "flags" )) { entry->flags = atoi(attribute_values[i]); } - else if(!strcmp (attribute_names[i], "name" )) { entry->name = g_strdup(attribute_values[i]); } + DB( g_print("\n[hb-xml] homebank_upgrade_to_v06\n") ); - budget = FALSE; - for(j=0;j<=12;j++) - { - gchar *tmpname; + lst_acc = g_hash_table_get_values(GLOBALS->h_acc); + lnk_acc = g_list_first(lst_acc); + while (lnk_acc != NULL) + { + Account *acc = lnk_acc->data; - tmpname = g_strdup_printf ("b%d", j); - if(!(strcmp (attribute_names[i], tmpname))) { entry->budget[j] = g_ascii_strtod(attribute_values[i], NULL); } - g_free(tmpname); + list = g_queue_peek_head_link(acc->txn_queue); + while (list != NULL) + { + Transaction *entry = list->data; + da_transaction_consistency(entry); + list = g_list_next(list); + } + lnk_acc = g_list_next(lnk_acc); + } + g_list_free(lst_acc); - if(entry->budget[j]) budget = TRUE; - } - if(budget == TRUE) - entry->flags |= GF_BUDGET; - } + list = g_list_first(GLOBALS->arc_list); + while (list != NULL) + { + Archive *entry = list->data; + da_archive_consistency(entry); + list = g_list_next(list); + } +} - //all attribute loaded: append - da_cat_insert( entry); - } -/* else if(!strcmp (element_name, "cur")) - { - Currency *entry = da_cur_malloc (); - for (i = 0; attribute_names[i] != NULL; i++) - { - //DB( g_print(" att=%s val=%s\n", attribute_names[i], attribute_values[i]) ); - - if(!strcmp (attribute_names[i], "key" )) { entry->key = atoi(attribute_values[i]); } - else if(!strcmp (attribute_names[i], "name" )) { entry->name = g_strdup(attribute_values[i]); } - else if(!strcmp (attribute_names[i], "iso" )) { entry->iso_code = g_strdup(attribute_values[i]); } - else if(!strcmp (attribute_names[i], "symb" )) { entry->symbol = g_strdup(attribute_values[i]); } - else if(!strcmp (attribute_names[i], "syprf" )) { entry->sym_prefix = atoi(attribute_values[i]); } - else if(!strcmp (attribute_names[i], "dchar" )) { entry->decimal_char = g_strdup(attribute_values[i]); } - else if(!strcmp (attribute_names[i], "gchar" )) { entry->grouping_char = g_strdup(attribute_values[i]); } - else if(!strcmp (attribute_names[i], "frac" )) { entry->frac_digits = atoi(attribute_values[i]); } - else if(!strcmp (attribute_names[i], "rate" )) { entry->rate = g_ascii_strtod(attribute_values[i], NULL); } - else if(!strcmp (attribute_names[i], "mdate ")) { entry->mdate = atoi(attribute_values[i]); } +// v0.7 AF_BUDGET deleted instead of AF_NOBUDGET +static void homebank_upgrade_to_v07(void) +{ +GList *lacc, *list; - } + DB( g_print("\n[hb-xml] homebank_upgrade_to_v07\n") ); - //all attribute loaded: append - da_cur_insert (entry); - } - */ - } - break; + lacc = list = g_hash_table_get_values(GLOBALS->h_acc); + while (list != NULL) + { + Account *acc = list->data; - case 't': + if( acc->flags & AF_OLDBUDGET ) // budget include { - if(!strcmp (element_name, "tags")) - { - Tag *entry = da_tag_malloc(); - - for (i = 0; attribute_names[i] != NULL; i++) - { - //DB( g_print(" att=%s val=%s\n", attribute_names[i], attribute_values[i]) ); - - if(!strcmp (attribute_names[i], "key" )) { entry->key = atoi(attribute_values[i]); } - //else if(!strcmp (attribute_names[i], "flags")) { entry->flags = atoi(attribute_values[i]); } - else if(!strcmp (attribute_names[i], "name" )) { entry->name = g_strdup(attribute_values[i]); } - } - - //all attribute loaded: append - da_tag_insert(entry); - - } + acc->flags &= ~(AF_OLDBUDGET); } - - case 'f': + else { - if(!strcmp (element_name, "fav")) - { - Archive *entry = da_archive_malloc(); + acc->flags |= AF_NOBUDGET; + } - for (i = 0; attribute_names[i] != NULL; i++) - { - //DB( g_print(" att=%s val=%s\n", attribute_names[i], attribute_values[i]) ); - - if(!strcmp (attribute_names[i], "amount" )) { entry->amount = g_ascii_strtod(attribute_values[i], NULL); } - else if(!strcmp (attribute_names[i], "account" )) { entry->kacc = atoi(attribute_values[i]); } - else if(!strcmp (attribute_names[i], "dst_account")) { entry->kxferacc = atoi(attribute_values[i]); } - else if(!strcmp (attribute_names[i], "paymode" )) { entry->paymode = atoi(attribute_values[i]); } - else if(!strcmp (attribute_names[i], "flags" )) { entry->flags = atoi(attribute_values[i]); } - else if(!strcmp (attribute_names[i], "payee" )) { entry->kpay = atoi(attribute_values[i]); } - else if(!strcmp (attribute_names[i], "category" )) { entry->kcat = atoi(attribute_values[i]); } - else if(!strcmp (attribute_names[i], "wording" )) { if(strcmp(attribute_values[i],"(null)") && attribute_values[i] != NULL) entry->wording = g_strdup(attribute_values[i]); } - else if(!strcmp (attribute_names[i], "nextdate" )) { entry->nextdate = atoi(attribute_values[i]); } - else if(!strcmp (attribute_names[i], "every" )) { entry->every = atoi(attribute_values[i]); } - else if(!strcmp (attribute_names[i], "unit" )) { entry->unit = atoi(attribute_values[i]); } - else if(!strcmp (attribute_names[i], "limit" )) { entry->limit = atoi(attribute_values[i]); } - else if(!strcmp (attribute_names[i], "weekend" )) { entry->weekend = atoi(attribute_values[i]); } + list = g_list_next(list); + } + g_list_free(lacc); - } +} - //all attribute loaded: append - GLOBALS->arc_list = g_list_append(GLOBALS->arc_list, entry); +static void homebank_upgrade_to_v08(void) +{ +GList *lst_acc, *lnk_acc; +GList *list; - } - } - break; + DB( g_print("\n[hb-xml] homebank_upgrade_to_v08\n") ); + + lst_acc = g_hash_table_get_values(GLOBALS->h_acc); + lnk_acc = g_list_first(lst_acc); + while (lnk_acc != NULL) + { + Account *acc = lnk_acc->data; - /* - case 'r': + list = g_queue_peek_head_link(acc->txn_queue); + while (list != NULL) { + Transaction *entry = list->data; + da_transaction_consistency(entry); + list = g_list_next(list); } - break; - */ + lnk_acc = g_list_next(lnk_acc); + } + g_list_free(lst_acc); - case 'o': - { - if(!strcmp (element_name, "ope")) - { - Transaction *entry = da_transaction_malloc(); - gchar *scat = NULL; - gchar *samt = NULL; - gchar *smem = NULL; - gboolean split = FALSE; - for (i = 0; attribute_names[i] != NULL; i++) - { - //DB( g_print(" att=%s val=%s\n", attribute_names[i], attribute_values[i]) ); - - if(!strcmp (attribute_names[i], "date" )) { entry->date = atoi(attribute_values[i]); } - else if(!strcmp (attribute_names[i], "amount" )) { entry->amount = g_ascii_strtod(attribute_values[i], NULL); } - else if(!strcmp (attribute_names[i], "account" )) { entry->kacc = atoi(attribute_values[i]); } - else if(!strcmp (attribute_names[i], "dst_account")) { entry->kxferacc = atoi(attribute_values[i]); } - else if(!strcmp (attribute_names[i], "paymode" )) { entry->paymode = atoi(attribute_values[i]); } - else if(!strcmp (attribute_names[i], "flags" )) { entry->flags = atoi(attribute_values[i]); } - else if(!strcmp (attribute_names[i], "payee" )) { entry->kpay = atoi(attribute_values[i]); } - else if(!strcmp (attribute_names[i], "category" )) { entry->kcat = atoi(attribute_values[i]); } - else if(!strcmp (attribute_names[i], "wording" )) { if(strcmp(attribute_values[i],"(null)") && attribute_values[i] != NULL) entry->wording = g_strdup(attribute_values[i]); } - else if(!strcmp (attribute_names[i], "info" )) { if(strcmp(attribute_values[i],"(null)") && attribute_values[i] != NULL) entry->info = g_strdup(attribute_values[i]); } - else if(!strcmp (attribute_names[i], "tags" )) - { - if(attribute_values[i] != NULL && strlen(attribute_values[i]) > 0 && strcmp(attribute_values[i],"(null)") != 0 ) - { - transaction_tags_parse(entry, attribute_values[i]); - } - } - else if(!strcmp (attribute_names[i], "kxfer" )) { entry->kxfer = atoi(attribute_values[i]); } - else if(!strcmp (attribute_names[i], "scat" )) { scat = (gchar *)attribute_values[i]; split = TRUE; } - else if(!strcmp (attribute_names[i], "samt" )) { samt = (gchar *)attribute_values[i]; split = TRUE; } - else if(!strcmp (attribute_names[i], "smem" )) { smem = (gchar *)attribute_values[i]; split = TRUE; } - } +} - //bugfix 303886 - //if(entry->kcat < 0) - // entry->kcat = 0; - if(split == TRUE) - { - transaction_splits_parse(entry, scat, samt, smem); - } +static void homebank_upgrade_to_v10(void) +{ +GList *lst_acc, *lnk_acc; +GList *list; - //all attribute loaded: append - // we use prepend here, the list will be reversed later for perf reason - da_transaction_prepend(entry); - } - } - break; + DB( g_print("\n[hb-xml] homebank_upgrade_to_v10\n") ); + + lst_acc = g_hash_table_get_values(GLOBALS->h_acc); + lnk_acc = g_list_first(lst_acc); + while (lnk_acc != NULL) + { + Account *acc = lnk_acc->data; + + list = g_queue_peek_head_link(acc->txn_queue); + while (list != NULL) + { + Transaction *entry = list->data; + entry->status = TXN_STATUS_NONE; + if(entry->flags & OF_OLDVALID) + entry->status = TXN_STATUS_RECONCILED; + else + if(entry->flags & OF_OLDREMIND) + entry->status = TXN_STATUS_REMIND; + //remove those flags + entry->flags &= ~(OF_OLDVALID|OF_OLDREMIND); + list = g_list_next(list); + } + lnk_acc = g_list_next(lnk_acc); } + g_list_free(lst_acc); } -/* -static void -end_element_handler (GMarkupParseContext *context, - const gchar *element_name, - gpointer user_data, - GError **error) + +static void homebank_upgrade_to_v11(void) { - ParseContext *ctx = user_data; +GList *list; - //DB( g_print("-- end element: %s\n", element_name) ); + DB( g_print("\n[hb-xml] homebank_upgrade_to_v11\n") ); + list = g_list_first(GLOBALS->arc_list); + while (list != NULL) + { + Archive *entry = list->data; + + entry->status = TXN_STATUS_NONE; + if(entry->flags & OF_OLDVALID) + entry->status = TXN_STATUS_RECONCILED; + else + if(entry->flags & OF_OLDREMIND) + entry->status = TXN_STATUS_REMIND; + + //remove those flags + entry->flags &= ~(OF_OLDVALID|OF_OLDREMIND); + + list = g_list_next(list); + } } -*/ -static GMarkupParser hb_parser = { - start_element_handler, - NULL, //end_element_handler, - NULL, //text_handler, - NULL, - NULL //cleanup -}; -/* -** XML load homebank file: hbfile -*/ -gint homebank_load_xml(gchar *filename) +// v0.6 to v0.7 : assign a default currency +static void homebank_upgrade_to_v12(void) { -gint retval; -gchar *buffer; -gsize length; -GError *error = NULL; -ParseContext ctx = { 0 }; -GMarkupParseContext *context; -gboolean rc; - - DB( g_print("\n[hb-xml] homebank_load_xml\n") ); + // set a base currency to the hbfile if not + DB( g_print("GLOBALS->kcur %d\n", GLOBALS->kcur) ); - retval = XML_OK; - if (!g_file_get_contents (filename, &buffer, &length, &error)) - { - //g_message ("%s", error->message); - retval = XML_IO_ERROR; - g_error_free (error); - } - else - { - gchar *v_buffer; - gdouble version; + ui_dialog_upgrade_choose_currency(); +} - /* v3.4 add :: prevent load of future file version */ - v_buffer = g_strstr_len(buffer, 50, " FILE_VERSION ) + lst_acc = g_hash_table_get_values(GLOBALS->h_acc); + lnk_acc = g_list_first(lst_acc); + while (lnk_acc != NULL) + { + Account *acc = lnk_acc->data; + + list = g_queue_peek_head_link(acc->txn_queue); + while (list != NULL) { - DB( g_print("- failed: version %f is not supported (max is %f)\n", version, FILE_VERSION) ); - return XML_VERSION_ERROR; + Transaction *entry = list->data; + + //also strong link internal xfer + if(entry->paymode == PAYMODE_INTXFER && entry->kxfer == 0) + { + Transaction *child = transaction_old_get_child_transfer(entry); + if(child != NULL) + { + transaction_xfer_change_to_child(entry, child); + } + } + + da_transaction_consistency(entry); + + list = g_list_next(list); } - else - { - DB( g_print("- ok : version=%.1f\n", version) ); + lnk_acc = g_list_next(lnk_acc); + } + g_list_free(lst_acc); - /* 1st: validate the file is well in utf-8 */ - DB( g_print("- ensure UTF-8\n") ); - buffer = homebank_utf8_ensure(buffer); - /* then process the buffer */ - #if MYDEBUG == 1 - GTimer *t = g_timer_new(); - g_print("- start parse\n"); - #endif + lrul = list = g_hash_table_get_values(GLOBALS->h_rul); + while (list != NULL) + { + Assign *entry = list->data; - context = g_markup_parse_context_new (&hb_parser, 0, &ctx, NULL); + cat = da_cat_get(entry->kcat); + if(cat == NULL) + { + DB( g_print(" !! fixing cat for rul: %d is unknow\n", entry->kcat) ); + entry->kcat = 0; + } - error = NULL; - rc = g_markup_parse_context_parse (context, buffer, length, &error); + pay = da_pay_get(entry->kpay); + if(pay == NULL) + { + DB( g_print(" !! fixing pay for rul: %d is unknow\n", entry->kpay) ); + entry->kpay = 0; + } - if( error ) - g_print("failed: %s\n", error->message); - if( rc == FALSE ) - { - error = NULL; - g_markup_parse_context_end_parse(context, &error); + list = g_list_next(list); + } + g_list_free(lrul); +} - if( error ) - g_print("failed: %s\n", error->message); - } - g_markup_parse_context_free (context); - g_free (buffer); +/* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */ - //reverse the glist (see g_list append idiom to perf for reason - // we use prepend and then reverse - GLOBALS->ope_list = g_list_reverse(GLOBALS->ope_list); - - DB( g_print("- end parse : %f sec\n", g_timer_elapsed(t, NULL)) ); - DB( g_timer_destroy (t) ); - /* file upgrade / bugfix */ - if( version <= 0.1 ) - homebank_upgrade_to_v02(); - if( version <= 0.2 ) - homebank_upgrade_to_v03(); - if( version <= 0.3 ) - homebank_upgrade_to_v04(); - if( version <= 0.4 ) - homebank_upgrade_to_v05(); - if( version <= 0.5 ) - { - homebank_upgrade_to_v06(); - homebank_upgrade_lower_v06(); - } - if( version <= 0.6 ) - { - homebank_upgrade_to_v07(); - hbfile_sanity_check(); - } - if( version <= 0.7 ) - homebank_upgrade_to_v08(); - if( version <= 0.8 ) - hbfile_sanity_check(); +static void homebank_load_xml_acc(ParseContext *ctx, const gchar **attribute_names, const gchar **attribute_values) +{ +Account *entry = da_acc_malloc(); +gint i; - // next ? - - } + for (i = 0; attribute_names[i] != NULL; i++) + { + //DB( g_print(" att='%s' val='%s'\n", attribute_names[i], attribute_values[i]) ); + + if(!strcmp (attribute_names[i], "key" )) { entry->key = atoi(attribute_values[i]); } + else if(!strcmp (attribute_names[i], "flags" )) { entry->flags = atoi(attribute_values[i]); } + else if(!strcmp (attribute_names[i], "pos" )) { entry->pos = atoi(attribute_values[i]); } + else if(!strcmp (attribute_names[i], "type" )) { entry->type = atoi(attribute_values[i]); } + else if(!strcmp (attribute_names[i], "curr" )) { entry->kcur = atoi(attribute_values[i]); } + else if(!strcmp (attribute_names[i], "name" )) { if(strcmp(attribute_values[i],"(null)") && attribute_values[i] != NULL) entry->name = g_strdup(attribute_values[i]); } + else if(!strcmp (attribute_names[i], "number" )) { if(strcmp(attribute_values[i],"(null)") && attribute_values[i] != NULL) entry->number = g_strdup(attribute_values[i]); } + else if(!strcmp (attribute_names[i], "bankname")) { if(strcmp(attribute_values[i],"(null)") && attribute_values[i] != NULL) entry->bankname = g_strdup(attribute_values[i]); } + else if(!strcmp (attribute_names[i], "initial" )) { entry->initial = g_ascii_strtod(attribute_values[i], NULL); } + + else if(!strcmp (attribute_names[i], "minimum" )) { entry->minimum = g_ascii_strtod(attribute_values[i], NULL); } + else if(!strcmp (attribute_names[i], "cheque1" )) { entry->cheque1 = atoi(attribute_values[i]); } + else if(!strcmp (attribute_names[i], "cheque2" )) { entry->cheque2 = atoi(attribute_values[i]); } + else if(!strcmp (attribute_names[i], "notes" )) { if(strcmp(attribute_values[i],"(null)") && attribute_values[i] != NULL) entry->notes = g_strdup(attribute_values[i]); } } - return retval; + //all attribute loaded: append + da_acc_insert(entry); } -/* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */ - -// v0.1 to v0.2 : we must change account reference by making a +1 to its index references -static void homebank_upgrade_to_v02(void) +static void homebank_load_xml_asg(ParseContext *ctx, const gchar **attribute_names, const gchar **attribute_values) { -GList *list; - - DB( g_print("\n[hb-xml] homebank_upgrade_to_v02\n") ); +Assign *entry = da_asg_malloc(); +gint exact = 0; +gint i; - list = g_list_first(GLOBALS->ope_list); - while (list != NULL) + for (i = 0; attribute_names[i] != NULL; i++) { - Transaction *entry = list->data; - entry->kacc++; - entry->kxferacc++; - list = g_list_next(list); + //DB( g_print(" att='%s' val='%s'\n", attribute_names[i], attribute_values[i]) ); + + if(!strcmp (attribute_names[i], "key" )) { entry->key = atoi(attribute_values[i]); } + else if(!strcmp (attribute_names[i], "flags" )) { entry->flags = atoi(attribute_values[i]); } + else if(!strcmp (attribute_names[i], "field" )) { entry->field = atoi(attribute_values[i]); } + else if(!strcmp (attribute_names[i], "name" )) { if(strcmp(attribute_values[i],"(null)") && attribute_values[i] != NULL) entry->text = g_strdup(attribute_values[i]); } + else if(!strcmp (attribute_names[i], "payee" )) { entry->kpay = atoi(attribute_values[i]); } + else if(!strcmp (attribute_names[i], "category")) { entry->kcat = atoi(attribute_values[i]); } + else if(!strcmp (attribute_names[i], "paymode" )) { entry->paymode = atoi(attribute_values[i]); } + // prior v08 + else if(!strcmp (attribute_names[i], "exact" )) { exact = atoi(attribute_values[i]); } } - list = g_list_first(GLOBALS->arc_list); - while (list != NULL) + /* in v08 exact moved to flag */ + if( ctx->file_version <= 0.7) { - Archive *entry = list->data; - entry->kacc++; - entry->kxferacc++; - list = g_list_next(list); + entry->flags = (ASGF_DOCAT|ASGF_DOPAY); + if( exact > 0 ) + entry->flags |= ASGF_EXACT; } + + //all attribute loaded: append + da_asg_append(entry); + } -// v0.2 to v0.3 : we must assume categories exists : bugs 303886, 303738 -static void homebank_upgrade_to_v03(void) + +static void homebank_load_xml_pay(ParseContext *ctx, const gchar **attribute_names, const gchar **attribute_values) { -GList *list; +Payee *entry = da_pay_malloc(); +gint i; - DB( g_print("\n[hb-xml] homebank_upgrade_to_v03\n") ); - - list = g_list_first(GLOBALS->ope_list); - while (list != NULL) + for (i = 0; attribute_names[i] != NULL; i++) { - Transaction *entry = list->data; + //DB( g_print(" att='%s' val='%s'\n", attribute_names[i], attribute_values[i]) ); - da_transaction_consistency(entry); - list = g_list_next(list); + if(!strcmp (attribute_names[i], "key" )) { entry->key = atoi(attribute_values[i]); } + //else if(!strcmp (attribute_names[i], "flags")) { entry->flags = atoi(attribute_values[i]); } + else if(!strcmp (attribute_names[i], "name" )) { entry->name = g_strdup(attribute_values[i]); } + else if(!strcmp (attribute_names[i], "category")) { entry->kcat = atoi(attribute_values[i]); } + else if(!strcmp (attribute_names[i], "paymode" )) { entry->paymode = atoi(attribute_values[i]); } } - list = g_list_first(GLOBALS->arc_list); - while (list != NULL) - { - Archive *entry = list->data; + //all attribute loaded: append + da_pay_insert(entry); +} - da_archive_consistency(entry); - list = g_list_next(list); + +static void homebank_load_xml_prop(ParseContext *ctx, const gchar **attribute_names, const gchar **attribute_values) +{ +gint i; + + for (i = 0; attribute_names[i] != NULL; i++) + { + if(!strcmp (attribute_names[i], "title" )) { g_free(GLOBALS->owner); GLOBALS->owner = g_strdup(attribute_values[i]); } + else if(!strcmp (attribute_names[i], "curr" )) { GLOBALS->kcur = atoi(attribute_values[i]); } + else if(!strcmp (attribute_names[i], "car_category")) { GLOBALS->vehicle_category = atoi(attribute_values[i]); } + else if(!strcmp (attribute_names[i], "auto_smode" )) { GLOBALS->auto_smode = atoi(attribute_values[i]); } + else if(!strcmp (attribute_names[i], "auto_weekday")) { GLOBALS->auto_weekday = atoi(attribute_values[i]); } + else if(!strcmp (attribute_names[i], "auto_nbdays" )) { GLOBALS->auto_nbdays = atoi(attribute_values[i]); } } } -static void homebank_upgrade_to_v04(void) + +static void homebank_load_xml_cat(ParseContext *ctx, const gchar **attribute_names, const gchar **attribute_values) { - DB( g_print("\n[hb-xml] homebank_upgrade_to_v04\n") ); +Category *entry = da_cat_malloc(); +gboolean budget; +gint i, j; - GLOBALS->arc_list = da_archive_sort(GLOBALS->arc_list); + for (i = 0; attribute_names[i] != NULL; i++) + { + //DB( g_print(" att='%s' val='%s'\n", attribute_names[i], attribute_values[i]) ); + + if(!strcmp (attribute_names[i], "key" )) { entry->key = atoi(attribute_values[i]); } + else if(!strcmp (attribute_names[i], "parent")) { entry->parent = atoi(attribute_values[i]); } + else if(!strcmp (attribute_names[i], "flags" )) { entry->flags = atoi(attribute_values[i]); } + else if(!strcmp (attribute_names[i], "name" )) { entry->name = g_strdup(attribute_values[i]); } + + budget = FALSE; + for(j=0;j<=12;j++) + { + gchar *tmpname; + + tmpname = g_strdup_printf ("b%d", j); + if(!(strcmp (attribute_names[i], tmpname))) { entry->budget[j] = g_ascii_strtod(attribute_values[i], NULL); } + g_free(tmpname); + + if(entry->budget[j]) budget = TRUE; + } + if(budget == TRUE) + entry->flags |= GF_BUDGET; + + } + + //all attribute loaded: append + da_cat_insert( entry); } -// v0.4 to v0.5 : -// we must assume kxferacc exists in archives for internal xfer : bug 528923 -// if not, remove automation from the archive -static void homebank_upgrade_to_v05(void) +static void homebank_load_xml_cur(ParseContext *ctx, const gchar **attribute_names, const gchar **attribute_values) { -GList *list; +Currency *entry = da_cur_malloc (); +gint i; - DB( g_print("\n[hb-xml] homebank_upgrade_to_v05\n") ); + for (i = 0; attribute_names[i] != NULL; i++) + { + //DB( g_print(" att='%s' val='%s'\n", attribute_names[i], attribute_values[i]) ); + + if(!strcmp (attribute_names[i], "key" )) { entry->key = atoi(attribute_values[i]); } + else if(!strcmp (attribute_names[i], "name" )) { entry->name = g_strdup(attribute_values[i]); } + else if(!strcmp (attribute_names[i], "iso" )) { entry->iso_code = g_strdup(attribute_values[i]); } + else if(!strcmp (attribute_names[i], "symb" )) { entry->symbol = g_strdup(attribute_values[i]); } + else if(!strcmp (attribute_names[i], "syprf" )) { entry->sym_prefix = atoi(attribute_values[i]); } + else if(!strcmp (attribute_names[i], "dchar" )) { entry->decimal_char = g_strdup(attribute_values[i]); } + else if(!strcmp (attribute_names[i], "gchar" )) { entry->grouping_char = g_strdup(attribute_values[i]); } + else if(!strcmp (attribute_names[i], "frac" )) { entry->frac_digits = atoi(attribute_values[i]); } + else if(!strcmp (attribute_names[i], "rate" )) { entry->rate = g_ascii_strtod(attribute_values[i], NULL); } + else if(!strcmp (attribute_names[i], "mdate ")) { entry->mdate = atoi(attribute_values[i]); } - list = g_list_first(GLOBALS->arc_list); - while (list != NULL) + } + + //all attribute loaded: append + da_cur_insert (entry); +} + + +static void homebank_load_xml_tag(ParseContext *ctx, const gchar **attribute_names, const gchar **attribute_values) +{ +Tag *entry = da_tag_malloc(); +gint i; + + for (i = 0; attribute_names[i] != NULL; i++) { - Archive *entry = list->data; + //DB( g_print(" att='%s' val='%s'\n", attribute_names[i], attribute_values[i]) ); - da_archive_consistency(entry); - list = g_list_next(list); + if(!strcmp (attribute_names[i], "key" )) { entry->key = atoi(attribute_values[i]); } + //else if(!strcmp (attribute_names[i], "flags")) { entry->flags = atoi(attribute_values[i]); } + else if(!strcmp (attribute_names[i], "name" )) { entry->name = g_strdup(attribute_values[i]); } } + + //all attribute loaded: append + da_tag_insert(entry); } -// v0.5 to v0.6 : we must change kxferacc to 0 on non Xfer transactions -//#677351 -static void homebank_upgrade_to_v06(void) +static void homebank_load_xml_fav(ParseContext *ctx, const gchar **attribute_names, const gchar **attribute_values) { -GList *list; +Archive *entry = da_archive_malloc(); +gchar *scat = NULL; +gchar *samt = NULL; +gchar *smem = NULL; +gboolean split = FALSE; +gint i; + + for (i = 0; attribute_names[i] != NULL; i++) + { + //DB( g_print(" att='%s' val='%s'\n", attribute_names[i], attribute_values[i]) ); + + if(!strcmp (attribute_names[i], "amount" )) { entry->amount = g_ascii_strtod(attribute_values[i], NULL); } + else if(!strcmp (attribute_names[i], "account" )) { entry->kacc = atoi(attribute_values[i]); } + else if(!strcmp (attribute_names[i], "dst_account")) { entry->kxferacc = atoi(attribute_values[i]); } + else if(!strcmp (attribute_names[i], "paymode" )) { entry->paymode = atoi(attribute_values[i]); } + else if(!strcmp (attribute_names[i], "st" )) { entry->status = atoi(attribute_values[i]); } + else if(!strcmp (attribute_names[i], "flags" )) { entry->flags = atoi(attribute_values[i]); } + else if(!strcmp (attribute_names[i], "payee" )) { entry->kpay = atoi(attribute_values[i]); } + else if(!strcmp (attribute_names[i], "category" )) { entry->kcat = atoi(attribute_values[i]); } + else if(!strcmp (attribute_names[i], "wording" )) { if(strcmp(attribute_values[i],"(null)") && attribute_values[i] != NULL) entry->wording = g_strdup(attribute_values[i]); } + else if(!strcmp (attribute_names[i], "nextdate" )) { entry->nextdate = atoi(attribute_values[i]); } + else if(!strcmp (attribute_names[i], "every" )) { entry->every = atoi(attribute_values[i]); } + else if(!strcmp (attribute_names[i], "unit" )) { entry->unit = atoi(attribute_values[i]); } + else if(!strcmp (attribute_names[i], "limit" )) { entry->limit = atoi(attribute_values[i]); } + else if(!strcmp (attribute_names[i], "weekend" )) { entry->weekend = atoi(attribute_values[i]); } + else if(!strcmp (attribute_names[i], "scat" )) { scat = (gchar *)attribute_values[i]; split = TRUE; } + else if(!strcmp (attribute_names[i], "samt" )) { samt = (gchar *)attribute_values[i]; split = TRUE; } + else if(!strcmp (attribute_names[i], "smem" )) { smem = (gchar *)attribute_values[i]; split = TRUE; } - DB( g_print("\n[hb-xml] homebank_upgrade_to_v06\n") ); + } - list = g_list_first(GLOBALS->ope_list); - while (list != NULL) + if(split == TRUE) { - Transaction *entry = list->data; - da_transaction_consistency(entry); - list = g_list_next(list); + if (da_splits_parse(entry->splits, scat, samt, smem) > 0) + { + entry->flags |= OF_SPLIT; //Flag that Splits are active + } } - list = g_list_first(GLOBALS->arc_list); - while (list != NULL) + //all attribute loaded: append + GLOBALS->arc_list = g_list_append(GLOBALS->arc_list, entry); +} + + +static void homebank_load_xml_ope(ParseContext *ctx, const gchar **attribute_names, const gchar **attribute_values) +{ +Transaction *entry = da_transaction_malloc(); +gchar *scat = NULL; +gchar *samt = NULL; +gchar *smem = NULL; +gboolean split = FALSE; +gint i; + + for (i = 0; attribute_names[i] != NULL; i++) { - Archive *entry = list->data; - da_archive_consistency(entry); - list = g_list_next(list); + //DB( g_print(" att='%s' val='%s'\n", attribute_names[i], attribute_values[i]) ); + + if(!strcmp (attribute_names[i], "date" )) { entry->date = atoi(attribute_values[i]); } + else if(!strcmp (attribute_names[i], "amount" )) { entry->amount = g_ascii_strtod(attribute_values[i], NULL); } + else if(!strcmp (attribute_names[i], "account" )) { entry->kacc = atoi(attribute_values[i]); } + else if(!strcmp (attribute_names[i], "dst_account")) { entry->kxferacc = atoi(attribute_values[i]); } + else if(!strcmp (attribute_names[i], "paymode" )) { entry->paymode = atoi(attribute_values[i]); } + else if(!strcmp (attribute_names[i], "st" )) { entry->status = atoi(attribute_values[i]); } + else if(!strcmp (attribute_names[i], "flags" )) { entry->flags = atoi(attribute_values[i]); } + else if(!strcmp (attribute_names[i], "payee" )) { entry->kpay = atoi(attribute_values[i]); } + else if(!strcmp (attribute_names[i], "category" )) { entry->kcat = atoi(attribute_values[i]); } + else if(!strcmp (attribute_names[i], "wording" )) { if(strcmp(attribute_values[i],"(null)") && attribute_values[i] != NULL) entry->wording = g_strdup(attribute_values[i]); } + else if(!strcmp (attribute_names[i], "info" )) { if(strcmp(attribute_values[i],"(null)") && attribute_values[i] != NULL) entry->info = g_strdup(attribute_values[i]); } + else if(!strcmp (attribute_names[i], "tags" )) + { + if(attribute_values[i] != NULL && strlen(attribute_values[i]) > 0 && strcmp(attribute_values[i],"(null)") != 0 ) + { + transaction_tags_parse(entry, attribute_values[i]); + } + } + else if(!strcmp (attribute_names[i], "kxfer" )) { entry->kxfer = atoi(attribute_values[i]); } + else if(!strcmp (attribute_names[i], "scat" )) { scat = (gchar *)attribute_values[i]; split = TRUE; } + else if(!strcmp (attribute_names[i], "samt" )) { samt = (gchar *)attribute_values[i]; split = TRUE; } + else if(!strcmp (attribute_names[i], "smem" )) { smem = (gchar *)attribute_values[i]; split = TRUE; } } + + //bugfix 303886 + //if(entry->kcat < 0) + // entry->kcat = 0; + + if(split == TRUE) + { + if (da_splits_parse(entry->splits, scat, samt, smem) > 0) + { + entry->flags |= OF_SPLIT; //Flag that Splits are active + } + } + + //all attribute loaded: append + // we use prepend here, the list will be reversed later for perf reason + da_transaction_prepend(entry); } -// v0.7 AF_BUDGET removed instead of AF_NOBUDGET -static void homebank_upgrade_to_v07(void) + + +static void +start_element_handler (GMarkupParseContext *context, + const gchar *element_name, + const gchar **attribute_names, + const gchar **attribute_values, + gpointer user_data, + GError **error) { -GList *lacc, *list; +ParseContext *ctx = user_data; +//GtkUIManager *self = ctx->self; - DB( g_print("\n[hb-xml] homebank_upgrade_to_v07\n") ); + //DB( g_print("** start element: %s\n", element_name) ); - lacc = list = g_hash_table_get_values(GLOBALS->h_acc); - while (list != NULL) + switch(element_name[0]) { - Account *acc = list->data; + case 'a': + { + if(!strcmp (element_name, "account")) //account + { + homebank_load_xml_acc(ctx, attribute_names, attribute_values); + } + else if(!strcmp (element_name, "asg")) //assign + { + homebank_load_xml_asg(ctx, attribute_names, attribute_values); + } + } + break; - if( acc->flags & AF_OLDBUDGET ) // budget include + case 'p': { - acc->flags &= ~(AF_OLDBUDGET); + if(!strcmp (element_name, "pay")) + { + homebank_load_xml_pay(ctx, attribute_names, attribute_values); + } + else if(!strcmp (element_name, "properties")) + { + homebank_load_xml_prop(ctx, attribute_names, attribute_values); + } } - else + break; + + case 'c': { - acc->flags |= AF_NOBUDGET; + if(!strcmp (element_name, "cat")) + { + homebank_load_xml_cat(ctx, attribute_names, attribute_values); + } + else if(!strcmp (element_name, "cur")) + { + homebank_load_xml_cur(ctx, attribute_names, attribute_values); + } } + break; - list = g_list_next(list); + case 't': + { + if(!strcmp (element_name, "tags")) + { + homebank_load_xml_tag(ctx, attribute_names, attribute_values); + } + } + + case 'f': + { + if(!strcmp (element_name, "fav")) + { + homebank_load_xml_fav(ctx, attribute_names, attribute_values); + } + } + break; + + case 'o': + { + if(!strcmp (element_name, "ope")) + { + homebank_load_xml_ope(ctx, attribute_names, attribute_values); + } + } + break; } - g_list_free(lacc); +} + + +/* +static void +end_element_handler (GMarkupParseContext *context, + const gchar *element_name, + gpointer user_data, + GError **error) +{ + ParseContext *ctx = user_data; + + //DB( g_print("-- end element: %s\n", element_name) ); + } +*/ -static void homebank_upgrade_to_v08(void) +static GMarkupParser hb_parser = { + start_element_handler, + NULL, //end_element_handler, + NULL, //text_handler, + NULL, + NULL //cleanup +}; + + +static gboolean hb_xml_get_version(ParseContext *ctx, gchar *buffer) { -GList *list; +gchar *v_buffer; - DB( g_print("\n[hb-xml] homebank_upgrade_to_v08\n") ); + ctx->file_version = 0.0; + ctx->data_version = 0; - list = g_list_first(GLOBALS->ope_list); - while (list != NULL) - { - Transaction *entry = list->data; - da_transaction_consistency(entry); - list = g_list_next(list); - } + /* v3.4 add :: prevent load of future file version */ + v_buffer = g_strstr_len(buffer, 50, "file_version = g_ascii_strtod(v_buffer+13, NULL); /* a little hacky, but works ! */ + if( ctx->file_version == 0.0 ) + ctx->file_version = 0.1; + else if( ctx->file_version == 5.0 ) //was a mistake + ctx->file_version = 1.0; + + v_buffer = g_strstr_len(buffer+13, 50, "d="); + if( v_buffer ) + { + DB( g_print(" d=%s)\n\n", v_buffer) ); + + ctx->data_version = atoi(v_buffer+3); + } + return TRUE; } -// v0.6 to v0.7 : assign a default currency /* -static void homebank_upgrade_to_v08(void) +** XML load homebank file: hbfile +*/ +gint homebank_load_xml(gchar *filename) { +gint retval; +gchar *buffer; +gsize length; +GError *error = NULL; +ParseContext ctx; +GMarkupParseContext *context; +gboolean rc; + + DB( g_print("\n[hb-xml] homebank_load_xml\n") ); + + retval = XML_OK; + if (!g_file_get_contents (filename, &buffer, &length, &error)) + { + //g_message ("%s", error->message); + retval = XML_IO_ERROR; + g_error_free (error); + } + else + { + if( hb_xml_get_version(&ctx, buffer) == FALSE ) + { + return XML_FILE_ERROR; + } - // set a base currency to the hbfile if not - g_print("GLOBALS->kcur %d\n", GLOBALS->kcur); + if( ctx.file_version > FILE_VERSION ) + { + DB( g_print("- failed: version %f is not supported (max is %f)\n", ctx.file_version, FILE_VERSION) ); + return XML_VERSION_ERROR; + } + else + { + DB( g_print("- file ok : v=%.1f data_v=%06d\n", ctx.file_version, ctx.data_version) ); - if(GLOBALS->kcur == 0) - { - //struct iso4217format *choice = ui_cur_select_dialog_new(GLOBALS->mainwindow); - struct iso4217format *curfmt = iso4217format_get(PREFS->curr_default); + /* 1st: validate the file is well in utf-8 */ + DB( g_print("- ensure UTF-8\n") ); + buffer = homebank_utf8_ensure(buffer); - if(curfmt == NULL) - curfmt = iso4217format_get_en_us(); - - - Currency *item = currency_add_from_user(curfmt); + /* then process the buffer */ + #if MYDEBUG == 1 + GTimer *t = g_timer_new(); + g_print("- start parse\n"); + #endif - GLOBALS->kcur = item->key; + context = g_markup_parse_context_new (&hb_parser, 0, &ctx, NULL); - g_print("GLOBALS->kcur %d\n", GLOBALS->kcur); + error = NULL; + rc = g_markup_parse_context_parse (context, buffer, length, &error); - // set every accounts to base currecny - GList *list = g_hash_table_get_values(GLOBALS->h_acc); - while (list != NULL) - { - Account *acc; - acc = list->data; + if( error ) + g_print("failed: %s\n", error->message); - acc->kcur = item->key; + if( rc == FALSE ) + { + error = NULL; + g_markup_parse_context_end_parse(context, &error); - list = g_list_next(list); + if( error ) + g_print("failed: %s\n", error->message); } - g_list_free(list); - - - } -} -*/ - - -// lower v0.6 : we must assume categories/payee exists -// and strong link to xfer -// #632496 -static void homebank_upgrade_lower_v06(void) -{ -Category *cat; -Payee *pay; -GList *lrul, *list; - DB( g_print("\n[hb-xml] homebank_upgrade_lower_v06\n") ); - - list = g_list_first(GLOBALS->ope_list); - while (list != NULL) - { - Transaction *entry = list->data; + g_markup_parse_context_free (context); + g_free (buffer); - da_transaction_consistency(entry); + DB( g_print("- end parse : %f sec\n", g_timer_elapsed(t, NULL)) ); + DB( g_timer_destroy (t) ); - //also strong link internal xfer - if(entry->paymode == PAYMODE_INTXFER) - { - Transaction *child = transaction_old_get_child_transfer(entry); - if(child != NULL) + /* file upgrade / bugfix */ + if( ctx.file_version <= 0.1 ) + homebank_upgrade_to_v02(); + if( ctx.file_version <= 0.2 ) + homebank_upgrade_to_v03(); + if( ctx.file_version <= 0.3 ) + homebank_upgrade_to_v04(); + if( ctx.file_version <= 0.4 ) + homebank_upgrade_to_v05(); + if( ctx.file_version <= 0.5 ) { - transaction_xfer_change_to_child(entry, child); + homebank_upgrade_to_v06(); + homebank_upgrade_lower_v06(); + } + if( ctx.file_version <= 0.6 ) + { + homebank_upgrade_to_v07(); + hbfile_sanity_check(); + } + if( ctx.file_version <= 0.7 ) // <= 4.5 + { + homebank_upgrade_to_v08(); + } + if( ctx.file_version <= 0.8 ) // <= 4.6 + { + hbfile_sanity_check(); + } + if( ctx.file_version <= 0.9 ) // <= 4.6.3 + { + hbfile_sanity_check(); + homebank_upgrade_to_v10(); + } + if( ctx.file_version <= 1.0 ) // <= 5.0.0 + { + hbfile_sanity_check(); + homebank_upgrade_to_v11(); + } + //starting 5.0.4 data upgrade is done without changing file_version + if( ctx.data_version < 050005 ) // <= 5.0.5 + { + hbfile_sanity_check(); + } + if( ctx.file_version <= 1.1 ) // <= 5.1.0 + { + hbfile_sanity_check(); + homebank_upgrade_to_v12(); } - } - - list = g_list_next(list); - } - - - lrul = list = g_hash_table_get_values(GLOBALS->h_rul); - while (list != NULL) - { - Assign *entry = list->data; - - cat = da_cat_get(entry->kcat); - if(cat == NULL) - { - DB( g_print(" !! fixing cat for rul: %d is unknow\n", entry->kcat) ); - entry->kcat = 0; - } - pay = da_pay_get(entry->kpay); - if(pay == NULL) - { - DB( g_print(" !! fixing pay for rul: %d is unknow\n", entry->kpay) ); - entry->kpay = 0; + // next ? + } - - - list = g_list_next(list); } - g_list_free(lrul); - + return retval; } + /* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */ /* @@ -801,6 +965,79 @@ static void hb_xml_append_txt(GString *gstring, gchar *attrname, gchar *value) } } +static void +append_escaped_text (GString *str, + const gchar *text, + gssize length) +{ + const gchar *p; + const gchar *end; + gunichar c; + + p = text; + end = text + length; + + while (p < end) + { + const gchar *next; + next = g_utf8_next_char (p); + + switch (*p) + { + case '&': + g_string_append (str, "&"); + break; + + case '<': + g_string_append (str, "<"); + break; + + case '>': + g_string_append (str, ">"); + break; + + case '\'': + g_string_append (str, "'"); + break; + + case '"': + g_string_append (str, """); + break; + + default: + c = g_utf8_get_char (p); + if ((0x1 <= c && c <= 0x8) || + (0xa <= c && c <= 0xd) || //chnaged here from b<->c to a<->d + (0xe <= c && c <= 0x1f) || + (0x7f <= c && c <= 0x84) || + (0x86 <= c && c <= 0x9f)) + g_string_append_printf (str, "&#x%x;", c); + else + g_string_append_len (str, p, next - p); + break; + } + + p = next; + } +} + +// we override g_markup_escape_text from glib to encode \n (LF) & \r (CR) +static void hb_xml_append_txt_crlf(GString *gstring, gchar *attrname, gchar *value) +{ + if(value != NULL && *value != 0) + { + gssize length; + GString *escaped; + + //gchar *escaped = g_markup_escape_text(value, -1); + length = strlen (value); + escaped = g_string_sized_new (length); + append_escaped_text (escaped, value, length); + g_string_append_printf(gstring, "%s=\"%s\" ", attrname, escaped->str); + g_string_free (escaped, TRUE); + } +} + static void hb_xml_append_int0(GString *gstring, gchar *attrname, guint32 value) { g_string_append_printf(gstring, "%s=\"%d\" ", attrname, value); @@ -824,13 +1061,18 @@ char buf[G_ASCII_DTOSTR_BUF_SIZE]; } +/* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */ + + /* ** XML properties save */ -static void homebank_save_xml_prop(GIOChannel *io) +static gint homebank_save_xml_prop(GIOChannel *io) { gchar *title; GString *node; +gint retval = XML_OK; +GError *error = NULL; title = GLOBALS->owner == NULL ? "" : GLOBALS->owner; @@ -839,6 +1081,7 @@ GString *node; g_string_assign(node, "kcur); hb_xml_append_int(node, "car_category", GLOBALS->vehicle_category); hb_xml_append_int0(node, "auto_smode", GLOBALS->auto_smode); hb_xml_append_int(node, "auto_weekday", GLOBALS->auto_weekday); @@ -846,61 +1089,67 @@ GString *node; g_string_append(node, "/>\n"); - g_io_channel_write_chars(io, node->str, -1, NULL, NULL); + error = NULL; + g_io_channel_write_chars(io, node->str, -1, NULL, &error); + if(error) + { + retval = XML_IO_ERROR; + g_error_free(error); + } g_string_free(node, TRUE); + return retval; } /* ** XML currency save */ -/* -static void homebank_save_xml_cur(GIOChannel *io) +static gint homebank_save_xml_cur(GIOChannel *io) { GList *list; gchar *tmpstr; char buf1[G_ASCII_DTOSTR_BUF_SIZE]; +gint retval = XML_OK; list = g_hash_table_get_values(GLOBALS->h_cur); while (list != NULL) { Currency *item = list->data; - if(item->key != 0) - { - tmpstr = g_markup_printf_escaped( - "\n", - item->key, - item->iso_code, - item->name, - item->symbol, - item->sym_prefix, - item->decimal_char, - item->grouping_char, - item->frac_digits, - g_ascii_dtostr (buf1, sizeof (buf1), item->rate), - item->mdate - ); - - g_io_channel_write_chars(io, tmpstr, -1, NULL, NULL); - g_free(tmpstr); + tmpstr = g_markup_printf_escaped( + "\n", + item->key, + item->iso_code, + item->name, + item->symbol, + item->sym_prefix, + item->decimal_char, + item->grouping_char, + item->frac_digits, + g_ascii_dtostr (buf1, sizeof (buf1), item->rate), + item->mdate + ); + + g_io_channel_write_chars(io, tmpstr, -1, NULL, NULL); + g_free(tmpstr); - } list = g_list_next(list); } g_list_free(list); + return retval; } -*/ /* ** XML account save */ -static void homebank_save_xml_acc(GIOChannel *io) +static gint homebank_save_xml_acc(GIOChannel *io) { GList *lacc, *list; GString *node; +gint retval = XML_OK; +GError *error = NULL; node = g_string_sized_new(255); @@ -909,7 +1158,7 @@ GString *node; { Account *item = list->data; - item->flags &= ~(AF_ADDED|AF_CHANGED); //remove flag + item->flags &= ~(AF_ADDED|AF_CHANGED); //delete flag g_string_assign(node, "flags); hb_xml_append_int(node, "pos", item->pos); hb_xml_append_int(node, "type", item->type); - //hb_xml_append_int(node, "curr", item->kcur); + hb_xml_append_int(node, "curr", item->kcur); hb_xml_append_txt(node, "name", item->name); hb_xml_append_txt(node, "number", item->number); hb_xml_append_txt(node, "bankname", item->bankname); hb_xml_append_amt(node, "initial", item->initial); + hb_xml_append_amt(node, "minimum", item->minimum); hb_xml_append_int(node, "cheque1", item->cheque1); hb_xml_append_int(node, "cheque2", item->cheque2); + hb_xml_append_txt_crlf(node, "notes", item->notes); g_string_append(node, "/>\n"); - g_io_channel_write_chars(io, node->str, -1, NULL, NULL); + error = NULL; + g_io_channel_write_chars(io, node->str, -1, NULL, &error); + + if(error) + { + retval = XML_IO_ERROR; + g_error_free(error); + } + list = g_list_next(list); } g_list_free(lacc); g_string_free(node, TRUE); + return retval; } /* ** XML payee save */ -static void homebank_save_xml_pay(GIOChannel *io) +static gint homebank_save_xml_pay(GIOChannel *io) { GList *lpay, *list; -gchar *tmpstr; +GString *node; +gint retval = XML_OK; +GError *error = NULL; + + node = g_string_sized_new(255); lpay = list = payee_glist_sorted(0); while (list != NULL) @@ -950,29 +1214,43 @@ gchar *tmpstr; if(item->key != 0) { - tmpstr = g_markup_printf_escaped("\n", - item->key, - item->name - ); + g_string_assign(node, "key); + hb_xml_append_txt(node, "name", item->name); + hb_xml_append_int(node, "category", item->kcat); + hb_xml_append_int(node, "paymode" , item->paymode); + + g_string_append(node, "/>\n"); + + error = NULL; + g_io_channel_write_chars(io, node->str, -1, NULL, &error); + + if(error) + { + retval = XML_IO_ERROR; + g_error_free(error); + } } list = g_list_next(list); } g_list_free(lpay); + g_string_free(node, TRUE); + return retval; } /* ** XML category save */ -static void homebank_save_xml_cat(GIOChannel *io) +static gint homebank_save_xml_cat(GIOChannel *io) { GList *lcat, *list; GString *node; char buf[G_ASCII_DTOSTR_BUF_SIZE]; guint i; +gint retval = XML_OK; +GError *error = NULL; node = g_string_sized_new(255); @@ -999,22 +1277,33 @@ guint i; } g_string_append(node, "/>\n"); - g_io_channel_write_chars(io, node->str, -1, NULL, NULL); + + error = NULL; + g_io_channel_write_chars(io, node->str, -1, NULL, &error); + + if(error) + { + retval = XML_IO_ERROR; + g_error_free(error); + } } list = g_list_next(list); } g_list_free(lcat); g_string_free(node, TRUE); + return retval; } /* ** XML tag save */ -static void homebank_save_xml_tag(GIOChannel *io) +static gint homebank_save_xml_tag(GIOChannel *io) { GList *ltag, *list; gchar *tmpstr; +gint retval = XML_OK; +GError *error = NULL; ltag = list = tag_glist_sorted(0); while (list != NULL) @@ -1023,28 +1312,37 @@ gchar *tmpstr; if(item->key != 0) { - tmpstr = g_markup_printf_escaped("\n", + tmpstr = g_markup_printf_escaped("\n", item->key, item->name ); - g_io_channel_write_chars(io, tmpstr, -1, NULL, NULL); + error = NULL; + g_io_channel_write_chars(io, tmpstr, -1, NULL, &error); g_free(tmpstr); - + + if(error) + { + retval = XML_IO_ERROR; + g_error_free(error); + } } list = g_list_next(list); } g_list_free(ltag); + return retval; } /* ** XML assign save */ -static void homebank_save_xml_asg(GIOChannel *io) +static gint homebank_save_xml_asg(GIOChannel *io) { GList *lasg, *list; GString *node; +gint retval = XML_OK; +GError *error = NULL; node = g_string_sized_new(255); @@ -1058,19 +1356,27 @@ GString *node; hb_xml_append_int(node, "key" , item->key); hb_xml_append_int(node, "flags" , item->flags); hb_xml_append_int(node, "field" , item->field); - hb_xml_append_txt(node, "name" , item->name); + hb_xml_append_txt(node, "name" , item->text); hb_xml_append_int(node, "payee" , item->kpay); hb_xml_append_int(node, "category", item->kcat); - //hb_xml_append_int(node, "paymode" , item->paymode); + hb_xml_append_int(node, "paymode" , item->paymode); g_string_append(node, "/>\n"); - g_io_channel_write_chars(io, node->str, -1, NULL, NULL); + error = NULL; + g_io_channel_write_chars(io, node->str, -1, NULL, &error); + + if(error) + { + retval = XML_IO_ERROR; + g_error_free(error); + } list = g_list_next(list); } g_list_free(lasg); g_string_free(node, TRUE); + return retval; } @@ -1078,10 +1384,12 @@ GString *node; /* ** XML archive save */ -static void homebank_save_xml_arc(GIOChannel *io) +static gint homebank_save_xml_arc(GIOChannel *io) { GList *list; GString *node; +gint retval = XML_OK; +GError *error = NULL; node = g_string_sized_new(255); @@ -1096,6 +1404,7 @@ GString *node; hb_xml_append_int(node, "account", item->kacc); hb_xml_append_int(node, "dst_account", item->kxferacc); hb_xml_append_int(node, "paymode", item->paymode); + hb_xml_append_int(node, "st", item->status); hb_xml_append_int(node, "flags", item->flags); hb_xml_append_int(node, "payee", item->kpay); hb_xml_append_int(node, "category", item->kcat); @@ -1106,74 +1415,125 @@ GString *node; hb_xml_append_int(node, "limit", item->limit); hb_xml_append_int(node, "weekend", item->weekend); + if(da_splits_count(item->splits) > 0) + { + gchar *cats, *amounts, *memos; + + da_splits_tostring(item->splits, &cats, &amounts, &memos); + g_string_append_printf(node, "scat=\"%s\" ", cats); + g_string_append_printf(node, "samt=\"%s\" ", amounts); + + //fix #1173910 + gchar *escaped = g_markup_escape_text(memos, -1); + g_string_append_printf(node, "smem=\"%s\" ", escaped); + g_free(escaped); + + g_free(cats); + g_free(amounts); + g_free(memos); + } + g_string_append(node, "/>\n"); - g_io_channel_write_chars(io, node->str, -1, NULL, NULL); + error = NULL; + g_io_channel_write_chars(io, node->str, -1, NULL, &error); + if(error) + { + retval = XML_IO_ERROR; + g_error_free(error); + } + list = g_list_next(list); } g_string_free(node, TRUE); + return retval; } /* ** XML transaction save */ -static void homebank_save_xml_ope(GIOChannel *io) +static gint homebank_save_xml_ope(GIOChannel *io) { +GList *lst_acc, *lnk_acc; GList *list; GString *node; gchar *tagstr; +gint retval = XML_OK; +GError *error = NULL; node = g_string_sized_new(255); - list = g_list_first(GLOBALS->ope_list); - while (list != NULL) + lst_acc = g_hash_table_get_values(GLOBALS->h_acc); + lnk_acc = g_list_first(lst_acc); + while (lnk_acc != NULL) { - Transaction *item = list->data; + Account *acc = lnk_acc->data; - item->flags &= ~(OF_AUTO|OF_ADDED|OF_CHANGED); //remove flag - tagstr = transaction_tags_tostring(item); + list = g_queue_peek_head_link(acc->txn_queue); + while (list != NULL) + { + Transaction *item = list->data; - g_string_assign(node, "date); - hb_xml_append_amt(node, "amount", item->amount); - hb_xml_append_int(node, "account", item->kacc); - hb_xml_append_int(node, "dst_account", item->kxferacc); - hb_xml_append_int(node, "paymode", item->paymode); - hb_xml_append_int(node, "flags", item->flags); - hb_xml_append_int(node, "payee", item->kpay); - hb_xml_append_int(node, "category", item->kcat); - hb_xml_append_txt(node, "wording", item->wording); - hb_xml_append_txt(node, "info", item->info); - hb_xml_append_txt(node, "tags", tagstr); - hb_xml_append_int(node, "kxfer", item->kxfer); + item->flags &= ~(OF_AUTO|OF_ADDED|OF_CHANGED); //delete flag + tagstr = transaction_tags_tostring(item); - if(da_transaction_splits_count(item) > 0) + g_string_assign(node, "date); + hb_xml_append_amt(node, "amount", item->amount); + hb_xml_append_int(node, "account", item->kacc); + hb_xml_append_int(node, "dst_account", item->kxferacc); + hb_xml_append_int(node, "paymode", item->paymode); + hb_xml_append_int(node, "st", item->status); + hb_xml_append_int(node, "flags", item->flags); + hb_xml_append_int(node, "payee", item->kpay); + hb_xml_append_int(node, "category", item->kcat); + hb_xml_append_txt(node, "wording", item->wording); + hb_xml_append_txt(node, "info", item->info); + hb_xml_append_txt(node, "tags", tagstr); + hb_xml_append_int(node, "kxfer", item->kxfer); + + if(da_splits_count(item->splits) > 0) { - gchar *cats, *amounts, *memos; + gchar *cats, *amounts, *memos; - transaction_splits_tostring(item, &cats, &amounts, &memos); - g_string_append_printf(node, "scat=\"%s\" ", cats); - g_string_append_printf(node, "samt=\"%s\" ", amounts); - - //fix #1173910 - gchar *escaped = g_markup_escape_text(memos, -1); - g_string_append_printf(node, "smem=\"%s\" ", escaped); - g_free(escaped); + da_splits_tostring(item->splits, &cats, &amounts, &memos); + g_string_append_printf(node, "scat=\"%s\" ", cats); + g_string_append_printf(node, "samt=\"%s\" ", amounts); + + //fix #1173910 + gchar *escaped = g_markup_escape_text(memos, -1); + g_string_append_printf(node, "smem=\"%s\" ", escaped); + g_free(escaped); + + g_free(cats); + g_free(amounts); + g_free(memos); + } - g_free(cats); - g_free(amounts); - g_free(memos); - } + g_string_append(node, "/>\n"); - g_string_append(node, "/>\n"); + g_free(tagstr); + + error = NULL; + g_io_channel_write_chars(io, node->str, -1, NULL, &error); + + if(error) + { + retval = XML_IO_ERROR; + g_error_free(error); + } - g_free(tagstr); - g_io_channel_write_chars(io, node->str, -1, NULL, NULL); - list = g_list_next(list); + list = g_list_next(list); + } + + lnk_acc = g_list_next(lnk_acc); } + g_list_free(lst_acc); + g_string_free(node, TRUE); + return retval; } /* @@ -1185,30 +1545,36 @@ GIOChannel *io; char buf1[G_ASCII_DTOSTR_BUF_SIZE]; gchar *outstr; gint retval = XML_OK; +GError *error = NULL; - io = g_io_channel_new_file(filename, "w", NULL); + io = g_io_channel_new_file(filename, "w", &error); if(io == NULL) { g_message("file error on: %s", filename); retval = XML_IO_ERROR; + + if(error) + g_print("failed: %s\n", error->message); + + g_error_free(error); } else { g_io_channel_write_chars(io, "\n", -1, NULL, NULL); - outstr = g_strdup_printf("\n", g_ascii_dtostr (buf1, sizeof (buf1), FILE_VERSION)); + outstr = g_strdup_printf("\n", g_ascii_dtostr (buf1, sizeof (buf1), FILE_VERSION), HB_VERSION_NUM); g_io_channel_write_chars(io, outstr, -1, NULL, NULL); g_free(outstr); - homebank_save_xml_prop(io); - //homebank_save_xml_cur(io); - homebank_save_xml_acc(io); - homebank_save_xml_pay(io); - homebank_save_xml_cat(io); - homebank_save_xml_tag(io); - homebank_save_xml_asg(io); - homebank_save_xml_arc(io); - homebank_save_xml_ope(io); + retval = homebank_save_xml_prop(io); + retval = homebank_save_xml_cur(io); + retval = homebank_save_xml_acc(io); + retval = homebank_save_xml_pay(io); + retval = homebank_save_xml_cat(io); + retval = homebank_save_xml_tag(io); + retval = homebank_save_xml_asg(io); + retval = homebank_save_xml_arc(io); + retval = homebank_save_xml_ope(io); g_io_channel_write_chars(io, "\n", -1, NULL, NULL);