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