00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022 #include "config.h"
00023
00024 #include <glib.h>
00025 #include <glib/gstdio.h>
00026 #include <fcntl.h>
00027 #include <string.h>
00028 #include <unistd.h>
00029 #include <zlib.h>
00030 #include <errno.h>
00031
00032 #include "gnc-engine.h"
00033 #include "gnc-pricedb-p.h"
00034 #include "Scrub.h"
00035 #include "SX-book.h"
00036 #include "SX-book-p.h"
00037 #include "Transaction.h"
00038 #include "TransactionP.h"
00039 #include "TransLog.h"
00040 #include "sixtp-dom-parsers.h"
00041 #include "io-gncxml-v2.h"
00042 #include "io-gncxml-gen.h"
00043
00044 #include "sixtp.h"
00045 #include "sixtp-parsers.h"
00046 #include "sixtp-utils.h"
00047 #include "gnc-xml.h"
00048 #include "io-utils.h"
00049
00050 static QofLogModule log_module = GNC_MOD_IO;
00051
00052
00053 static GHashTable *threads = NULL;
00054 G_LOCK_DEFINE_STATIC(threads);
00055
00056 typedef struct {
00057 gint fd;
00058 gchar *filename;
00059 gchar *perms;
00060 gboolean compress;
00061 } gz_thread_params_t;
00062
00063
00064 struct file_backend {
00065 gboolean ok;
00066 gpointer data;
00067 sixtp_gdv2 * gd;
00068 const char * tag;
00069 sixtp * parser;
00070 FILE * out;
00071 QofBook * book;
00072 };
00073
00074 #define GNC_V2_STRING "gnc-v2"
00075 extern const gchar *gnc_v2_book_version_string;
00076
00077 void
00078 run_callback(sixtp_gdv2 *data, const char *type)
00079 {
00080 if(data->countCallback)
00081 {
00082 data->countCallback(data, type);
00083 }
00084 }
00085
00086 static void
00087 clear_up_account_commodity(
00088 gnc_commodity_table *tbl, Account *act,
00089 gnc_commodity * (*getter) (const Account *account),
00090 void (*setter) (Account *account, gnc_commodity *comm),
00091 int (*scu_getter) (const Account *account),
00092 void (*scu_setter) (Account *account, int scu))
00093 {
00094 gnc_commodity *gcom;
00095 gnc_commodity *com = getter(act);
00096 int old_scu;
00097
00098 if (scu_getter)
00099 old_scu = scu_getter(act);
00100 else
00101 old_scu = 0;
00102
00103 if(!com)
00104 {
00105 return;
00106 }
00107
00108 gcom = gnc_commodity_table_lookup(tbl, gnc_commodity_get_namespace(com),
00109 gnc_commodity_get_mnemonic(com));
00110
00111 if (gcom == com)
00112 {
00113 return;
00114 }
00115 else if(!gcom)
00116 {
00117 PWARN("unable to find global commodity for %s adding new",
00118 gnc_commodity_get_unique_name(com));
00119 gnc_commodity_table_insert(tbl, com);
00120 }
00121 else
00122 {
00123 setter(act, gcom);
00124 if (old_scu != 0 && scu_setter)
00125 scu_setter(act, old_scu);
00126 gnc_commodity_destroy(com);
00127 }
00128 }
00129
00130 static void
00131 clear_up_transaction_commodity(
00132 gnc_commodity_table *tbl, Transaction *trans,
00133 gnc_commodity * (*getter) (const Transaction *trans),
00134 void (*setter) (Transaction *trans, gnc_commodity *comm))
00135 {
00136 gnc_commodity *gcom;
00137 gnc_commodity *com = getter(trans);
00138
00139 if(!com)
00140 {
00141 return;
00142 }
00143
00144 gcom = gnc_commodity_table_lookup(tbl, gnc_commodity_get_namespace(com),
00145 gnc_commodity_get_mnemonic(com));
00146
00147 if(gcom == com)
00148 {
00149 return;
00150 }
00151 else if(!gcom)
00152 {
00153 PWARN("unable to find global commodity for %s adding new",
00154 gnc_commodity_get_unique_name(com));
00155 gnc_commodity_table_insert(tbl, com);
00156 }
00157 else
00158 {
00159 xaccTransBeginEdit(trans);
00160 setter(trans, gcom);
00161 xaccTransCommitEdit(trans);
00162 gnc_commodity_destroy(com);
00163 }
00164 }
00165
00166 static gboolean
00167 add_account_local(sixtp_gdv2 *data, Account *act)
00168 {
00169 gnc_commodity_table *table;
00170 Account *parent, *root;
00171 int type;
00172
00173 table = gnc_book_get_commodity_table (data->book);
00174
00175 clear_up_account_commodity(table, act,
00176 DxaccAccountGetCurrency,
00177 DxaccAccountSetCurrency,
00178 NULL, NULL);
00179
00180 clear_up_account_commodity(table, act,
00181 xaccAccountGetCommodity,
00182 xaccAccountSetCommodity,
00183 xaccAccountGetCommoditySCUi,
00184 xaccAccountSetCommoditySCU);
00185
00186 xaccAccountScrubCommodity (act);
00187 xaccAccountScrubKvp (act);
00188
00189
00190
00191
00192 type = xaccAccountGetType(act);
00193 if (type == ACCT_TYPE_ROOT) {
00194 gnc_book_set_root_account(data->book, act);
00195 } else {
00196 parent = gnc_account_get_parent(act);
00197 if (parent == NULL) {
00198 root = gnc_book_get_root_account(data->book);
00199 gnc_account_append_child(root, act);
00200 }
00201 }
00202
00203 data->counter.accounts_loaded++;
00204 run_callback(data, "account");
00205
00206 return FALSE;
00207 }
00208
00209 static gboolean
00210 add_book_local(sixtp_gdv2 *data, QofBook *book)
00211 {
00212 data->counter.books_loaded++;
00213 run_callback(data, "book");
00214
00215 return FALSE;
00216 }
00217
00218 static gboolean
00219 add_commodity_local(sixtp_gdv2 *data, gnc_commodity *com)
00220 {
00221 gnc_commodity_table *table;
00222
00223 table = gnc_book_get_commodity_table (data->book);
00224
00225 gnc_commodity_table_insert(table, com);
00226
00227 data->counter.commodities_loaded++;
00228 run_callback(data, "commodities");
00229
00230 return TRUE;
00231 }
00232
00233 static gboolean
00234 add_transaction_local(sixtp_gdv2 *data, Transaction *trn)
00235 {
00236 gnc_commodity_table *table;
00237
00238 table = gnc_book_get_commodity_table (data->book);
00239
00240 xaccTransBeginEdit (trn);
00241 clear_up_transaction_commodity(table, trn,
00242 xaccTransGetCurrency,
00243 xaccTransSetCurrency);
00244
00245 xaccTransScrubCurrency (trn);
00246 xaccTransCommitEdit (trn);
00247
00248 data->counter.transactions_loaded++;
00249 run_callback(data, "transaction");
00250 return TRUE;
00251 }
00252
00253 static gboolean
00254 add_schedXaction_local(sixtp_gdv2 *data, SchedXaction *sx)
00255 {
00256 SchedXactions *sxes;
00257 sxes = gnc_book_get_schedxactions(data->book);
00258 gnc_sxes_add_sx(sxes, sx);
00259 data->counter.schedXactions_loaded++;
00260 run_callback(data, "schedXactions");
00261 return TRUE;
00262 }
00263
00264 static gboolean
00265 add_template_transaction_local( sixtp_gdv2 *data,
00266 gnc_template_xaction_data *txd )
00267 {
00268 GList *n;
00269 Account *tmpAcct;
00270 Account *acctRoot = NULL;
00271 QofBook *book;
00272
00273 book = data->book;
00274
00275
00276
00277
00278 for ( n = txd->accts; n; n = n->next ) {
00279 if ( gnc_account_get_parent( (Account*)n->data ) == NULL ) {
00280
00281 acctRoot = gnc_book_get_template_root(book);
00282 tmpAcct = gnc_account_lookup_by_name( acctRoot,
00283 xaccAccountGetName( (Account*)n->data ) );
00284 if ( tmpAcct != NULL ) {
00285
00286
00287
00288
00289 gnc_account_remove_child( acctRoot, tmpAcct );
00290 }
00291
00292 gnc_account_append_child( acctRoot, (Account*)n->data );
00293 }
00294
00295 }
00296
00297 for ( n = txd->transactions; n; n = n->next ) {
00298
00299 add_transaction_local( data, (Transaction*)n->data );
00300 }
00301
00302 return TRUE;
00303 }
00304
00305 static gboolean
00306 add_pricedb_local(sixtp_gdv2 *data, GNCPriceDB *db)
00307 {
00308
00309 return TRUE;
00310 }
00311
00312 static void
00313 do_counter_cb (const char *type, gpointer data_p, gpointer be_data_p)
00314 {
00315 GncXmlDataType_t *data = data_p;
00316 struct file_backend *be_data = be_data_p;
00317
00318 g_return_if_fail (type && data && be_data);
00319 g_return_if_fail (data->version == GNC_FILE_BACKEND_VERS);
00320
00321 if (be_data->ok == TRUE)
00322 return;
00323
00324 if (!safe_strcmp (be_data->tag, data->type_name))
00325 be_data->ok = TRUE;
00326
00327
00328 }
00329
00330 static gboolean
00331 gnc_counter_end_handler(gpointer data_for_children,
00332 GSList* data_from_children, GSList* sibling_data,
00333 gpointer parent_data, gpointer global_data,
00334 gpointer *result, const gchar *tag)
00335 {
00336 char *strval;
00337 gint64 val;
00338 char *type;
00339 xmlNodePtr tree = (xmlNodePtr)data_for_children;
00340 gxpf_data *gdata = (gxpf_data*)global_data;
00341 sixtp_gdv2 *sixdata = (sixtp_gdv2*)gdata->parsedata;
00342 gboolean ret = TRUE;
00343
00344 if (parent_data)
00345 return TRUE;
00346
00347
00348
00349 if (!tag)
00350 return TRUE;
00351
00352 g_return_val_if_fail(tree, FALSE);
00353
00354
00355
00356
00357
00358 type = (char*)xmlGetProp(tree, BAD_CAST "cd:type");
00359 strval = dom_tree_to_text(tree);
00360 if (!string_to_gint64(strval, &val))
00361 {
00362 PERR ("string_to_gint64 failed with input: %s",
00363 strval ? strval : "(null)");
00364 ret = FALSE;
00365 }
00366 else if (safe_strcmp(type, "transaction") == 0)
00367 {
00368 sixdata->counter.transactions_total = val;
00369 }
00370 else if (safe_strcmp(type, "account") == 0)
00371 {
00372 sixdata->counter.accounts_total = val;
00373 }
00374 else if (safe_strcmp(type, "book") == 0)
00375 {
00376 sixdata->counter.books_total = val;
00377 }
00378 else if (safe_strcmp(type, "commodity") == 0)
00379 {
00380 sixdata->counter.commodities_total = val;
00381 }
00382 else if (safe_strcmp(type, "schedxaction") == 0)
00383 {
00384 sixdata->counter.schedXactions_total = val;
00385 }
00386 else if (safe_strcmp(type, "budget") == 0)
00387 {
00388 sixdata->counter.budgets_total = val;
00389 }
00390 else
00391 {
00392 struct file_backend be_data;
00393
00394 be_data.ok = FALSE;
00395 be_data.tag = type;
00396
00397 qof_object_foreach_backend (GNC_FILE_BACKEND, do_counter_cb, &be_data);
00398
00399 if (be_data.ok == FALSE)
00400 {
00401 PERR("Unknown type: %s", type ? type : "(null)");
00402
00403
00404
00405
00406
00407
00408 ret = TRUE;
00409 }
00410 }
00411
00412 g_free (strval);
00413 xmlFree (type);
00414 xmlFreeNode(tree);
00415 return ret;
00416 }
00417
00418 static sixtp*
00419 gnc_counter_sixtp_parser_create(void)
00420 {
00421 return sixtp_dom_parser_new(gnc_counter_end_handler, NULL, NULL);
00422 }
00423
00424 static void
00425 debug_print_counter_data(load_counter *data)
00426 {
00427 DEBUG("Transactions: Total: %d, Loaded: %d",
00428 data->transactions_total, data->transactions_loaded);
00429 DEBUG("Accounts: Total: %d, Loaded: %d",
00430 data->accounts_total, data->accounts_loaded);
00431 DEBUG("Books: Total: %d, Loaded: %d",
00432 data->books_total, data->books_loaded);
00433 DEBUG("Commodities: Total: %d, Loaded: %d",
00434 data->commodities_total, data->commodities_loaded);
00435 DEBUG("Scheduled Transactions: Total: %d, Loaded: %d",
00436 data->schedXactions_total, data->schedXactions_loaded);
00437 DEBUG("Budgets: Total: %d, Loaded: %d",
00438 data->budgets_total, data->budgets_loaded);
00439 }
00440
00441 static void
00442 file_rw_feedback (sixtp_gdv2 *gd, const char *type)
00443 {
00444 load_counter *counter;
00445 int loaded, total, percentage;
00446
00447 g_assert(gd != NULL);
00448 if (!gd->gui_display_fn)
00449 return;
00450
00451 counter = &gd->counter;
00452 loaded = counter->transactions_loaded + counter->accounts_loaded +
00453 counter->books_loaded + counter->commodities_loaded +
00454 counter->schedXactions_loaded + counter->budgets_loaded;
00455 total = counter->transactions_total + counter->accounts_total +
00456 counter->books_total + counter->commodities_total +
00457 counter->schedXactions_total + counter->budgets_total;
00458 if (total == 0)
00459 total = 1;
00460
00461 percentage = (loaded * 100)/total;
00462 if (percentage > 100) {
00463
00464
00465
00466
00467
00468
00469
00470
00471
00472
00473
00474
00475
00476
00477 }
00478 gd->gui_display_fn(NULL, percentage);
00479 }
00480
00481 static const char *BOOK_TAG = "gnc:book";
00482 static const char *BOOK_ID_TAG = "book:id";
00483 static const char *BOOK_SLOTS_TAG = "book:slots";
00484 static const char *ACCOUNT_TAG = "gnc:account";
00485 static const char *PRICEDB_TAG = "gnc:pricedb";
00486 static const char *COMMODITY_TAG = "gnc:commodity";
00487 static const char *COUNT_DATA_TAG = "gnc:count-data";
00488 static const char *TRANSACTION_TAG = "gnc:transaction";
00489 static const char *SCHEDXACTION_TAG = "gnc:schedxaction";
00490 static const char *TEMPLATE_TRANSACTION_TAG = "gnc:template-transactions";
00491 static const char *BUDGET_TAG = "gnc:budget";
00492
00493 static void
00494 add_item_cb (const char *type, gpointer data_p, gpointer be_data_p)
00495 {
00496 GncXmlDataType_t *data = data_p;
00497 struct file_backend *be_data = be_data_p;
00498
00499 g_return_if_fail (type && data && be_data);
00500 g_return_if_fail (data->version == GNC_FILE_BACKEND_VERS);
00501
00502 if (be_data->ok)
00503 return;
00504
00505 if (!safe_strcmp (be_data->tag, data->type_name)) {
00506 if (data->add_item)
00507 (data->add_item)(be_data->gd, be_data->data);
00508
00509 be_data->ok = TRUE;
00510 }
00511 }
00512
00513 static gboolean
00514 book_callback(const char *tag, gpointer globaldata, gpointer data)
00515 {
00516 sixtp_gdv2 *gd = (sixtp_gdv2*)globaldata;
00517
00518 if(safe_strcmp(tag, ACCOUNT_TAG) == 0)
00519 {
00520 add_account_local(gd, (Account*)data);
00521 }
00522 else if(safe_strcmp(tag, PRICEDB_TAG) == 0)
00523 {
00524 add_pricedb_local(gd, (GNCPriceDB*)data);
00525 }
00526 else if(safe_strcmp(tag, COMMODITY_TAG) == 0)
00527 {
00528 add_commodity_local(gd, (gnc_commodity*)data);
00529 }
00530 else if(safe_strcmp(tag, TRANSACTION_TAG) == 0)
00531 {
00532 add_transaction_local(gd, (Transaction*)data);
00533 }
00534 else if(safe_strcmp(tag, SCHEDXACTION_TAG) == 0)
00535 {
00536 add_schedXaction_local(gd, (SchedXaction*)data);
00537 }
00538 else if(safe_strcmp(tag, TEMPLATE_TRANSACTION_TAG) == 0)
00539 {
00540 add_template_transaction_local( gd, (gnc_template_xaction_data*)data );
00541 }
00542 else if(safe_strcmp(tag, BUDGET_TAG) == 0)
00543 {
00544
00545 }
00546 else
00547 {
00548 struct file_backend be_data;
00549
00550 be_data.ok = FALSE;
00551 be_data.tag = tag;
00552 be_data.gd = gd;
00553 be_data.data = data;
00554
00555 qof_object_foreach_backend (GNC_FILE_BACKEND, add_item_cb, &be_data);
00556
00557 if (be_data.ok == FALSE)
00558 {
00559 PWARN ("unexpected tag %s", tag);
00560 }
00561 }
00562 return TRUE;
00563 }
00564
00565 static gboolean
00566 generic_callback(const char *tag, gpointer globaldata, gpointer data)
00567 {
00568 sixtp_gdv2 *gd = (sixtp_gdv2*)globaldata;
00569
00570 if(safe_strcmp(tag, BOOK_TAG) == 0)
00571 {
00572 add_book_local(gd, (QofBook*)data);
00573 book_callback(tag, globaldata, data);
00574 }
00575 else
00576 {
00577
00578 book_callback(tag, globaldata, data);
00579 }
00580 return TRUE;
00581 }
00582
00583 static void
00584 add_parser_cb (const char *type, gpointer data_p, gpointer be_data_p)
00585 {
00586 GncXmlDataType_t *data = data_p;
00587 struct file_backend *be_data = be_data_p;
00588
00589 g_return_if_fail (type && data && be_data);
00590 g_return_if_fail (data->version == GNC_FILE_BACKEND_VERS);
00591
00592 if (be_data->ok == FALSE)
00593 return;
00594
00595 if (data->create_parser)
00596 if(!sixtp_add_some_sub_parsers(
00597 be_data->parser, TRUE,
00598 data->type_name, (data->create_parser)(),
00599 NULL, NULL))
00600 be_data->ok = FALSE;
00601 }
00602
00603 static void
00604 scrub_cb (const char *type, gpointer data_p, gpointer be_data_p)
00605 {
00606 GncXmlDataType_t *data = data_p;
00607 struct file_backend *be_data = be_data_p;
00608
00609 g_return_if_fail (type && data && be_data);
00610 g_return_if_fail (data->version == GNC_FILE_BACKEND_VERS);
00611
00612 if (data->scrub)
00613 (data->scrub)(be_data->book);
00614 }
00615
00616 static sixtp_gdv2 *
00617 gnc_sixtp_gdv2_new (
00618 QofBook *book,
00619 gboolean exporting,
00620 countCallbackFn countcallback,
00621 QofBePercentageFunc gui_display_fn)
00622 {
00623 sixtp_gdv2 *gd = g_new0(sixtp_gdv2, 1);
00624
00625 if (gd == NULL) return NULL;
00626
00627 gd->book = book;
00628 gd->counter.accounts_loaded = 0;
00629 gd->counter.accounts_total = 0;
00630 gd->counter.books_loaded = 0;
00631 gd->counter.books_total = 0;
00632 gd->counter.commodities_loaded = 0;
00633 gd->counter.commodities_total = 0;
00634 gd->counter.transactions_loaded = 0;
00635 gd->counter.transactions_total = 0;
00636 gd->counter.prices_loaded = 0;
00637 gd->counter.prices_total = 0;
00638 gd->counter.schedXactions_loaded = 0;
00639 gd->counter.schedXactions_total = 0;
00640 gd->counter.budgets_loaded = 0;
00641 gd->counter.budgets_total = 0;
00642 gd->exporting = exporting;
00643 gd->countCallback = countcallback;
00644 gd->gui_display_fn = gui_display_fn;
00645 return gd;
00646 }
00647
00648 static gboolean
00649 qof_session_load_from_xml_file_v2_full(
00650 FileBackend *fbe, QofBook *book,
00651 sixtp_push_handler push_handler, gpointer push_user_data)
00652 {
00653 Account *root;
00654 QofBackend *be = &fbe->be;
00655 sixtp_gdv2 *gd;
00656 sixtp *top_parser;
00657 sixtp *main_parser;
00658 sixtp *book_parser;
00659 struct file_backend be_data;
00660 gboolean retval;
00661
00662 gd = gnc_sixtp_gdv2_new(book, FALSE, file_rw_feedback, be->percentage);
00663
00664 top_parser = sixtp_new();
00665 main_parser = sixtp_new();
00666 book_parser = sixtp_new();
00667
00668 if(!sixtp_add_some_sub_parsers(
00669 top_parser, TRUE,
00670 GNC_V2_STRING, main_parser,
00671 NULL, NULL))
00672 {
00673 goto bail;
00674 }
00675
00676 if(!sixtp_add_some_sub_parsers(
00677 main_parser, TRUE,
00678 COUNT_DATA_TAG, gnc_counter_sixtp_parser_create(),
00679 BOOK_TAG, book_parser,
00680
00681
00682
00683
00684 PRICEDB_TAG, gnc_pricedb_sixtp_parser_create(),
00685 COMMODITY_TAG, gnc_commodity_sixtp_parser_create(),
00686 ACCOUNT_TAG, gnc_account_sixtp_parser_create(),
00687 TRANSACTION_TAG, gnc_transaction_sixtp_parser_create(),
00688 SCHEDXACTION_TAG, gnc_schedXaction_sixtp_parser_create(),
00689 TEMPLATE_TRANSACTION_TAG, gnc_template_transaction_sixtp_parser_create(),
00690 NULL, NULL))
00691 {
00692 goto bail;
00693 }
00694
00695 if(!sixtp_add_some_sub_parsers(
00696 book_parser, TRUE,
00697 BOOK_ID_TAG, gnc_book_id_sixtp_parser_create(),
00698 BOOK_SLOTS_TAG, gnc_book_slots_sixtp_parser_create(),
00699 COUNT_DATA_TAG, gnc_counter_sixtp_parser_create(),
00700 PRICEDB_TAG, gnc_pricedb_sixtp_parser_create(),
00701 COMMODITY_TAG, gnc_commodity_sixtp_parser_create(),
00702 ACCOUNT_TAG, gnc_account_sixtp_parser_create(),
00703 BUDGET_TAG, gnc_budget_sixtp_parser_create(),
00704 TRANSACTION_TAG, gnc_transaction_sixtp_parser_create(),
00705 SCHEDXACTION_TAG, gnc_schedXaction_sixtp_parser_create(),
00706 TEMPLATE_TRANSACTION_TAG, gnc_template_transaction_sixtp_parser_create(),
00707 NULL, NULL))
00708 {
00709 goto bail;
00710 }
00711
00712 be_data.ok = TRUE;
00713 be_data.parser = book_parser;
00714 qof_object_foreach_backend (GNC_FILE_BACKEND, add_parser_cb, &be_data);
00715 if (be_data.ok == FALSE)
00716 goto bail;
00717
00718
00719 xaccLogDisable ();
00720 xaccDisableDataScrubbing();
00721
00722 if (push_handler) {
00723 gpointer parse_result = NULL;
00724 gxpf_data gpdata;
00725
00726 gpdata.cb = generic_callback;
00727 gpdata.parsedata = gd;
00728 gpdata.bookdata = book;
00729
00730 retval = sixtp_parse_push(top_parser, push_handler, push_user_data,
00731 NULL, &gpdata, &parse_result);
00732 } else {
00733 retval = gnc_xml_parse_file(top_parser, fbe->fullpath,
00734 generic_callback, gd, book);
00735 }
00736
00737 if (!retval) {
00738 sixtp_destroy(top_parser);
00739 xaccLogEnable ();
00740 xaccEnableDataScrubbing();
00741 goto bail;
00742 }
00743 debug_print_counter_data(&gd->counter);
00744
00745
00746 sixtp_destroy (top_parser);
00747 g_free(gd);
00748
00749 xaccEnableDataScrubbing();
00750
00751
00752 qof_book_mark_saved (book);
00753
00754
00755 memset(&be_data, 0, sizeof(be_data));
00756 be_data.book = book;
00757 qof_object_foreach_backend (GNC_FILE_BACKEND, scrub_cb, &be_data);
00758
00759
00760 root = gnc_book_get_root_account(book);
00761 xaccAccountTreeScrubQuoteSources (root, gnc_book_get_commodity_table(book));
00762
00763
00764 xaccAccountTreeScrubCommodities (root);
00765
00766
00767 xaccAccountTreeScrubSplits (root);
00768
00769
00770
00771
00772 gnc_account_foreach_descendant(root,
00773 (AccountCb) xaccAccountCommitEdit,
00774 NULL);
00775
00776
00777 xaccLogEnable ();
00778
00779 return TRUE;
00780
00781 bail:
00782 g_free(gd);
00783 return FALSE;
00784 }
00785
00786 gboolean
00787 qof_session_load_from_xml_file_v2(FileBackend *fbe, QofBook *book)
00788 {
00789 return qof_session_load_from_xml_file_v2_full(fbe, book, NULL, NULL);
00790 }
00791
00792
00793
00794 static void
00795 write_counts(FILE* out, ...)
00796 {
00797 va_list ap;
00798 char *type;
00799
00800 va_start(ap, out);
00801 type = va_arg(ap, char *);
00802
00803 while(type)
00804 {
00805 int amount = va_arg(ap, int);
00806
00807 if(amount != 0)
00808 {
00809 #if GNUCASH_REALLY_BUILD_AN_XML_TREE_ON_OUTPUT
00810 char *val;
00811 xmlNodePtr node;
00812
00813 val = g_strdup_printf("%d", amount);
00814
00815 node = xmlNewNode(NULL, BAD_CAST COUNT_DATA_TAG);
00816
00817
00818
00819
00820
00821 xmlSetProp(node, BAD_CAST "cd:type", BAD_CAST type);
00822 xmlNodeAddContent(node, BAD_CAST val);
00823
00824 xmlElemDump(out, NULL, node);
00825 fprintf(out, "\n");
00826
00827 g_free(val);
00828 xmlFreeNode(node);
00829 #else
00830 fprintf(out, "<%s %s=\"%s\">%d</%s>\n",
00831 COUNT_DATA_TAG, "cd:type", type, amount, COUNT_DATA_TAG);
00832 #endif
00833
00834 }
00835
00836 type = va_arg(ap, char *);
00837 }
00838
00839 va_end(ap);
00840 }
00841
00842 static gint
00843 compare_namespaces(gconstpointer a, gconstpointer b)
00844 {
00845 const gchar *sa = (const gchar *) a;
00846 const gchar *sb = (const gchar *) b;
00847 return(safe_strcmp(sa, sb));
00848 }
00849
00850 static gint
00851 compare_commodity_ids(gconstpointer a, gconstpointer b)
00852 {
00853 const gnc_commodity *ca = (const gnc_commodity *) a;
00854 const gnc_commodity *cb = (const gnc_commodity *) b;
00855 return(safe_strcmp(gnc_commodity_get_mnemonic(ca),
00856 gnc_commodity_get_mnemonic(cb)));
00857 }
00858
00859 static void write_pricedb (FILE *out, QofBook *book, sixtp_gdv2 *gd);
00860 static void write_transactions (FILE *out, QofBook *book, sixtp_gdv2 *gd);
00861 static void write_template_transaction_data (FILE *out, QofBook *book, sixtp_gdv2 *gd);
00862 static void write_schedXactions(FILE *out, QofBook *book, sixtp_gdv2 *gd);
00863 static void write_budget (QofInstance *ent, gpointer data);
00864
00865 static void
00866 write_counts_cb (const char *type, gpointer data_p, gpointer be_data_p)
00867 {
00868 GncXmlDataType_t *data = data_p;
00869 struct file_backend *be_data = be_data_p;
00870
00871 g_return_if_fail (type && data && be_data);
00872 g_return_if_fail (data->version == GNC_FILE_BACKEND_VERS);
00873
00874 if (data->get_count)
00875 write_counts (be_data->out, data->type_name,
00876 (data->get_count) (be_data->book),
00877 NULL);
00878 }
00879
00880 static void
00881 write_data_cb (const char *type, gpointer data_p, gpointer be_data_p)
00882 {
00883 GncXmlDataType_t *data = data_p;
00884 struct file_backend *be_data = be_data_p;
00885
00886 g_return_if_fail (type && data && be_data);
00887 g_return_if_fail (data->version == GNC_FILE_BACKEND_VERS);
00888
00889 if (data->write)
00890 (data->write)(be_data->out, be_data->book);
00891 }
00892
00893 static void
00894 write_book(FILE *out, QofBook *book, sixtp_gdv2 *gd)
00895 {
00896 struct file_backend be_data;
00897
00898 #ifdef IMPLEMENT_BOOK_DOM_TREES_LATER
00899
00900
00901
00902
00903
00904 xmlNodePtr node;
00905
00906 node = gnc_book_dom_tree_create(book);
00907
00908 if(!node)
00909 {
00910 return;
00911 }
00912
00913 xmlElemDump(out, NULL, node);
00914 if(fprintf(out, "\n") < 0)
00915 {
00916 qof_backend_set_error(qof_book_get_backend(book), ERR_FILEIO_WRITE_ERROR);
00917 return;
00918 }
00919
00920 xmlFreeNode(node);
00921 #endif
00922
00923 be_data.out = out;
00924 be_data.book = book;
00925 be_data.gd = gd;
00926 if(fprintf( out, "<%s version=\"%s\">\n", BOOK_TAG, gnc_v2_book_version_string) < 0)
00927 {
00928 qof_backend_set_error(qof_book_get_backend(book), ERR_FILEIO_WRITE_ERROR);
00929 return;
00930 }
00931 write_book_parts (out, book);
00932
00933
00934
00935
00936 write_counts(out,
00937 "commodity",
00938 gnc_commodity_table_get_size(
00939 gnc_book_get_commodity_table(book)),
00940 "account",
00941 1 + gnc_account_n_descendants(gnc_book_get_root_account(book)),
00942 "transaction",
00943 gnc_book_count_transactions(book),
00944 "schedxaction",
00945 g_list_length(gnc_book_get_schedxactions(book)->sx_list),
00946 "budget", qof_collection_count(
00947 qof_book_get_collection(book, GNC_ID_BUDGET)),
00948 NULL);
00949
00950 qof_object_foreach_backend (GNC_FILE_BACKEND, write_counts_cb, &be_data);
00951
00952 write_commodities(out, book, gd);
00953 write_pricedb(out, book, gd);
00954 write_accounts(out, book, gd);
00955 write_transactions(out, book, gd);
00956 write_template_transaction_data(out, book, gd);
00957 write_schedXactions(out, book, gd);
00958
00959 qof_collection_foreach(qof_book_get_collection(book, GNC_ID_BUDGET),
00960 write_budget, &be_data);
00961
00962 qof_object_foreach_backend (GNC_FILE_BACKEND, write_data_cb, &be_data);
00963
00964 if(fprintf( out, "</%s>\n", BOOK_TAG ) < 0) {
00965 qof_backend_set_error(qof_book_get_backend(book), ERR_FILEIO_WRITE_ERROR);
00966 }
00967 }
00968
00969 void
00970 write_commodities(FILE *out, QofBook *book, sixtp_gdv2 *gd)
00971 {
00972 gnc_commodity_table *tbl;
00973 GList *namespaces;
00974 GList *lp;
00975
00976 tbl = gnc_book_get_commodity_table(book);
00977
00978 namespaces = gnc_commodity_table_get_namespaces(tbl);
00979 if(namespaces)
00980 {
00981 namespaces = g_list_sort(namespaces, compare_namespaces);
00982 }
00983
00984 for(lp = namespaces; lp; lp = lp->next)
00985 {
00986 GList *comms, *lp2;
00987 xmlNodePtr comnode;
00988
00989 comms = gnc_commodity_table_get_commodities(tbl, lp->data);
00990 comms = g_list_sort(comms, compare_commodity_ids);
00991
00992 for(lp2 = comms; lp2; lp2 = lp2->next) {
00993 comnode = gnc_commodity_dom_tree_create(lp2->data);
00994 if (comnode == NULL)
00995 continue;
00996
00997 xmlElemDump(out, NULL, comnode);
00998 fprintf(out, "\n");
00999
01000 xmlFreeNode(comnode);
01001 gd->counter.commodities_loaded++;
01002 run_callback(gd, "commodities");
01003 }
01004
01005 g_list_free (comms);
01006 }
01007
01008 if (namespaces) g_list_free (namespaces);
01009 }
01010
01011 static void
01012 write_pricedb(FILE *out, QofBook *book, sixtp_gdv2 *gd)
01013 {
01014 xmlNodePtr node;
01015
01016 node = gnc_pricedb_dom_tree_create(gnc_book_get_pricedb(book));
01017
01018 if(!node)
01019 {
01020 return;
01021 }
01022
01023 xmlElemDump(out, NULL, node);
01024 fprintf(out, "\n");
01025
01026 xmlFreeNode(node);
01027 }
01028
01029 static int
01030 xml_add_trn_data(Transaction *t, gpointer data)
01031 {
01032 struct file_backend *be_data = data;
01033 xmlNodePtr node;
01034
01035 node = gnc_transaction_dom_tree_create(t);
01036
01037 xmlElemDump(be_data->out, NULL, node);
01038 fprintf(be_data->out, "\n");
01039
01040 xmlFreeNode(node);
01041 be_data->gd->counter.transactions_loaded++;
01042 run_callback(be_data->gd, "transaction");
01043 return 0;
01044 }
01045
01046 static void
01047 write_transactions(FILE *out, QofBook *book, sixtp_gdv2 *gd)
01048 {
01049 struct file_backend be_data;
01050
01051 be_data.out = out;
01052 be_data.gd = gd;
01053 xaccAccountTreeForEachTransaction(gnc_book_get_root_account(book),
01054 xml_add_trn_data,
01055 (gpointer) &be_data);
01056 }
01057
01058 static void
01059 write_template_transaction_data( FILE *out, QofBook *book, sixtp_gdv2 *gd )
01060 {
01061 Account *ra;
01062 struct file_backend be_data;
01063
01064 be_data.out = out;
01065 be_data.gd = gd;
01066
01067 ra = gnc_book_get_template_root(book);
01068 if ( gnc_account_n_descendants(ra) > 0 )
01069 {
01070 fprintf( out, "<%s>\n", TEMPLATE_TRANSACTION_TAG );
01071 write_account_tree( out, ra, gd );
01072 xaccAccountTreeForEachTransaction( ra, xml_add_trn_data, (gpointer)&be_data );
01073 fprintf( out, "</%s>\n", TEMPLATE_TRANSACTION_TAG );
01074 }
01075 }
01076
01077 static void
01078 write_schedXactions( FILE *out, QofBook *book, sixtp_gdv2 *gd)
01079 {
01080 GList *schedXactions;
01081 SchedXaction *tmpSX;
01082 xmlNodePtr node;
01083
01084 schedXactions = gnc_book_get_schedxactions(book)->sx_list;
01085
01086 if ( schedXactions == NULL )
01087 return;
01088
01089 do {
01090 tmpSX = schedXactions->data;
01091 node = gnc_schedXaction_dom_tree_create( tmpSX );
01092 xmlElemDump( out, NULL, node );
01093 fprintf( out, "\n" );
01094 xmlFreeNode( node );
01095 gd->counter.schedXactions_loaded++;
01096 run_callback(gd, "schedXactions");
01097 } while ( (schedXactions = schedXactions->next) );
01098 }
01099
01100 static void
01101 write_budget (QofInstance *ent, gpointer data)
01102 {
01103 xmlNodePtr node;
01104 struct file_backend* be = data;
01105
01106 GncBudget *bgt = GNC_BUDGET(ent);
01107 node = gnc_budget_dom_tree_create(bgt);
01108 xmlElemDump( be->out, NULL, node );
01109 fprintf( be->out, "\n" );
01110 xmlFreeNode( node );
01111
01112 be->gd->counter.budgets_loaded++;
01113 run_callback(be->gd, "budgets");
01114 }
01115
01116 void
01117 gnc_xml2_write_namespace_decl (FILE *out, const char *namespace)
01118 {
01119 g_return_if_fail (namespace);
01120 fprintf(out, "\n xmlns:%s=\"http://www.gnucash.org/XML/%s\"",
01121 namespace, namespace);
01122 }
01123
01124 static void
01125 do_write_namespace_cb (const char *type, gpointer data_p, gpointer file_p)
01126 {
01127 GncXmlDataType_t *data = data_p;
01128 FILE *out = file_p;
01129
01130 g_return_if_fail (type && data && out);
01131 g_re