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  auto tmp = dom_tree_to_guid (node);
214 
215  g_return_val_if_fail (tmp, FALSE);
216  xaccSchedXactionSetGUID (sx, &*tmp);
217 
218  return TRUE;
219 }
220 
221 static
222 gboolean
223 sx_name_handler (xmlNodePtr node, gpointer sx_pdata)
224 {
225  struct sx_pdata* pdata = static_cast<decltype (pdata)> (sx_pdata);
226  return apply_xmlnode_text (xaccSchedXactionSetName, pdata->sx, node);
227 }
228 
229 static gboolean
230 sx_enabled_handler (xmlNodePtr node, gpointer sx_pdata)
231 {
232  struct sx_pdata* pdata = static_cast<decltype (pdata)> (sx_pdata);
233  auto set_enabled = [](SchedXaction* sx, const char* txt)
234  {
235  sx->enabled = !g_strcmp0 (txt, "y");
236  };
237  return apply_xmlnode_text (set_enabled, pdata->sx, node);
238 }
239 
240 static gboolean
241 sx_autoCreate_handler (xmlNodePtr node, gpointer sx_pdata)
242 {
243  struct sx_pdata* pdata = static_cast<decltype (pdata)> (sx_pdata);
244  auto set_autocreate = [](SchedXaction* sx, const char* txt)
245  {
246  sx->autoCreateOption = !g_strcmp0 (txt, "y");
247  };
248  return apply_xmlnode_text (set_autocreate, pdata->sx, node);
249 }
250 
251 static gboolean
252 sx_notify_handler (xmlNodePtr node, gpointer sx_pdata)
253 {
254  struct sx_pdata* pdata = static_cast<decltype (pdata)> (sx_pdata);
255  auto set_notify = [](SchedXaction* sx, const char* txt)
256  {
257  sx->autoCreateNotify = !g_strcmp0 (txt, "y");
258  };
259  return apply_xmlnode_text (set_notify, pdata->sx, node);
260 }
261 
262 static gboolean
263 sx_advCreate_handler (xmlNodePtr node, gpointer sx_pdata)
264 {
265  struct sx_pdata* pdata = static_cast<decltype (pdata)> (sx_pdata);
266  SchedXaction* sx = pdata->sx;
267  gint64 advCreate;
268 
269  if (! dom_tree_to_integer (node, &advCreate))
270  {
271  return FALSE;
272  }
273 
274  xaccSchedXactionSetAdvanceCreation (sx, advCreate);
275  return TRUE;
276 }
277 
278 static gboolean
279 sx_advRemind_handler (xmlNodePtr node, gpointer sx_pdata)
280 {
281  struct sx_pdata* pdata = static_cast<decltype (pdata)> (sx_pdata);
282  SchedXaction* sx = pdata->sx;
283  gint64 advRemind;
284 
285  if (! dom_tree_to_integer (node, &advRemind))
286  {
287  return FALSE;
288  }
289 
290  xaccSchedXactionSetAdvanceReminder (sx, advRemind);
291  return TRUE;
292 }
293 
294 static
295 gboolean
296 sx_set_date (xmlNodePtr node, SchedXaction* sx,
297  void (*settor) (SchedXaction* sx, const GDate* d))
298 {
299  GDate* date;
300  date = dom_tree_to_gdate (node);
301  g_return_val_if_fail (date, FALSE);
302  (*settor) (sx, date);
303  g_date_free (date);
304 
305  return TRUE;
306 }
307 
308 static
309 gboolean
310 sx_instcount_handler (xmlNodePtr node, gpointer sx_pdata)
311 {
312  struct sx_pdata* pdata = static_cast<decltype (pdata)> (sx_pdata);
313  SchedXaction* sx = pdata->sx;
314  gint64 instanceNum;
315 
316  if (! dom_tree_to_integer (node, &instanceNum))
317  {
318  return FALSE;
319  }
320 
321  gnc_sx_set_instance_count (sx, instanceNum);
322  return TRUE;
323 }
324 
325 static
326 gboolean
327 sx_start_handler (xmlNodePtr node, gpointer sx_pdata)
328 {
329  struct sx_pdata* pdata = static_cast<decltype (pdata)> (sx_pdata);
330  SchedXaction* sx = pdata->sx;
331 
332  return sx_set_date (node, sx, xaccSchedXactionSetStartDate);
333 }
334 
335 static
336 gboolean
337 sx_last_handler (xmlNodePtr node, gpointer sx_pdata)
338 {
339  struct sx_pdata* pdata = static_cast<decltype (pdata)> (sx_pdata);
340  SchedXaction* sx = pdata->sx;
341 
342  return sx_set_date (node, sx, xaccSchedXactionSetLastOccurDate);
343 }
344 
345 static
346 gboolean
347 sx_end_handler (xmlNodePtr node, gpointer sx_pdata)
348 {
349  struct sx_pdata* pdata = static_cast<decltype (pdata)> (sx_pdata);
350  SchedXaction* sx = pdata->sx;
351 
352  return sx_set_date (node, sx, xaccSchedXactionSetEndDate);
353 }
354 
355 static void
356 _fixup_recurrence_start_dates (const GDate* sx_start_date, GList* schedule)
357 {
358  GList* iter;
359  for (iter = schedule; iter != NULL; iter = iter->next)
360  {
361  Recurrence* r;
362  GDate start, next;
363 
364  r = (Recurrence*)iter->data;
365 
366  start = *sx_start_date;
367  g_date_subtract_days (&start, 1);
368 
369  g_date_clear (&next, 1);
370 
371  recurrenceNextInstance (r, &start, &next);
372  g_return_if_fail (g_date_valid (&next));
373 
374  {
375  gchar date_str[128];
376  gchar* sched_str;
377 
378  g_date_strftime (date_str, 127, "%x", &next);
379  sched_str = recurrenceToString (r);
380  DEBUG ("setting recurrence [%s] start date to [%s]",
381  sched_str, date_str);
382  g_free (sched_str);
383  }
384 
385  recurrenceSet (r,
386  recurrenceGetMultiplier (r),
387  recurrenceGetPeriodType (r),
388  &next,
389  recurrenceGetWeekendAdjust (r));
390  }
391 
392  if (g_list_length (schedule) == 1
393  && recurrenceGetPeriodType ((Recurrence*)g_list_nth_data (schedule,
394  0)) == PERIOD_ONCE)
395  {
396  char date_buf[128];
397  Recurrence* fixup = (Recurrence*)g_list_nth_data (schedule, 0);
398  g_date_strftime (date_buf, 127, "%x", sx_start_date);
399  recurrenceSet (fixup, 1, PERIOD_ONCE, sx_start_date, WEEKEND_ADJ_NONE);
400  DEBUG ("fixed up period=ONCE Recurrence to date [%s]", date_buf);
401  }
402 }
403 
404 static gboolean
405 sx_freqspec_handler (xmlNodePtr node, gpointer sx_pdata)
406 {
407  struct sx_pdata* pdata = static_cast<decltype (pdata)> (sx_pdata);
408  SchedXaction* sx = pdata->sx;
409  GList* schedule;
410  gchar* debug_str;
411 
412  g_return_val_if_fail (node, FALSE);
413 
414  schedule = dom_tree_freqSpec_to_recurrences (node, pdata->book);
415  gnc_sx_set_schedule (sx, schedule);
416  debug_str = recurrenceListToString (schedule);
417  DEBUG ("parsed from freqspec [%s]", debug_str);
418  g_free (debug_str);
419 
420  _fixup_recurrence_start_dates (xaccSchedXactionGetStartDate (sx), schedule);
421  pdata->saw_freqspec = TRUE;
422 
423  return TRUE;
424 }
425 
426 static gboolean
427 sx_schedule_recurrence_handler (xmlNodePtr node, gpointer parsing_data)
428 {
429  GList** schedule = (GList**)parsing_data;
430  gchar* sched_str;
431  Recurrence* r = dom_tree_to_recurrence (node);
432  g_return_val_if_fail (r, FALSE);
433  sched_str = recurrenceToString (r);
434  DEBUG ("parsed recurrence [%s]", sched_str);
435  g_free (sched_str);
436  *schedule = g_list_append (*schedule, r);
437  return TRUE;
438 }
439 
440 struct dom_tree_handler sx_recurrence_list_handlers[] =
441 {
442  { "gnc:recurrence", sx_schedule_recurrence_handler, 0, 0 },
443  { NULL, NULL, 0, 0 }
444 };
445 
446 static gboolean
447 sx_recurrence_handler (xmlNodePtr node, gpointer _pdata)
448 {
449  struct sx_pdata* parsing_data = static_cast<decltype (parsing_data)> (_pdata);
450  GList* schedule = NULL;
451  gchar* debug_str;
452 
453  g_return_val_if_fail (node, FALSE);
454 
455  if (!dom_tree_generic_parse (node, sx_recurrence_list_handlers, &schedule))
456  return FALSE;
457  // g_return_val_if_fail(schedule, FALSE);
458  debug_str = recurrenceListToString (schedule);
459  DEBUG ("setting freshly-parsed schedule: [%s]", debug_str);
460  g_free (debug_str);
461  gnc_sx_set_schedule (parsing_data->sx, schedule);
462  parsing_data->saw_recurrence = TRUE;
463  return TRUE;
464 }
465 
466 static
467 gboolean
468 sx_defer_last_handler (xmlNodePtr node, gpointer gpTSD)
469 {
470  GDate* gd;
471  SXTmpStateData* tsd = (SXTmpStateData*)gpTSD;
472 
473  g_return_val_if_fail (node, FALSE);
474  gd = dom_tree_to_gdate (node);
475  g_return_val_if_fail (gd, FALSE);
476  tsd->last_date = *gd;
477  g_date_free (gd);
478  return TRUE;
479 }
480 
481 static
482 gboolean
483 sx_defer_rem_occur_handler (xmlNodePtr node, gpointer gpTSD)
484 {
485  gint64 remOccur;
486  SXTmpStateData* tsd = (SXTmpStateData*)gpTSD;
487  g_return_val_if_fail (node, FALSE);
488 
489  if (! dom_tree_to_integer (node, &remOccur))
490  {
491  return FALSE;
492  }
493  tsd->num_occur_rem = remOccur;
494  return TRUE;
495 }
496 
497 static
498 gboolean
499 sx_defer_inst_count_handler (xmlNodePtr node, gpointer gpTSD)
500 {
501  gint64 instCount;
502  SXTmpStateData* tsd = (SXTmpStateData*)gpTSD;
503  g_return_val_if_fail (node, FALSE);
504 
505  if (! dom_tree_to_integer (node, &instCount))
506  {
507  return FALSE;
508  }
509  tsd->num_inst = instCount;
510  return TRUE;
511 }
512 
513 struct dom_tree_handler sx_defer_dom_handlers[] =
514 {
515  /* tag name, handler, opt, ? */
516  { SX_LAST, sx_defer_last_handler, 1, 0 },
517  { SX_REM_OCCUR, sx_defer_rem_occur_handler, 1, 0 },
518  { SX_INSTANCE_COUNT, sx_defer_inst_count_handler, 1, 0 },
519  { NULL, NULL, 0, 0 }
520 };
521 
522 static
523 gboolean
524 sx_defer_inst_handler (xmlNodePtr node, gpointer sx_pdata)
525 {
526  struct sx_pdata* pdata = static_cast<decltype (pdata)> (sx_pdata);
527  SchedXaction* sx = pdata->sx;
528  SXTmpStateData* tsd;
529 
530  g_return_val_if_fail (node, FALSE);
531 
532  tsd = g_new0 (SXTmpStateData, 1);
533  g_assert (sx_defer_dom_handlers != NULL);
534  if (!dom_tree_generic_parse (node,
535  sx_defer_dom_handlers,
536  tsd))
537  {
538  xmlElemDump (stdout, NULL, node);
539  g_free (tsd);
540  tsd = NULL;
541  return FALSE;
542  }
543 
544  /* We assume they were serialized in sorted order, here. */
545  sx->deferredList = g_list_append (sx->deferredList, tsd);
546  return TRUE;
547 }
548 
549 static
550 gboolean
551 sx_numOccur_handler (xmlNodePtr node, gpointer sx_pdata)
552 {
553  struct sx_pdata* pdata = static_cast<decltype (pdata)> (sx_pdata);
554  SchedXaction* sx = pdata->sx;
555  gint64 numOccur;
556 
557  if (! dom_tree_to_integer (node, &numOccur))
558  {
559  return FALSE;
560  }
561 
562  xaccSchedXactionSetNumOccur (sx, numOccur);
563 
564  return TRUE;
565 }
566 
567 
568 static
569 gboolean
570 sx_templ_acct_handler (xmlNodePtr node, gpointer sx_pdata)
571 {
572  struct sx_pdata* pdata = static_cast<decltype (pdata)> (sx_pdata);
573  SchedXaction* sx = pdata->sx;
574  auto templ_acct_guid = dom_tree_to_guid (node);
575  Account* account;
576 
577  if (!templ_acct_guid)
578  {
579  return FALSE;
580  }
581 
582  account = xaccAccountLookup (&*templ_acct_guid, pdata->book);
583  sx_set_template_account (sx, account);
584 
585  return TRUE;
586 }
587 
588 
589 static
590 gboolean
591 sx_remOccur_handler (xmlNodePtr node, gpointer sx_pdata)
592 {
593  struct sx_pdata* pdata = static_cast<decltype (pdata)> (sx_pdata);
594  SchedXaction* sx = pdata->sx;
595  gint64 remOccur;
596 
597  if (! dom_tree_to_integer (node, &remOccur))
598  {
599  return FALSE;
600  }
601 
602  xaccSchedXactionSetRemOccur (sx, remOccur);
603 
604  return TRUE;
605 }
606 
607 static
608 gboolean
609 sx_slots_handler (xmlNodePtr node, gpointer sx_pdata)
610 {
611  struct sx_pdata* pdata = static_cast<decltype (pdata)> (sx_pdata);
612  SchedXaction* sx = pdata->sx;
613 
614  return dom_tree_create_instance_slots (node, QOF_INSTANCE (sx));
615 }
616 
617 struct dom_tree_handler sx_dom_handlers[] =
618 {
619  { SX_ID, sx_id_handler, 1, 0 },
620  { SX_NAME, sx_name_handler, 1, 0 },
621  { SX_ENABLED, sx_enabled_handler, 0, 0 },
622  { SX_AUTOCREATE, sx_autoCreate_handler, 1, 0 },
623  { SX_AUTOCREATE_NOTIFY, sx_notify_handler, 1, 0 },
624  { SX_ADVANCE_CREATE_DAYS, sx_advCreate_handler, 1, 0 },
625  { SX_ADVANCE_REMIND_DAYS, sx_advRemind_handler, 1, 0 },
626  { SX_INSTANCE_COUNT, sx_instcount_handler, 0, 0 },
627  { SX_START, sx_start_handler, 1, 0 },
628  { SX_LAST, sx_last_handler, 0, 0 },
629  { SX_NUM_OCCUR, sx_numOccur_handler, 0, 0 },
630  { SX_REM_OCCUR, sx_remOccur_handler, 0, 0 },
631  { SX_END, sx_end_handler, 0, 0 },
632  { SX_TEMPL_ACCT, sx_templ_acct_handler, 0, 0 },
633  { SX_FREQSPEC, sx_freqspec_handler, 0, 0 },
634  { SX_SCHEDULE, sx_recurrence_handler, 0, 0 },
635  { SX_DEFER_INSTANCE, sx_defer_inst_handler, 0, 0 },
636  { SX_SLOTS, sx_slots_handler, 0, 0 },
637  { NULL, NULL, 0, 0 }
638 };
639 
640 static gboolean
641 gnc_schedXaction_end_handler (gpointer data_for_children,
642  GSList* data_from_children, GSList* sibling_data,
643  gpointer parent_data, gpointer global_data,
644  gpointer* result, const gchar* tag)
645 {
646  SchedXaction* sx;
647  gboolean successful = FALSE;
648  xmlNodePtr tree = (xmlNodePtr)data_for_children;
649  gxpf_data* gdata = (gxpf_data*)global_data;
650  struct sx_pdata sx_pdata;
651 
652  if (parent_data)
653  {
654  return TRUE;
655  }
656 
657  if (!tag)
658  {
659  return TRUE;
660  }
661 
662  g_return_val_if_fail (tree, FALSE);
663 
664  sx = xaccSchedXactionMalloc (static_cast<QofBook*> (gdata->bookdata));
665 
666  memset (&sx_pdata, 0, sizeof (sx_pdata));
667  sx_pdata.sx = sx;
668  sx_pdata.book = static_cast<decltype (sx_pdata.book)> (gdata->bookdata);
669 
670  g_assert (sx_dom_handlers != NULL);
671 
672  successful = dom_tree_generic_parse (tree, sx_dom_handlers, &sx_pdata);
673  if (!successful)
674  {
675  g_critical ("failed to parse scheduled xaction");
676  xmlElemDump (stdout, NULL, tree);
677  gnc_sx_begin_edit (sx);
679  goto done;
680  }
681 
682  if (tree->properties)
683  {
684  gchar* sx_name = xaccSchedXactionGetName (sx);
685  xmlAttr* attr;
686  for (attr = tree->properties; attr != NULL; attr = attr->next)
687  {
688  xmlChar* attr_value = attr->children->content;
689  DEBUG ("sx attribute name[%s] value[%s]", attr->name, attr_value);
690  if (strcmp ((const char*)attr->name, "version") != 0)
691  {
692  g_warning ("unknown sx attribute [%s]", attr->name);
693  continue;
694  }
695 
696  // if version == 1.0.0: ensure freqspec, no recurrence
697  // if version == 2.0.0: ensure recurrence, no freqspec.
698  if (strcmp ((const char*)attr_value,
699  schedxaction_version_string) == 0)
700  {
701  if (!sx_pdata.saw_freqspec)
702  g_critical ("did not see freqspec in version 1 sx [%s]", sx_name);
703  if (sx_pdata.saw_recurrence)
704  g_warning ("saw recurrence in supposedly version 1 sx [%s]", sx_name);
705  }
706 
707  if (strcmp ((const char*)attr_value,
708  schedxaction_version2_string) == 0)
709  {
710  if (sx_pdata.saw_freqspec)
711  g_warning ("saw freqspec in version 2 sx [%s]", sx_name);
712  if (!sx_pdata.saw_recurrence)
713  g_critical ("did not find recurrence in version 2 sx [%s]", sx_name);
714  }
715  }
716  }
717 
718  // generic_callback -> book_callback: insert the SX in the book
719  gdata->cb (tag, gdata->parsedata, sx);
720 
721  /* FIXME: this should be removed somewhere near 1.8 release time. */
722  if (sx->template_acct == NULL)
723  {
724  Account* ra = NULL;
725  Account* acct = NULL;
726  sixtp_gdv2* sixdata = static_cast<decltype (sixdata)> (gdata->parsedata);
727  QofBook* book;
728  gchar guidstr[GUID_ENCODING_LENGTH + 1];
729 
730  book = sixdata->book;
731 
732  /* We're dealing with a pre-200107<near-end-of-month> rgmerk
733  change re: storing template accounts. */
734  /* Fix: get account with name of our GncGUID from the template
735  accounts. Make that our template_acct pointer. */
737  ra = gnc_book_get_template_root (book);
738  if (ra == NULL)
739  {
740  g_warning ("Error getting template root account from being-parsed Book.");
741  xmlFreeNode (tree);
742  return FALSE;
743  }
744  acct = gnc_account_lookup_by_name (ra, guidstr);
745  if (acct == NULL)
746  {
747  g_warning ("no template account with name [%s]", guidstr);
748  xmlFreeNode (tree);
749  return FALSE;
750  }
751  DEBUG ("template account name [%s] for SX with GncGUID [%s]",
752  xaccAccountGetName (acct), guidstr);
753 
754  /* FIXME: free existing template account.
755  * HUH????? We only execute this if there isn't
756  * currently an existing template account, don't we?
757  * <rgmerk>
758  */
759 
760  sx->template_acct = acct;
761  }
762 
763 done:
764  xmlFreeNode (tree);
765 
766  return successful;
767 }
768 
769 sixtp*
770 gnc_schedXaction_sixtp_parser_create (void)
771 {
772  return sixtp_dom_parser_new (gnc_schedXaction_end_handler, NULL, NULL);
773 }
774 
775 static
776 gboolean
777 tt_act_handler (xmlNodePtr node, gpointer data)
778 {
779  gnc_template_xaction_data* txd = static_cast<decltype (txd)> (data);
780  Account* acc;
781  gnc_commodity* com;
782 
783  acc = dom_tree_to_account (node, txd->book);
784 
785  if (acc == NULL)
786  {
787  return FALSE;
788  }
789  else
790  {
791  xaccAccountBeginEdit (acc);
792 
793  /* Check for the lack of a commodity [signifying that the
794  pre-7/11/2001-CIT-change SX template Account was parsed [but
795  incorrectly]. */
796  if (xaccAccountGetCommodity (acc) == NULL)
797  {
798 #if 1
799  gnc_commodity_table* table;
800 
801  table = gnc_commodity_table_get_table (txd->book);
802  com = gnc_commodity_table_lookup (table,
803  GNC_COMMODITY_NS_TEMPLATE, "template");
804 #else
805  /* FIXME: This should first look in the table of the
806  book, maybe? The right thing happens [WRT file
807  load/save] if we just _new all the time, but it
808  doesn't seem right. This whole block should go
809  away at some point, but the same concern still
810  applies for
811  SchedXaction.c:xaccSchedXactionInit... */
812  com = gnc_commodity_new (txd->book,
813  "template", GNC_COMMODITY_NS_TEMPLATE,
814  "template", "template",
815  1);
816 #endif
817  xaccAccountSetCommodity (acc, com);
818  }
819 
820  txd->accts = g_list_append (txd->accts, acc);
821  }
822 
823  return TRUE;
824 }
825 
826 static
827 gboolean
828 tt_trn_handler (xmlNodePtr node, gpointer data)
829 {
830  gnc_template_xaction_data* txd = static_cast<decltype (txd)> (data);
831  Transaction* trn;
832 
833  trn = dom_tree_to_transaction (node, txd->book);
834 
835  if (trn == NULL)
836  {
837  return FALSE;
838  }
839  else
840  {
841  txd->transactions = g_list_append (txd->transactions, trn);
842  }
843 
844  return TRUE;
845 }
846 
847 struct dom_tree_handler tt_dom_handlers[] =
848 {
849  { GNC_ACCOUNT_TAG, tt_act_handler, 0, 0 },
850  { GNC_TRANSACTION_TAG, tt_trn_handler, 0, 0 },
851  { NULL, NULL, 0, 0 },
852 };
853 
854 static gboolean
855 gnc_template_transaction_end_handler (gpointer data_for_children,
856  GSList* data_from_children,
857  GSList* sibling_data,
858  gpointer parent_data,
859  gpointer global_data,
860  gpointer* result,
861  const gchar* tag)
862 {
863  gboolean successful = FALSE;
864  xmlNodePtr tree = static_cast<decltype (tree)> (data_for_children);
865  gxpf_data* gdata = static_cast<decltype (gdata)> (global_data);
866  QofBook* book = static_cast<decltype (book)> (gdata->bookdata);
867  GList* n;
868  gnc_template_xaction_data txd;
869 
870  txd.book = book;
871  txd.accts = NULL;
872  txd.transactions = NULL;
873 
874  /* the DOM tree will have an account tree [the template
875  accounts] and a list of transactions [which will be members
876  of the template account].
877 
878  we want to parse through the dom trees for each, placing
879  the null-parent account in the book's template-group slot,
880  the others under it, and the transactions as normal. */
881 
882  if (parent_data)
883  {
884  return TRUE;
885  }
886 
887  if (!tag)
888  {
889  return TRUE;
890  }
891 
892  g_return_val_if_fail (tree, FALSE);
893 
894  successful = dom_tree_generic_parse (tree, tt_dom_handlers, &txd);
895 
896  if (successful)
897  {
898  gdata->cb (tag, gdata->parsedata, &txd);
899  }
900  else
901  {
902  g_warning ("failed to parse template transaction");
903  xmlElemDump (stdout, NULL, tree);
904  }
905 
906  /* cleanup */
907  for (n = txd.accts; n; n = n->next)
908  {
909  n->data = NULL;
910  }
911  for (n = txd.transactions; n; n = n->next)
912  {
913  n->data = NULL;
914  }
915  g_list_free (txd.accts);
916  g_list_free (txd.transactions);
917 
918  xmlFreeNode (tree);
919 
920  return successful;
921 }
922 
923 sixtp*
924 gnc_template_transaction_sixtp_parser_create (void)
925 {
926  return sixtp_dom_parser_new (gnc_template_transaction_end_handler,
927  NULL, NULL);
928 }
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:208
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:3067
#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:1473
gnc_commodity * xaccAccountGetCommodity(const Account *acc)
Get the account&#39;s commodity.
Definition: Account.cpp:3375
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:3263
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:2652
Account * xaccAccountLookup(const GncGUID *guid, QofBook *book)
The xaccAccountLookup() subroutine will return the account associated with the given id...
Definition: Account.cpp:2048
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.