+ DB( g_print(" - retval='%s'\n", retval) );
+ return retval;
+}
+
+
+/* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */
+
+gchar *hb_import_filetype_char_get(GenAcc *genacc)
+{
+gchar *retval = "";
+
+ switch(genacc->filetype)
+ {
+#ifndef NOOFX
+ case FILETYPE_OFX:
+ retval = "OFX/QFX";
+ break;
+#endif
+ case FILETYPE_QIF:
+ retval = "QIF";
+ break;
+
+ case FILETYPE_CSV_HB:
+ retval = "CSV";
+ break;
+ }
+
+ return retval;
+}
+
+
+void
+hb_import_load_all(ImportContext *ictx)
+{
+GList *list;
+
+ DB( g_print("\n[import] load all\n") );
+
+ da_import_context_clear (ictx);
+
+ list = g_list_first(ictx->gen_lst_file);
+ while (list != NULL)
+ {
+ GenFile *genfile = list->data;
+
+ if(genfile->filetype != FILETYPE_UNKNOWN)
+ {
+ //todo: move this to alien analysis
+ genfile->encoding = homebank_file_getencoding(genfile->filepath);
+
+ ictx->curr_kfile = genfile->key;
+
+ DB( g_print(" -> key = '%d'\n", genfile->key) );
+ DB( g_print(" -> filepath = '%s'\n", genfile->filepath) );
+ DB( g_print(" -> encoding = '%s'\n", genfile->encoding) );
+
+ genfile->loaded = FALSE;
+ genfile->invaliddatefmt = FALSE;
+
+ switch(genfile->filetype)
+ {
+ #ifndef NOOFX
+ case FILETYPE_OFX:
+ homebank_ofx_import(ictx, genfile);
+ break;
+ #endif
+ case FILETYPE_QIF:
+ homebank_qif_import(ictx, genfile);
+ break;
+
+ case FILETYPE_CSV_HB:
+ homebank_csv_import(ictx, genfile);
+ break;
+ }
+
+ genfile->loaded = TRUE;
+ }
+
+ list = g_list_next(list);
+ }
+
+ // sort by date
+ ictx->gen_lst_txn = da_gen_txn_sort(ictx->gen_lst_txn);
+
+}
+
+
+gint
+hb_import_gen_acc_count_txn(ImportContext *ictx, GenAcc *genacc)
+{
+GList *list;
+gint count = 0;
+
+ DB( g_print("\n[import] gen_acc_count_txn\n") );
+
+ genacc->n_txnall = 0;
+ genacc->n_txnimp = 0;
+
+ list = g_list_first(ictx->gen_lst_txn);
+ while (list != NULL)
+ {
+ GenTxn *gentxn = list->data;
+
+ if(gentxn->kacc == genacc->key)
+ {
+ genacc->n_txnall++;
+ count++;
+
+ DB( g_print(" count %03d: gentxn in=%d dup=%d '%s'\n", count, gentxn->to_import, gentxn->is_dst_similar, gentxn->memo) );
+
+ if(gentxn->to_import)
+ genacc->n_txnimp++;
+ }
+ list = g_list_next(list);
+ }
+ return count;
+}
+
+
+/**
+ * uncheck duplicate within the import context files
+ */
+gint
+hb_import_gen_txn_check_duplicate(ImportContext *ictx, GenAcc *genacc)
+{
+GList *list1, *list2;
+gint count = 0;
+
+ DB( g_print("\n[import] gen_txn_check_duplicate\n") );
+
+
+ list1 = g_list_first(ictx->gen_lst_txn);
+ while (list1 != NULL)
+ {
+ GenTxn *gentxn1 = list1->data;
+
+ if( (genacc->key == gentxn1->kacc) && (gentxn1->julian != 0) ) //same account, valid date
+ {
+ list2 = g_list_next(list1);
+ while (list2 != NULL)
+ {
+ GenTxn *gentxn2 = list2->data;
+
+ if( (gentxn2->julian > gentxn1->julian) )
+ break;
+
+ //todo: maybe reinforce controls here
+ if( (gentxn2->kacc == gentxn1->kacc)
+ && (gentxn2->julian == gentxn1->julian)
+ && (gentxn2->amount == gentxn1->amount)
+ && (hb_string_compare(gentxn2->memo, gentxn1->memo) == 0)
+ && (hb_string_compare(gentxn2->payee, gentxn1->payee) == 0)
+ )
+ {
+ gentxn1->to_import = FALSE;
+ gentxn1->is_imp_similar = TRUE;
+ count++;
+
+ DB( g_print(" found import dup %d=%d %.2f %.2f in=%d dup=%d\n", gentxn1->julian, gentxn2->julian, gentxn2->amount, gentxn1->amount, gentxn1->to_import, gentxn1->is_imp_similar) );
+
+ }
+ list2 = g_list_next(list2);
+ }
+ }
+ list1 = g_list_next(list1);
+ }
+ return count;
+}
+
+
+/**
+ * uncheck existing txn into target account
+ *
+ */
+gint
+hb_import_gen_txn_check_target_similar(ImportContext *ictx, GenAcc *genacc)
+{
+GList *list1, *list2;
+gint count = 0;
+
+ DB( g_print("\n[import] gen_txn_check_target_similar\n") );
+
+ list1 = g_list_first(ictx->gen_lst_txn);
+ while (list1 != NULL)
+ {
+ GenTxn *gentxn = list1->data;
+
+ if(genacc->key == gentxn->kacc)
+ {
+ gentxn->to_import = TRUE;
+ gentxn->is_dst_similar = FALSE;
+
+ if(genacc->kacc == DST_ACC_SKIP)
+ {
+ gentxn->to_import = FALSE;
+ }
+ else
+ {
+ Account *acc = da_acc_get(genacc->kacc);
+
+ if(acc != NULL)
+ {
+ //clear previous existing
+ if(gentxn->lst_existing != NULL)
+ {
+ g_list_free(gentxn->lst_existing);
+ gentxn->lst_existing = NULL;
+ }
+
+ // try to find existing transaction
+ list2 = g_queue_peek_tail_link(acc->txn_queue);
+ while (list2 != NULL)
+ {
+ Transaction *txn = list2->data;
+
+ //break if the date goes below the gentxn date + gap
+ if( txn->date < (gentxn->julian - ictx->opt_daygap) )
+ break;
+
+ //#1586211 add of date tolerance
+ //todo: maybe reinforce controls here
+ if( ( txn->kacc == genacc->kacc )
+ && ( gentxn->julian <= (txn->date + ictx->opt_daygap) )
+ && ( gentxn->julian >= (txn->date - ictx->opt_daygap) )
+ && ( txn->amount == gentxn->amount )
+ )
+ {
+ gentxn->lst_existing = g_list_append(gentxn->lst_existing, txn);
+ gentxn->to_import = FALSE;
+ gentxn->is_dst_similar = TRUE;
+ count++;
+
+ DB( g_print(" found dst acc dup %d %.2f '%s' in=%d, dup=%d\n", gentxn->julian, gentxn->amount, gentxn->memo, gentxn->to_import, gentxn->is_dst_similar) );
+ }
+
+ list2 = g_list_previous(list2);
+ }
+ }
+
+ }
+ }
+
+ list1 = g_list_next(list1);
+ }
+
+ return count;
+}
+
+
+/**
+ * try to indentify xfer for OFX
+ *
+ */
+static gint
+hb_import_gen_xfer_eval(ImportContext *ictx, GList *list)
+{
+GList *root, *list1, *list2;
+GList *match = NULL;
+gint count = 0;
+
+ DB( g_print("\n[import] gen xfer eval\n") );
+
+ root = list1 = g_list_first(list);
+ while (list1 != NULL)
+ {
+ Transaction *txn1 = list1->data;
+ GenAcc *acc;
+
+ acc = da_gen_acc_get_by_key(ictx->gen_lst_acc, txn1->kacc);
+
+ DB( g_print(" src: kacc:%d dat:%d amt:%.2f %s kfxacc:%d\n", txn1->kacc, txn1->date, txn1->amount, txn1->memo, txn1->kxferacc) );
+
+ if( (acc != NULL) && (acc->filetype == FILETYPE_OFX) )
+ {
+ match = NULL;
+ count = 0;
+ list2 = g_list_next(root);
+ while (list2 != NULL)
+ {
+ Transaction *txn2 = list2->data;
+
+ //DB( g_print(" -- chk: kacc:%d dat:%d amt:%.2f %s\n", txn2->kacc, txn2->date, txn2->amount, txn2->memo) );
+ if( (txn2->date > txn1->date) )
+ break;
+
+ if( (txn2 == txn1) || (txn2->paymode == PAYMODE_INTXFER) )
+ goto next;
+
+ //todo: maybe reinforce controls here
+ if( (txn2->kacc != txn1->kacc)
+ && (txn2->date == txn1->date)
+ && (txn2->amount == -txn1->amount)
+ && (hb_string_compare(txn2->memo, txn1->memo) == 0)
+ )
+ {
+ DB( g_print(" match: kacc:%d dat:%d amt:%.2f %s kfxacc:%d\n", txn2->kacc, txn2->date, txn2->amount, txn2->memo, txn2->kxferacc) );
+ match = g_list_append(match, txn2);
+ count++;
+ }
+ next:
+ list2 = g_list_next(list2);
+ }
+
+ if(count == 1) //we found a single potential xfer, transform it
+ {
+ Transaction *txn2 ;
+
+ DB( g_print(" single found => convert both\n") );
+
+ list2 = g_list_first(match);
+ txn2 = list2->data;
+
+
+ txn1->paymode = PAYMODE_INTXFER;
+ transaction_xfer_change_to_child(txn1, txn2);
+
+ /*list2 = g_list_first(match);
+ txn2 = list2->data;
+
+ txn1->paymode = PAYMODE_INTXFER;
+ txn1->kxferacc = txn2->kacc;
+
+ txn2->paymode = PAYMODE_INTXFER;
+ txn2->kxferacc = txn1->kacc;
+ */
+ }
+ // if more than one, we cannot be sure
+ g_list_free(match);
+ }
+
+ list1 = g_list_next(list1);
+ }
+
+ return count;
+}
+
+
+/**
+ * apply the user option: date format, payee/memo/info mapping
+ *
+ */
+gboolean
+hb_import_option_apply(ImportContext *ictx, GenAcc *genacc)
+{
+GList *list;
+
+ DB( g_print("\n[import] option apply\n") );