diff --git a/libgnucash/engine/Account.cpp b/libgnucash/engine/Account.cpp index b7aaef0a7b..1208425b37 100644 --- a/libgnucash/engine/Account.cpp +++ b/libgnucash/engine/Account.cpp @@ -5432,60 +5432,39 @@ build_non_bayes (const char *key, const GValue *value, gpointer user_data) g_free (guid_string); } -static void -build_bayes_layer_two (const char *key, KvpValue * val, imap_info imapInfo) +static std::tuple +parse_bayes_imap_info (std::string const & imap_bayes_entry) { - QofBook *book; - Account *map_account = NULL; - GncGUID *guid; - gchar *kvp_path; - gchar *count; - struct imap_info *imapInfo_node; - // Get the book - book = qof_instance_get_book (imapInfo.source_account); - if (val->get_type() == KvpValue::Type::INT64) - { - PINFO("build_bayes_layer_two: account '%s', token_count: '%" G_GINT64_FORMAT "'", - key, val->get()); - count = g_strdup_printf ("%" G_GINT64_FORMAT, val->get()); - } - else - count = g_strdup ("0"); - kvp_path = g_strconcat (imapInfo.category_head, "/", key, NULL); - PINFO("build_bayes_layer_two: kvp_path is '%s'", kvp_path); - guid = g_new (GncGUID, 1); - if (string_to_guid (key, guid)) - map_account = xaccAccountLookup (guid, book); - g_free (guid); - imapInfo_node = static_cast (g_malloc(sizeof(*imapInfo_node))); - imapInfo_node->source_account = imapInfo.source_account; - imapInfo_node->map_account = map_account; - imapInfo_node->full_category = g_strdup (kvp_path); - imapInfo_node->match_string = g_strdup (imapInfo.match_string); - imapInfo_node->category_head = g_strdup (imapInfo.category_head); - imapInfo_node->count = g_strdup (count); - imapInfo.list = g_list_append (imapInfo.list, imapInfo_node); - g_free (kvp_path); - g_free (count); + auto header_length = strlen (IMAP_FRAME_BAYES); + std::string header {imap_bayes_entry.substr (0, header_length)}; + auto guid_start = imap_bayes_entry.size() - GUID_ENCODING_LENGTH; + std::string keyword {imap_bayes_entry.substr (header_length + 1, guid_start - header_length - 2)}; + std::string account_guid {imap_bayes_entry.substr (guid_start)}; + return {header, keyword, account_guid}; } static void build_bayes (const char *key, KvpValue * value, imap_info & imapInfo) { - struct imap_info imapInfol2; - PINFO("build_bayes: match string '%s'", (char*)key); - - std::string prefix {g_strdup_printf (IMAP_FRAME_BAYES "-%s", key)}; - PINFO("build_bayes: prefix is '%s', key '%s'", prefix.c_str(), key); - imapInfol2.source_account = imapInfo.source_account; - imapInfol2.match_string = g_strdup (key); - imapInfol2.category_head = g_strdup (prefix.c_str()); - imapInfol2.list = imapInfo.list; - qof_instance_foreach_slot_prefix (QOF_INSTANCE(imapInfo.source_account), prefix, - build_bayes_layer_two, imapInfol2); - imapInfo.list = imapInfol2.list; - g_free (imapInfol2.match_string); - g_free (imapInfol2.category_head); + auto slots = qof_instance_get_slots_prefix (QOF_INSTANCE (imapInfo.source_account), IMAP_FRAME_BAYES); + if (!slots.size()) return; + for (auto const & entry : slots) + { + auto parsed_key = parse_bayes_imap_info (entry.first); + auto temp_guid = gnc::GUID::from_string (std::get <2> (parsed_key)); + GncGUID guid = temp_guid; + auto map_account = xaccAccountLookup (&guid, gnc_account_get_book (imapInfo.source_account)); + std::string category_head {std::get <0> (parsed_key) + "-" + std::get <1> (parsed_key)}; + auto imap_node = static_cast (g_malloc (sizeof (imap_info))); + auto count = entry.second->get (); + imap_node->source_account = imapInfo.source_account; + imap_node->map_account = map_account; + imap_node->full_category = g_strdup (key); + imap_node->match_string = g_strdup (std::get <1> (parsed_key).c_str ()); + imap_node->category_head = g_strdup (category_head.c_str ()); + imap_node->count = g_strdup_printf ("%" G_GINT64_FORMAT, count); + imapInfo.list = g_list_append (imapInfo.list, imap_node); + }; } GList * @@ -5498,7 +5477,6 @@ gnc_account_imap_get_info_bayes (Account *acc) return imapInfo.list; } - GList * gnc_account_imap_get_info (Account *acc, const char *category) { diff --git a/libgnucash/engine/qofinstance-p.h b/libgnucash/engine/qofinstance-p.h index a54a58138c..bce6ead1fd 100644 --- a/libgnucash/engine/qofinstance-p.h +++ b/libgnucash/engine/qofinstance-p.h @@ -173,8 +173,9 @@ bool qof_instance_has_path_slot (QofInstance const *, std::vector c void qof_instance_slot_path_delete (QofInstance const *, std::vector const &); void qof_instance_slot_path_delete_if_empty (QofInstance const *, std::vector const &); + /** Returns all keys that match the given prefix and their corresponding values.*/ -std::map +std::vector > qof_instance_get_slots_prefix (QofInstance const *, std::string const & prefix); /* Don't pass nullptr as the function */ diff --git a/libgnucash/engine/qofinstance.cpp b/libgnucash/engine/qofinstance.cpp index 64826d5083..a222668f3c 100644 --- a/libgnucash/engine/qofinstance.cpp +++ b/libgnucash/engine/qofinstance.cpp @@ -1353,6 +1353,17 @@ qof_instance_slot_delete_if_empty (const QofInstance *inst, const char *path) } } +std::vector > +qof_instance_get_slots_prefix (QofInstance const * inst, std::string const & prefix) +{ + std::vector > ret; + inst->kvp_data->for_each_slot_temp ([&prefix, &ret] (std::string const & key, KvpValue * val) { + if (key.find (prefix) == 0) + ret.emplace_back (key, val); + }); + return ret; +} + namespace { struct wrap_param { @@ -1360,6 +1371,7 @@ struct wrap_param void *user_data; }; } + static void wrap_gvalue_function (const char* key, KvpValue *val, wrap_param & param) { diff --git a/libgnucash/engine/test/gtest-import-map.cpp b/libgnucash/engine/test/gtest-import-map.cpp index 117fe59cda..1d5b693490 100644 --- a/libgnucash/engine/test/gtest-import-map.cpp +++ b/libgnucash/engine/test/gtest-import-map.cpp @@ -381,11 +381,30 @@ TEST_F(ImapBayesTest, ConvertAccountBayes) TEST_F (ImapBayesTest, import_map_with_delimiters) { GList * tokens {nullptr}; - tokens = g_list_prepend(tokens, const_cast("one/two/three")); - gnc_account_imap_add_account_bayes(t_imap, tokens, t_expense_account1); - gnc_account_imap_add_account_bayes(t_imap, tokens, t_expense_account1); - gnc_account_imap_add_account_bayes(t_imap, tokens, t_expense_account1); + tokens = g_list_prepend (tokens, const_cast ("one/two/three")); + gnc_account_imap_add_account_bayes (t_imap, tokens, t_expense_account1); + gnc_account_imap_add_account_bayes (t_imap, tokens, t_expense_account1); + gnc_account_imap_add_account_bayes (t_imap, tokens, t_expense_account1); + auto account = gnc_account_imap_find_account_bayes (t_imap, tokens); + EXPECT_EQ (account, t_expense_account1); +} +TEST_F (ImapBayesTest, get_bayes_info) +{ + GList * tokens {nullptr}; + tokens = g_list_prepend (tokens, const_cast ("one/two/three")); + gnc_account_imap_add_account_bayes(t_imap, tokens, t_expense_account1); auto account = gnc_account_imap_find_account_bayes (t_imap, tokens); EXPECT_EQ (account, t_expense_account1); + auto infos = gnc_account_imap_get_info_bayes (t_bank_account); + EXPECT_EQ (g_list_first (infos), g_list_last (infos)); + auto info = static_cast (g_list_first (infos)->data); + EXPECT_EQ (info->source_account, t_bank_account); + EXPECT_EQ (info->map_account, t_expense_account1); + auto acct1_guid = guid_to_string (xaccAccountGetGUID(t_expense_account1)); //Food + EXPECT_STREQ (info->full_category, (std::string {IMAP_FRAME_BAYES} + "-one-two-three-" + acct1_guid).c_str ()); + EXPECT_STREQ (info->match_string, "one-two-three"); + EXPECT_STREQ (info->category_head, (std::string {IMAP_FRAME_BAYES} + "-one-two-three").c_str ()); + EXPECT_STREQ (info->count, "1"); } +