GnuCash 2.4.99
gnc-account-xml-v2.c
00001 /********************************************************************\
00002  * gnc-account-xml-v2.c -- account xml i/o implementation           *
00003  *                                                                  *
00004  * Copyright (C) 2001 James LewisMoss <dres@debian.org>             *
00005  * Copyright (C) 2002 Linas Vepstas <linas@linas.org>               *
00006  *                                                                  *
00007  * This program is free software; you can redistribute it and/or    *
00008  * modify it under the terms of the GNU General Public License as   *
00009  * published by the Free Software Foundation; either version 2 of   *
00010  * the License, or (at your option) any later version.              *
00011  *                                                                  *
00012  * This program is distributed in the hope that it will be useful,  *
00013  * but WITHOUT ANY WARRANTY; without even the implied warranty of   *
00014  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the    *
00015  * GNU General Public License for more details.                     *
00016  *                                                                  *
00017  * You should have received a copy of the GNU General Public License*
00018  * along with this program; if not, contact:                        *
00019  *                                                                  *
00020  * Free Software Foundation           Voice:  +1-617-542-5942       *
00021  * 51 Franklin Street, Fifth Floor    Fax:    +1-617-542-2652       *
00022  * Boston, MA  02110-1301,  USA       gnu@gnu.org                   *
00023  *                                                                  *
00024 \********************************************************************/
00025 
00026 #include "config.h"
00027 
00028 #include <glib.h>
00029 #include <stdlib.h>
00030 #include <string.h>
00031 
00032 #include "gnc-xml-helper.h"
00033 #include "sixtp.h"
00034 #include "sixtp-utils.h"
00035 #include "sixtp-parsers.h"
00036 #include "sixtp-utils.h"
00037 #include "sixtp-dom-parsers.h"
00038 #include "sixtp-dom-generators.h"
00039 
00040 #include "gnc-xml.h"
00041 #include "io-gncxml-gen.h"
00042 #include "io-gncxml-v2.h"
00043 
00044 #include "sixtp-dom-parsers.h"
00045 #include "AccountP.h"
00046 #include "Account.h"
00047 
00048 static QofLogModule log_module = GNC_MOD_IO;
00049 
00050 const gchar *account_version_string = "2.0.0";
00051 
00052 /* ids */
00053 #define gnc_account_string "gnc:account"
00054 #define act_name_string "act:name"
00055 #define act_id_string "act:id"
00056 #define act_type_string "act:type"
00057 #define act_commodity_string "act:commodity"
00058 #define act_commodity_scu_string "act:commodity-scu"
00059 #define act_non_standard_scu_string "act:non-standard-scu"
00060 #define act_code_string "act:code"
00061 #define act_description_string "act:description"
00062 #define act_slots_string "act:slots"
00063 #define act_parent_string "act:parent"
00064 #define act_lots_string "act:lots"
00065 /* The currency and security strings should not appear in newer
00066  * xml files (anything post-gnucash-1.6) */
00067 #define act_currency_string "act:currency"
00068 #define act_currency_scu_string "act:currency-scu"
00069 #define act_security_string "act:security"
00070 #define act_security_scu_string "act:security-scu"
00071 #define act_hidden_string "act:hidden"
00072 #define act_placeholder_string "act:placeholder"
00073 
00074 xmlNodePtr
00075 gnc_account_dom_tree_create(Account *act,
00076                             gboolean exporting,
00077                             gboolean allow_incompat)
00078 {
00079     const char *str;
00080     kvp_frame *kf;
00081     xmlNodePtr ret;
00082     GList *lots, *n;
00083     Account *parent;
00084     gnc_commodity *acct_commodity;
00085 
00086     ENTER ("(account=%p)", act);
00087 
00088     ret = xmlNewNode(NULL, BAD_CAST gnc_account_string);
00089     xmlSetProp(ret, BAD_CAST "version", BAD_CAST account_version_string);
00090 
00091     xmlAddChild(ret, text_to_dom_tree(act_name_string,
00092                                       xaccAccountGetName(act)));
00093 
00094     xmlAddChild(ret, guid_to_dom_tree(act_id_string, xaccAccountGetGUID(act)));
00095 
00096     xmlAddChild(ret, text_to_dom_tree(
00097                     act_type_string,
00098                     xaccAccountTypeEnumAsString(xaccAccountGetType(act))));
00099 
00100     /* Don't write new XML tags in version 2.3.x and 2.4.x because it
00101        would mean 2.2.x cannot read those files again. But we can
00102        enable writing these tags in 2.5.x or late in 2.4.x. */
00103     /*
00104     xmlAddChild(ret, boolean_to_dom_tree(
00105                                                 act_hidden_string,
00106                                                 xaccAccountGetHidden(act)));
00107     xmlAddChild(ret, boolean_to_dom_tree(
00108                                                 act_placeholder_string,
00109                                                 xaccAccountGetPlaceholder(act)));
00110     */
00111 
00112     acct_commodity = xaccAccountGetCommodity(act);
00113     if (acct_commodity != NULL)
00114     {
00115         xmlAddChild(ret, commodity_ref_to_dom_tree(act_commodity_string,
00116                     acct_commodity));
00117 
00118         xmlAddChild(ret, int_to_dom_tree(act_commodity_scu_string,
00119                                          xaccAccountGetCommoditySCUi(act)));
00120 
00121         if (xaccAccountGetNonStdSCU(act))
00122             xmlNewChild(ret, NULL, BAD_CAST act_non_standard_scu_string, NULL);
00123     }
00124 
00125     str = xaccAccountGetCode(act);
00126     if (str && strlen(str) > 0)
00127     {
00128         xmlAddChild(ret, text_to_dom_tree(act_code_string, str));
00129     }
00130 
00131     str = xaccAccountGetDescription(act);
00132     if (str && strlen(str) > 0)
00133     {
00134         xmlAddChild(ret, text_to_dom_tree(act_description_string, str));
00135     }
00136 
00137     kf = xaccAccountGetSlots(act);
00138     if (kf)
00139     {
00140         xmlNodePtr kvpnode = kvp_frame_to_dom_tree(act_slots_string, kf);
00141         if (kvpnode)
00142         {
00143             xmlAddChild(ret, kvpnode);
00144         }
00145     }
00146 
00147     parent = gnc_account_get_parent(act);
00148     if (parent)
00149     {
00150         if (!gnc_account_is_root(parent) || allow_incompat)
00151             xmlAddChild(ret, guid_to_dom_tree(act_parent_string,
00152                                               xaccAccountGetGUID(parent)));
00153     }
00154 
00155     lots = xaccAccountGetLotList (act);
00156     PINFO ("lot list=%p", lots);
00157     if (lots && !exporting)
00158     {
00159         xmlNodePtr toaddto = xmlNewChild(ret, NULL, BAD_CAST act_lots_string, NULL);
00160 
00161         lots = g_list_sort(lots, qof_instance_guid_compare);
00162 
00163         for (n = lots; n; n = n->next)
00164         {
00165             GNCLot * lot = n->data;
00166             xmlAddChild(toaddto, gnc_lot_dom_tree_create(lot));
00167         }
00168     }
00169     g_list_free(lots);
00170 
00171     LEAVE("");
00172     return ret;
00173 }
00174 
00175 /***********************************************************************/
00176 
00177 struct account_pdata
00178 {
00179     Account *account;
00180     QofBook *book;
00181 };
00182 
00183 static inline gboolean
00184 set_string(xmlNodePtr node, Account* act,
00185            void (*func)(Account *act, const gchar *txt))
00186 {
00187     gchar* txt = dom_tree_to_text(node);
00188     g_return_val_if_fail(txt, FALSE);
00189 
00190     func(act, txt);
00191 
00192     g_free(txt);
00193 
00194     return TRUE;
00195 }
00196 
00197 static gboolean
00198 account_name_handler (xmlNodePtr node, gpointer act_pdata)
00199 {
00200     struct account_pdata *pdata = act_pdata;
00201 
00202     return set_string(node, pdata->account, xaccAccountSetName);
00203 }
00204 
00205 static gboolean
00206 account_id_handler (xmlNodePtr node, gpointer act_pdata)
00207 {
00208     struct account_pdata *pdata = act_pdata;
00209     GncGUID *guid;
00210 
00211     guid = dom_tree_to_guid(node);
00212     g_return_val_if_fail(guid, FALSE);
00213 
00214     xaccAccountSetGUID(pdata->account, guid);
00215 
00216     g_free(guid);
00217 
00218     return TRUE;
00219 }
00220 
00221 static gboolean
00222 account_type_handler (xmlNodePtr node, gpointer act_pdata)
00223 {
00224     struct account_pdata *pdata = act_pdata;
00225     GNCAccountType type = ACCT_TYPE_INVALID;
00226     char *string;
00227 
00228     string = (char*) xmlNodeGetContent (node->xmlChildrenNode);
00229     xaccAccountStringToType(string, &type);
00230     xmlFree (string);
00231 
00232     xaccAccountSetType(pdata->account, type);
00233 
00234     return TRUE;
00235 }
00236 
00237 static gboolean
00238 account_commodity_handler (xmlNodePtr node, gpointer act_pdata)
00239 {
00240     struct account_pdata *pdata = act_pdata;
00241     gnc_commodity *ref;
00242 
00243 //    ref = dom_tree_to_commodity_ref_no_engine(node, pdata->book);
00244     ref = dom_tree_to_commodity_ref(node, pdata->book);
00245     xaccAccountSetCommodity(pdata->account, ref);
00246 
00247     return TRUE;
00248 }
00249 
00250 static gboolean
00251 account_commodity_scu_handler (xmlNodePtr node, gpointer act_pdata)
00252 {
00253     struct account_pdata *pdata = act_pdata;
00254     gint64 val;
00255 
00256     dom_tree_to_integer(node, &val);
00257     xaccAccountSetCommoditySCU(pdata->account, val);
00258 
00259     return TRUE;
00260 }
00261 
00262 static gboolean
00263 account_hidden_handler (xmlNodePtr node, gpointer act_pdata)
00264 {
00265     struct account_pdata *pdata = act_pdata;
00266     gboolean val;
00267 
00268     dom_tree_to_boolean(node, &val);
00269     xaccAccountSetHidden(pdata->account, val);
00270 
00271     return TRUE;
00272 }
00273 
00274 static gboolean
00275 account_placeholder_handler (xmlNodePtr node, gpointer act_pdata)
00276 {
00277     struct account_pdata *pdata = act_pdata;
00278     gboolean val;
00279 
00280     dom_tree_to_boolean(node, &val);
00281     xaccAccountSetPlaceholder(pdata->account, val);
00282 
00283     return TRUE;
00284 }
00285 
00286 static gboolean
00287 account_non_standard_scu_handler (xmlNodePtr node, gpointer act_pdata)
00288 {
00289     struct account_pdata *pdata = act_pdata;
00290 
00291     xaccAccountSetNonStdSCU(pdata->account, TRUE);
00292 
00293     return TRUE;
00294 }
00295 
00296 /* ============================================================== */
00297 /* The following deprecated routines are here only to service
00298  * older XML files. */
00299 
00300 static gboolean
00301 deprecated_account_currency_handler (xmlNodePtr node, gpointer act_pdata)
00302 {
00303     struct account_pdata *pdata = act_pdata;
00304     gnc_commodity *ref;
00305 
00306     PWARN("Account %s: Obsolete xml tag 'act:currency' will not be preserved.",
00307           xaccAccountGetName( pdata->account ));
00308     ref = dom_tree_to_commodity_ref_no_engine(node, pdata->book);
00309     DxaccAccountSetCurrency(pdata->account, ref);
00310 
00311     return TRUE;
00312 }
00313 
00314 static gboolean
00315 deprecated_account_currency_scu_handler (xmlNodePtr node, gpointer act_pdata)
00316 {
00317     struct account_pdata *pdata = act_pdata;
00318     PWARN("Account %s: Obsolete xml tag 'act:currency-scu' will not be preserved.",
00319           xaccAccountGetName( pdata->account ));
00320     return TRUE;
00321 }
00322 
00323 static gboolean
00324 deprecated_account_security_handler (xmlNodePtr node, gpointer act_pdata)
00325 {
00326     struct account_pdata *pdata = act_pdata;
00327     gnc_commodity *ref, *orig = xaccAccountGetCommodity(pdata->account);
00328 
00329     PWARN("Account %s: Obsolete xml tag 'act:security' will not be preserved.",
00330           xaccAccountGetName( pdata->account ));
00331     /* If the account has both a commodity and a security elemet, and
00332        the commodity is a currecny, then the commodity is probably
00333        wrong. In that case we want to replace it with the
00334        security. jralls 2010-11-02 */
00335     if (!orig || gnc_commodity_is_currency( orig ) )
00336     {
00337         ref = dom_tree_to_commodity_ref_no_engine(node, pdata->book);
00338         xaccAccountSetCommodity(pdata->account, ref);
00339         /* If the SCU was set, it was probably wrong, so zero it out
00340            so that the SCU handler can fix it if there's a
00341            security-scu element. jralls 2010-11-02 */
00342         xaccAccountSetCommoditySCU(pdata->account, 0);
00343     }
00344 
00345     return TRUE;
00346 }
00347 
00348 static gboolean
00349 deprecated_account_security_scu_handler (xmlNodePtr node, gpointer act_pdata)
00350 {
00351     struct account_pdata *pdata = act_pdata;
00352     gint64 val;
00353 
00354     PWARN("Account %s: Obsolete xml tag 'act:security-scu' will not be preserved.",
00355           xaccAccountGetName( pdata->account ));
00356     if (!xaccAccountGetCommoditySCU(pdata->account))
00357     {
00358         dom_tree_to_integer(node, &val);
00359         xaccAccountSetCommoditySCU(pdata->account, val);
00360     }
00361 
00362     return TRUE;
00363 }
00364 
00365 /* ============================================================== */
00366 
00367 static gboolean
00368 account_slots_handler (xmlNodePtr node, gpointer act_pdata)
00369 {
00370     struct account_pdata *pdata = act_pdata;
00371 
00372     return dom_tree_to_kvp_frame_given
00373            (node, xaccAccountGetSlots (pdata->account));
00374 }
00375 
00376 static gboolean
00377 account_parent_handler (xmlNodePtr node, gpointer act_pdata)
00378 {
00379     struct account_pdata *pdata = act_pdata;
00380     Account *parent;
00381     GncGUID *gid;
00382 
00383     gid = dom_tree_to_guid(node);
00384     g_return_val_if_fail(gid, FALSE);
00385 
00386     parent = xaccAccountLookup(gid, pdata->book);
00387     if (!parent)
00388     {
00389         g_free (gid);
00390         g_return_val_if_fail(parent, FALSE);
00391     }
00392 
00393     gnc_account_append_child(parent, pdata->account);
00394 
00395     g_free (gid);
00396 
00397     return TRUE;
00398 }
00399 
00400 static gboolean
00401 account_code_handler(xmlNodePtr node, gpointer act_pdata)
00402 {
00403     struct account_pdata *pdata = act_pdata;
00404 
00405     return set_string(node, pdata->account, xaccAccountSetCode);
00406 }
00407 
00408 static gboolean
00409 account_description_handler(xmlNodePtr node, gpointer act_pdata)
00410 {
00411     struct account_pdata *pdata = act_pdata;
00412 
00413     return set_string(node, pdata->account, xaccAccountSetDescription);
00414 }
00415 
00416 static gboolean
00417 account_lots_handler(xmlNodePtr node, gpointer act_pdata)
00418 {
00419     struct account_pdata *pdata = act_pdata;
00420     xmlNodePtr mark;
00421 
00422     g_return_val_if_fail(node, FALSE);
00423     g_return_val_if_fail(node->xmlChildrenNode, FALSE);
00424 
00425     for (mark = node->xmlChildrenNode; mark; mark = mark->next)
00426     {
00427         GNCLot *lot;
00428 
00429         if (safe_strcmp("text", (char*) mark->name) == 0)
00430             continue;
00431 
00432         lot = dom_tree_to_lot(mark, pdata->book);
00433 
00434         if (lot)
00435         {
00436             xaccAccountInsertLot (pdata->account, lot);
00437         }
00438         else
00439         {
00440             return FALSE;
00441         }
00442     }
00443     return TRUE;
00444 }
00445 
00446 static struct dom_tree_handler account_handlers_v2[] =
00447 {
00448     { act_name_string, account_name_handler, 1, 0 },
00449     { act_id_string, account_id_handler, 1, 0 },
00450     { act_type_string, account_type_handler, 1, 0 },
00451     { act_commodity_string, account_commodity_handler, 0, 0 },
00452     { act_commodity_scu_string, account_commodity_scu_handler, 0, 0 },
00453     { act_non_standard_scu_string, account_non_standard_scu_handler, 0, 0 },
00454     { act_code_string, account_code_handler, 0, 0 },
00455     { act_description_string, account_description_handler, 0, 0},
00456     { act_slots_string, account_slots_handler, 0, 0 },
00457     { act_parent_string, account_parent_handler, 0, 0 },
00458     { act_lots_string, account_lots_handler, 0, 0 },
00459     { act_hidden_string, account_hidden_handler, 0, 0 },
00460     { act_placeholder_string, account_placeholder_handler, 0, 0 },
00461 
00462     /* These should not appear in  newer xml files; only in old
00463      * (circa gnucash-1.6) xml files. We maintain them for backward
00464      * compatibility. */
00465     { act_currency_string, deprecated_account_currency_handler, 0, 0 },
00466     { act_currency_scu_string, deprecated_account_currency_scu_handler, 0, 0 },
00467     { act_security_string, deprecated_account_security_handler, 0, 0 },
00468     { act_security_scu_string, deprecated_account_security_scu_handler, 0, 0 },
00469     { NULL, 0, 0, 0 }
00470 };
00471 
00472 static gboolean
00473 gnc_account_end_handler(gpointer data_for_children,
00474                         GSList* data_from_children, GSList* sibling_data,
00475                         gpointer parent_data, gpointer global_data,
00476                         gpointer *result, const gchar *tag)
00477 {
00478     int successful;
00479     Account *acc, *parent, *root;
00480     xmlNodePtr tree = (xmlNodePtr)data_for_children;
00481     gxpf_data *gdata = (gxpf_data*)global_data;
00482     QofBook *book = gdata->bookdata;
00483     int type;
00484 
00485     successful = TRUE;
00486 
00487     if (parent_data)
00488     {
00489         return TRUE;
00490     }
00491 
00492     /* OK.  For some messed up reason this is getting called again with a
00493        NULL tag.  So we ignore those cases */
00494     if (!tag)
00495     {
00496         return TRUE;
00497     }
00498 
00499     g_return_val_if_fail(tree, FALSE);
00500 
00501     acc = dom_tree_to_account(tree, book);
00502     if (acc != NULL)
00503     {
00504         gdata->cb(tag, gdata->parsedata, acc);
00505         /*
00506          * Now return the account to the "edit" state.  At the end of reading
00507          * all the transactions, we will Commit.  This replaces #splits
00508          * rebalances with #accounts rebalances at the end.  A BIG win!
00509          */
00510         xaccAccountBeginEdit(acc);
00511 
00512         /* Backwards compatability.  If there's no parent, see if this
00513          * account is of type ROOT.  If not, find or create a ROOT
00514          * account and make that the parent. */
00515         parent = gnc_account_get_parent(acc);
00516         if (parent == NULL)
00517         {
00518             type = xaccAccountGetType(acc);
00519             if (type != ACCT_TYPE_ROOT)
00520             {
00521                 root = gnc_book_get_root_account(book);
00522                 if (root == NULL)
00523                 {
00524                     root = gnc_account_create_root(book);
00525                 }
00526                 gnc_account_append_child(root, acc);
00527             }
00528         }
00529     }
00530 
00531     xmlFreeNode(tree);
00532 
00533     return acc != NULL;
00534 }
00535 
00536 Account*
00537 dom_tree_to_account (xmlNodePtr node, QofBook *book)
00538 {
00539     struct account_pdata act_pdata;
00540     Account *accToRet;
00541     gboolean successful;
00542 
00543     accToRet = xaccMallocAccount(book);
00544     xaccAccountBeginEdit(accToRet);
00545 
00546     act_pdata.account = accToRet;
00547     act_pdata.book = book;
00548 
00549     successful = dom_tree_generic_parse (node, account_handlers_v2,
00550                                          &act_pdata);
00551     if (successful)
00552     {
00553         xaccAccountCommitEdit (accToRet);
00554     }
00555     else
00556     {
00557         PERR ("failed to parse account tree");
00558         xaccAccountDestroy (accToRet);
00559         accToRet = NULL;
00560     }
00561 
00562     return accToRet;
00563 }
00564 
00565 sixtp*
00566 gnc_account_sixtp_parser_create(void)
00567 {
00568     return sixtp_dom_parser_new(gnc_account_end_handler, NULL, NULL);
00569 }
00570 
00571 /* ======================  END OF FILE ===================*/
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Defines