]> Dogcows Code - chaz/homebank/blob - src/hb-xml.c
add plugin engine (supports C and Perl plugins)
[chaz/homebank] / src / hb-xml.c
1 /* HomeBank -- Free, easy, personal accounting for everyone.
2 * Copyright (C) 1995-2014 Maxime DOYEN
3 *
4 * This file is part of HomeBank.
5 *
6 * HomeBank is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * HomeBank is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program. If not, see <http://www.gnu.org/licenses/>.
18 */
19
20
21 #include "homebank.h"
22
23 #include "hb-transaction.h"
24 #include "hb-xml.h"
25
26 #include "ext.h"
27
28 /****************************************************************************/
29 /* Debug macros */
30 /****************************************************************************/
31 #define MYDEBUG 0
32
33 #if MYDEBUG
34 #define DB(x) (x);
35 #else
36 #define DB(x);
37 #endif
38
39 /* our global datas */
40 extern struct HomeBank *GLOBALS;
41 extern struct Preferences *PREFS;
42
43 typedef struct _ParseContext ParseContext;
44 struct _ParseContext
45 {
46 gdouble version;
47
48 };
49
50 static void homebank_upgrade_to_v02(void);
51 static void homebank_upgrade_to_v03(void);
52 static void homebank_upgrade_to_v04(void);
53 static void homebank_upgrade_to_v05(void);
54 static void homebank_upgrade_lower_v06(void);
55 static void homebank_upgrade_to_v06(void);
56 static void homebank_upgrade_to_v07(void);
57 static void homebank_upgrade_to_v08(void);
58
59 static void
60 start_element_handler (GMarkupParseContext *context,
61 const gchar *element_name,
62 const gchar **attribute_names,
63 const gchar **attribute_values,
64 gpointer user_data,
65 GError **error)
66 {
67 ParseContext *ctx = user_data;
68 //GtkUIManager *self = ctx->self;
69 gint i, j;
70
71 //DB( g_print("** start element: %s\n", element_name) );
72
73 switch(element_name[0])
74 {
75 //get file version
76 /*
77 case 'h':
78 {
79 if(!strcmp (element_name, "homebank"))
80 {
81 if(!strcmp (attribute_names[0], "v" ))
82 {
83 version = g_ascii_strtod(attribute_values[0], NULL);
84 DB( g_print(" version %f\n", version) );
85 }
86
87 }
88 }
89 */
90
91 case 'a':
92 {
93 if(!strcmp (element_name, "account"))
94 {
95 Account *entry = da_acc_malloc();
96
97 for (i = 0; attribute_names[i] != NULL; i++)
98 {
99 //DB( g_print(" att=%s val=%s\n", attribute_names[i], attribute_values[i]) );
100
101 if(!strcmp (attribute_names[i], "key" )) { entry->key = atoi(attribute_values[i]); }
102 else if(!strcmp (attribute_names[i], "flags" )) { entry->flags = atoi(attribute_values[i]); }
103 else if(!strcmp (attribute_names[i], "pos" )) { entry->pos = atoi(attribute_values[i]); }
104 else if(!strcmp (attribute_names[i], "type" )) { entry->type = atoi(attribute_values[i]); }
105 //else if(!strcmp (attribute_names[i], "curr" )) { entry->kcur = atoi(attribute_values[i]); }
106 else if(!strcmp (attribute_names[i], "name" )) { if(strcmp(attribute_values[i],"(null)") && attribute_values[i] != NULL) entry->name = g_strdup(attribute_values[i]); }
107 else if(!strcmp (attribute_names[i], "number" )) { if(strcmp(attribute_values[i],"(null)") && attribute_values[i] != NULL) entry->number = g_strdup(attribute_values[i]); }
108 else if(!strcmp (attribute_names[i], "bankname")) { if(strcmp(attribute_values[i],"(null)") && attribute_values[i] != NULL) entry->bankname = g_strdup(attribute_values[i]); }
109 else if(!strcmp (attribute_names[i], "initial" )) { entry->initial = g_ascii_strtod(attribute_values[i], NULL); }
110 else if(!strcmp (attribute_names[i], "minimum" )) { entry->minimum = g_ascii_strtod(attribute_values[i], NULL); }
111 else if(!strcmp (attribute_names[i], "cheque1" )) { entry->cheque1 = atoi(attribute_values[i]); }
112 else if(!strcmp (attribute_names[i], "cheque2" )) { entry->cheque2 = atoi(attribute_values[i]); }
113
114 }
115
116 //version upgrade: type was added in 0.2
117 //todo: for stock account
118 /*
119 if(version <= 0.1)
120 {
121 entry->type = ACC_TYPE_BANK;
122 DB( g_print(" acctype forced to BANK\n") );
123 }
124 */
125
126 DB( g_print(" version %f\n", ctx->version) );
127
128 //upgrade to v0.2 file
129 // we must change account reference by making a +1 to its index references
130 if( ctx->version == 0.1 )
131 {
132 entry->key++;
133 entry->pos = entry->key;
134 }
135
136 //all attribute loaded: append
137 da_acc_insert(entry);
138 }
139
140 //assign
141 else if(!strcmp (element_name, "asg"))
142 {
143 Assign *entry = da_asg_malloc();
144 gint exact = 0;
145
146 for (i = 0; attribute_names[i] != NULL; i++)
147 {
148 //DB( g_print(" att=%s val=%s\n", attribute_names[i], attribute_values[i]) );
149
150 if(!strcmp (attribute_names[i], "key" )) { entry->key = atoi(attribute_values[i]); }
151 else if(!strcmp (attribute_names[i], "flags" )) { entry->flags = atoi(attribute_values[i]); }
152 else if(!strcmp (attribute_names[i], "field" )) { entry->field = atoi(attribute_values[i]); }
153 else if(!strcmp (attribute_names[i], "name" )) { if(strcmp(attribute_values[i],"(null)") && attribute_values[i] != NULL) entry->name = g_strdup(attribute_values[i]); }
154 else if(!strcmp (attribute_names[i], "payee" )) { entry->kpay = atoi(attribute_values[i]); }
155 else if(!strcmp (attribute_names[i], "category")) { entry->kcat = atoi(attribute_values[i]); }
156 //else if(!strcmp (attribute_names[i], "paymode" )) { entry->paymode = atoi(attribute_values[i]); }
157 // prior v08
158 else if(!strcmp (attribute_names[i], "exact" )) { exact = atoi(attribute_values[i]); }
159 }
160
161 /* in v08 exact moved to flag */
162 if( ctx->version <= 0.7)
163 {
164 entry->flags = (ASGF_DOCAT|ASGF_DOPAY);
165 if( exact > 0 )
166 entry->flags |= ASGF_EXACT;
167 }
168
169 //all attribute loaded: append
170 da_asg_append(entry);
171
172 }
173
174 }
175 break;
176
177 case 'p':
178 {
179 if(!strcmp (element_name, "pay"))
180 {
181 Payee *entry = da_pay_malloc();
182
183 for (i = 0; attribute_names[i] != NULL; i++)
184 {
185 //DB( g_print(" att=%s val=%s\n", attribute_names[i], attribute_values[i]) );
186
187 if(!strcmp (attribute_names[i], "key" )) { entry->key = atoi(attribute_values[i]); }
188 //else if(!strcmp (attribute_names[i], "flags")) { entry->flags = atoi(attribute_values[i]); }
189 else if(!strcmp (attribute_names[i], "name" )) { entry->name = g_strdup(attribute_values[i]); }
190 }
191
192 //all attribute loaded: append
193 da_pay_insert(entry);
194
195 }
196 else if(!strcmp (element_name, "properties"))
197 {
198 for (i = 0; attribute_names[i] != NULL; i++)
199 {
200 if(!strcmp (attribute_names[i], "title" )) { g_free(GLOBALS->owner); GLOBALS->owner = g_strdup(attribute_values[i]); }
201 //else if(!strcmp (attribute_names[i], "curr" )) { GLOBALS->kcur = atoi(attribute_values[i]); }
202 else if(!strcmp (attribute_names[i], "car_category")) { GLOBALS->vehicle_category = atoi(attribute_values[i]); }
203 else if(!strcmp (attribute_names[i], "auto_smode" )) { GLOBALS->auto_smode = atoi(attribute_values[i]); }
204 else if(!strcmp (attribute_names[i], "auto_weekday")) { GLOBALS->auto_weekday = atoi(attribute_values[i]); }
205 else if(!strcmp (attribute_names[i], "auto_nbdays" )) { GLOBALS->auto_nbdays = atoi(attribute_values[i]); }
206 }
207 }
208 }
209 break;
210
211 case 'c':
212 {
213 if(!strcmp (element_name, "cat"))
214 {
215 Category *entry = da_cat_malloc();
216 gboolean budget;
217
218 for (i = 0; attribute_names[i] != NULL; i++)
219 {
220 //DB( g_print(" att=%s val=%s\n", attribute_names[i], attribute_values[i]) );
221
222 if(!strcmp (attribute_names[i], "key" )) { entry->key = atoi(attribute_values[i]); }
223 else if(!strcmp (attribute_names[i], "parent")) { entry->parent = atoi(attribute_values[i]); }
224 else if(!strcmp (attribute_names[i], "flags" )) { entry->flags = atoi(attribute_values[i]); }
225 else if(!strcmp (attribute_names[i], "name" )) { entry->name = g_strdup(attribute_values[i]); }
226
227 budget = FALSE;
228 for(j=0;j<=12;j++)
229 {
230 gchar *tmpname;
231
232 tmpname = g_strdup_printf ("b%d", j);
233 if(!(strcmp (attribute_names[i], tmpname))) { entry->budget[j] = g_ascii_strtod(attribute_values[i], NULL); }
234 g_free(tmpname);
235
236 if(entry->budget[j]) budget = TRUE;
237 }
238 if(budget == TRUE)
239 entry->flags |= GF_BUDGET;
240
241 }
242
243 //all attribute loaded: append
244 da_cat_insert( entry);
245 }
246 /* else if(!strcmp (element_name, "cur"))
247 {
248 Currency *entry = da_cur_malloc ();
249
250 for (i = 0; attribute_names[i] != NULL; i++)
251 {
252 //DB( g_print(" att=%s val=%s\n", attribute_names[i], attribute_values[i]) );
253
254 if(!strcmp (attribute_names[i], "key" )) { entry->key = atoi(attribute_values[i]); }
255 else if(!strcmp (attribute_names[i], "name" )) { entry->name = g_strdup(attribute_values[i]); }
256 else if(!strcmp (attribute_names[i], "iso" )) { entry->iso_code = g_strdup(attribute_values[i]); }
257 else if(!strcmp (attribute_names[i], "symb" )) { entry->symbol = g_strdup(attribute_values[i]); }
258 else if(!strcmp (attribute_names[i], "syprf" )) { entry->sym_prefix = atoi(attribute_values[i]); }
259 else if(!strcmp (attribute_names[i], "dchar" )) { entry->decimal_char = g_strdup(attribute_values[i]); }
260 else if(!strcmp (attribute_names[i], "gchar" )) { entry->grouping_char = g_strdup(attribute_values[i]); }
261 else if(!strcmp (attribute_names[i], "frac" )) { entry->frac_digits = atoi(attribute_values[i]); }
262 else if(!strcmp (attribute_names[i], "rate" )) { entry->rate = g_ascii_strtod(attribute_values[i], NULL); }
263 else if(!strcmp (attribute_names[i], "mdate ")) { entry->mdate = atoi(attribute_values[i]); }
264
265 }
266
267 //all attribute loaded: append
268 da_cur_insert (entry);
269 }
270 */
271 }
272 break;
273
274 case 't':
275 {
276 if(!strcmp (element_name, "tags"))
277 {
278 Tag *entry = da_tag_malloc();
279
280 for (i = 0; attribute_names[i] != NULL; i++)
281 {
282 //DB( g_print(" att=%s val=%s\n", attribute_names[i], attribute_values[i]) );
283
284 if(!strcmp (attribute_names[i], "key" )) { entry->key = atoi(attribute_values[i]); }
285 //else if(!strcmp (attribute_names[i], "flags")) { entry->flags = atoi(attribute_values[i]); }
286 else if(!strcmp (attribute_names[i], "name" )) { entry->name = g_strdup(attribute_values[i]); }
287 }
288
289 //all attribute loaded: append
290 da_tag_insert(entry);
291
292 }
293 }
294
295 case 'f':
296 {
297 if(!strcmp (element_name, "fav"))
298 {
299 Archive *entry = da_archive_malloc();
300
301 for (i = 0; attribute_names[i] != NULL; i++)
302 {
303 //DB( g_print(" att=%s val=%s\n", attribute_names[i], attribute_values[i]) );
304
305 if(!strcmp (attribute_names[i], "amount" )) { entry->amount = g_ascii_strtod(attribute_values[i], NULL); }
306 else if(!strcmp (attribute_names[i], "account" )) { entry->kacc = atoi(attribute_values[i]); }
307 else if(!strcmp (attribute_names[i], "dst_account")) { entry->kxferacc = atoi(attribute_values[i]); }
308 else if(!strcmp (attribute_names[i], "paymode" )) { entry->paymode = atoi(attribute_values[i]); }
309 else if(!strcmp (attribute_names[i], "flags" )) { entry->flags = atoi(attribute_values[i]); }
310 else if(!strcmp (attribute_names[i], "payee" )) { entry->kpay = atoi(attribute_values[i]); }
311 else if(!strcmp (attribute_names[i], "category" )) { entry->kcat = atoi(attribute_values[i]); }
312 else if(!strcmp (attribute_names[i], "wording" )) { if(strcmp(attribute_values[i],"(null)") && attribute_values[i] != NULL) entry->wording = g_strdup(attribute_values[i]); }
313 else if(!strcmp (attribute_names[i], "nextdate" )) { entry->nextdate = atoi(attribute_values[i]); }
314 else if(!strcmp (attribute_names[i], "every" )) { entry->every = atoi(attribute_values[i]); }
315 else if(!strcmp (attribute_names[i], "unit" )) { entry->unit = atoi(attribute_values[i]); }
316 else if(!strcmp (attribute_names[i], "limit" )) { entry->limit = atoi(attribute_values[i]); }
317 else if(!strcmp (attribute_names[i], "weekend" )) { entry->weekend = atoi(attribute_values[i]); }
318
319 }
320
321 //all attribute loaded: append
322 GLOBALS->arc_list = g_list_append(GLOBALS->arc_list, entry);
323
324 }
325 }
326 break;
327
328 /*
329 case 'r':
330 {
331 }
332 break;
333 */
334
335 case 'o':
336 {
337 if(!strcmp (element_name, "ope"))
338 {
339 Transaction *entry = da_transaction_malloc();
340 gchar *scat = NULL;
341 gchar *samt = NULL;
342 gchar *smem = NULL;
343 gboolean split = FALSE;
344
345 for (i = 0; attribute_names[i] != NULL; i++)
346 {
347 //DB( g_print(" att=%s val=%s\n", attribute_names[i], attribute_values[i]) );
348
349 if(!strcmp (attribute_names[i], "date" )) { entry->date = atoi(attribute_values[i]); }
350 else if(!strcmp (attribute_names[i], "amount" )) { entry->amount = g_ascii_strtod(attribute_values[i], NULL); }
351 else if(!strcmp (attribute_names[i], "account" )) { entry->kacc = atoi(attribute_values[i]); }
352 else if(!strcmp (attribute_names[i], "dst_account")) { entry->kxferacc = atoi(attribute_values[i]); }
353 else if(!strcmp (attribute_names[i], "paymode" )) { entry->paymode = atoi(attribute_values[i]); }
354 else if(!strcmp (attribute_names[i], "flags" )) { entry->flags = atoi(attribute_values[i]); }
355 else if(!strcmp (attribute_names[i], "payee" )) { entry->kpay = atoi(attribute_values[i]); }
356 else if(!strcmp (attribute_names[i], "category" )) { entry->kcat = atoi(attribute_values[i]); }
357 else if(!strcmp (attribute_names[i], "wording" )) { if(strcmp(attribute_values[i],"(null)") && attribute_values[i] != NULL) entry->wording = g_strdup(attribute_values[i]); }
358 else if(!strcmp (attribute_names[i], "info" )) { if(strcmp(attribute_values[i],"(null)") && attribute_values[i] != NULL) entry->info = g_strdup(attribute_values[i]); }
359 else if(!strcmp (attribute_names[i], "tags" ))
360 {
361 if(attribute_values[i] != NULL && strlen(attribute_values[i]) > 0 && strcmp(attribute_values[i],"(null)") != 0 )
362 {
363 transaction_tags_parse(entry, attribute_values[i]);
364 }
365 }
366 else if(!strcmp (attribute_names[i], "kxfer" )) { entry->kxfer = atoi(attribute_values[i]); }
367 else if(!strcmp (attribute_names[i], "scat" )) { scat = (gchar *)attribute_values[i]; split = TRUE; }
368 else if(!strcmp (attribute_names[i], "samt" )) { samt = (gchar *)attribute_values[i]; split = TRUE; }
369 else if(!strcmp (attribute_names[i], "smem" )) { smem = (gchar *)attribute_values[i]; split = TRUE; }
370 }
371
372 //bugfix 303886
373 //if(entry->kcat < 0)
374 // entry->kcat = 0;
375
376 if(split == TRUE)
377 {
378 transaction_splits_parse(entry, scat, samt, smem);
379 }
380
381 //all attribute loaded: append
382 // we use prepend here, the list will be reversed later for perf reason
383 da_transaction_prepend(entry);
384 }
385 }
386 break;
387
388
389
390 }
391
392 }
393
394 /*
395 static void
396 end_element_handler (GMarkupParseContext *context,
397 const gchar *element_name,
398 gpointer user_data,
399 GError **error)
400 {
401 ParseContext *ctx = user_data;
402
403 //DB( g_print("-- end element: %s\n", element_name) );
404
405
406 }
407 */
408
409 static GMarkupParser hb_parser = {
410 start_element_handler,
411 NULL, //end_element_handler,
412 NULL, //text_handler,
413 NULL,
414 NULL //cleanup
415 };
416
417 /*
418 ** XML load homebank file: hbfile
419 */
420 gint homebank_load_xml(gchar *filename)
421 {
422 gint retval;
423 gchar *buffer;
424 gsize length;
425 GError *error = NULL;
426 ParseContext ctx = { 0 };
427 GMarkupParseContext *context;
428 gboolean rc;
429
430 DB( g_print("\n[hb-xml] homebank_load_xml\n") );
431
432 GValue filename_val = G_VALUE_INIT;
433 ext_hook("load_file", EXT_STRING(&filename_val, filename), NULL);
434
435 retval = XML_OK;
436 if (!g_file_get_contents (filename, &buffer, &length, &error))
437 {
438 //g_message ("%s", error->message);
439 retval = XML_IO_ERROR;
440 g_error_free (error);
441 }
442 else
443 {
444 gchar *v_buffer;
445 gdouble version;
446
447 /* v3.4 add :: prevent load of future file version */
448 v_buffer = g_strstr_len(buffer, 50, "<homebank v=");
449 if( v_buffer == NULL )
450 return XML_FILE_ERROR;
451
452 DB( g_print("- id line: --(%.50s)\n\n", v_buffer) );
453
454 version = g_ascii_strtod(v_buffer+13, NULL); /* a little hacky, but works ! */
455 if( version == 0.0 )
456 version = 0.1;
457
458 ctx.version = version;
459
460 if( version > FILE_VERSION )
461 {
462 DB( g_print("- failed: version %f is not supported (max is %f)\n", version, FILE_VERSION) );
463 return XML_VERSION_ERROR;
464 }
465 else
466 {
467 DB( g_print("- ok : version=%.1f\n", version) );
468
469 /* 1st: validate the file is well in utf-8 */
470 DB( g_print("- ensure UTF-8\n") );
471 buffer = homebank_utf8_ensure(buffer);
472
473 /* then process the buffer */
474 #if MYDEBUG == 1
475 GTimer *t = g_timer_new();
476 g_print("- start parse\n");
477 #endif
478
479 context = g_markup_parse_context_new (&hb_parser, 0, &ctx, NULL);
480
481 error = NULL;
482 rc = g_markup_parse_context_parse (context, buffer, length, &error);
483
484 if( error )
485 g_print("failed: %s\n", error->message);
486
487 if( rc == FALSE )
488 {
489 error = NULL;
490 g_markup_parse_context_end_parse(context, &error);
491
492 if( error )
493 g_print("failed: %s\n", error->message);
494 }
495
496 g_markup_parse_context_free (context);
497 g_free (buffer);
498
499 //reverse the glist (see g_list append idiom to perf for reason
500 // we use prepend and then reverse
501 GLOBALS->ope_list = g_list_reverse(GLOBALS->ope_list);
502
503 DB( g_print("- end parse : %f sec\n", g_timer_elapsed(t, NULL)) );
504 DB( g_timer_destroy (t) );
505
506 /* file upgrade / bugfix */
507 if( version <= 0.1 )
508 homebank_upgrade_to_v02();
509 if( version <= 0.2 )
510 homebank_upgrade_to_v03();
511 if( version <= 0.3 )
512 homebank_upgrade_to_v04();
513 if( version <= 0.4 )
514 homebank_upgrade_to_v05();
515 if( version <= 0.5 )
516 {
517 homebank_upgrade_to_v06();
518 homebank_upgrade_lower_v06();
519 }
520 if( version <= 0.6 )
521 {
522 homebank_upgrade_to_v07();
523 hbfile_sanity_check();
524 }
525 if( version <= 0.7 )
526 homebank_upgrade_to_v08();
527 if( version <= 0.8 )
528 hbfile_sanity_check();
529
530 // next ?
531
532 }
533 }
534
535 return retval;
536 }
537
538
539 /* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */
540
541 // v0.1 to v0.2 : we must change account reference by making a +1 to its index references
542 static void homebank_upgrade_to_v02(void)
543 {
544 GList *list;
545
546 DB( g_print("\n[hb-xml] homebank_upgrade_to_v02\n") );
547
548 list = g_list_first(GLOBALS->ope_list);
549 while (list != NULL)
550 {
551 Transaction *entry = list->data;
552 entry->kacc++;
553 entry->kxferacc++;
554 list = g_list_next(list);
555 }
556
557 list = g_list_first(GLOBALS->arc_list);
558 while (list != NULL)
559 {
560 Archive *entry = list->data;
561 entry->kacc++;
562 entry->kxferacc++;
563 list = g_list_next(list);
564 }
565 }
566
567 // v0.2 to v0.3 : we must assume categories exists : bugs 303886, 303738
568 static void homebank_upgrade_to_v03(void)
569 {
570 GList *list;
571
572 DB( g_print("\n[hb-xml] homebank_upgrade_to_v03\n") );
573
574 list = g_list_first(GLOBALS->ope_list);
575 while (list != NULL)
576 {
577 Transaction *entry = list->data;
578
579 da_transaction_consistency(entry);
580 list = g_list_next(list);
581 }
582
583 list = g_list_first(GLOBALS->arc_list);
584 while (list != NULL)
585 {
586 Archive *entry = list->data;
587
588 da_archive_consistency(entry);
589 list = g_list_next(list);
590 }
591 }
592
593 static void homebank_upgrade_to_v04(void)
594 {
595 DB( g_print("\n[hb-xml] homebank_upgrade_to_v04\n") );
596
597 GLOBALS->arc_list = da_archive_sort(GLOBALS->arc_list);
598 }
599
600
601 // v0.4 to v0.5 :
602 // we must assume kxferacc exists in archives for internal xfer : bug 528923
603 // if not, remove automation from the archive
604 static void homebank_upgrade_to_v05(void)
605 {
606 GList *list;
607
608 DB( g_print("\n[hb-xml] homebank_upgrade_to_v05\n") );
609
610 list = g_list_first(GLOBALS->arc_list);
611 while (list != NULL)
612 {
613 Archive *entry = list->data;
614
615 da_archive_consistency(entry);
616 list = g_list_next(list);
617 }
618 }
619
620
621 // v0.5 to v0.6 : we must change kxferacc to 0 on non Xfer transactions
622 //#677351
623 static void homebank_upgrade_to_v06(void)
624 {
625 GList *list;
626
627 DB( g_print("\n[hb-xml] homebank_upgrade_to_v06\n") );
628
629 list = g_list_first(GLOBALS->ope_list);
630 while (list != NULL)
631 {
632 Transaction *entry = list->data;
633 da_transaction_consistency(entry);
634 list = g_list_next(list);
635 }
636
637 list = g_list_first(GLOBALS->arc_list);
638 while (list != NULL)
639 {
640 Archive *entry = list->data;
641 da_archive_consistency(entry);
642 list = g_list_next(list);
643 }
644 }
645
646
647 // v0.7 AF_BUDGET removed instead of AF_NOBUDGET
648 static void homebank_upgrade_to_v07(void)
649 {
650 GList *lacc, *list;
651
652 DB( g_print("\n[hb-xml] homebank_upgrade_to_v07\n") );
653
654 lacc = list = g_hash_table_get_values(GLOBALS->h_acc);
655 while (list != NULL)
656 {
657 Account *acc = list->data;
658
659 if( acc->flags & AF_OLDBUDGET ) // budget include
660 {
661 acc->flags &= ~(AF_OLDBUDGET);
662 }
663 else
664 {
665 acc->flags |= AF_NOBUDGET;
666 }
667
668 list = g_list_next(list);
669 }
670 g_list_free(lacc);
671
672 }
673
674 static void homebank_upgrade_to_v08(void)
675 {
676 GList *list;
677
678 DB( g_print("\n[hb-xml] homebank_upgrade_to_v08\n") );
679
680 list = g_list_first(GLOBALS->ope_list);
681 while (list != NULL)
682 {
683 Transaction *entry = list->data;
684 da_transaction_consistency(entry);
685 list = g_list_next(list);
686 }
687
688
689 }
690
691
692 // v0.6 to v0.7 : assign a default currency
693 /*
694 static void homebank_upgrade_to_v08(void)
695 {
696
697 // set a base currency to the hbfile if not
698 g_print("GLOBALS->kcur %d\n", GLOBALS->kcur);
699
700 if(GLOBALS->kcur == 0)
701 {
702 //struct iso4217format *choice = ui_cur_select_dialog_new(GLOBALS->mainwindow);
703 struct iso4217format *curfmt = iso4217format_get(PREFS->curr_default);
704
705 if(curfmt == NULL)
706 curfmt = iso4217format_get_en_us();
707
708
709 Currency *item = currency_add_from_user(curfmt);
710
711 GLOBALS->kcur = item->key;
712
713 g_print("GLOBALS->kcur %d\n", GLOBALS->kcur);
714
715 // set every accounts to base currecny
716 GList *list = g_hash_table_get_values(GLOBALS->h_acc);
717 while (list != NULL)
718 {
719 Account *acc;
720 acc = list->data;
721
722 acc->kcur = item->key;
723
724 list = g_list_next(list);
725 }
726 g_list_free(list);
727
728
729 }
730 }
731 */
732
733
734 // lower v0.6 : we must assume categories/payee exists
735 // and strong link to xfer
736 // #632496
737 static void homebank_upgrade_lower_v06(void)
738 {
739 Category *cat;
740 Payee *pay;
741 GList *lrul, *list;
742
743 DB( g_print("\n[hb-xml] homebank_upgrade_lower_v06\n") );
744
745 list = g_list_first(GLOBALS->ope_list);
746 while (list != NULL)
747 {
748 Transaction *entry = list->data;
749
750 da_transaction_consistency(entry);
751
752 //also strong link internal xfer
753 if(entry->paymode == PAYMODE_INTXFER)
754 {
755 Transaction *child = transaction_old_get_child_transfer(entry);
756 if(child != NULL)
757 {
758 transaction_xfer_change_to_child(entry, child);
759 }
760 }
761
762 list = g_list_next(list);
763 }
764
765
766 lrul = list = g_hash_table_get_values(GLOBALS->h_rul);
767 while (list != NULL)
768 {
769 Assign *entry = list->data;
770
771 cat = da_cat_get(entry->kcat);
772 if(cat == NULL)
773 {
774 DB( g_print(" !! fixing cat for rul: %d is unknow\n", entry->kcat) );
775 entry->kcat = 0;
776 }
777
778 pay = da_pay_get(entry->kpay);
779 if(pay == NULL)
780 {
781 DB( g_print(" !! fixing pay for rul: %d is unknow\n", entry->kpay) );
782 entry->kpay = 0;
783 }
784
785
786 list = g_list_next(list);
787 }
788 g_list_free(lrul);
789
790
791 }
792
793
794 /* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */
795
796 /*
797 ** misc xml attributes methods
798 */
799 static void hb_xml_append_txt(GString *gstring, gchar *attrname, gchar *value)
800 {
801 if(value != NULL && *value != 0)
802 {
803 gchar *escaped = g_markup_escape_text(value, -1);
804 g_string_append_printf(gstring, "%s=\"%s\" ", attrname, escaped);
805 g_free(escaped);
806 }
807 }
808
809 static void hb_xml_append_int0(GString *gstring, gchar *attrname, guint32 value)
810 {
811 g_string_append_printf(gstring, "%s=\"%d\" ", attrname, value);
812 }
813
814 static void hb_xml_append_int(GString *gstring, gchar *attrname, guint32 value)
815 {
816 if(value != 0)
817 {
818 hb_xml_append_int0(gstring, attrname, value);
819 }
820 }
821
822 static void hb_xml_append_amt(GString *gstring, gchar *attrname, gdouble amount)
823 {
824 char buf[G_ASCII_DTOSTR_BUF_SIZE];
825
826 //we must use this, as fprintf use locale decimal settings and not '.'
827 g_ascii_dtostr (buf, sizeof (buf), amount);
828 g_string_append_printf(gstring, "%s=\"%s\" ", attrname, buf);
829 }
830
831
832 /*
833 ** XML properties save
834 */
835 static void homebank_save_xml_prop(GIOChannel *io)
836 {
837 gchar *title;
838 GString *node;
839
840 title = GLOBALS->owner == NULL ? "" : GLOBALS->owner;
841
842 node = g_string_sized_new(255);
843
844 g_string_assign(node, "<properties ");
845
846 hb_xml_append_txt(node, "title", title);
847 hb_xml_append_int(node, "car_category", GLOBALS->vehicle_category);
848 hb_xml_append_int0(node, "auto_smode", GLOBALS->auto_smode);
849 hb_xml_append_int(node, "auto_weekday", GLOBALS->auto_weekday);
850 hb_xml_append_int(node, "auto_nbdays", GLOBALS->auto_nbdays);
851
852 g_string_append(node, "/>\n");
853
854 g_io_channel_write_chars(io, node->str, -1, NULL, NULL);
855
856 g_string_free(node, TRUE);
857 }
858
859
860 /*
861 ** XML currency save
862 */
863 /*
864 static void homebank_save_xml_cur(GIOChannel *io)
865 {
866 GList *list;
867 gchar *tmpstr;
868 char buf1[G_ASCII_DTOSTR_BUF_SIZE];
869
870 list = g_hash_table_get_values(GLOBALS->h_cur);
871 while (list != NULL)
872 {
873 Currency *item = list->data;
874
875 if(item->key != 0)
876 {
877 tmpstr = g_markup_printf_escaped(
878 "<cur key=\"%d\" iso=\"%s\" name=\"%s\" symb=\"%s\" syprf=\"%d\" dchar=\"%s\" gchar=\"%s\" frac=\"%d\" rate=\"%s\" mdate=\"%d\" />\n",
879 item->key,
880 item->iso_code,
881 item->name,
882 item->symbol,
883 item->sym_prefix,
884 item->decimal_char,
885 item->grouping_char,
886 item->frac_digits,
887 g_ascii_dtostr (buf1, sizeof (buf1), item->rate),
888 item->mdate
889 );
890
891 g_io_channel_write_chars(io, tmpstr, -1, NULL, NULL);
892 g_free(tmpstr);
893
894 }
895 list = g_list_next(list);
896 }
897 g_list_free(list);
898 }
899 */
900
901
902 /*
903 ** XML account save
904 */
905 static void homebank_save_xml_acc(GIOChannel *io)
906 {
907 GList *lacc, *list;
908 GString *node;
909
910 node = g_string_sized_new(255);
911
912 lacc = list = account_glist_sorted(0);
913 while (list != NULL)
914 {
915 Account *item = list->data;
916
917 item->flags &= ~(AF_ADDED|AF_CHANGED); //remove flag
918
919 g_string_assign(node, "<account ");
920
921 hb_xml_append_int(node, "key", item->key);
922 hb_xml_append_int(node, "flags", item->flags);
923 hb_xml_append_int(node, "pos", item->pos);
924 hb_xml_append_int(node, "type", item->type);
925 //hb_xml_append_int(node, "curr", item->kcur);
926 hb_xml_append_txt(node, "name", item->name);
927 hb_xml_append_txt(node, "number", item->number);
928 hb_xml_append_txt(node, "bankname", item->bankname);
929 hb_xml_append_amt(node, "initial", item->initial);
930 hb_xml_append_amt(node, "minimum", item->minimum);
931 hb_xml_append_int(node, "cheque1", item->cheque1);
932 hb_xml_append_int(node, "cheque2", item->cheque2);
933
934 g_string_append(node, "/>\n");
935
936 g_io_channel_write_chars(io, node->str, -1, NULL, NULL);
937 list = g_list_next(list);
938 }
939 g_list_free(lacc);
940 g_string_free(node, TRUE);
941 }
942
943 /*
944 ** XML payee save
945 */
946 static void homebank_save_xml_pay(GIOChannel *io)
947 {
948 GList *lpay, *list;
949 gchar *tmpstr;
950
951 lpay = list = payee_glist_sorted(0);
952 while (list != NULL)
953 {
954 Payee *item = list->data;
955
956 if(item->key != 0)
957 {
958 tmpstr = g_markup_printf_escaped("<pay key=\"%d\" name=\"%s\"/>\n",
959 item->key,
960 item->name
961 );
962
963 g_io_channel_write_chars(io, tmpstr, -1, NULL, NULL);
964 g_free(tmpstr);
965
966 }
967 list = g_list_next(list);
968 }
969 g_list_free(lpay);
970 }
971
972 /*
973 ** XML category save
974 */
975 static void homebank_save_xml_cat(GIOChannel *io)
976 {
977 GList *lcat, *list;
978 GString *node;
979 char buf[G_ASCII_DTOSTR_BUF_SIZE];
980 guint i;
981
982 node = g_string_sized_new(255);
983
984 lcat = list = category_glist_sorted(0);
985 while (list != NULL)
986 {
987 Category *item = list->data;
988
989 if(item->key != 0)
990 {
991 g_string_assign(node, "<cat ");
992
993 hb_xml_append_int(node, "key", item->key);
994 hb_xml_append_int(node, "parent", item->parent);
995 hb_xml_append_int(node, "flags", item->flags);
996 hb_xml_append_txt(node, "name", item->name);
997
998 for(i=0;i<=12;i++)
999 {
1000 if(item->budget[i] != 0)
1001 {
1002 g_string_append_printf(node,"b%d=\"%s\" ", i, g_ascii_dtostr (buf, sizeof (buf), item->budget[i]));
1003 }
1004 }
1005
1006 g_string_append(node, "/>\n");
1007 g_io_channel_write_chars(io, node->str, -1, NULL, NULL);
1008
1009 }
1010 list = g_list_next(list);
1011 }
1012 g_list_free(lcat);
1013 g_string_free(node, TRUE);
1014 }
1015
1016 /*
1017 ** XML tag save
1018 */
1019 static void homebank_save_xml_tag(GIOChannel *io)
1020 {
1021 GList *ltag, *list;
1022 gchar *tmpstr;
1023
1024 ltag = list = tag_glist_sorted(0);
1025 while (list != NULL)
1026 {
1027 Tag *item = list->data;
1028
1029 if(item->key != 0)
1030 {
1031 tmpstr = g_markup_printf_escaped("<tag key=\"%d\" name=\"%s\" />\n",
1032 item->key,
1033 item->name
1034 );
1035
1036 g_io_channel_write_chars(io, tmpstr, -1, NULL, NULL);
1037 g_free(tmpstr);
1038
1039 }
1040 list = g_list_next(list);
1041 }
1042 g_list_free(ltag);
1043 }
1044
1045
1046 /*
1047 ** XML assign save
1048 */
1049 static void homebank_save_xml_asg(GIOChannel *io)
1050 {
1051 GList *lasg, *list;
1052 GString *node;
1053
1054 node = g_string_sized_new(255);
1055
1056 lasg = list = assign_glist_sorted(0);
1057 while (list != NULL)
1058 {
1059 Assign *item = list->data;
1060
1061 g_string_assign(node, "<asg ");
1062
1063 hb_xml_append_int(node, "key" , item->key);
1064 hb_xml_append_int(node, "flags" , item->flags);
1065 hb_xml_append_int(node, "field" , item->field);
1066 hb_xml_append_txt(node, "name" , item->name);
1067 hb_xml_append_int(node, "payee" , item->kpay);
1068 hb_xml_append_int(node, "category", item->kcat);
1069 //hb_xml_append_int(node, "paymode" , item->paymode);
1070
1071 g_string_append(node, "/>\n");
1072
1073 g_io_channel_write_chars(io, node->str, -1, NULL, NULL);
1074
1075 list = g_list_next(list);
1076 }
1077 g_list_free(lasg);
1078 g_string_free(node, TRUE);
1079 }
1080
1081
1082
1083 /*
1084 ** XML archive save
1085 */
1086 static void homebank_save_xml_arc(GIOChannel *io)
1087 {
1088 GList *list;
1089 GString *node;
1090
1091 node = g_string_sized_new(255);
1092
1093 list = g_list_first(GLOBALS->arc_list);
1094 while (list != NULL)
1095 {
1096 Archive *item = list->data;
1097
1098 g_string_assign(node, "<fav ");
1099
1100 hb_xml_append_amt(node, "amount", item->amount);
1101 hb_xml_append_int(node, "account", item->kacc);
1102 hb_xml_append_int(node, "dst_account", item->kxferacc);
1103 hb_xml_append_int(node, "paymode", item->paymode);
1104 hb_xml_append_int(node, "flags", item->flags);
1105 hb_xml_append_int(node, "payee", item->kpay);
1106 hb_xml_append_int(node, "category", item->kcat);
1107 hb_xml_append_txt(node, "wording", item->wording);
1108 hb_xml_append_int(node, "nextdate", item->nextdate);
1109 hb_xml_append_int(node, "every", item->every);
1110 hb_xml_append_int(node, "unit", item->unit);
1111 hb_xml_append_int(node, "limit", item->limit);
1112 hb_xml_append_int(node, "weekend", item->weekend);
1113
1114 g_string_append(node, "/>\n");
1115
1116 g_io_channel_write_chars(io, node->str, -1, NULL, NULL);
1117 list = g_list_next(list);
1118 }
1119 g_string_free(node, TRUE);
1120 }
1121
1122
1123 /*
1124 ** XML transaction save
1125 */
1126 static void homebank_save_xml_ope(GIOChannel *io)
1127 {
1128 GList *list;
1129 GString *node;
1130 gchar *tagstr;
1131
1132 node = g_string_sized_new(255);
1133
1134 list = g_list_first(GLOBALS->ope_list);
1135 while (list != NULL)
1136 {
1137 Transaction *item = list->data;
1138
1139 item->flags &= ~(OF_AUTO|OF_ADDED|OF_CHANGED); //remove flag
1140 tagstr = transaction_tags_tostring(item);
1141
1142 g_string_assign(node, "<ope ");
1143
1144 hb_xml_append_int(node, "date", item->date);
1145 hb_xml_append_amt(node, "amount", item->amount);
1146 hb_xml_append_int(node, "account", item->kacc);
1147 hb_xml_append_int(node, "dst_account", item->kxferacc);
1148 hb_xml_append_int(node, "paymode", item->paymode);
1149 hb_xml_append_int(node, "flags", item->flags);
1150 hb_xml_append_int(node, "payee", item->kpay);
1151 hb_xml_append_int(node, "category", item->kcat);
1152 hb_xml_append_txt(node, "wording", item->wording);
1153 hb_xml_append_txt(node, "info", item->info);
1154 hb_xml_append_txt(node, "tags", tagstr);
1155 hb_xml_append_int(node, "kxfer", item->kxfer);
1156
1157 if(da_transaction_splits_count(item) > 0)
1158 {
1159 gchar *cats, *amounts, *memos;
1160
1161 transaction_splits_tostring(item, &cats, &amounts, &memos);
1162 g_string_append_printf(node, "scat=\"%s\" ", cats);
1163 g_string_append_printf(node, "samt=\"%s\" ", amounts);
1164
1165 //fix #1173910
1166 gchar *escaped = g_markup_escape_text(memos, -1);
1167 g_string_append_printf(node, "smem=\"%s\" ", escaped);
1168 g_free(escaped);
1169
1170 g_free(cats);
1171 g_free(amounts);
1172 g_free(memos);
1173 }
1174
1175 g_string_append(node, "/>\n");
1176
1177 g_free(tagstr);
1178 g_io_channel_write_chars(io, node->str, -1, NULL, NULL);
1179 list = g_list_next(list);
1180 }
1181 g_string_free(node, TRUE);
1182 }
1183
1184 /*
1185 ** XML save homebank file: hbfile
1186 */
1187 gint homebank_save_xml(gchar *filename)
1188 {
1189 GIOChannel *io;
1190 char buf1[G_ASCII_DTOSTR_BUF_SIZE];
1191 gchar *outstr;
1192 gint retval = XML_OK;
1193
1194 GValue filename_val = G_VALUE_INIT;
1195 ext_hook("save_file", EXT_STRING(&filename_val, filename), NULL);
1196
1197 io = g_io_channel_new_file(filename, "w", NULL);
1198 if(io == NULL)
1199 {
1200 g_message("file error on: %s", filename);
1201 retval = XML_IO_ERROR;
1202 }
1203 else
1204 {
1205 g_io_channel_write_chars(io, "<?xml version=\"1.0\"?>\n", -1, NULL, NULL);
1206
1207 outstr = g_strdup_printf("<homebank v=\"%s\">\n", g_ascii_dtostr (buf1, sizeof (buf1), FILE_VERSION));
1208 g_io_channel_write_chars(io, outstr, -1, NULL, NULL);
1209 g_free(outstr);
1210
1211 homebank_save_xml_prop(io);
1212 //homebank_save_xml_cur(io);
1213 homebank_save_xml_acc(io);
1214 homebank_save_xml_pay(io);
1215 homebank_save_xml_cat(io);
1216 homebank_save_xml_tag(io);
1217 homebank_save_xml_asg(io);
1218 homebank_save_xml_arc(io);
1219 homebank_save_xml_ope(io);
1220
1221 g_io_channel_write_chars(io, "</homebank>\n", -1, NULL, NULL);
1222
1223 g_io_channel_unref (io);
1224 }
1225 return retval;
1226 }
1227
This page took 0.101225 seconds and 4 git commands to generate.