GnuCash 2.4.99
gnc-schedxaction-xml-v2.c
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 }
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Defines