]> Dogcows Code - chaz/homebank/blob - src/hb-xml.c
Merge branch 'master' into ext-perl
[chaz/homebank] / src / hb-xml.c
1 /* HomeBank -- Free, easy, personal accounting for everyone.
2 * Copyright (C) 1995-2019 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 #include "ui-dialogs.h"
29
30 /****************************************************************************/
31 /* Debug macros */
32 /****************************************************************************/
33 #define MYDEBUG 0
34
35 #if MYDEBUG
36 #define DB(x) (x);
37 #else
38 #define DB(x);
39 #endif
40
41 /* our global datas */
42 extern struct HomeBank *GLOBALS;
43 extern struct Preferences *PREFS;
44
45
46 /* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */
47
48
49 // v0.1 to v0.2 : we must change account reference by making a +1 to its index references
50 static void homebank_upgrade_to_v02(void)
51 {
52 GList *lst_acc, *lnk_acc;
53 GList *list;
54 GHashTable *h_old_acc;
55
56
57 DB( g_print("\n[hb-xml] homebank_upgrade_to_v02\n") );
58
59 //keep old hashtable with us
60 h_old_acc = GLOBALS->h_acc;
61 da_acc_new();
62
63 lst_acc = g_hash_table_get_values(h_old_acc);
64 lnk_acc = g_list_first(lst_acc);
65 while (lnk_acc != NULL)
66 {
67 Account *acc = lnk_acc->data;
68
69 acc->key++;
70 acc->pos++;
71 da_acc_insert (acc);
72
73 list = g_queue_peek_head_link(acc->txn_queue);
74 while (list != NULL)
75 {
76 Transaction *entry = list->data;
77 entry->kacc++;
78 entry->kxferacc++;
79 list = g_list_next(list);
80 }
81 lnk_acc = g_list_next(lnk_acc);
82 }
83 g_list_free(lst_acc);
84
85 //we loose some small memory here
86 g_hash_table_steal_all(h_old_acc);
87
88 list = g_list_first(GLOBALS->arc_list);
89 while (list != NULL)
90 {
91 Archive *entry = list->data;
92 entry->kacc++;
93 entry->kxferacc++;
94 list = g_list_next(list);
95 }
96 }
97
98 // v0.2 to v0.3 : we must assume categories exists : bugs 303886, 303738
99 static void homebank_upgrade_to_v03(void)
100 {
101 GList *lst_acc, *lnk_acc;
102 GList *list;
103
104 DB( g_print("\n[hb-xml] homebank_upgrade_to_v03\n") );
105
106 lst_acc = g_hash_table_get_values(GLOBALS->h_acc);
107 lnk_acc = g_list_first(lst_acc);
108 while (lnk_acc != NULL)
109 {
110 Account *acc = lnk_acc->data;
111
112 list = g_queue_peek_head_link(acc->txn_queue);
113 while (list != NULL)
114 {
115 Transaction *entry = list->data;
116
117 da_transaction_consistency(entry);
118 list = g_list_next(list);
119 }
120 lnk_acc = g_list_next(lnk_acc);
121 }
122 g_list_free(lst_acc);
123
124
125 list = g_list_first(GLOBALS->arc_list);
126 while (list != NULL)
127 {
128 Archive *entry = list->data;
129
130 da_archive_consistency(entry);
131 list = g_list_next(list);
132 }
133 }
134
135 static void homebank_upgrade_to_v04(void)
136 {
137 DB( g_print("\n[hb-xml] homebank_upgrade_to_v04\n") );
138
139 GLOBALS->arc_list = da_archive_sort(GLOBALS->arc_list);
140 }
141
142
143 // v0.4 to v0.5 :
144 // we must assume kxferacc exists in archives for internal xfer : bug 528923
145 // if not, delete automation from the archive
146 static void homebank_upgrade_to_v05(void)
147 {
148 GList *list;
149
150 DB( g_print("\n[hb-xml] homebank_upgrade_to_v05\n") );
151
152 list = g_list_first(GLOBALS->arc_list);
153 while (list != NULL)
154 {
155 Archive *entry = list->data;
156
157 da_archive_consistency(entry);
158 list = g_list_next(list);
159 }
160 }
161
162
163 // v0.5 to v0.6 : we must change kxferacc to 0 on non Xfer transactions
164 //#677351
165 static void homebank_upgrade_to_v06(void)
166 {
167 GList *lst_acc, *lnk_acc;
168 GList *list;
169
170 DB( g_print("\n[hb-xml] homebank_upgrade_to_v06\n") );
171
172 lst_acc = g_hash_table_get_values(GLOBALS->h_acc);
173 lnk_acc = g_list_first(lst_acc);
174 while (lnk_acc != NULL)
175 {
176 Account *acc = lnk_acc->data;
177
178 list = g_queue_peek_head_link(acc->txn_queue);
179 while (list != NULL)
180 {
181 Transaction *entry = list->data;
182 da_transaction_consistency(entry);
183 list = g_list_next(list);
184 }
185 lnk_acc = g_list_next(lnk_acc);
186 }
187 g_list_free(lst_acc);
188
189
190 list = g_list_first(GLOBALS->arc_list);
191 while (list != NULL)
192 {
193 Archive *entry = list->data;
194 da_archive_consistency(entry);
195 list = g_list_next(list);
196 }
197 }
198
199
200 // v0.7 AF_BUDGET deleted instead of AF_NOBUDGET
201 static void homebank_upgrade_to_v07(void)
202 {
203 GList *lacc, *list;
204
205 DB( g_print("\n[hb-xml] homebank_upgrade_to_v07\n") );
206
207 lacc = list = g_hash_table_get_values(GLOBALS->h_acc);
208 while (list != NULL)
209 {
210 Account *acc = list->data;
211
212 if( acc->flags & AF_OLDBUDGET ) // budget include
213 {
214 acc->flags &= ~(AF_OLDBUDGET);
215 }
216 else
217 {
218 acc->flags |= AF_NOBUDGET;
219 }
220
221 list = g_list_next(list);
222 }
223 g_list_free(lacc);
224
225 }
226
227 static void homebank_upgrade_to_v08(void)
228 {
229 GList *lst_acc, *lnk_acc;
230 GList *list;
231
232 DB( g_print("\n[hb-xml] homebank_upgrade_to_v08\n") );
233
234 lst_acc = g_hash_table_get_values(GLOBALS->h_acc);
235 lnk_acc = g_list_first(lst_acc);
236 while (lnk_acc != NULL)
237 {
238 Account *acc = lnk_acc->data;
239
240 list = g_queue_peek_head_link(acc->txn_queue);
241 while (list != NULL)
242 {
243 Transaction *entry = list->data;
244 da_transaction_consistency(entry);
245 list = g_list_next(list);
246 }
247 lnk_acc = g_list_next(lnk_acc);
248 }
249 g_list_free(lst_acc);
250
251
252 }
253
254
255 static void homebank_upgrade_to_v10(void)
256 {
257 GList *lst_acc, *lnk_acc;
258 GList *list;
259
260 DB( g_print("\n[hb-xml] homebank_upgrade_to_v10\n") );
261
262 lst_acc = g_hash_table_get_values(GLOBALS->h_acc);
263 lnk_acc = g_list_first(lst_acc);
264 while (lnk_acc != NULL)
265 {
266 Account *acc = lnk_acc->data;
267
268 list = g_queue_peek_head_link(acc->txn_queue);
269 while (list != NULL)
270 {
271 Transaction *entry = list->data;
272
273 entry->status = TXN_STATUS_NONE;
274 if(entry->flags & OF_OLDVALID)
275 entry->status = TXN_STATUS_RECONCILED;
276 else
277 if(entry->flags & OF_OLDREMIND)
278 entry->status = TXN_STATUS_REMIND;
279
280 //remove those flags
281 entry->flags &= ~(OF_OLDVALID|OF_OLDREMIND);
282
283 list = g_list_next(list);
284 }
285 lnk_acc = g_list_next(lnk_acc);
286 }
287 g_list_free(lst_acc);
288
289 }
290
291
292 static void homebank_upgrade_to_v11(void)
293 {
294 GList *list;
295
296 DB( g_print("\n[hb-xml] homebank_upgrade_to_v11\n") );
297
298 list = g_list_first(GLOBALS->arc_list);
299 while (list != NULL)
300 {
301 Archive *entry = list->data;
302
303 entry->status = TXN_STATUS_NONE;
304 if(entry->flags & OF_OLDVALID)
305 entry->status = TXN_STATUS_RECONCILED;
306 else
307 if(entry->flags & OF_OLDREMIND)
308 entry->status = TXN_STATUS_REMIND;
309
310 //remove those flags
311 entry->flags &= ~(OF_OLDVALID|OF_OLDREMIND);
312
313 list = g_list_next(list);
314 }
315
316 }
317
318
319 // v0.6 to v0.7 : assign a default currency
320 static void homebank_upgrade_to_v12(void)
321 {
322 DB( g_print("\n[hb-xml] homebank_upgrade_to_v12\n") );
323
324 // set a base currency to the hbfile if not
325 DB( g_print("GLOBALS->kcur %d\n", GLOBALS->kcur) );
326
327 ui_dialog_upgrade_choose_currency();
328 }
329
330
331 static void homebank_upgrade_to_v12_7(void)
332 {
333 GList *lst_acc, *lnk_acc;
334
335 DB( g_print("\n[hb-xml] homebank_upgrade_to_v12\n") );
336
337 //#1674045 exclude closed account from everywhere to
338 //keep continuity for user that don't want to change this
339 lst_acc = g_hash_table_get_values(GLOBALS->h_acc);
340 lnk_acc = g_list_first(lst_acc);
341 while (lnk_acc != NULL)
342 {
343 Account *acc = lnk_acc->data;
344
345 if( acc->flags & AF_CLOSED )
346 {
347 if( !(acc->flags & AF_NOSUMMARY) )
348 acc->flags |= AF_NOSUMMARY;
349 if( !(acc->flags & AF_NOBUDGET) )
350 acc->flags |= AF_NOBUDGET;
351 if( !(acc->flags & AF_NOREPORT) )
352 acc->flags |= AF_NOREPORT;
353 }
354 lnk_acc = g_list_next(lnk_acc);
355 }
356 g_list_free(lst_acc);
357 }
358
359
360 static void homebank_upgrade_to_v13(void)
361 {
362 GList *tmplist;
363 guint32 newkey;
364
365 DB( g_print("\n[hb-xml] homebank_upgrade_to_v13\n") );
366
367 //#1008629 assign a key to each archive
368 newkey = 1;
369 tmplist = g_list_first(GLOBALS->arc_list);
370 while (tmplist != NULL)
371 {
372 Archive *item = tmplist->data;
373
374 item->key = newkey++;
375 tmplist = g_list_next(tmplist);
376 }
377
378 }
379
380
381 // lower v0.6 : we must assume categories/payee exists
382 // and strong link to xfer
383 // #632496
384 static void homebank_upgrade_lower_v06(void)
385 {
386 GList *lst_acc, *lnk_acc;
387 Category *cat;
388 Payee *pay;
389 GList *lrul, *list;
390
391 DB( g_print("\n[hb-xml] homebank_upgrade_lower_v06\n") );
392
393 lst_acc = g_hash_table_get_values(GLOBALS->h_acc);
394 lnk_acc = g_list_first(lst_acc);
395 while (lnk_acc != NULL)
396 {
397 Account *acc = lnk_acc->data;
398
399 list = g_queue_peek_head_link(acc->txn_queue);
400 while (list != NULL)
401 {
402 Transaction *entry = list->data;
403
404 //also strong link internal xfer
405 if(entry->paymode == PAYMODE_INTXFER && entry->kxfer == 0)
406 {
407 Transaction *child = transaction_old_get_child_transfer(entry);
408 if(child != NULL)
409 {
410 transaction_xfer_change_to_child(entry, child);
411 }
412 }
413
414 da_transaction_consistency(entry);
415
416 list = g_list_next(list);
417 }
418 lnk_acc = g_list_next(lnk_acc);
419 }
420 g_list_free(lst_acc);
421
422
423 lrul = list = g_hash_table_get_values(GLOBALS->h_rul);
424 while (list != NULL)
425 {
426 Assign *entry = list->data;
427
428 cat = da_cat_get(entry->kcat);
429 if(cat == NULL)
430 {
431 DB( g_print(" !! fixing cat for rul: %d is unknown\n", entry->kcat) );
432 entry->kcat = 0;
433 }
434
435 pay = da_pay_get(entry->kpay);
436 if(pay == NULL)
437 {
438 DB( g_print(" !! fixing pay for rul: %d is unknown\n", entry->kpay) );
439 entry->kpay = 0;
440 }
441
442
443 list = g_list_next(list);
444 }
445 g_list_free(lrul);
446 }
447
448
449 /* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */
450
451
452 static void homebank_load_xml_acc(ParseContext *ctx, const gchar **attribute_names, const gchar **attribute_values)
453 {
454 Account *entry = da_acc_malloc();
455 gint i;
456
457 for (i = 0; attribute_names[i] != NULL; i++)
458 {
459 //DB( g_print(" att='%s' val='%s'\n", attribute_names[i], attribute_values[i]) );
460
461 if(!strcmp (attribute_names[i], "key" )) { entry->key = atoi(attribute_values[i]); }
462 else if(!strcmp (attribute_names[i], "flags" )) { entry->flags = atoi(attribute_values[i]); }
463 else if(!strcmp (attribute_names[i], "pos" )) { entry->pos = atoi(attribute_values[i]); }
464 else if(!strcmp (attribute_names[i], "type" )) { entry->type = atoi(attribute_values[i]); }
465 else if(!strcmp (attribute_names[i], "curr" )) { entry->kcur = atoi(attribute_values[i]); }
466 else if(!strcmp (attribute_names[i], "name" )) { if(strcmp(attribute_values[i],"(null)") && attribute_values[i] != NULL) entry->name = g_strdup(attribute_values[i]); }
467 else if(!strcmp (attribute_names[i], "number" )) { if(strcmp(attribute_values[i],"(null)") && attribute_values[i] != NULL) entry->number = g_strdup(attribute_values[i]); }
468 else if(!strcmp (attribute_names[i], "bankname")) { if(strcmp(attribute_values[i],"(null)") && attribute_values[i] != NULL) entry->bankname = g_strdup(attribute_values[i]); }
469 else if(!strcmp (attribute_names[i], "initial" )) { entry->initial = g_ascii_strtod(attribute_values[i], NULL); }
470
471 else if(!strcmp (attribute_names[i], "minimum" )) { entry->minimum = g_ascii_strtod(attribute_values[i], NULL); }
472 else if(!strcmp (attribute_names[i], "cheque1" )) { entry->cheque1 = atoi(attribute_values[i]); }
473 else if(!strcmp (attribute_names[i], "cheque2" )) { entry->cheque2 = atoi(attribute_values[i]); }
474 else if(!strcmp (attribute_names[i], "notes" )) { if(strcmp(attribute_values[i],"(null)") && attribute_values[i] != NULL) entry->notes = g_strdup(attribute_values[i]); }
475 else if(!strcmp (attribute_names[i], "tpl" )) { entry->karc = atoi(attribute_values[i]); }
476 }
477
478 //all attribute loaded: append
479 da_acc_insert(entry);
480 }
481
482
483 static void homebank_load_xml_asg(ParseContext *ctx, const gchar **attribute_names, const gchar **attribute_values)
484 {
485 Assign *entry = da_asg_malloc();
486 gint exact = 0;
487 gint i;
488
489 for (i = 0; attribute_names[i] != NULL; i++)
490 {
491 //DB( g_print(" att='%s' val='%s'\n", attribute_names[i], attribute_values[i]) );
492
493 if(!strcmp (attribute_names[i], "key" )) { entry->key = atoi(attribute_values[i]); }
494 else if(!strcmp (attribute_names[i], "flags" )) { entry->flags = atoi(attribute_values[i]); }
495 else if(!strcmp (attribute_names[i], "field" )) { entry->field = atoi(attribute_values[i]); }
496 else if(!strcmp (attribute_names[i], "name" )) { if(strcmp(attribute_values[i],"(null)") && attribute_values[i] != NULL) entry->text = g_strdup(attribute_values[i]); }
497 else if(!strcmp (attribute_names[i], "payee" )) { entry->kpay = atoi(attribute_values[i]); }
498 else if(!strcmp (attribute_names[i], "category")) { entry->kcat = atoi(attribute_values[i]); }
499 else if(!strcmp (attribute_names[i], "paymode" )) { entry->paymode = atoi(attribute_values[i]); }
500 // prior v08
501 else if(!strcmp (attribute_names[i], "exact" )) { exact = atoi(attribute_values[i]); }
502 }
503
504 /* in v08 exact moved to flag */
505 if( ctx->file_version <= 0.7)
506 {
507 entry->flags = (ASGF_DOCAT|ASGF_DOPAY);
508 if( exact > 0 )
509 entry->flags |= ASGF_EXACT;
510 }
511
512 //all attribute loaded: append
513 da_asg_append(entry);
514
515 }
516
517
518 static void homebank_load_xml_pay(ParseContext *ctx, const gchar **attribute_names, const gchar **attribute_values)
519 {
520 Payee *entry = da_pay_malloc();
521 gint i;
522
523 for (i = 0; attribute_names[i] != NULL; i++)
524 {
525 //DB( g_print(" att='%s' val='%s'\n", attribute_names[i], attribute_values[i]) );
526
527 if(!strcmp (attribute_names[i], "key" )) { entry->key = atoi(attribute_values[i]); }
528 //else if(!strcmp (attribute_names[i], "flags")) { entry->flags = atoi(attribute_values[i]); }
529 else if(!strcmp (attribute_names[i], "name" )) { entry->name = g_strdup(attribute_values[i]); }
530 else if(!strcmp (attribute_names[i], "category")) { entry->kcat = atoi(attribute_values[i]); }
531 else if(!strcmp (attribute_names[i], "paymode" )) { entry->paymode = atoi(attribute_values[i]); }
532 }
533
534 //all attribute loaded: append
535 da_pay_insert(entry);
536 }
537
538
539 static void homebank_load_xml_prop(ParseContext *ctx, const gchar **attribute_names, const gchar **attribute_values)
540 {
541 gint i;
542
543 for (i = 0; attribute_names[i] != NULL; i++)
544 {
545 if(!strcmp (attribute_names[i], "title" )) { g_free(GLOBALS->owner); GLOBALS->owner = g_strdup(attribute_values[i]); }
546 else if(!strcmp (attribute_names[i], "curr" )) { GLOBALS->kcur = atoi(attribute_values[i]); }
547 else if(!strcmp (attribute_names[i], "car_category")) { GLOBALS->vehicle_category = atoi(attribute_values[i]); }
548 else if(!strcmp (attribute_names[i], "auto_smode" )) { GLOBALS->auto_smode = atoi(attribute_values[i]); }
549 else if(!strcmp (attribute_names[i], "auto_weekday")) { GLOBALS->auto_weekday = atoi(attribute_values[i]); }
550 else if(!strcmp (attribute_names[i], "auto_nbdays" )) { GLOBALS->auto_nbdays = atoi(attribute_values[i]); }
551 }
552 }
553
554
555 static void homebank_load_xml_cat(ParseContext *ctx, const gchar **attribute_names, const gchar **attribute_values)
556 {
557 Category *entry = da_cat_malloc();
558 gboolean budget;
559 gint i, j;
560
561 for (i = 0; attribute_names[i] != NULL; i++)
562 {
563 //DB( g_print(" att='%s' val='%s'\n", attribute_names[i], attribute_values[i]) );
564
565 if(!strcmp (attribute_names[i], "key" )) { entry->key = atoi(attribute_values[i]); }
566 else if(!strcmp (attribute_names[i], "parent")) { entry->parent = atoi(attribute_values[i]); }
567 else if(!strcmp (attribute_names[i], "flags" )) { entry->flags = atoi(attribute_values[i]); }
568 else if(!strcmp (attribute_names[i], "name" )) { entry->name = g_strdup(attribute_values[i]); }
569
570 budget = FALSE;
571 for(j=0;j<=12;j++)
572 {
573 gchar *tmpname;
574
575 tmpname = g_strdup_printf ("b%d", j);
576 if(!(strcmp (attribute_names[i], tmpname))) { entry->budget[j] = g_ascii_strtod(attribute_values[i], NULL); }
577 g_free(tmpname);
578
579 if(entry->budget[j]) budget = TRUE;
580 }
581 if(budget == TRUE)
582 entry->flags |= GF_BUDGET;
583
584 }
585
586 //all attribute loaded: append
587 da_cat_insert( entry);
588 }
589
590
591 static void homebank_load_xml_cur(ParseContext *ctx, const gchar **attribute_names, const gchar **attribute_values)
592 {
593 Currency *entry = da_cur_malloc ();
594 gint i;
595
596 for (i = 0; attribute_names[i] != NULL; i++)
597 {
598 //DB( g_print(" att='%s' val='%s'\n", attribute_names[i], attribute_values[i]) );
599
600 if(!strcmp (attribute_names[i], "key" )) { entry->key = atoi(attribute_values[i]); }
601 else if(!strcmp (attribute_names[i], "flags" )) { entry->flags = atoi(attribute_values[i]); }
602 else if(!strcmp (attribute_names[i], "name" )) { entry->name = g_strdup(attribute_values[i]); }
603 else if(!strcmp (attribute_names[i], "iso" )) { entry->iso_code = g_strdup(attribute_values[i]); }
604 else if(!strcmp (attribute_names[i], "symb" )) { entry->symbol = g_strdup(attribute_values[i]); }
605 else if(!strcmp (attribute_names[i], "syprf" )) { entry->sym_prefix = atoi(attribute_values[i]); }
606 else if(!strcmp (attribute_names[i], "dchar" )) { entry->decimal_char = g_strdup(attribute_values[i]); }
607 else if(!strcmp (attribute_names[i], "gchar" )) { entry->grouping_char = g_strdup(attribute_values[i]); }
608 else if(!strcmp (attribute_names[i], "frac" )) { entry->frac_digits = atoi(attribute_values[i]); }
609 else if(!strcmp (attribute_names[i], "rate" )) { entry->rate = g_ascii_strtod(attribute_values[i], NULL); }
610 else if(!strcmp (attribute_names[i], "mdate ")) { entry->mdate = atoi(attribute_values[i]); }
611
612 }
613
614 //all attribute loaded: append
615 da_cur_insert (entry);
616 }
617
618
619 /*static void homebank_load_xml_tag(ParseContext *ctx, const gchar **attribute_names, const gchar **attribute_values)
620 {
621 Tag *entry = da_tag_malloc();
622 gint i;
623
624 for (i = 0; attribute_names[i] != NULL; i++)
625 {
626 //DB( g_print(" att='%s' val='%s'\n", attribute_names[i], attribute_values[i]) );
627
628 if(!strcmp (attribute_names[i], "key" )) { entry->key = atoi(attribute_values[i]); }
629 //else if(!strcmp (attribute_names[i], "flags")) { entry->flags = atoi(attribute_values[i]); }
630 else if(!strcmp (attribute_names[i], "name" )) { entry->name = g_strdup(attribute_values[i]); }
631 }
632
633 //all attribute loaded: append
634 da_tag_insert(entry);
635 }*/
636
637
638 static void homebank_load_xml_fav(ParseContext *ctx, const gchar **attribute_names, const gchar **attribute_values)
639 {
640 Archive *entry = da_archive_malloc();
641 gchar *scat = NULL;
642 gchar *samt = NULL;
643 gchar *smem = NULL;
644 gboolean split = FALSE;
645 gint i;
646
647 for (i = 0; attribute_names[i] != NULL; i++)
648 {
649 //DB( g_print(" att='%s' val='%s'\n", attribute_names[i], attribute_values[i]) );
650
651 if(!strcmp (attribute_names[i], "key" )) { entry->key = atoi(attribute_values[i]); }
652 else if(!strcmp (attribute_names[i], "amount" )) { entry->amount = g_ascii_strtod(attribute_values[i], NULL); }
653 else if(!strcmp (attribute_names[i], "account" )) { entry->kacc = atoi(attribute_values[i]); }
654 else if(!strcmp (attribute_names[i], "dst_account")) { entry->kxferacc = atoi(attribute_values[i]); }
655 else if(!strcmp (attribute_names[i], "paymode" )) { entry->paymode = atoi(attribute_values[i]); }
656 else if(!strcmp (attribute_names[i], "st" )) { entry->status = atoi(attribute_values[i]); }
657 else if(!strcmp (attribute_names[i], "flags" )) { entry->flags = atoi(attribute_values[i]); }
658 else if(!strcmp (attribute_names[i], "payee" )) { entry->kpay = atoi(attribute_values[i]); }
659 else if(!strcmp (attribute_names[i], "category" )) { entry->kcat = atoi(attribute_values[i]); }
660 else if(!strcmp (attribute_names[i], "wording" )) { if(strcmp(attribute_values[i],"(null)") && attribute_values[i] != NULL) entry->memo = g_strdup(attribute_values[i]); }
661 else if(!strcmp (attribute_names[i], "tags" ))
662 {
663 if(attribute_values[i] != NULL && strlen(attribute_values[i]) > 0 && strcmp(attribute_values[i],"(null)") != 0 )
664 {
665 entry->tags = tags_parse(attribute_values[i]);
666 }
667 }
668 else if(!strcmp (attribute_names[i], "nextdate" )) { entry->nextdate = atoi(attribute_values[i]); }
669 else if(!strcmp (attribute_names[i], "every" )) { entry->every = atoi(attribute_values[i]); }
670 else if(!strcmp (attribute_names[i], "unit" )) { entry->unit = atoi(attribute_values[i]); }
671 else if(!strcmp (attribute_names[i], "limit" )) { entry->limit = atoi(attribute_values[i]); }
672 else if(!strcmp (attribute_names[i], "weekend" )) { entry->weekend = atoi(attribute_values[i]); }
673 else if(!strcmp (attribute_names[i], "gap" )) { entry->daygap = atoi(attribute_values[i]); }
674 else if(!strcmp (attribute_names[i], "scat" )) { scat = (gchar *)attribute_values[i]; split = TRUE; }
675 else if(!strcmp (attribute_names[i], "samt" )) { samt = (gchar *)attribute_values[i]; split = TRUE; }
676 else if(!strcmp (attribute_names[i], "smem" )) { smem = (gchar *)attribute_values[i]; split = TRUE; }
677
678 }
679
680 if(split == TRUE)
681 {
682 entry->splits = da_split_new ();
683 if (da_splits_parse(entry->splits, scat, samt, smem) > 0)
684 {
685 entry->flags |= OF_SPLIT; //Flag that Splits are active
686 }
687 }
688
689 //all attribute loaded: append
690 //GLOBALS->arc_list = g_list_append(GLOBALS->arc_list, entry);
691 da_archive_append(entry);
692 }
693
694
695 static void homebank_load_xml_ope(ParseContext *ctx, const gchar **attribute_names, const gchar **attribute_values)
696 {
697 Transaction *entry = da_transaction_malloc();
698 gchar *scat = NULL;
699 gchar *samt = NULL;
700 gchar *smem = NULL;
701 gboolean split = FALSE;
702 gint i;
703
704 for (i = 0; attribute_names[i] != NULL; i++)
705 {
706 //DB( g_print(" att='%s' val='%s'\n", attribute_names[i], attribute_values[i]) );
707
708 if(!strcmp (attribute_names[i], "date" )) { entry->date = atoi(attribute_values[i]); }
709 else if(!strcmp (attribute_names[i], "amount" )) { entry->amount = g_ascii_strtod(attribute_values[i], NULL); }
710 else if(!strcmp (attribute_names[i], "account" )) { entry->kacc = atoi(attribute_values[i]); }
711 else if(!strcmp (attribute_names[i], "dst_account")) { entry->kxferacc = atoi(attribute_values[i]); }
712 else if(!strcmp (attribute_names[i], "paymode" )) { entry->paymode = atoi(attribute_values[i]); }
713 else if(!strcmp (attribute_names[i], "st" )) { entry->status = atoi(attribute_values[i]); }
714 else if(!strcmp (attribute_names[i], "flags" )) { entry->flags = atoi(attribute_values[i]); }
715 else if(!strcmp (attribute_names[i], "payee" )) { entry->kpay = atoi(attribute_values[i]); }
716 else if(!strcmp (attribute_names[i], "category" )) { entry->kcat = atoi(attribute_values[i]); }
717 else if(!strcmp (attribute_names[i], "wording" )) { if(strcmp(attribute_values[i],"(null)") && attribute_values[i] != NULL) entry->memo = g_strdup(attribute_values[i]); }
718 else if(!strcmp (attribute_names[i], "info" )) { if(strcmp(attribute_values[i],"(null)") && attribute_values[i] != NULL) entry->info = g_strdup(attribute_values[i]); }
719 else if(!strcmp (attribute_names[i], "tags" ))
720 {
721 if(attribute_values[i] != NULL && strlen(attribute_values[i]) > 0 && strcmp(attribute_values[i],"(null)") != 0 )
722 {
723 entry->tags = tags_parse(attribute_values[i]);
724 }
725 }
726 else if(!strcmp (attribute_names[i], "kxfer" )) { entry->kxfer = atoi(attribute_values[i]); }
727 else if(!strcmp (attribute_names[i], "scat" )) { scat = (gchar *)attribute_values[i]; split = TRUE; }
728 else if(!strcmp (attribute_names[i], "samt" )) { samt = (gchar *)attribute_values[i]; split = TRUE; }
729 else if(!strcmp (attribute_names[i], "smem" )) { smem = (gchar *)attribute_values[i]; split = TRUE; }
730 }
731
732 //bugfix 303886
733 //if(entry->kcat < 0)
734 // entry->kcat = 0;
735
736 if(split == TRUE)
737 {
738 entry->splits = da_split_new ();
739 if (da_splits_parse(entry->splits, scat, samt, smem) > 0)
740 {
741 entry->flags |= OF_SPLIT; //Flag that Splits are active
742 }
743 }
744
745 //all attribute loaded: append
746 // for perf reason we use prepend here, the list will be reversed later
747 da_transaction_prepend(entry);
748 }
749
750
751
752
753 static void
754 start_element_handler (GMarkupParseContext *context,
755 const gchar *element_name,
756 const gchar **attribute_names,
757 const gchar **attribute_values,
758 gpointer user_data,
759 GError **error)
760 {
761 ParseContext *ctx = user_data;
762 //GtkUIManager *self = ctx->self;
763
764 //DB( g_print("** start element: '%s'\n", element_name) );
765
766 switch(element_name[0])
767 {
768 case 'a':
769 {
770 if(!strcmp (element_name, "account")) //account
771 {
772 homebank_load_xml_acc(ctx, attribute_names, attribute_values);
773 }
774 else if(!strcmp (element_name, "asg")) //assign
775 {
776 homebank_load_xml_asg(ctx, attribute_names, attribute_values);
777 }
778 }
779 break;
780
781 case 'p':
782 {
783 if(!strcmp (element_name, "pay"))
784 {
785 homebank_load_xml_pay(ctx, attribute_names, attribute_values);
786 }
787 else if(!strcmp (element_name, "properties"))
788 {
789 homebank_load_xml_prop(ctx, attribute_names, attribute_values);
790 }
791 }
792 break;
793
794
795
796
797
798
799
800
801
802
803 case 'c':
804 {
805 if(!strcmp (element_name, "cat"))
806 {
807 homebank_load_xml_cat(ctx, attribute_names, attribute_values);
808 }
809 else if(!strcmp (element_name, "cur"))
810 {
811 homebank_load_xml_cur(ctx, attribute_names, attribute_values);
812 }
813 }
814 break;
815
816 //TODO: < 5.2 misstyped here, should be tag without a s
817 //commented > 5.2 useless not loaded, but no side effect
818 /*case 't':
819 {
820 if(!strcmp (element_name, "tags"))
821 {
822 homebank_load_xml_tag(ctx, attribute_names, attribute_values);
823 }
824 }
825 break;*/
826
827 case 'f':
828 {
829 if(!strcmp (element_name, "fav"))
830 {
831 homebank_load_xml_fav(ctx, attribute_names, attribute_values);
832 }
833 }
834 break;
835
836 case 'o':
837 {
838 if(!strcmp (element_name, "ope"))
839 {
840 homebank_load_xml_ope(ctx, attribute_names, attribute_values);
841 }
842 }
843 break;
844 }
845 }
846
847
848 /*
849 static void
850 end_element_handler (GMarkupParseContext *context,
851 const gchar *element_name,
852 gpointer user_data,
853 GError **error)
854 {
855 ParseContext *ctx = user_data;
856
857 //DB( g_print("-- end element: %s\n", element_name) );
858
859
860 }
861 */
862
863 static GMarkupParser hb_parser = {
864 start_element_handler,
865 NULL, //end_element_handler,
866 NULL, //text_handler,
867 NULL,
868 NULL //cleanup
869 };
870
871
872 static gboolean hb_xml_get_version(ParseContext *ctx, gchar *buffer)
873 {
874 gchar *v_buffer;
875
876 ctx->file_version = 0.0;
877 ctx->data_version = 0;
878
879 /* v3.4 add :: prevent load of future file version */
880 v_buffer = g_strstr_len(buffer, 50, "<homebank v=");
881 if( v_buffer == NULL )
882 return FALSE;
883
884 DB( g_print("- id line: --(%.50s)\n\n", v_buffer) );
885
886 ctx->file_version = g_ascii_strtod(v_buffer+13, NULL); /* a little hacky, but works ! */
887 if( ctx->file_version == 0.0 )
888 ctx->file_version = 0.1;
889 else if( ctx->file_version == 5.0 ) //was a mistake
890 ctx->file_version = 1.0;
891
892 v_buffer = g_strstr_len(buffer+13, 50, "d=");
893 if( v_buffer )
894 {
895 DB( g_print(" d=%s)\n\n", v_buffer) );
896
897 ctx->data_version = atoi(v_buffer+3);
898 }
899 return TRUE;
900 }
901
902
903 /*
904 ** XML load homebank file: hbfile
905 */
906 gint homebank_load_xml(gchar *filename)
907 {
908 gint retval;
909 gchar *buffer;
910 gsize length;
911 GError *error = NULL;
912 ParseContext ctx;
913 GMarkupParseContext *context;
914 gboolean rc;
915
916 DB( g_print("\n[hb-xml] homebank_load_xml\n") );
917
918 GValue filename_val = G_VALUE_INIT;
919 ext_hook("load_file", EXT_STRING(&filename_val, filename), NULL);
920
921 retval = XML_OK;
922 if (!g_file_get_contents (filename, &buffer, &length, &error))
923 {
924 if(error)
925 {
926 g_warning("unable to load file %s: %s", filename, error->message);
927 g_error_free(error);
928 retval = XML_IO_ERROR;
929 }
930 }
931 else
932 {
933 if( hb_xml_get_version(&ctx, buffer) == FALSE )
934 {
935 return XML_FILE_ERROR;
936 }
937
938 if( ctx.file_version > FILE_VERSION )
939 {
940 DB( g_print("- failed: version %f is not supported (max is %f)\n", ctx.file_version, FILE_VERSION) );
941 return XML_VERSION_ERROR;
942 }
943 else
944 {
945 DB( g_print("- file ok : v=%.1f data_v=%06d\n", ctx.file_version, ctx.data_version) );
946
947 /* 1st: validate the file is well in utf-8 */
948 DB( g_print("- ensure UTF-8\n") );
949 buffer = homebank_utf8_ensure(buffer);
950
951 /* then process the buffer */
952 #if MYDEBUG == 1
953 GTimer *t = g_timer_new();
954 g_print("- start parse\n");
955 #endif
956
957 context = g_markup_parse_context_new (&hb_parser, 0, &ctx, NULL);
958
959 error = NULL;
960 rc = g_markup_parse_context_parse (context, buffer, length, &error);
961
962 if( error )
963 {
964 g_print("failed: %s\n", error->message);
965 g_error_free (error);
966 }
967
968
969 if( rc == FALSE )
970 {
971 error = NULL;
972 g_markup_parse_context_end_parse(context, &error);
973
974 if( error )
975 {
976 g_print("failed: %s\n", error->message);
977 g_error_free (error);
978 }
979 }
980
981 g_markup_parse_context_free (context);
982 g_free (buffer);
983
984 DB( g_print("- end parse : %f sec\n", g_timer_elapsed(t, NULL)) );
985 DB( g_timer_destroy (t) );
986
987 /* file upgrade / bugfix */
988 // group a test for very old version
989 if( ctx.file_version <= 1.0 )
990 {
991 if( ctx.file_version <= 0.1 )
992 homebank_upgrade_to_v02();
993 if( ctx.file_version <= 0.2 )
994 homebank_upgrade_to_v03();
995 if( ctx.file_version <= 0.3 )
996 homebank_upgrade_to_v04();
997 if( ctx.file_version <= 0.4 )
998 homebank_upgrade_to_v05();
999 if( ctx.file_version <= 0.5 )
1000 {
1001 homebank_upgrade_to_v06();
1002 homebank_upgrade_lower_v06();
1003 }
1004 if( ctx.file_version <= 0.6 )
1005 {
1006 homebank_upgrade_to_v07();
1007 hbfile_sanity_check();
1008 }
1009 if( ctx.file_version <= 0.7 ) // <= 4.5
1010 {
1011 homebank_upgrade_to_v08();
1012 }
1013 if( ctx.file_version <= 0.8 ) // <= 4.6
1014 {
1015 hbfile_sanity_check();
1016 }
1017 if( ctx.file_version <= 0.9 ) // <= 4.6.3
1018 {
1019 hbfile_sanity_check();
1020 homebank_upgrade_to_v10();
1021 }
1022 if( ctx.file_version <= 1.0 ) // <= 5.0.0
1023 {
1024 hbfile_sanity_check();
1025 homebank_upgrade_to_v11();
1026 }
1027 }
1028
1029 //starting 5.0.4 data upgrade is done without changing file_version
1030 //file version is changed only when the structure change
1031 //don't start number below with 0 to avoid octal interpretation
1032 if( ctx.data_version <= 50005 ) // <= 5.0.5
1033 {
1034 hbfile_sanity_check();
1035 }
1036 if( ctx.file_version <= 1.1 ) // <= 5.1.0
1037 {
1038 hbfile_sanity_check();
1039 homebank_upgrade_to_v12();
1040 }
1041 if( ctx.data_version <= 50106 ) // < 5.1.6
1042 {
1043 homebank_upgrade_to_v12_7();
1044 }
1045 if( ctx.file_version < 1.3 ) // <= 5.2
1046 {
1047 hbfile_sanity_check();
1048 homebank_upgrade_to_v13();
1049 }
1050 if( ctx.data_version <= 50203 )
1051 {
1052 hbfile_sanity_check();
1053 }
1054
1055 // next ?
1056
1057 }
1058 }
1059
1060 return retval;
1061 }
1062
1063
1064 /* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */
1065
1066 /*
1067 ** misc xml attributes methods
1068 */
1069 static void hb_xml_append_txt(GString *gstring, gchar *attrname, gchar *value)
1070 {
1071 if(value != NULL && *value != 0)
1072 {
1073 gchar *escaped = g_markup_escape_text(value, -1);
1074 g_string_append_printf(gstring, " %s=\"%s\"", attrname, escaped);
1075 g_free(escaped);
1076 }
1077 }
1078
1079 static void
1080 append_escaped_text (GString *str,
1081 const gchar *text,
1082 gssize length)
1083 {
1084 const gchar *p;
1085 const gchar *end;
1086 gunichar c;
1087
1088 p = text;
1089 end = text + length;
1090
1091 while (p < end)
1092 {
1093 const gchar *next;
1094 next = g_utf8_next_char (p);
1095
1096 switch (*p)
1097 {
1098 case '&':
1099 g_string_append (str, "&amp;");
1100 break;
1101
1102 case '<':
1103 g_string_append (str, "&lt;");
1104 break;
1105
1106 case '>':
1107 g_string_append (str, "&gt;");
1108 break;
1109
1110 case '\'':
1111 g_string_append (str, "&apos;");
1112 break;
1113
1114 case '"':
1115 g_string_append (str, "&quot;");
1116 break;
1117
1118 default:
1119 c = g_utf8_get_char (p);
1120 if ((0x1 <= c && c <= 0x8) ||
1121 (0xa <= c && c <= 0xd) || //chnaged here from b<->c to a<->d
1122 (0xe <= c && c <= 0x1f) ||
1123 (0x7f <= c && c <= 0x84) ||
1124 (0x86 <= c && c <= 0x9f))
1125 g_string_append_printf (str, "&#x%x;", c);
1126 else
1127 g_string_append_len (str, p, next - p);
1128 break;
1129 }
1130
1131 p = next;
1132 }
1133 }
1134
1135 // we override g_markup_escape_text from glib to encode \n (LF) & \r (CR)
1136 static void hb_xml_append_txt_crlf(GString *gstring, gchar *attrname, gchar *value)
1137 {
1138 if(value != NULL && *value != 0)
1139 {
1140 gssize length;
1141 GString *escaped;
1142
1143 //gchar *escaped = g_markup_escape_text(value, -1);
1144 length = strlen (value);
1145 escaped = g_string_sized_new (length);
1146 append_escaped_text (escaped, value, length);
1147 g_string_append_printf(gstring, " %s=\"%s\"", attrname, escaped->str);
1148 g_string_free (escaped, TRUE);
1149 }
1150 }
1151
1152 static void hb_xml_append_int0(GString *gstring, gchar *attrname, guint32 value)
1153 {
1154 g_string_append_printf(gstring, " %s=\"%d\"", attrname, value);
1155 }
1156
1157 static void hb_xml_append_int(GString *gstring, gchar *attrname, guint32 value)
1158 {
1159 if(value != 0)
1160 {
1161 hb_xml_append_int0(gstring, attrname, value);
1162 }
1163 }
1164
1165 static void hb_xml_append_amt(GString *gstring, gchar *attrname, gdouble amount)
1166 {
1167 char buf[G_ASCII_DTOSTR_BUF_SIZE];
1168
1169 //we must use this, as fprintf use locale decimal settings and not '.'
1170 g_ascii_dtostr (buf, sizeof (buf), amount);
1171 g_string_append_printf(gstring, " %s=\"%s\"", attrname, buf);
1172 }
1173
1174
1175 /* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */
1176
1177
1178 /*
1179 ** XML properties save
1180 */
1181 static gint homebank_save_xml_prop(GIOChannel *io)
1182 {
1183 gchar *title;
1184 GString *node;
1185 gint retval = XML_OK;
1186 GError *error = NULL;
1187
1188 title = GLOBALS->owner == NULL ? "" : GLOBALS->owner;
1189
1190 node = g_string_sized_new(255);
1191
1192 g_string_assign(node, "<properties");
1193
1194 hb_xml_append_txt(node, "title", title);
1195 hb_xml_append_int(node, "curr", GLOBALS->kcur);
1196 hb_xml_append_int(node, "car_category", GLOBALS->vehicle_category);
1197 hb_xml_append_int0(node, "auto_smode", GLOBALS->auto_smode);
1198 hb_xml_append_int(node, "auto_weekday", GLOBALS->auto_weekday);
1199 hb_xml_append_int(node, "auto_nbdays", GLOBALS->auto_nbdays);
1200
1201 g_string_append(node, "/>\n");
1202
1203 error = NULL;
1204 g_io_channel_write_chars(io, node->str, -1, NULL, &error);
1205 if(error)
1206 {
1207 retval = XML_IO_ERROR;
1208 g_error_free(error);
1209 }
1210
1211 g_string_free(node, TRUE);
1212 return retval;
1213 }
1214
1215
1216 /*
1217 ** XML currency save
1218 */
1219 static gint homebank_save_xml_cur(GIOChannel *io)
1220 {
1221 GList *list;
1222 gchar *tmpstr;
1223 char buf1[G_ASCII_DTOSTR_BUF_SIZE];
1224 gint retval = XML_OK;
1225
1226 list = g_hash_table_get_values(GLOBALS->h_cur);
1227 while (list != NULL)
1228 {
1229 Currency *item = list->data;
1230
1231 tmpstr = g_markup_printf_escaped(
1232 "<cur key=\"%d\" flags=\"%d\" iso=\"%s\" name=\"%s\" symb=\"%s\" syprf=\"%d\" dchar=\"%s\" gchar=\"%s\" frac=\"%d\" rate=\"%s\" mdate=\"%d\"/>\n",
1233 item->key,
1234 item->flags,
1235 item->iso_code,
1236 item->name,
1237 item->symbol,
1238 item->sym_prefix,
1239 item->decimal_char,
1240 item->grouping_char,
1241 item->frac_digits,
1242 g_ascii_dtostr (buf1, sizeof (buf1), item->rate),
1243 item->mdate
1244 );
1245
1246 g_io_channel_write_chars(io, tmpstr, -1, NULL, NULL);
1247 g_free(tmpstr);
1248
1249 list = g_list_next(list);
1250 }
1251 g_list_free(list);
1252 return retval;
1253 }
1254
1255
1256 /*
1257 ** XML account save
1258 */
1259 static gint homebank_save_xml_acc(GIOChannel *io)
1260 {
1261 GList *lacc, *list;
1262 GString *node;
1263 gint retval = XML_OK;
1264 GError *error = NULL;
1265
1266 node = g_string_sized_new(255);
1267
1268 lacc = list = account_glist_sorted(0);
1269 while (list != NULL)
1270 {
1271 Account *item = list->data;
1272
1273 item->flags &= ~(AF_ADDED|AF_CHANGED); //delete flag
1274
1275 g_string_assign(node, "<account");
1276
1277 hb_xml_append_int(node, "key", item->key);
1278 hb_xml_append_int(node, "flags", item->flags);
1279 hb_xml_append_int(node, "pos", item->pos);
1280 hb_xml_append_int(node, "type", item->type);
1281 hb_xml_append_int(node, "curr", item->kcur);
1282 hb_xml_append_txt(node, "name", item->name);
1283 hb_xml_append_txt(node, "number", item->number);
1284 hb_xml_append_txt(node, "bankname", item->bankname);
1285 hb_xml_append_amt(node, "initial", item->initial);
1286
1287 hb_xml_append_amt(node, "minimum", item->minimum);
1288 hb_xml_append_int(node, "cheque1", item->cheque1);
1289 hb_xml_append_int(node, "cheque2", item->cheque2);
1290 hb_xml_append_txt_crlf(node, "notes", item->notes);
1291 hb_xml_append_int(node, "tpl", item->karc);
1292
1293
1294 g_string_append(node, "/>\n");
1295
1296 error = NULL;
1297 g_io_channel_write_chars(io, node->str, -1, NULL, &error);
1298
1299 if(error)
1300 {
1301 retval = XML_IO_ERROR;
1302 g_error_free(error);
1303 }
1304
1305 list = g_list_next(list);
1306 }
1307 g_list_free(lacc);
1308 g_string_free(node, TRUE);
1309 return retval;
1310 }
1311
1312 /*
1313 ** XML payee save
1314 */
1315 static gint homebank_save_xml_pay(GIOChannel *io)
1316 {
1317 GList *lpay, *list;
1318 GString *node;
1319 gint retval = XML_OK;
1320 GError *error = NULL;
1321
1322 node = g_string_sized_new(255);
1323
1324 lpay = list = payee_glist_sorted(0);
1325 while (list != NULL)
1326 {
1327 Payee *item = list->data;
1328
1329 if(item->key != 0)
1330 {
1331 g_string_assign(node, "<pay");
1332
1333 hb_xml_append_int(node, "key", item->key);
1334 hb_xml_append_txt(node, "name", item->name);
1335 hb_xml_append_int(node, "category", item->kcat);
1336 hb_xml_append_int(node, "paymode" , item->paymode);
1337
1338 g_string_append(node, "/>\n");
1339
1340 error = NULL;
1341 g_io_channel_write_chars(io, node->str, -1, NULL, &error);
1342
1343 if(error)
1344 {
1345 retval = XML_IO_ERROR;
1346 g_error_free(error);
1347 }
1348
1349 }
1350 list = g_list_next(list);
1351 }
1352 g_list_free(lpay);
1353 g_string_free(node, TRUE);
1354 return retval;
1355 }
1356
1357 /*
1358 ** XML category save
1359 */
1360 static gint homebank_save_xml_cat(GIOChannel *io)
1361 {
1362 GList *lcat, *list;
1363 GString *node;
1364 char buf[G_ASCII_DTOSTR_BUF_SIZE];
1365 guint i;
1366 gint retval = XML_OK;
1367 GError *error = NULL;
1368
1369 node = g_string_sized_new(255);
1370
1371 lcat = list = category_glist_sorted(0);
1372 while (list != NULL)
1373 {
1374 Category *item = list->data;
1375
1376 if(item->key != 0)
1377 {
1378 g_string_assign(node, "<cat");
1379
1380 hb_xml_append_int(node, "key", item->key);
1381 hb_xml_append_int(node, "parent", item->parent);
1382 hb_xml_append_int(node, "flags", item->flags);
1383 hb_xml_append_txt(node, "name", item->name);
1384
1385 for(i=0;i<=12;i++)
1386 {
1387 if(item->budget[i] != 0)
1388 {
1389 g_string_append_printf(node," b%d=\"%s\"", i, g_ascii_dtostr (buf, sizeof (buf), item->budget[i]));
1390 }
1391 }
1392
1393 g_string_append(node, "/>\n");
1394
1395 error = NULL;
1396 g_io_channel_write_chars(io, node->str, -1, NULL, &error);
1397
1398 if(error)
1399 {
1400 retval = XML_IO_ERROR;
1401 g_error_free(error);
1402 }
1403
1404 }
1405 list = g_list_next(list);
1406 }
1407 g_list_free(lcat);
1408 g_string_free(node, TRUE);
1409 return retval;
1410 }
1411
1412 /*
1413 ** XML tag save
1414 */
1415 /*static gint homebank_save_xml_tag(GIOChannel *io)
1416 {
1417 GList *ltag, *list;
1418 gchar *tmpstr;
1419 gint retval = XML_OK;
1420 GError *error = NULL;
1421
1422 ltag = list = tag_glist_sorted(0);
1423 while (list != NULL)
1424 {
1425 Tag *item = list->data;
1426
1427 if(item->key != 0)
1428 {
1429 tmpstr = g_markup_printf_escaped("<tag key=\"%d\" name=\"%s\"/>\n",
1430 item->key,
1431 item->name
1432 );
1433
1434 error = NULL;
1435 g_io_channel_write_chars(io, tmpstr, -1, NULL, &error);
1436 g_free(tmpstr);
1437
1438 if(error)
1439 {
1440 retval = XML_IO_ERROR;
1441 g_error_free(error);
1442 }
1443 }
1444 list = g_list_next(list);
1445 }
1446 g_list_free(ltag);
1447 return retval;
1448 }*/
1449
1450
1451 /*
1452 ** XML assign save
1453 */
1454 static gint homebank_save_xml_asg(GIOChannel *io)
1455 {
1456 GList *lasg, *list;
1457 GString *node;
1458 gint retval = XML_OK;
1459 GError *error = NULL;
1460
1461 node = g_string_sized_new(255);
1462
1463 lasg = list = assign_glist_sorted(0);
1464 while (list != NULL)
1465 {
1466 Assign *item = list->data;
1467
1468 g_string_assign(node, "<asg");
1469
1470 hb_xml_append_int(node, "key" , item->key);
1471 hb_xml_append_int(node, "flags" , item->flags);
1472 hb_xml_append_int(node, "field" , item->field);
1473 hb_xml_append_txt(node, "name" , item->text);
1474 hb_xml_append_int(node, "payee" , item->kpay);
1475 hb_xml_append_int(node, "category", item->kcat);
1476 hb_xml_append_int(node, "paymode" , item->paymode);
1477
1478 g_string_append(node, "/>\n");
1479
1480 error = NULL;
1481 g_io_channel_write_chars(io, node->str, -1, NULL, &error);
1482
1483 if(error)
1484 {
1485 retval = XML_IO_ERROR;
1486 g_error_free(error);
1487 }
1488
1489 list = g_list_next(list);
1490 }
1491 g_list_free(lasg);
1492 g_string_free(node, TRUE);
1493 return retval;
1494 }
1495
1496
1497
1498 /*
1499 ** XML archive save
1500 */
1501 static gint homebank_save_xml_arc(GIOChannel *io)
1502 {
1503 GList *list;
1504 GString *node;
1505 gchar *tagstr;
1506 gint retval = XML_OK;
1507 GError *error = NULL;
1508
1509 node = g_string_sized_new(255);
1510
1511 list = g_list_first(GLOBALS->arc_list);
1512 while (list != NULL)
1513 {
1514 Archive *item = list->data;
1515
1516 tagstr = tags_tostring(item->tags);
1517
1518 g_string_assign(node, "<fav");
1519
1520 hb_xml_append_int(node, "key", item->key);
1521 hb_xml_append_amt(node, "amount", item->amount);
1522 hb_xml_append_int(node, "account", item->kacc);
1523 hb_xml_append_int(node, "dst_account", item->kxferacc);
1524 hb_xml_append_int(node, "paymode", item->paymode);
1525 hb_xml_append_int(node, "st", item->status);
1526 hb_xml_append_int(node, "flags", item->flags);
1527 hb_xml_append_int(node, "payee", item->kpay);
1528 hb_xml_append_int(node, "category", item->kcat);
1529 hb_xml_append_txt(node, "wording", item->memo);
1530 hb_xml_append_txt(node, "tags", tagstr);
1531 hb_xml_append_int(node, "nextdate", item->nextdate);
1532 hb_xml_append_int(node, "every", item->every);
1533 hb_xml_append_int(node, "unit", item->unit);
1534 hb_xml_append_int(node, "limit", item->limit);
1535 hb_xml_append_int(node, "weekend", item->weekend);
1536 hb_xml_append_int(node, "gap", item->daygap);
1537
1538 if(da_splits_length(item->splits) > 0)
1539 {
1540 gchar *cats, *amounts, *memos;
1541
1542 da_splits_tostring(item->splits, &cats, &amounts, &memos);
1543 g_string_append_printf(node, " scat=\"%s\"", cats);
1544 g_string_append_printf(node, " samt=\"%s\"", amounts);
1545
1546 //fix #1173910
1547 gchar *escaped = g_markup_escape_text(memos, -1);
1548 g_string_append_printf(node, " smem=\"%s\"", escaped);
1549 g_free(escaped);
1550
1551 g_free(cats);
1552 g_free(amounts);
1553 g_free(memos);
1554 }
1555
1556 g_string_append(node, "/>\n");
1557
1558 g_free(tagstr);
1559
1560 error = NULL;
1561 g_io_channel_write_chars(io, node->str, -1, NULL, &error);
1562 if(error)
1563 {
1564 retval = XML_IO_ERROR;
1565 g_error_free(error);
1566 }
1567
1568 list = g_list_next(list);
1569 }
1570 g_string_free(node, TRUE);
1571 return retval;
1572 }
1573
1574
1575 /*
1576 ** XML transaction save
1577 */
1578 static gint homebank_save_xml_ope(GIOChannel *io)
1579 {
1580 GList *lst_acc, *lnk_acc;
1581 GList *list;
1582 GString *node;
1583 gchar *tagstr;
1584 gint retval = XML_OK;
1585 GError *error = NULL;
1586
1587 node = g_string_sized_new(255);
1588
1589 lst_acc = g_hash_table_get_values(GLOBALS->h_acc);
1590 lnk_acc = g_list_first(lst_acc);
1591 while (lnk_acc != NULL)
1592 {
1593 Account *acc = lnk_acc->data;
1594
1595 list = g_queue_peek_head_link(acc->txn_queue);
1596 while (list != NULL)
1597 {
1598 Transaction *item = list->data;
1599
1600 item->flags &= ~(OF_AUTO|OF_ADDED|OF_CHANGED); //delete flag
1601 tagstr = tags_tostring(item->tags);
1602
1603 g_string_assign(node, "<ope");
1604
1605 hb_xml_append_int(node, "date", item->date);
1606 hb_xml_append_amt(node, "amount", item->amount);
1607 hb_xml_append_int(node, "account", item->kacc);
1608 hb_xml_append_int(node, "dst_account", item->kxferacc);
1609 hb_xml_append_int(node, "paymode", item->paymode);
1610 hb_xml_append_int(node, "st", item->status);
1611 hb_xml_append_int(node, "flags", item->flags);
1612 hb_xml_append_int(node, "payee", item->kpay);
1613 hb_xml_append_int(node, "category", item->kcat);
1614 hb_xml_append_txt(node, "wording", item->memo);
1615 hb_xml_append_txt(node, "info", item->info);
1616 hb_xml_append_txt(node, "tags", tagstr);
1617 hb_xml_append_int(node, "kxfer", item->kxfer);
1618
1619 if(da_splits_length(item->splits) > 0)
1620 {
1621 gchar *cats, *amounts, *memos;
1622
1623 da_splits_tostring(item->splits, &cats, &amounts, &memos);
1624 g_string_append_printf(node, " scat=\"%s\"", cats);
1625 g_string_append_printf(node, " samt=\"%s\"", amounts);
1626
1627 //fix #1173910
1628 gchar *escaped = g_markup_escape_text(memos, -1);
1629 g_string_append_printf(node, " smem=\"%s\"", escaped);
1630 g_free(escaped);
1631
1632 g_free(cats);
1633 g_free(amounts);
1634 g_free(memos);
1635 }
1636
1637 g_string_append(node, "/>\n");
1638
1639 g_free(tagstr);
1640
1641 error = NULL;
1642 g_io_channel_write_chars(io, node->str, -1, NULL, &error);
1643
1644 if(error)
1645 {
1646 retval = XML_IO_ERROR;
1647 g_error_free(error);
1648 }
1649
1650 list = g_list_next(list);
1651 }
1652
1653 lnk_acc = g_list_next(lnk_acc);
1654 }
1655 g_list_free(lst_acc);
1656
1657 g_string_free(node, TRUE);
1658 return retval;
1659 }
1660
1661 /*
1662 ** XML save homebank file: hbfile
1663 */
1664 gint homebank_save_xml(gchar *filename)
1665 {
1666 GIOChannel *io;
1667 char buf1[G_ASCII_DTOSTR_BUF_SIZE];
1668 gchar *outstr;
1669 gint retval = XML_OK;
1670 GError *error = NULL;
1671
1672 GValue filename_val = G_VALUE_INIT;
1673 ext_hook("save_file", EXT_STRING(&filename_val, filename), NULL);
1674
1675 io = g_io_channel_new_file(filename, "w", &error);
1676 if(error)
1677 {
1678 g_warning("unable to save file %s: %s", filename, error->message);
1679 g_error_free(error);
1680 return(XML_IO_ERROR);
1681 }
1682
1683 g_io_channel_write_chars(io, "<?xml version=\"1.0\"?>\n", -1, NULL, NULL);
1684
1685 outstr = g_strdup_printf("<homebank v=\"%s\" d=\"%06d\">\n", g_ascii_dtostr (buf1, sizeof (buf1), FILE_VERSION), HB_VERSION_NUM);
1686 g_io_channel_write_chars(io, outstr, -1, NULL, NULL);
1687 g_free(outstr);
1688
1689 retval = homebank_save_xml_prop(io);
1690 retval = homebank_save_xml_cur(io);
1691 retval = homebank_save_xml_acc(io);
1692 retval = homebank_save_xml_pay(io);
1693 retval = homebank_save_xml_cat(io);
1694 //retval = homebank_save_xml_tag(io);
1695 retval = homebank_save_xml_asg(io);
1696 retval = homebank_save_xml_arc(io);
1697
1698 retval = homebank_save_xml_ope(io);
1699
1700 g_io_channel_write_chars(io, "</homebank>\n", -1, NULL, NULL);
1701
1702 g_io_channel_unref (io);
1703
1704 return retval;
1705 }
1706
This page took 0.119123 seconds and 4 git commands to generate.