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