GnuCash  2.6.99
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
gnc-schedxaction-xml-v2.c
1 /********************************************************************
2  * gnc-schedxactions-xml-v2.c -- xml routines for transactions *
3  * Copyright (C) 2001,2007 Joshua Sled <[email protected]> *
4  * *
5  * This program is free software; you can redistribute it and/or *
6  * modify it under the terms of the GNU General Public License as *
7  * published by the Free Software Foundation; either version 2 of *
8  * the License, or (at your option) any later version. *
9  * *
10  * This program is distributed in the hope that it will be useful, *
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of *
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
13  * GNU General Public License for more details. *
14  * *
15  * You should have received a copy of the GNU General Public License*
16  * along with this program; if not, contact: *
17  * *
18  * Free Software Foundation Voice: +1-617-542-5942 *
19  * 51 Franklin Street, Fifth Floor Fax: +1-617-542-2652 *
20  * Boston, MA 02110-1301, USA [email protected] *
21  * *
22  *******************************************************************/
23 
24 #include "config.h"
25 
26 #include <glib.h>
27 #include <string.h>
28 
29 #include "SX-book.h"
30 
31 #include "gnc-xml-helper.h"
32 
33 #include "sixtp.h"
34 #include "sixtp-utils.h"
35 #include "sixtp-parsers.h"
36 #include "sixtp-utils.h"
37 #include "sixtp-dom-parsers.h"
38 #include "sixtp-dom-generators.h"
39 
40 #include "gnc-xml.h"
41 
42 #include "io-gncxml-v2.h"
43 #include "io-gncxml-gen.h"
44 
45 #include "sixtp-dom-parsers.h"
46 
47 #undef G_LOG_DOMAIN
48 #define G_LOG_DOMAIN "gnc.backend.file.sx"
49 
50 #define SX_ID "sx:id"
51 #define SX_NAME "sx:name"
52 #define SX_ENABLED "sx:enabled"
53 #define SX_AUTOCREATE "sx:autoCreate"
54 #define SX_AUTOCREATE_NOTIFY "sx:autoCreateNotify"
55 #define SX_ADVANCE_CREATE_DAYS "sx:advanceCreateDays"
56 #define SX_ADVANCE_REMIND_DAYS "sx:advanceRemindDays"
57 #define SX_INSTANCE_COUNT "sx:instanceCount"
58 #define SX_START "sx:start"
59 #define SX_LAST "sx:last"
60 #define SX_NUM_OCCUR "sx:num-occur"
61 #define SX_REM_OCCUR "sx:rem-occur"
62 #define SX_END "sx:end"
63 #define SX_TEMPL_ACCT "sx:templ-acct"
64 #define SX_FREQSPEC "sx:freqspec"
65 #define SX_SCHEDULE "sx:schedule"
66 #define SX_SLOTS "sx:slots"
67 #define SX_DEFER_INSTANCE "sx:deferredInstance"
68 
69 /*
70  * FIXME: These should be defined in a header somewhere
71  */
72 
73 #define GNC_ACCOUNT_TAG "gnc:account"
74 #define GNC_TRANSACTION_TAG "gnc:transaction"
75 #define GNC_SCHEDXACTION_TAG "gnc:schedxaction"
76 
77 const gchar *schedxaction_version_string = "1.0.0";
78 const gchar *schedxaction_version2_string = "2.0.0";
79 
80 xmlNodePtr
81 gnc_schedXaction_dom_tree_create(SchedXaction *sx)
82 {
83  xmlNodePtr ret;
84  const GDate *date;
85  gint instCount;
86  const GncGUID *templ_acc_guid;
87  gboolean allow_2_2_incompat = TRUE;
88  gchar *name = g_strdup (xaccSchedXactionGetName(sx));
89 
90  templ_acc_guid = xaccAccountGetGUID(sx->template_acct);
91 
92  /* FIXME: this should be the same as the def in io-gncxml-v2.c */
93  ret = xmlNewNode (NULL, BAD_CAST GNC_SCHEDXACTION_TAG);
94 
95  if (allow_2_2_incompat)
96  xmlSetProp(ret, BAD_CAST "version", BAD_CAST schedxaction_version2_string);
97  else
98  xmlSetProp(ret, BAD_CAST "version", BAD_CAST schedxaction_version_string);
99 
100  xmlAddChild( ret,
101  guid_to_dom_tree(SX_ID,
103 
104  xmlNewTextChild( ret, NULL, BAD_CAST SX_NAME, checked_char_cast (name));
105  g_free (name);
106 
107  if (allow_2_2_incompat)
108  {
109  xmlNewTextChild( ret, NULL, BAD_CAST SX_ENABLED,
110  BAD_CAST ( sx->enabled ? "y" : "n" ) );
111  }
112 
113  xmlNewTextChild( ret, NULL, BAD_CAST SX_AUTOCREATE,
114  BAD_CAST ( sx->autoCreateOption ? "y" : "n" ) );
115  xmlNewTextChild( ret, NULL, BAD_CAST SX_AUTOCREATE_NOTIFY,
116  BAD_CAST ( sx->autoCreateNotify ? "y" : "n" ) );
117  xmlAddChild(ret, int_to_dom_tree(SX_ADVANCE_CREATE_DAYS,
118  sx->advanceCreateDays));
119  xmlAddChild(ret, int_to_dom_tree(SX_ADVANCE_REMIND_DAYS,
120  sx->advanceRemindDays));
121 
122  instCount = gnc_sx_get_instance_count( sx, NULL );
123  xmlAddChild( ret, int_to_dom_tree( SX_INSTANCE_COUNT,
124  instCount ) );
125 
126  xmlAddChild( ret,
127  gdate_to_dom_tree( SX_START,
128  xaccSchedXactionGetStartDate(sx) ) );
129 
130  date = xaccSchedXactionGetLastOccurDate(sx);
131  if ( g_date_valid( date ) )
132  {
133  xmlAddChild( ret, gdate_to_dom_tree( SX_LAST, date ) );
134  }
135 
136  if ( xaccSchedXactionHasOccurDef(sx) )
137  {
138 
139  xmlAddChild(ret, int_to_dom_tree( SX_NUM_OCCUR,
140  xaccSchedXactionGetNumOccur(sx)));
141  xmlAddChild(ret, int_to_dom_tree( SX_REM_OCCUR,
142  xaccSchedXactionGetRemOccur(sx)));
143 
144  }
145  else if ( xaccSchedXactionHasEndDate(sx) )
146  {
147  xmlAddChild( ret,
148  gdate_to_dom_tree( SX_END,
150  }
151 
152  /* output template account GncGUID */
153  xmlAddChild( ret,
154  guid_to_dom_tree(SX_TEMPL_ACCT,
155  templ_acc_guid));
156 
157  if (allow_2_2_incompat)
158  {
159  xmlNodePtr schedule_node = xmlNewNode(NULL,
160  BAD_CAST "sx:schedule");
161  GList *schedule = gnc_sx_get_schedule(sx);
162  for (; schedule != NULL; schedule = schedule->next)
163  {
164  xmlAddChild(schedule_node, recurrence_to_dom_tree("gnc:recurrence", (Recurrence*)schedule->data));
165  }
166  xmlAddChild(ret, schedule_node);
167  }
168 
169  /* Output deferred-instance list. */
170  {
171  xmlNodePtr instNode;
172  SXTmpStateData *tsd;
173  GList *l;
174 
175  for ( l = gnc_sx_get_defer_instances( sx ); l; l = l->next )
176  {
177  tsd = (SXTmpStateData*)l->data;
178 
179  instNode = xmlNewNode( NULL, BAD_CAST SX_DEFER_INSTANCE );
180  if ( g_date_valid( &tsd->last_date ) )
181  {
182  xmlAddChild( instNode, gdate_to_dom_tree( SX_LAST,
183  &tsd->last_date ) );
184  }
185  xmlAddChild( instNode, int_to_dom_tree( SX_REM_OCCUR,
186  tsd->num_occur_rem ) );
187  xmlAddChild( instNode, int_to_dom_tree( SX_INSTANCE_COUNT,
188  tsd->num_inst ) );
189  xmlAddChild( ret, instNode );
190  }
191  }
192 
193  /* output kvp_frame */
194  {
195  xmlNodePtr kvpnode =
196  kvp_frame_to_dom_tree( SX_SLOTS,
198  if ( kvpnode )
199  {
200  xmlAddChild(ret, kvpnode);
201  }
202  }
203 
204  return ret;
205 }
206 
207 struct sx_pdata
208 {
209  SchedXaction *sx;
210  QofBook *book;
211  gboolean saw_freqspec;
212  gboolean saw_recurrence;
213 };
214 
215 static
216 gboolean
217 sx_id_handler( xmlNodePtr node, gpointer sx_pdata )
218 {
219  struct sx_pdata *pdata = sx_pdata;
220  SchedXaction *sx = pdata->sx;
221  GncGUID *tmp = dom_tree_to_guid( node );
222 
223  g_return_val_if_fail( tmp, FALSE );
224  xaccSchedXactionSetGUID(sx, tmp);
225  g_free( tmp );
226 
227  return TRUE;
228 }
229 
230 static
231 gboolean
232 sx_name_handler( xmlNodePtr node, gpointer sx_pdata )
233 {
234  struct sx_pdata *pdata = sx_pdata;
235  SchedXaction *sx = pdata->sx;
236  gchar *tmp = dom_tree_to_text( node );
237  g_debug("sx named [%s]", tmp);
238  g_return_val_if_fail( tmp, FALSE );
239  xaccSchedXactionSetName( sx, tmp );
240  g_free( tmp );
241  return TRUE;
242 }
243 
244 static gboolean
245 sx_enabled_handler( xmlNodePtr node, gpointer sx_pdata )
246 {
247  struct sx_pdata *pdata = sx_pdata;
248  SchedXaction *sx = pdata->sx;
249  gchar *tmp = dom_tree_to_text( node );
250 
251  sx->enabled = (g_strcmp0( tmp, "y" ) == 0 ? TRUE : FALSE );
252 
253  return TRUE;
254 }
255 
256 static gboolean
257 sx_autoCreate_handler( xmlNodePtr node, gpointer sx_pdata )
258 {
259  struct sx_pdata *pdata = sx_pdata;
260  SchedXaction *sx = pdata->sx;
261  gchar *tmp = dom_tree_to_text( node );
262 
263  sx->autoCreateOption = (g_strcmp0( tmp, "y" ) == 0 ? TRUE : FALSE );
264 
265  return TRUE;
266 }
267 
268 static gboolean
269 sx_notify_handler( xmlNodePtr node, gpointer sx_pdata )
270 {
271  struct sx_pdata *pdata = sx_pdata;
272  SchedXaction *sx = pdata->sx;
273  gchar *tmp = dom_tree_to_text( node );
274 
275  sx->autoCreateNotify = (g_strcmp0( tmp, "y" ) == 0 ? TRUE : FALSE );
276 
277  return TRUE;
278 }
279 
280 static gboolean
281 sx_advCreate_handler( xmlNodePtr node, gpointer sx_pdata )
282 {
283  struct sx_pdata *pdata = sx_pdata;
284  SchedXaction *sx = pdata->sx;
285  gint64 advCreate;
286 
287  if ( ! dom_tree_to_integer( node, &advCreate ) )
288  {
289  return FALSE;
290  }
291 
292  xaccSchedXactionSetAdvanceCreation( sx, advCreate );
293  return TRUE;
294 }
295 
296 static gboolean
297 sx_advRemind_handler( xmlNodePtr node, gpointer sx_pdata )
298 {
299  struct sx_pdata *pdata = sx_pdata;
300  SchedXaction *sx = pdata->sx;
301  gint64 advRemind;
302 
303  if ( ! dom_tree_to_integer( node, &advRemind ) )
304  {
305  return FALSE;
306  }
307 
308  xaccSchedXactionSetAdvanceReminder( sx, advRemind );
309  return TRUE;
310 }
311 
312 static
313 gboolean
314 sx_set_date( xmlNodePtr node, SchedXaction *sx,
315  void (*settor)( SchedXaction *sx, const GDate *d ) )
316 {
317  GDate *date;
318  date = dom_tree_to_gdate( node );
319  g_return_val_if_fail( date, FALSE );
320  (*settor)( sx, date );
321  g_date_free( date );
322 
323  return TRUE;
324 }
325 
326 static
327 gboolean
328 sx_instcount_handler( xmlNodePtr node, gpointer sx_pdata )
329 {
330  struct sx_pdata *pdata = sx_pdata;
331  SchedXaction *sx = pdata->sx;
332  gint64 instanceNum;
333 
334  if ( ! dom_tree_to_integer( node, &instanceNum ) )
335  {
336  return FALSE;
337  }
338 
339  gnc_sx_set_instance_count( sx, instanceNum );
340  return TRUE;
341 }
342 
343 static
344 gboolean
345 sx_start_handler( xmlNodePtr node, gpointer sx_pdata )
346 {
347  struct sx_pdata *pdata = sx_pdata;
348  SchedXaction *sx = pdata->sx;
349 
350  return sx_set_date( node, sx, xaccSchedXactionSetStartDate );
351 }
352 
353 static
354 gboolean
355 sx_last_handler( xmlNodePtr node, gpointer sx_pdata )
356 {
357  struct sx_pdata *pdata = sx_pdata;
358  SchedXaction *sx = pdata->sx;
359 
360  return sx_set_date( node, sx, xaccSchedXactionSetLastOccurDate );
361 }
362 
363 static
364 gboolean
365 sx_end_handler( xmlNodePtr node, gpointer sx_pdata )
366 {
367  struct sx_pdata *pdata = sx_pdata;
368  SchedXaction *sx = pdata->sx;
369 
370  return sx_set_date( node, sx, xaccSchedXactionSetEndDate );
371 }
372 
373 static void
374 _fixup_recurrence_start_dates(const GDate *sx_start_date, GList *schedule)
375 {
376  GList *iter;
377  for (iter = schedule; iter != NULL; iter = iter->next)
378  {
379  Recurrence *r;
380  GDate start, next;
381 
382  r = (Recurrence*)iter->data;
383 
384  start = *sx_start_date;
385  g_date_subtract_days(&start, 1);
386 
387  g_date_clear(&next, 1);
388 
389  recurrenceNextInstance(r, &start, &next);
390  g_return_if_fail(g_date_valid(&next));
391 
392  {
393  gchar date_str[128];
394  gchar *sched_str;
395 
396  g_date_strftime(date_str, 127, "%x", &next);
397  sched_str = recurrenceToString(r);
398  g_debug("setting recurrence [%s] start date to [%s]",
399  sched_str, date_str);
400  g_free(sched_str);
401  }
402 
403  recurrenceSet(r,
404  recurrenceGetMultiplier(r),
405  recurrenceGetPeriodType(r),
406  &next,
407  recurrenceGetWeekendAdjust(r));
408  }
409 
410  if (g_list_length(schedule) == 1
411  && recurrenceGetPeriodType((Recurrence*)g_list_nth_data(schedule, 0)) == PERIOD_ONCE)
412  {
413  char date_buf[128];
414  Recurrence *fixup = (Recurrence*)g_list_nth_data(schedule, 0);
415  g_date_strftime(date_buf, 127, "%x", sx_start_date);
416  recurrenceSet(fixup, 1, PERIOD_ONCE, sx_start_date, WEEKEND_ADJ_NONE);
417  g_debug("fixed up period=ONCE Recurrence to date [%s]", date_buf);
418  }
419 }
420 
421 static gboolean
422 sx_freqspec_handler( xmlNodePtr node, gpointer sx_pdata )
423 {
424  struct sx_pdata *pdata = sx_pdata;
425  SchedXaction *sx = pdata->sx;
426  GList *schedule;
427  gchar* debug_str;
428 
429  g_return_val_if_fail( node, FALSE );
430 
431  schedule = dom_tree_freqSpec_to_recurrences(node, pdata->book);
432  gnc_sx_set_schedule(sx, schedule);
433  debug_str = recurrenceListToString(schedule);
434  g_debug("parsed from freqspec [%s]", debug_str);
435  g_free(debug_str);
436 
437  _fixup_recurrence_start_dates(xaccSchedXactionGetStartDate(sx), schedule);
438  pdata->saw_freqspec = TRUE;
439 
440  return TRUE;
441 }
442 
443 static gboolean
444 sx_schedule_recurrence_handler(xmlNodePtr node, gpointer parsing_data)
445 {
446  GList **schedule = (GList**)parsing_data;
447  gchar* sched_str;
448  Recurrence *r = dom_tree_to_recurrence(node);
449  g_return_val_if_fail(r, FALSE);
450  sched_str = recurrenceToString(r);
451  g_debug("parsed recurrence [%s]", sched_str);
452  g_free(sched_str);
453  *schedule = g_list_append(*schedule, r);
454  return TRUE;
455 }
456 
457 struct dom_tree_handler sx_recurrence_list_handlers[] =
458 {
459  { "gnc:recurrence", sx_schedule_recurrence_handler, 0, 0 },
460  { NULL, NULL, 0, 0 }
461 };
462 
463 static gboolean
464 sx_recurrence_handler(xmlNodePtr node, gpointer _pdata)
465 {
466  struct sx_pdata *parsing_data = _pdata;
467  GList *schedule = NULL;
468  gchar* debug_str;
469 
470  g_return_val_if_fail(node, FALSE);
471 
472  if (!dom_tree_generic_parse(node, sx_recurrence_list_handlers, &schedule))
473  return FALSE;
474  // g_return_val_if_fail(schedule, FALSE);
475  debug_str = recurrenceListToString(schedule);
476  g_debug("setting freshly-parsed schedule: [%s]", debug_str);
477  g_free(debug_str);
478  gnc_sx_set_schedule(parsing_data->sx, schedule);
479  parsing_data->saw_recurrence = TRUE;
480  return TRUE;
481 }
482 
483 static
484 gboolean
485 sx_defer_last_handler( xmlNodePtr node, gpointer gpTSD )
486 {
487  GDate *gd;
488  SXTmpStateData *tsd = (SXTmpStateData*)gpTSD;
489 
490  g_return_val_if_fail( node, FALSE );
491  gd = dom_tree_to_gdate( node );
492  g_return_val_if_fail( gd, FALSE );
493  tsd->last_date = *gd;
494  g_date_free( gd );
495  return TRUE;
496 }
497 
498 static
499 gboolean
500 sx_defer_rem_occur_handler( xmlNodePtr node, gpointer gpTSD )
501 {
502  gint64 remOccur;
503  SXTmpStateData *tsd = (SXTmpStateData*)gpTSD;
504  g_return_val_if_fail( node, FALSE );
505 
506  if ( ! dom_tree_to_integer( node, &remOccur ) )
507  {
508  return FALSE;
509  }
510  tsd->num_occur_rem = remOccur;
511  return TRUE;
512 }
513 
514 static
515 gboolean
516 sx_defer_inst_count_handler( xmlNodePtr node, gpointer gpTSD )
517 {
518  gint64 instCount;
519  SXTmpStateData *tsd = (SXTmpStateData*)gpTSD;
520  g_return_val_if_fail( node, FALSE );
521 
522  if ( ! dom_tree_to_integer( node, &instCount ) )
523  {
524  return FALSE;
525  }
526  tsd->num_inst = instCount;
527  return TRUE;
528 }
529 
530 struct dom_tree_handler sx_defer_dom_handlers[] =
531 {
532  /* tag name, handler, opt, ? */
533  { SX_LAST, sx_defer_last_handler, 1, 0 },
534  { SX_REM_OCCUR, sx_defer_rem_occur_handler, 1, 0 },
535  { SX_INSTANCE_COUNT, sx_defer_inst_count_handler, 1, 0 },
536  { NULL, NULL, 0, 0 }
537 };
538 
539 static
540 gboolean
541 sx_defer_inst_handler( xmlNodePtr node, gpointer sx_pdata )
542 {
543  struct sx_pdata *pdata = sx_pdata;
544  SchedXaction *sx = pdata->sx;
545  SXTmpStateData *tsd;
546 
547  g_return_val_if_fail( node, FALSE );
548 
549  tsd = g_new0( SXTmpStateData, 1 );
550  g_assert( sx_defer_dom_handlers != NULL );
551  if ( !dom_tree_generic_parse( node,
552  sx_defer_dom_handlers,
553  tsd ) )
554  {
555  xmlElemDump(stdout, NULL, node);
556  g_free( tsd );
557  tsd = NULL;
558  return FALSE;
559  }
560 
561  /* We assume they were serialized in sorted order, here. */
562  sx->deferredList = g_list_append( sx->deferredList, tsd );
563  return TRUE;
564 }
565 
566 static
567 gboolean
568 sx_numOccur_handler( xmlNodePtr node, gpointer sx_pdata )
569 {
570  struct sx_pdata *pdata = sx_pdata;
571  SchedXaction *sx = pdata->sx;
572  gint64 numOccur;
573 
574  if ( ! dom_tree_to_integer( node, &numOccur ) )
575  {
576  return FALSE;
577  }
578 
579  xaccSchedXactionSetNumOccur( sx, numOccur );
580 
581  return TRUE;
582 }
583 
584 
585 static
586 gboolean
587 sx_templ_acct_handler( xmlNodePtr node, gpointer sx_pdata)
588 {
589  struct sx_pdata *pdata = sx_pdata;
590  SchedXaction *sx = pdata->sx;
591  GncGUID *templ_acct_guid = dom_tree_to_guid(node);
592  Account *account;
593 
594  if (!templ_acct_guid)
595  {
596  return FALSE;
597  }
598 
599  account = xaccAccountLookup(templ_acct_guid, pdata->book);
600  sx_set_template_account(sx, account);
601  g_free(templ_acct_guid);
602 
603  return TRUE;
604 }
605 
606 
607 static
608 gboolean
609 sx_remOccur_handler( xmlNodePtr node, gpointer sx_pdata )
610 {
611  struct sx_pdata *pdata = sx_pdata;
612  SchedXaction *sx = pdata->sx;
613  gint64 remOccur;
614 
615  if ( ! dom_tree_to_integer( node, &remOccur ) )
616  {
617  return FALSE;
618  }
619 
620  xaccSchedXactionSetRemOccur( sx, remOccur );
621 
622  return TRUE;
623 }
624 
625 static
626 gboolean
627 sx_slots_handler( xmlNodePtr node, gpointer sx_pdata )
628 {
629  struct sx_pdata *pdata = sx_pdata;
630  SchedXaction *sx = pdata->sx;
631 
632  return dom_tree_to_kvp_frame_given( node, xaccSchedXactionGetSlots (sx) );
633 }
634 
635 struct dom_tree_handler sx_dom_handlers[] =
636 {
637  { SX_ID, sx_id_handler, 1, 0 },
638  { SX_NAME, sx_name_handler, 1, 0 },
639  { SX_ENABLED, sx_enabled_handler, 0, 0 },
640  { SX_AUTOCREATE, sx_autoCreate_handler, 1, 0 },
641  { SX_AUTOCREATE_NOTIFY, sx_notify_handler, 1, 0 },
642  { SX_ADVANCE_CREATE_DAYS, sx_advCreate_handler, 1, 0 },
643  { SX_ADVANCE_REMIND_DAYS, sx_advRemind_handler, 1, 0 },
644  { SX_INSTANCE_COUNT, sx_instcount_handler, 0, 0 },
645  { SX_START, sx_start_handler, 1, 0 },
646  { SX_LAST, sx_last_handler, 0, 0 },
647  { SX_NUM_OCCUR, sx_numOccur_handler, 0, 0 },
648  { SX_REM_OCCUR, sx_remOccur_handler, 0, 0 },
649  { SX_END, sx_end_handler, 0, 0 },
650  { SX_TEMPL_ACCT, sx_templ_acct_handler, 0, 0 },
651  { SX_FREQSPEC, sx_freqspec_handler, 0, 0 },
652  { SX_SCHEDULE, sx_recurrence_handler, 0, 0 },
653  { SX_DEFER_INSTANCE, sx_defer_inst_handler, 0, 0 },
654  { SX_SLOTS, sx_slots_handler, 0, 0 },
655  { NULL, NULL, 0, 0 }
656 };
657 
658 static gboolean
659 gnc_schedXaction_end_handler(gpointer data_for_children,
660  GSList* data_from_children, GSList* sibling_data,
661  gpointer parent_data, gpointer global_data,
662  gpointer *result, const gchar *tag)
663 {
664  SchedXaction *sx;
665  gboolean successful = FALSE;
666  xmlNodePtr tree = (xmlNodePtr)data_for_children;
667  gxpf_data *gdata = (gxpf_data*)global_data;
668  struct sx_pdata sx_pdata;
669 
670  if ( parent_data )
671  {
672  return TRUE;
673  }
674 
675  if ( !tag )
676  {
677  return TRUE;
678  }
679 
680  g_return_val_if_fail( tree, FALSE );
681 
682  sx = xaccSchedXactionMalloc( gdata->bookdata );
683 
684  memset(&sx_pdata, 0, sizeof(sx_pdata));
685  sx_pdata.sx = sx;
686  sx_pdata.book = gdata->bookdata;
687 
688  g_assert( sx_dom_handlers != NULL );
689 
690  successful = dom_tree_generic_parse( tree, sx_dom_handlers, &sx_pdata );
691  if (!successful)
692  {
693  g_critical("failed to parse scheduled xaction");
694  xmlElemDump( stdout, NULL, tree );
695  gnc_sx_begin_edit( sx );
697  goto done;
698  }
699 
700  if (tree->properties)
701  {
702  gchar *sx_name = xaccSchedXactionGetName(sx);
703  xmlAttr *attr;
704  for (attr = tree->properties; attr != NULL; attr = attr->next)
705  {
706  xmlChar *attr_value = attr->children->content;
707  g_debug("sx attribute name[%s] value[%s]", attr->name, attr_value);
708  if (strcmp((const char *)attr->name, "version") != 0)
709  {
710  g_warning("unknown sx attribute [%s]", attr->name);
711  continue;
712  }
713 
714  // if version == 1.0.0: ensure freqspec, no recurrence
715  // if version == 2.0.0: ensure recurrence, no freqspec.
716  if (strcmp((const char *)attr_value,
717  schedxaction_version_string) == 0)
718  {
719  if (!sx_pdata.saw_freqspec)
720  g_critical("did not see freqspec in version 1 sx [%s]", sx_name);
721  if (sx_pdata.saw_recurrence)
722  g_warning("saw recurrence in supposedly version 1 sx [%s]", sx_name);
723  }
724 
725  if (strcmp((const char *)attr_value,
726  schedxaction_version2_string) == 0)
727  {
728  if (sx_pdata.saw_freqspec)
729  g_warning("saw freqspec in version 2 sx [%s]", sx_name);
730  if (!sx_pdata.saw_recurrence)
731  g_critical("did not find recurrence in version 2 sx [%s]", sx_name);
732  }
733  }
734  }
735 
736  // generic_callback -> book_callback: insert the SX in the book
737  gdata->cb( tag, gdata->parsedata, sx );
738 
739  /* FIXME: this should be removed somewhere near 1.8 release time. */
740  if ( sx->template_acct == NULL )
741  {
742  Account *ra = NULL;
743  Account *acct = NULL;
744  sixtp_gdv2 *sixdata = gdata->parsedata;
745  QofBook *book;
746  gchar guidstr[GUID_ENCODING_LENGTH+1];
747 
748  book = sixdata->book;
749 
750  /* We're dealing with a pre-200107<near-end-of-month> rgmerk
751  change re: storing template accounts. */
752  /* Fix: get account with name of our GncGUID from the template
753  accounts. Make that our template_acct pointer. */
755  ra = gnc_book_get_template_root(book);
756  if ( ra == NULL )
757  {
758  g_warning( "Error getting template root account from being-parsed Book." );
759  xmlFreeNode( tree );
760  return FALSE;
761  }
762  acct = gnc_account_lookup_by_name( ra, guidstr );
763  if ( acct == NULL )
764  {
765  g_warning("no template account with name [%s]", guidstr);
766  xmlFreeNode( tree );
767  return FALSE;
768  }
769  g_debug("template account name [%s] for SX with GncGUID [%s]",
770  xaccAccountGetName( acct ), guidstr );
771 
772  /* FIXME: free existing template account.
773  * HUH????? We only execute this if there isn't
774  * currently an existing template account, don't we?
775  * <rgmerk>
776  */
777 
778  sx->template_acct = acct;
779  }
780 
781 done:
782  xmlFreeNode( tree );
783 
784  return successful;
785 }
786 
787 sixtp*
788 gnc_schedXaction_sixtp_parser_create(void)
789 {
790  return sixtp_dom_parser_new( gnc_schedXaction_end_handler, NULL, NULL );
791 }
792 
793 static
794 gboolean
795 tt_act_handler( xmlNodePtr node, gpointer data )
796 {
797  gnc_template_xaction_data *txd = data;
798  Account *acc;
799  gnc_commodity *com;
800 
801  acc = dom_tree_to_account(node, txd->book);
802 
803  if ( acc == NULL )
804  {
805  return FALSE;
806  }
807  else
808  {
809  xaccAccountBeginEdit (acc);
810 
811  /* Check for the lack of a commodity [signifying that the
812  pre-7/11/2001-CIT-change SX template Account was parsed [but
813  incorrectly]. */
814  if ( xaccAccountGetCommodity( acc ) == NULL )
815  {
816 #if 1
818 
819  table = gnc_commodity_table_get_table( txd->book );
820  com = gnc_commodity_table_lookup( table,
821  "template", "template" );
822 #else
823  /* FIXME: This should first look in the table of the
824  book, maybe? The right thing happens [WRT file
825  load/save] if we just _new all the time, but it
826  doesn't seem right. This whole block should go
827  away at some point, but the same concern still
828  applies for
829  SchedXaction.c:xaccSchedXactionInit... */
830  com = gnc_commodity_new( txd->book,
831  "template", "template",
832  "template", "template",
833  1 );
834 #endif
835  xaccAccountSetCommodity( acc, com );
836  }
837 
838  txd->accts = g_list_append( txd->accts, acc );
839  }
840 
841  return TRUE;
842 }
843 
844 static
845 gboolean
846 tt_trn_handler( xmlNodePtr node, gpointer data )
847 {
848  gnc_template_xaction_data *txd = data;
849  Transaction *trn;
850 
851  trn = dom_tree_to_transaction( node, txd->book );
852 
853  if ( trn == NULL )
854  {
855  return FALSE;
856  }
857  else
858  {
859  txd->transactions = g_list_append( txd->transactions, trn );
860  }
861 
862  return TRUE;
863 }
864 
865 struct dom_tree_handler tt_dom_handlers[] =
866 {
867  { GNC_ACCOUNT_TAG, tt_act_handler, 0, 0 },
868  { GNC_TRANSACTION_TAG, tt_trn_handler, 0, 0 },
869  { NULL, NULL, 0, 0 },
870 };
871 
872 static gboolean
873 gnc_template_transaction_end_handler(gpointer data_for_children,
874  GSList* data_from_children,
875  GSList* sibling_data,
876  gpointer parent_data,
877  gpointer global_data,
878  gpointer *result,
879  const gchar *tag)
880 {
881  gboolean successful = FALSE;
882  xmlNodePtr tree = data_for_children;
883  gxpf_data *gdata = global_data;
884  QofBook *book = gdata->bookdata;
885  GList *n;
887 
888  txd.book = book;
889  txd.accts = NULL;
890  txd.transactions = NULL;
891 
892  /* the DOM tree will have an account tree [the template
893  accounts] and a list of transactions [which will be members
894  of the template account].
895 
896  we want to parse through the dom trees for each, placing
897  the null-parent account in the book's template-group slot,
898  the others under it, and the transactions as normal. */
899 
900  if ( parent_data )
901  {
902  return TRUE;
903  }
904 
905  if ( !tag )
906  {
907  return TRUE;
908  }
909 
910  g_return_val_if_fail( tree, FALSE );
911 
912  successful = dom_tree_generic_parse( tree, tt_dom_handlers, &txd );
913 
914  if ( successful )
915  {
916  gdata->cb( tag, gdata->parsedata, &txd );
917  }
918  else
919  {
920  g_warning("failed to parse template transaction");
921  xmlElemDump( stdout, NULL, tree );
922  }
923 
924  /* cleanup */
925  for ( n = txd.accts; n; n = n->next )
926  {
927  n->data = NULL;
928  }
929  for ( n = txd.transactions; n; n = n->next )
930  {
931  n->data = NULL;
932  }
933  g_list_free( txd.accts );
934  g_list_free( txd.transactions );
935 
936  xmlFreeNode( tree );
937 
938  return successful;
939 }
940 
941 sixtp*
942 gnc_template_transaction_sixtp_parser_create( void )
943 {
944  return sixtp_dom_parser_new( gnc_template_transaction_end_handler,
945  NULL, NULL );
946 }
const GDate * xaccSchedXactionGetEndDate(const SchedXaction *sx)
Definition: SchedXaction.c:628
void gnc_sx_set_schedule(SchedXaction *sx, GList *schedule)
Definition: SchedXaction.c:565
gnc_commodity_table * gnc_commodity_table_get_table(QofBook *book)
Definition: sixtp.h:93
void gnc_sx_set_instance_count(SchedXaction *sx, gint instance_num)
GList * gnc_sx_get_schedule(const SchedXaction *sx)
Definition: SchedXaction.c:559
#define xaccSchedXactionGetSlots(X)
Definition: SchedXaction.h:323
void xaccSchedXactionSetNumOccur(SchedXaction *sx, gint new_num)
Definition: SchedXaction.c:690
Account * gnc_book_get_template_root(const QofBook *book)
Definition: SX-book.c:65
gchar * guid_to_string_buff(const GncGUID *guid, gchar *buff)
Definition: guid.h:65
Account * gnc_account_lookup_by_name(const Account *parent, const char *name)
Definition: Account.c:2803
#define xaccAccountGetGUID(X)
Definition: Account.h:239
api for GnuCash version 2 XML-based file format
#define GUID_ENCODING_LENGTH
Definition: guid.h:74
gnc_commodity * gnc_commodity_new(QofBook *book, const char *fullname, const char *name_space, const char *mnemonic, const char *cusip, int fraction)
GList * deferredList
Definition: SchedXaction.h:118
Anchor Scheduled Transaction info in a book. See src/doc/books.txt for design overview.
#define xaccSchedXactionGetGUID(X)
Definition: SchedXaction.h:321
void xaccSchedXactionSetName(SchedXaction *sx, const gchar *newName)
Definition: SchedXaction.c:581
void xaccAccountBeginEdit(Account *acc)
Definition: Account.c:1280
gnc_commodity * xaccAccountGetCommodity(const Account *acc)
Definition: Account.c:3148
SchedXaction * xaccSchedXactionMalloc(QofBook *book)
Definition: SchedXaction.c:404
const char * xaccAccountGetName(const Account *acc)
Definition: Account.c:3031
gboolean xaccSchedXactionHasOccurDef(const SchedXaction *sx)
Definition: SchedXaction.c:678
void xaccSchedXactionSetEndDate(SchedXaction *sx, const GDate *newEnd)
Definition: SchedXaction.c:635
void xaccSchedXactionDestroy(SchedXaction *sx)
Definition: SchedXaction.c:473
void xaccAccountSetCommodity(Account *acc, gnc_commodity *com)
Definition: Account.c:2389
Account * xaccAccountLookup(const GncGUID *guid, QofBook *book)
Definition: Account.c:1827
GList * gnc_sx_get_defer_instances(SchedXaction *sx)
Returns the defer list from the SX.
gint gnc_sx_get_instance_count(const SchedXaction *sx, SXTmpStateData *stateData)
Get the instance count.