|
GnuCash 2.4.99
|
00001 /******************************************************************** 00002 * gnc-schedxactions-xml-v2.c -- xml routines for transactions * 00003 * Copyright (C) 2001,2007 Joshua Sled <jsled@asynchronous.org> * 00004 * * 00005 * This program is free software; you can redistribute it and/or * 00006 * modify it under the terms of the GNU General Public License as * 00007 * published by the Free Software Foundation; either version 2 of * 00008 * the License, or (at your option) any later version. * 00009 * * 00010 * This program is distributed in the hope that it will be useful, * 00011 * but WITHOUT ANY WARRANTY; without even the implied warranty of * 00012 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * 00013 * GNU General Public License for more details. * 00014 * * 00015 * You should have received a copy of the GNU General Public License* 00016 * along with this program; if not, contact: * 00017 * * 00018 * Free Software Foundation Voice: +1-617-542-5942 * 00019 * 51 Franklin Street, Fifth Floor Fax: +1-617-542-2652 * 00020 * Boston, MA 02110-1301, USA gnu@gnu.org * 00021 * * 00022 *******************************************************************/ 00023 00024 #include "config.h" 00025 00026 #include <glib.h> 00027 #include <string.h> 00028 00029 #include "SX-book.h" 00030 00031 #include "gnc-xml-helper.h" 00032 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 00042 #include "io-gncxml-v2.h" 00043 #include "io-gncxml-gen.h" 00044 00045 #include "sixtp-dom-parsers.h" 00046 00047 #include "gnc-gconf-utils.h" 00048 00049 #undef G_LOG_DOMAIN 00050 #define G_LOG_DOMAIN "gnc.backend.file.sx" 00051 00052 #define SX_ID "sx:id" 00053 #define SX_NAME "sx:name" 00054 #define SX_ENABLED "sx:enabled" 00055 #define SX_AUTOCREATE "sx:autoCreate" 00056 #define SX_AUTOCREATE_NOTIFY "sx:autoCreateNotify" 00057 #define SX_ADVANCE_CREATE_DAYS "sx:advanceCreateDays" 00058 #define SX_ADVANCE_REMIND_DAYS "sx:advanceRemindDays" 00059 #define SX_INSTANCE_COUNT "sx:instanceCount" 00060 #define SX_START "sx:start" 00061 #define SX_LAST "sx:last" 00062 #define SX_NUM_OCCUR "sx:num-occur" 00063 #define SX_REM_OCCUR "sx:rem-occur" 00064 #define SX_END "sx:end" 00065 #define SX_TEMPL_ACCT "sx:templ-acct" 00066 #define SX_FREQSPEC "sx:freqspec" 00067 #define SX_SCHEDULE "sx:schedule" 00068 #define SX_SLOTS "sx:slots" 00069 #define SX_DEFER_INSTANCE "sx:deferredInstance" 00070 00071 /* 00072 * FIXME: These should be defined in a header somewhere 00073 */ 00074 00075 #define GNC_ACCOUNT_TAG "gnc:account" 00076 #define GNC_TRANSACTION_TAG "gnc:transaction" 00077 #define GNC_SCHEDXACTION_TAG "gnc:schedxaction" 00078 00079 const gchar *schedxaction_version_string = "1.0.0"; 00080 const gchar *schedxaction_version2_string = "2.0.0"; 00081 00082 xmlNodePtr 00083 gnc_schedXaction_dom_tree_create(SchedXaction *sx) 00084 { 00085 xmlNodePtr ret; 00086 const GDate *date; 00087 gint instCount; 00088 const GncGUID *templ_acc_guid; 00089 gboolean allow_2_2_incompat = TRUE; 00090 00091 templ_acc_guid = xaccAccountGetGUID(sx->template_acct); 00092 00093 /* FIXME: this should be the same as the def in io-gncxml-v2.c */ 00094 ret = xmlNewNode( NULL, BAD_CAST GNC_SCHEDXACTION_TAG ); 00095 00096 if (allow_2_2_incompat) 00097 xmlSetProp(ret, BAD_CAST "version", BAD_CAST schedxaction_version2_string); 00098 else 00099 xmlSetProp(ret, BAD_CAST "version", BAD_CAST schedxaction_version_string); 00100 00101 xmlAddChild( ret, 00102 guid_to_dom_tree(SX_ID, 00103 xaccSchedXactionGetGUID(sx)) ); 00104 00105 xmlNewTextChild( ret, NULL, BAD_CAST SX_NAME, BAD_CAST xaccSchedXactionGetName(sx) ); 00106 00107 if (allow_2_2_incompat) 00108 { 00109 xmlNewTextChild( ret, NULL, BAD_CAST SX_ENABLED, 00110 BAD_CAST ( sx->enabled ? "y" : "n" ) ); 00111 } 00112 00113 xmlNewTextChild( ret, NULL, BAD_CAST SX_AUTOCREATE, 00114 BAD_CAST ( sx->autoCreateOption ? "y" : "n" ) ); 00115 xmlNewTextChild( ret, NULL, BAD_CAST SX_AUTOCREATE_NOTIFY, 00116 BAD_CAST ( sx->autoCreateNotify ? "y" : "n" ) ); 00117 xmlAddChild(ret, int_to_dom_tree(SX_ADVANCE_CREATE_DAYS, 00118 sx->advanceCreateDays)); 00119 xmlAddChild(ret, int_to_dom_tree(SX_ADVANCE_REMIND_DAYS, 00120 sx->advanceRemindDays)); 00121 00122 instCount = gnc_sx_get_instance_count( sx, NULL ); 00123 xmlAddChild( ret, int_to_dom_tree( SX_INSTANCE_COUNT, 00124 instCount ) ); 00125 00126 xmlAddChild( ret, 00127 gdate_to_dom_tree( SX_START, 00128 xaccSchedXactionGetStartDate(sx) ) ); 00129 00130 date = xaccSchedXactionGetLastOccurDate(sx); 00131 if ( g_date_valid( date ) ) 00132 { 00133 xmlAddChild( ret, gdate_to_dom_tree( SX_LAST, date ) ); 00134 } 00135 00136 if ( xaccSchedXactionHasOccurDef(sx) ) 00137 { 00138 00139 xmlAddChild(ret, int_to_dom_tree( SX_NUM_OCCUR, 00140 xaccSchedXactionGetNumOccur(sx))); 00141 xmlAddChild(ret, int_to_dom_tree( SX_REM_OCCUR, 00142 xaccSchedXactionGetRemOccur(sx))); 00143 00144 } 00145 else if ( xaccSchedXactionHasEndDate(sx) ) 00146 { 00147 xmlAddChild( ret, 00148 gdate_to_dom_tree( SX_END, 00149 xaccSchedXactionGetEndDate(sx) ) ); 00150 } 00151 00152 /* output template account GncGUID */ 00153 xmlAddChild( ret, 00154 guid_to_dom_tree(SX_TEMPL_ACCT, 00155 templ_acc_guid)); 00156 00157 if (allow_2_2_incompat) 00158 { 00159 xmlNodePtr schedule_node = xmlNewNode(NULL, 00160 BAD_CAST "sx:schedule"); 00161 GList *schedule = gnc_sx_get_schedule(sx); 00162 for (; schedule != NULL; schedule = schedule->next) 00163 { 00164 xmlAddChild(schedule_node, recurrence_to_dom_tree("gnc:recurrence", (Recurrence*)schedule->data)); 00165 } 00166 xmlAddChild(ret, schedule_node); 00167 } 00168 00169 /* Output deferred-instance list. */ 00170 { 00171 xmlNodePtr instNode; 00172 SXTmpStateData *tsd; 00173 GList *l; 00174 00175 for ( l = gnc_sx_get_defer_instances( sx ); l; l = l->next ) 00176 { 00177 tsd = (SXTmpStateData*)l->data; 00178 00179 instNode = xmlNewNode( NULL, BAD_CAST SX_DEFER_INSTANCE ); 00180 if ( g_date_valid( &tsd->last_date ) ) 00181 { 00182 xmlAddChild( instNode, gdate_to_dom_tree( SX_LAST, 00183 &tsd->last_date ) ); 00184 } 00185 xmlAddChild( instNode, int_to_dom_tree( SX_REM_OCCUR, 00186 tsd->num_occur_rem ) ); 00187 xmlAddChild( instNode, int_to_dom_tree( SX_INSTANCE_COUNT, 00188 tsd->num_inst ) ); 00189 xmlAddChild( ret, instNode ); 00190 } 00191 } 00192 00193 /* output kvp_frame */ 00194 { 00195 xmlNodePtr kvpnode = 00196 kvp_frame_to_dom_tree( SX_SLOTS, 00197 xaccSchedXactionGetSlots(sx) ); 00198 if ( kvpnode ) 00199 { 00200 xmlAddChild(ret, kvpnode); 00201 } 00202 } 00203 00204 return ret; 00205 } 00206 00207 struct sx_pdata 00208 { 00209 SchedXaction *sx; 00210 QofBook *book; 00211 gboolean saw_freqspec; 00212 gboolean saw_recurrence; 00213 }; 00214 00215 static 00216 gboolean 00217 sx_id_handler( xmlNodePtr node, gpointer sx_pdata ) 00218 { 00219 struct sx_pdata *pdata = sx_pdata; 00220 SchedXaction *sx = pdata->sx; 00221 GncGUID *tmp = dom_tree_to_guid( node ); 00222 00223 g_return_val_if_fail( tmp, FALSE ); 00224 xaccSchedXactionSetGUID(sx, tmp); 00225 g_free( tmp ); 00226 00227 return TRUE; 00228 } 00229 00230 static 00231 gboolean 00232 sx_name_handler( xmlNodePtr node, gpointer sx_pdata ) 00233 { 00234 struct sx_pdata *pdata = sx_pdata; 00235 SchedXaction *sx = pdata->sx; 00236 gchar *tmp = dom_tree_to_text( node ); 00237 g_debug("sx named [%s]", tmp); 00238 g_return_val_if_fail( tmp, FALSE ); 00239 xaccSchedXactionSetName( sx, tmp ); 00240 g_free( tmp ); 00241 return TRUE; 00242 } 00243 00244 static gboolean 00245 sx_enabled_handler( xmlNodePtr node, gpointer sx_pdata ) 00246 { 00247 struct sx_pdata *pdata = sx_pdata; 00248 SchedXaction *sx = pdata->sx; 00249 gchar *tmp = dom_tree_to_text( node ); 00250 00251 sx->enabled = (safe_strcmp( tmp, "y" ) == 0 ? TRUE : FALSE ); 00252 00253 return TRUE; 00254 } 00255 00256 static gboolean 00257 sx_autoCreate_handler( xmlNodePtr node, gpointer sx_pdata ) 00258 { 00259 struct sx_pdata *pdata = sx_pdata; 00260 SchedXaction *sx = pdata->sx; 00261 gchar *tmp = dom_tree_to_text( node ); 00262 00263 sx->autoCreateOption = (safe_strcmp( tmp, "y" ) == 0 ? TRUE : FALSE ); 00264 00265 return TRUE; 00266 } 00267 00268 static gboolean 00269 sx_notify_handler( xmlNodePtr node, gpointer sx_pdata ) 00270 { 00271 struct sx_pdata *pdata = sx_pdata; 00272 SchedXaction *sx = pdata->sx; 00273 gchar *tmp = dom_tree_to_text( node ); 00274 00275 sx->autoCreateNotify = (safe_strcmp( tmp, "y" ) == 0 ? TRUE : FALSE ); 00276 00277 return TRUE; 00278 } 00279 00280 static gboolean 00281 sx_advCreate_handler( xmlNodePtr node, gpointer sx_pdata ) 00282 { 00283 struct sx_pdata *pdata = sx_pdata; 00284 SchedXaction *sx = pdata->sx; 00285 gint64 advCreate; 00286 00287 if ( ! dom_tree_to_integer( node, &advCreate ) ) 00288 { 00289 return FALSE; 00290 } 00291 00292 xaccSchedXactionSetAdvanceCreation( sx, advCreate ); 00293 return TRUE; 00294 } 00295 00296 static gboolean 00297 sx_advRemind_handler( xmlNodePtr node, gpointer sx_pdata ) 00298 { 00299 struct sx_pdata *pdata = sx_pdata; 00300 SchedXaction *sx = pdata->sx; 00301 gint64 advRemind; 00302 00303 if ( ! dom_tree_to_integer( node, &advRemind ) ) 00304 { 00305 return FALSE; 00306 } 00307 00308 xaccSchedXactionSetAdvanceReminder( sx, advRemind ); 00309 return TRUE; 00310 } 00311 00312 static 00313 gboolean 00314 sx_set_date( xmlNodePtr node, SchedXaction *sx, 00315 void (*settor)( SchedXaction *sx, const GDate *d ) ) 00316 { 00317 GDate *date; 00318 date = dom_tree_to_gdate( node ); 00319 g_return_val_if_fail( date, FALSE ); 00320 (*settor)( sx, date ); 00321 g_date_free( date ); 00322 00323 return TRUE; 00324 } 00325 00326 static 00327 gboolean 00328 sx_instcount_handler( xmlNodePtr node, gpointer sx_pdata ) 00329 { 00330 struct sx_pdata *pdata = sx_pdata; 00331 SchedXaction *sx = pdata->sx; 00332 gint64 instanceNum; 00333 00334 if ( ! dom_tree_to_integer( node, &instanceNum ) ) 00335 { 00336 return FALSE; 00337 } 00338 00339 gnc_sx_set_instance_count( sx, instanceNum ); 00340 return TRUE; 00341 } 00342 00343 static 00344 gboolean 00345 sx_start_handler( xmlNodePtr node, gpointer sx_pdata ) 00346 { 00347 struct sx_pdata *pdata = sx_pdata; 00348 SchedXaction *sx = pdata->sx; 00349 00350 return sx_set_date( node, sx, xaccSchedXactionSetStartDate ); 00351 } 00352 00353 static 00354 gboolean 00355 sx_last_handler( xmlNodePtr node, gpointer sx_pdata ) 00356 { 00357 struct sx_pdata *pdata = sx_pdata; 00358 SchedXaction *sx = pdata->sx; 00359 00360 return sx_set_date( node, sx, xaccSchedXactionSetLastOccurDate ); 00361 } 00362 00363 static 00364 gboolean 00365 sx_end_handler( xmlNodePtr node, gpointer sx_pdata ) 00366 { 00367 struct sx_pdata *pdata = sx_pdata; 00368 SchedXaction *sx = pdata->sx; 00369 00370 return sx_set_date( node, sx, xaccSchedXactionSetEndDate ); 00371 } 00372 00373 static void 00374 _fixup_recurrence_start_dates(const GDate *sx_start_date, GList *schedule) 00375 { 00376 GList *iter; 00377 for (iter = schedule; iter != NULL; iter = iter->next) 00378 { 00379 Recurrence *r; 00380 GDate start, next; 00381 00382 r = (Recurrence*)iter->data; 00383 00384 start = *sx_start_date; 00385 g_date_subtract_days(&start, 1); 00386 00387 g_date_clear(&next, 1); 00388 00389 recurrenceNextInstance(r, &start, &next); 00390 g_return_if_fail(g_date_valid(&next)); 00391 00392 { 00393 gchar date_str[128]; 00394 gchar *sched_str; 00395 00396 g_date_strftime(date_str, 127, "%x", &next); 00397 sched_str = recurrenceToString(r); 00398 g_debug("setting recurrence [%s] start date to [%s]", 00399 sched_str, date_str); 00400 g_free(sched_str); 00401 } 00402 00403 recurrenceSet(r, 00404 recurrenceGetMultiplier(r), 00405 recurrenceGetPeriodType(r), 00406 &next, 00407 recurrenceGetWeekendAdjust(r)); 00408 } 00409 00410 if (g_list_length(schedule) == 1 00411 && recurrenceGetPeriodType((Recurrence*)g_list_nth_data(schedule, 0)) == PERIOD_ONCE) 00412 { 00413 char date_buf[128]; 00414 Recurrence *fixup = (Recurrence*)g_list_nth_data(schedule, 0); 00415 g_date_strftime(date_buf, 127, "%x", sx_start_date); 00416 recurrenceSet(fixup, 1, PERIOD_ONCE, sx_start_date, WEEKEND_ADJ_NONE); 00417 g_debug("fixed up period=ONCE Recurrence to date [%s]", date_buf); 00418 } 00419 } 00420 00421 static gboolean 00422 sx_freqspec_handler( xmlNodePtr node, gpointer sx_pdata ) 00423 { 00424 struct sx_pdata *pdata = sx_pdata; 00425 SchedXaction *sx = pdata->sx; 00426 GList *schedule; 00427 gchar* debug_str; 00428 00429 g_return_val_if_fail( node, FALSE ); 00430 00431 schedule = dom_tree_freqSpec_to_recurrences(node, pdata->book); 00432 gnc_sx_set_schedule(sx, schedule); 00433 debug_str = recurrenceListToString(schedule); 00434 g_debug("parsed from freqspec [%s]", debug_str); 00435 g_free(debug_str); 00436 00437 _fixup_recurrence_start_dates(xaccSchedXactionGetStartDate(sx), schedule); 00438 pdata->saw_freqspec = TRUE; 00439 00440 return TRUE; 00441 } 00442 00443 static gboolean 00444 sx_schedule_recurrence_handler(xmlNodePtr node, gpointer parsing_data) 00445 { 00446 GList **schedule = (GList**)parsing_data; 00447 gchar* sched_str; 00448 Recurrence *r = dom_tree_to_recurrence(node); 00449 g_return_val_if_fail(r, FALSE); 00450 sched_str = recurrenceToString(r); 00451 g_debug("parsed recurrence [%s]", sched_str); 00452 g_free(sched_str); 00453 *schedule = g_list_append(*schedule, r); 00454 return TRUE; 00455 } 00456 00457 struct dom_tree_handler sx_recurrence_list_handlers[] = 00458 { 00459 { "gnc:recurrence", sx_schedule_recurrence_handler, 0, 0 }, 00460 { NULL, NULL, 0, 0 } 00461 }; 00462 00463 static gboolean 00464 sx_recurrence_handler(xmlNodePtr node, gpointer _pdata) 00465 { 00466 struct sx_pdata *parsing_data = _pdata; 00467 GList *schedule = NULL; 00468 gchar* debug_str; 00469 00470 g_return_val_if_fail(node, FALSE); 00471 00472 if (!dom_tree_generic_parse(node, sx_recurrence_list_handlers, &schedule)) 00473 return FALSE; 00474 // g_return_val_if_fail(schedule, FALSE); 00475 debug_str = recurrenceListToString(schedule); 00476 g_debug("setting freshly-parsed schedule: [%s]", debug_str); 00477 g_free(debug_str); 00478 gnc_sx_set_schedule(parsing_data->sx, schedule); 00479 parsing_data->saw_recurrence = TRUE; 00480 return TRUE; 00481 } 00482 00483 static 00484 gboolean 00485 sx_defer_last_handler( xmlNodePtr node, gpointer gpTSD ) 00486 { 00487 GDate *gd; 00488 SXTmpStateData *tsd = (SXTmpStateData*)gpTSD; 00489 00490 g_return_val_if_fail( node, FALSE ); 00491 gd = dom_tree_to_gdate( node ); 00492 g_return_val_if_fail( gd, FALSE ); 00493 tsd->last_date = *gd; 00494 g_date_free( gd ); 00495 return TRUE; 00496 } 00497 00498 static 00499 gboolean 00500 sx_defer_rem_occur_handler( xmlNodePtr node, gpointer gpTSD ) 00501 { 00502 gint64 remOccur; 00503 SXTmpStateData *tsd = (SXTmpStateData*)gpTSD; 00504 g_return_val_if_fail( node, FALSE ); 00505 00506 if ( ! dom_tree_to_integer( node, &remOccur ) ) 00507 { 00508 return FALSE; 00509 } 00510 tsd->num_occur_rem = remOccur; 00511 return TRUE; 00512 } 00513 00514 static 00515 gboolean 00516 sx_defer_inst_count_handler( xmlNodePtr node, gpointer gpTSD ) 00517 { 00518 gint64 instCount; 00519 SXTmpStateData *tsd = (SXTmpStateData*)gpTSD; 00520 g_return_val_if_fail( node, FALSE ); 00521 00522 if ( ! dom_tree_to_integer( node, &instCount ) ) 00523 { 00524 return FALSE; 00525 } 00526 tsd->num_inst = instCount; 00527 return TRUE; 00528 } 00529 00530 struct dom_tree_handler sx_defer_dom_handlers[] = 00531 { 00532 /* tag name, handler, opt, ? */ 00533 { SX_LAST, sx_defer_last_handler, 1, 0 }, 00534 { SX_REM_OCCUR, sx_defer_rem_occur_handler, 1, 0 }, 00535 { SX_INSTANCE_COUNT, sx_defer_inst_count_handler, 1, 0 }, 00536 { NULL, NULL, 0, 0 } 00537 }; 00538 00539 static 00540 gboolean 00541 sx_defer_inst_handler( xmlNodePtr node, gpointer sx_pdata ) 00542 { 00543 struct sx_pdata *pdata = sx_pdata; 00544 SchedXaction *sx = pdata->sx; 00545 SXTmpStateData *tsd; 00546 00547 g_return_val_if_fail( node, FALSE ); 00548 00549 tsd = g_new0( SXTmpStateData, 1 ); 00550 g_assert( sx_defer_dom_handlers != NULL ); 00551 if ( !dom_tree_generic_parse( node, 00552 sx_defer_dom_handlers, 00553 tsd ) ) 00554 { 00555 xmlElemDump(stdout, NULL, node); 00556 g_free( tsd ); 00557 tsd = NULL; 00558 return FALSE; 00559 } 00560 00561 /* We assume they were serialized in sorted order, here. */ 00562 sx->deferredList = g_list_append( sx->deferredList, tsd ); 00563 return TRUE; 00564 } 00565 00566 static 00567 gboolean 00568 sx_numOccur_handler( xmlNodePtr node, gpointer sx_pdata ) 00569 { 00570 struct sx_pdata *pdata = sx_pdata; 00571 SchedXaction *sx = pdata->sx; 00572 gint64 numOccur; 00573 00574 if ( ! dom_tree_to_integer( node, &numOccur ) ) 00575 { 00576 return FALSE; 00577 } 00578 00579 xaccSchedXactionSetNumOccur( sx, numOccur ); 00580 00581 return TRUE; 00582 } 00583 00584 00585 static 00586 gboolean 00587 sx_templ_acct_handler( xmlNodePtr node, gpointer sx_pdata) 00588 { 00589 struct sx_pdata *pdata = sx_pdata; 00590 SchedXaction *sx = pdata->sx; 00591 GncGUID *templ_acct_guid = dom_tree_to_guid(node); 00592 Account *account; 00593 00594 if (!templ_acct_guid) 00595 { 00596 return FALSE; 00597 } 00598 00599 account = xaccAccountLookup(templ_acct_guid, pdata->book); 00600 sx_set_template_account(sx, account); 00601 g_free(templ_acct_guid); 00602 00603 return TRUE; 00604 } 00605 00606 00607 static 00608 gboolean 00609 sx_remOccur_handler( xmlNodePtr node, gpointer sx_pdata ) 00610 { 00611 struct sx_pdata *pdata = sx_pdata; 00612 SchedXaction *sx = pdata->sx; 00613 gint64 remOccur; 00614 00615 if ( ! dom_tree_to_integer( node, &remOccur ) ) 00616 { 00617 return FALSE; 00618 } 00619 00620 xaccSchedXactionSetRemOccur( sx, remOccur ); 00621 00622 return TRUE; 00623 } 00624 00625 static 00626 gboolean 00627 sx_slots_handler( xmlNodePtr node, gpointer sx_pdata ) 00628 { 00629 struct sx_pdata *pdata = sx_pdata; 00630 SchedXaction *sx = pdata->sx; 00631 00632 return dom_tree_to_kvp_frame_given( node, xaccSchedXactionGetSlots (sx) ); 00633 } 00634 00635 struct dom_tree_handler sx_dom_handlers[] = 00636 { 00637 { SX_ID, sx_id_handler, 1, 0 }, 00638 { SX_NAME, sx_name_handler, 1, 0 }, 00639 { SX_ENABLED, sx_enabled_handler, 0, 0 }, 00640 { SX_AUTOCREATE, sx_autoCreate_handler, 1, 0 }, 00641 { SX_AUTOCREATE_NOTIFY, sx_notify_handler, 1, 0 }, 00642 { SX_ADVANCE_CREATE_DAYS, sx_advCreate_handler, 1, 0 }, 00643 { SX_ADVANCE_REMIND_DAYS, sx_advRemind_handler, 1, 0 }, 00644 { SX_INSTANCE_COUNT, sx_instcount_handler, 0, 0 }, 00645 { SX_START, sx_start_handler, 1, 0 }, 00646 { SX_LAST, sx_last_handler, 0, 0 }, 00647 { SX_NUM_OCCUR, sx_numOccur_handler, 0, 0 }, 00648 { SX_REM_OCCUR, sx_remOccur_handler, 0, 0 }, 00649 { SX_END, sx_end_handler, 0, 0 }, 00650 { SX_TEMPL_ACCT, sx_templ_acct_handler, 0, 0 }, 00651 { SX_FREQSPEC, sx_freqspec_handler, 0, 0 }, 00652 { SX_SCHEDULE, sx_recurrence_handler, 0, 0 }, 00653 { SX_DEFER_INSTANCE, sx_defer_inst_handler, 0, 0 }, 00654 { SX_SLOTS, sx_slots_handler, 0, 0 }, 00655 { NULL, NULL, 0, 0 } 00656 }; 00657 00658 static gboolean 00659 gnc_schedXaction_end_handler(gpointer data_for_children, 00660 GSList* data_from_children, GSList* sibling_data, 00661 gpointer parent_data, gpointer global_data, 00662 gpointer *result, const gchar *tag) 00663 { 00664 SchedXaction *sx; 00665 gboolean successful = FALSE; 00666 xmlNodePtr tree = (xmlNodePtr)data_for_children; 00667 gxpf_data *gdata = (gxpf_data*)global_data; 00668 struct sx_pdata sx_pdata; 00669 00670 if ( parent_data ) 00671 { 00672 return TRUE; 00673 } 00674 00675 if ( !tag ) 00676 { 00677 return TRUE; 00678 } 00679 00680 g_return_val_if_fail( tree, FALSE ); 00681 00682 sx = xaccSchedXactionMalloc( gdata->bookdata ); 00683 00684 memset(&sx_pdata, 0, sizeof(sx_pdata)); 00685 sx_pdata.sx = sx; 00686 sx_pdata.book = gdata->bookdata; 00687 00688 g_assert( sx_dom_handlers != NULL ); 00689 00690 successful = dom_tree_generic_parse( tree, sx_dom_handlers, &sx_pdata ); 00691 if (!successful) 00692 { 00693 g_critical("failed to parse scheduled xaction"); 00694 xmlElemDump( stdout, NULL, tree ); 00695 gnc_sx_begin_edit( sx ); 00696 xaccSchedXactionDestroy( sx ); 00697 goto done; 00698 } 00699 00700 if (tree->properties) 00701 { 00702 gchar *sx_name = xaccSchedXactionGetName(sx); 00703 xmlAttr *attr; 00704 for (attr = tree->properties; attr != NULL; attr = attr->next) 00705 { 00706 xmlChar *attr_value = attr->children->content; 00707 g_debug("sx attribute name[%s] value[%s]", attr->name, attr_value); 00708 if (strcmp((const char *)attr->name, "version") != 0) 00709 { 00710 g_warning("unknown sx attribute [%s]", attr->name); 00711 continue; 00712 } 00713 00714 // if version == 1.0.0: ensure freqspec, no recurrence 00715 // if version == 2.0.0: ensure recurrence, no freqspec. 00716 if (strcmp((const char *)attr_value, 00717 schedxaction_version_string) == 0) 00718 { 00719 if (!sx_pdata.saw_freqspec) 00720 g_critical("did not see freqspec in version 1 sx [%s]", sx_name); 00721 if (sx_pdata.saw_recurrence) 00722 g_warning("saw recurrence in supposedly version 1 sx [%s]", sx_name); 00723 } 00724 00725 if (strcmp((const char *)attr_value, 00726 schedxaction_version2_string) == 0) 00727 { 00728 if (sx_pdata.saw_freqspec) 00729 g_warning("saw freqspec in version 2 sx [%s]", sx_name); 00730 if (!sx_pdata.saw_recurrence) 00731 g_critical("did not find recurrence in version 2 sx [%s]", sx_name); 00732 } 00733 } 00734 } 00735 00736 // generic_callback -> book_callback: insert the SX in the book 00737 gdata->cb( tag, gdata->parsedata, sx ); 00738 00739 /* FIXME: this should be removed somewhere near 1.8 release time. */ 00740 if ( sx->template_acct == NULL ) 00741 { 00742 Account *ra = NULL; 00743 const char *id = NULL; 00744 Account *acct = NULL; 00745 sixtp_gdv2 *sixdata = gdata->parsedata; 00746 QofBook *book; 00747 00748 book = sixdata->book; 00749 00750 /* We're dealing with a pre-200107<near-end-of-month> rgmerk 00751 change re: storing template accounts. */ 00752 /* Fix: get account with name of our GncGUID from the template 00753 accounts. Make that our template_acct pointer. */ 00754 /* THREAD-UNSAFE */ 00755 id = guid_to_string( xaccSchedXactionGetGUID( sx ) ); 00756 ra = gnc_book_get_template_root(book); 00757 if ( ra == NULL ) 00758 { 00759 g_warning( "Error getting template root account from being-parsed Book." ); 00760 xmlFreeNode( tree ); 00761 return FALSE; 00762 } 00763 acct = gnc_account_lookup_by_name( ra, id ); 00764 if ( acct == NULL ) 00765 { 00766 g_warning("no template account with name [%s]", id); 00767 xmlFreeNode( tree ); 00768 return FALSE; 00769 } 00770 g_debug("template account name [%s] for SX with GncGUID [%s]", 00771 xaccAccountGetName( acct ), id ); 00772 00773 /* FIXME: free existing template account. 00774 * HUH????? We only execute this if there isn't 00775 * currently an existing template account, don't we? 00776 * <rgmerk> 00777 */ 00778 00779 sx->template_acct = acct; 00780 } 00781 00782 done: 00783 xmlFreeNode( tree ); 00784 00785 return successful; 00786 } 00787 00788 sixtp* 00789 gnc_schedXaction_sixtp_parser_create(void) 00790 { 00791 return sixtp_dom_parser_new( gnc_schedXaction_end_handler, NULL, NULL ); 00792 } 00793 00794 static 00795 gboolean 00796 tt_act_handler( xmlNodePtr node, gpointer data ) 00797 { 00798 gnc_template_xaction_data *txd = data; 00799 Account *acc; 00800 gnc_commodity *com; 00801 00802 acc = dom_tree_to_account(node, txd->book); 00803 00804 if ( acc == NULL ) 00805 { 00806 return FALSE; 00807 } 00808 else 00809 { 00810 xaccAccountBeginEdit (acc); 00811 00812 /* Check for the lack of a commodity [signifying that the 00813 pre-7/11/2001-CIT-change SX template Account was parsed [but 00814 incorrectly]. */ 00815 if ( xaccAccountGetCommodity( acc ) == NULL ) 00816 { 00817 #if 1 00818 gnc_commodity_table* table; 00819 00820 table = gnc_commodity_table_get_table( txd->book ); 00821 com = gnc_commodity_table_lookup( table, 00822 "template", "template" ); 00823 #else 00824 /* FIXME: This should first look in the table of the 00825 book, maybe? The right thing happens [WRT file 00826 load/save] if we just _new all the time, but it 00827 doesn't seem right. This whole block should go 00828 away at some point, but the same concern still 00829 applies for 00830 SchedXaction.c:xaccSchedXactionInit... */ 00831 com = gnc_commodity_new( txd->book, 00832 "template", "template", 00833 "template", "template", 00834 1 ); 00835 #endif 00836 xaccAccountSetCommodity( acc, com ); 00837 } 00838 00839 txd->accts = g_list_append( txd->accts, acc ); 00840 } 00841 00842 return TRUE; 00843 } 00844 00845 static 00846 gboolean 00847 tt_trn_handler( xmlNodePtr node, gpointer data ) 00848 { 00849 gnc_template_xaction_data *txd = data; 00850 Transaction *trn; 00851 00852 trn = dom_tree_to_transaction( node, txd->book ); 00853 00854 if ( trn == NULL ) 00855 { 00856 return FALSE; 00857 } 00858 else 00859 { 00860 txd->transactions = g_list_append( txd->transactions, trn ); 00861 } 00862 00863 return TRUE; 00864 } 00865 00866 struct dom_tree_handler tt_dom_handlers[] = 00867 { 00868 { GNC_ACCOUNT_TAG, tt_act_handler, 0, 0 }, 00869 { GNC_TRANSACTION_TAG, tt_trn_handler, 0, 0 }, 00870 { NULL, NULL, 0, 0 }, 00871 }; 00872 00873 static gboolean 00874 gnc_template_transaction_end_handler(gpointer data_for_children, 00875 GSList* data_from_children, 00876 GSList* sibling_data, 00877 gpointer parent_data, 00878 gpointer global_data, 00879 gpointer *result, 00880 const gchar *tag) 00881 { 00882 gboolean successful = FALSE; 00883 xmlNodePtr tree = data_for_children; 00884 gxpf_data *gdata = global_data; 00885 QofBook *book = gdata->bookdata; 00886 GList *n; 00887 gnc_template_xaction_data txd; 00888 00889 txd.book = book; 00890 txd.accts = NULL; 00891 txd.transactions = NULL; 00892 00893 /* the DOM tree will have an account tree [the template 00894 accounts] and a list of transactions [which will be members 00895 of the template account]. 00896 00897 we want to parse through the dom trees for each, placing 00898 the null-parent account in the book's template-group slot, 00899 the others under it, and the transactions as normal. */ 00900 00901 if ( parent_data ) 00902 { 00903 return TRUE; 00904 } 00905 00906 if ( !tag ) 00907 { 00908 return TRUE; 00909 } 00910 00911 g_return_val_if_fail( tree, FALSE ); 00912 00913 successful = dom_tree_generic_parse( tree, tt_dom_handlers, &txd ); 00914 00915 if ( successful ) 00916 { 00917 gdata->cb( tag, gdata->parsedata, &txd ); 00918 } 00919 else 00920 { 00921 g_warning("failed to parse template transaction"); 00922 xmlElemDump( stdout, NULL, tree ); 00923 } 00924 00925 /* cleanup */ 00926 for ( n = txd.accts; n; n = n->next ) 00927 { 00928 n->data = NULL; 00929 } 00930 for ( n = txd.transactions; n; n = n->next ) 00931 { 00932 n->data = NULL; 00933 } 00934 g_list_free( txd.accts ); 00935 g_list_free( txd.transactions ); 00936 00937 xmlFreeNode( tree ); 00938 00939 return successful; 00940 } 00941 00942 sixtp* 00943 gnc_template_transaction_sixtp_parser_create( void ) 00944 { 00945 return sixtp_dom_parser_new( gnc_template_transaction_end_handler, 00946 NULL, NULL ); 00947 }
1.7.4