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