1 /* HomeBank -- Free, easy, personal accounting for everyone.
2 * Copyright (C) 1995-2021 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
homebank_upgrade_to_v02(void)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
homebank_upgrade_to_v03(void)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
homebank_upgrade_to_v04(void)133 static void homebank_upgrade_to_v04(void)
134 {
135 DB( g_print("\n[hb-xml] homebank_upgrade_to_v04\n") );
136
137 da_archive_glist_sorted(1);
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
homebank_upgrade_to_v05(void)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
homebank_upgrade_to_v06(void)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
homebank_upgrade_to_v07(void)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
homebank_upgrade_to_v08(void)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
homebank_upgrade_to_v10(void)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 & OLDF_VALID)
273 entry->status = TXN_STATUS_RECONCILED;
274 else
275 if(entry->flags & OLDF_REMIND)
276 entry->status = TXN_STATUS_REMIND;
277
278 //remove those flags
279 entry->flags &= ~(OLDF_VALID|OLDF_REMIND);
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
homebank_upgrade_to_v11(void)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 & OLDF_VALID)
303 entry->status = TXN_STATUS_RECONCILED;
304 else
305 if(entry->flags & OLDF_REMIND)
306 entry->status = TXN_STATUS_REMIND;
307
308 //remove those flags
309 entry->flags &= ~(OLDF_VALID|OLDF_REMIND);
310
311 list = g_list_next(list);
312 }
313
314 }
315
316
317 // v0.6 to v0.7 : assign a default currency
homebank_upgrade_to_v12(void)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
homebank_upgrade_to_v12_7(void)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
homebank_upgrade_to_v13(void)358 static void homebank_upgrade_to_v13(void)
359 {
360 GList *list;
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 list = g_list_first(GLOBALS->arc_list);
368 while (list != NULL)
369 {
370 Archive *item = list->data;
371
372 item->key = newkey++;
373 list = g_list_next(list);
374 }
375
376 }
377
378
homebank_upgrade_to_v14(void)379 static void homebank_upgrade_to_v14(void)
380 {
381 GList *lst_acc, *lnk_acc, *lasg;
382 GList *list;
383
384 DB( g_print("\n[hb-xml] homebank_upgrade_to_v14\n") );
385
386 //internal xfer no more a payment => goto a flags
387 //update every txn/arc
388 lst_acc = g_hash_table_get_values(GLOBALS->h_acc);
389 lnk_acc = g_list_first(lst_acc);
390 while (lnk_acc != NULL)
391 {
392 Account *acc = lnk_acc->data;
393
394 list = g_queue_peek_head_link(acc->txn_queue);
395 while (list != NULL)
396 {
397 Transaction *item = list->data;
398
399 if( item->paymode == OLDPAYMODE_INTXFER )
400 {
401 item->flags |= OF_INTXFER;
402 item->paymode = PAYMODE_NONE;
403 }
404 list = g_list_next(list);
405 }
406 lnk_acc = g_list_next(lnk_acc);
407 }
408 g_list_free(lst_acc);
409
410 list = g_list_first(GLOBALS->arc_list);
411 while (list != NULL)
412 {
413 Archive *item = list->data;
414
415 if( item->paymode == OLDPAYMODE_INTXFER )
416 {
417 item->flags |= OF_INTXFER;
418 item->paymode = PAYMODE_NONE;
419 }
420 list = g_list_next(list);
421 }
422
423 //assignment now have position+name, so initiate it
424 lasg = list = g_hash_table_get_values(GLOBALS->h_rul);
425 while (list != NULL)
426 {
427 Assign *item = list->data;
428
429 item->pos = item->key;
430 list = g_list_next(list);
431 }
432 g_list_free(lasg);
433
434 }
435
436
437
438 // lower v0.6 : we must assume categories/payee exists
439 // and strong link to xfer
440 // #632496
homebank_upgrade_lower_v06(void)441 static void homebank_upgrade_lower_v06(void)
442 {
443 GList *lst_acc, *lnk_acc;
444 Category *cat;
445 Payee *pay;
446 GList *lrul, *list;
447
448 DB( g_print("\n[hb-xml] homebank_upgrade_lower_v06\n") );
449
450 lst_acc = g_hash_table_get_values(GLOBALS->h_acc);
451 lnk_acc = g_list_first(lst_acc);
452 while (lnk_acc != NULL)
453 {
454 Account *acc = lnk_acc->data;
455
456 list = g_queue_peek_head_link(acc->txn_queue);
457 while (list != NULL)
458 {
459 Transaction *entry = list->data;
460
461 //also strong link internal xfer
462 if(entry->paymode == OLDPAYMODE_INTXFER && entry->kxfer == 0)
463 {
464 Transaction *child = transaction_old_get_child_transfer(entry);
465 if(child != NULL)
466 {
467 transaction_xfer_change_to_child(entry, child);
468 }
469 }
470
471 da_transaction_consistency(entry);
472
473 list = g_list_next(list);
474 }
475 lnk_acc = g_list_next(lnk_acc);
476 }
477 g_list_free(lst_acc);
478
479
480 lrul = list = g_hash_table_get_values(GLOBALS->h_rul);
481 while (list != NULL)
482 {
483 Assign *entry = list->data;
484
485 cat = da_cat_get(entry->kcat);
486 if(cat == NULL)
487 {
488 DB( g_print(" !! fixing cat for rul: %d is unknown\n", entry->kcat) );
489 entry->kcat = 0;
490 }
491
492 pay = da_pay_get(entry->kpay);
493 if(pay == NULL)
494 {
495 DB( g_print(" !! fixing pay for rul: %d is unknown\n", entry->kpay) );
496 entry->kpay = 0;
497 }
498
499
500 list = g_list_next(list);
501 }
502 g_list_free(lrul);
503 }
504
505
506 /* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */
507
508
homebank_load_xml_acc(ParseContext * ctx,const gchar ** attribute_names,const gchar ** attribute_values)509 static void homebank_load_xml_acc(ParseContext *ctx, const gchar **attribute_names, const gchar **attribute_values)
510 {
511 Account *entry = da_acc_malloc();
512 gint i;
513
514 for (i = 0; attribute_names[i] != NULL; i++)
515 {
516 //DB( g_print(" att='%s' val='%s'\n", attribute_names[i], attribute_values[i]) );
517
518 if(!strcmp (attribute_names[i], "key" )) { entry->key = atoi(attribute_values[i]); }
519 else if(!strcmp (attribute_names[i], "flags" )) { entry->flags = atoi(attribute_values[i]); }
520 else if(!strcmp (attribute_names[i], "pos" )) { entry->pos = atoi(attribute_values[i]); }
521 else if(!strcmp (attribute_names[i], "type" )) { entry->type = atoi(attribute_values[i]); }
522 else if(!strcmp (attribute_names[i], "curr" )) { entry->kcur = atoi(attribute_values[i]); }
523 else if(!strcmp (attribute_names[i], "name" )) { if(strcmp(attribute_values[i],"(null)") && attribute_values[i] != NULL) entry->name = g_strdup(attribute_values[i]); }
524 else if(!strcmp (attribute_names[i], "number" )) { if(strcmp(attribute_values[i],"(null)") && attribute_values[i] != NULL) entry->number = g_strdup(attribute_values[i]); }
525 else if(!strcmp (attribute_names[i], "bankname")) { if(strcmp(attribute_values[i],"(null)") && attribute_values[i] != NULL) entry->bankname = g_strdup(attribute_values[i]); }
526 else if(!strcmp (attribute_names[i], "initial" )) { entry->initial = g_ascii_strtod(attribute_values[i], NULL); }
527
528 else if(!strcmp (attribute_names[i], "minimum" )) { entry->minimum = g_ascii_strtod(attribute_values[i], NULL); }
529 else if(!strcmp (attribute_names[i], "maximum" )) { entry->maximum = g_ascii_strtod(attribute_values[i], NULL); }
530 else if(!strcmp (attribute_names[i], "cheque1" )) { entry->cheque1 = atoi(attribute_values[i]); }
531 else if(!strcmp (attribute_names[i], "cheque2" )) { entry->cheque2 = atoi(attribute_values[i]); }
532 else if(!strcmp (attribute_names[i], "notes" )) { if(strcmp(attribute_values[i],"(null)") && attribute_values[i] != NULL) entry->notes = g_strdup(attribute_values[i]); }
533 else if(!strcmp (attribute_names[i], "tpl" )) { entry->karc = atoi(attribute_values[i]); }
534 else if(!strcmp (attribute_names[i], "grp" )) { entry->kgrp = atoi(attribute_values[i]); }
535 //5.5
536 else if(!strcmp (attribute_names[i], "ccday" )) { entry->cccday = atoi(attribute_values[i]); }
537 else if(!strcmp (attribute_names[i], "rdate" )) { entry->rdate = atoi(attribute_values[i]); }
538 }
539
540 //all attribute loaded: append
541 da_acc_insert(entry);
542 }
543
544
homebank_load_xml_asg(ParseContext * ctx,const gchar ** attribute_names,const gchar ** attribute_values)545 static void homebank_load_xml_asg(ParseContext *ctx, const gchar **attribute_names, const gchar **attribute_values)
546 {
547 Assign *entry = da_asg_malloc();
548 gint exact = 0;
549 gint i;
550
551 for (i = 0; attribute_names[i] != NULL; i++)
552 {
553 //DB( g_print(" att='%s' val='%s'\n", attribute_names[i], attribute_values[i]) );
554
555 if(!strcmp (attribute_names[i], "key" )) { entry->key = atoi(attribute_values[i]); }
556 else if(!strcmp (attribute_names[i], "flags" )) { entry->flags = atoi(attribute_values[i]); }
557 else if(!strcmp (attribute_names[i], "pos" )) { entry->pos = atoi(attribute_values[i]); }
558 else if(!strcmp (attribute_names[i], "field" )) { entry->field = atoi(attribute_values[i]); }
559 else if(!strcmp (attribute_names[i], "name" )) { if(strcmp(attribute_values[i],"(null)") && attribute_values[i] != NULL) entry->search = g_strdup(attribute_values[i]); }
560 else if(!strcmp (attribute_names[i], "notes" )) { if(strcmp(attribute_values[i],"(null)") && attribute_values[i] != NULL) entry->notes = g_strdup(attribute_values[i]); }
561 else if(!strcmp (attribute_names[i], "payee" )) { entry->kpay = atoi(attribute_values[i]); }
562 else if(!strcmp (attribute_names[i], "category")) { entry->kcat = atoi(attribute_values[i]); }
563 else if(!strcmp (attribute_names[i], "paymode" )) { entry->paymode = atoi(attribute_values[i]); }
564 // prior v08
565 else if(!strcmp (attribute_names[i], "exact" )) { exact = atoi(attribute_values[i]); }
566 }
567
568 /* in v08 exact moved to flag */
569 if( ctx->file_version <= 0.7)
570 {
571 entry->flags = (ASGF_DOCAT|ASGF_DOPAY);
572 if( exact > 0 )
573 entry->flags |= ASGF_EXACT;
574 }
575
576 //all attribute loaded: append
577 //#1892828 append change the pos...
578 //da_asg_append(entry);
579 da_asg_insert(entry);
580
581 }
582
583
homebank_load_xml_pay(ParseContext * ctx,const gchar ** attribute_names,const gchar ** attribute_values)584 static void homebank_load_xml_pay(ParseContext *ctx, const gchar **attribute_names, const gchar **attribute_values)
585 {
586 Payee *entry = da_pay_malloc();
587 gint i;
588
589 for (i = 0; attribute_names[i] != NULL; i++)
590 {
591 //DB( g_print(" att='%s' val='%s'\n", attribute_names[i], attribute_values[i]) );
592
593 if(!strcmp (attribute_names[i], "key" )) { entry->key = atoi(attribute_values[i]); }
594 //else if(!strcmp (attribute_names[i], "flags")) { entry->flags = atoi(attribute_values[i]); }
595 else if(!strcmp (attribute_names[i], "name" )) { entry->name = g_strdup(attribute_values[i]); }
596 else if(!strcmp (attribute_names[i], "category")) { entry->kcat = atoi(attribute_values[i]); }
597 else if(!strcmp (attribute_names[i], "paymode" )) { entry->paymode = atoi(attribute_values[i]); }
598 }
599
600 //all attribute loaded: append
601 da_pay_insert(entry);
602 }
603
604
homebank_load_xml_prop(ParseContext * ctx,const gchar ** attribute_names,const gchar ** attribute_values)605 static void homebank_load_xml_prop(ParseContext *ctx, const gchar **attribute_names, const gchar **attribute_values)
606 {
607 gint i;
608
609 for (i = 0; attribute_names[i] != NULL; i++)
610 {
611 if(!strcmp (attribute_names[i], "title" )) { g_free(GLOBALS->owner); GLOBALS->owner = g_strdup(attribute_values[i]); }
612 else if(!strcmp (attribute_names[i], "curr" )) { GLOBALS->kcur = atoi(attribute_values[i]); }
613 else if(!strcmp (attribute_names[i], "car_category")) { GLOBALS->vehicle_category = atoi(attribute_values[i]); }
614 else if(!strcmp (attribute_names[i], "auto_smode" )) { GLOBALS->auto_smode = atoi(attribute_values[i]); }
615 else if(!strcmp (attribute_names[i], "auto_weekday")) { GLOBALS->auto_weekday = atoi(attribute_values[i]); }
616 else if(!strcmp (attribute_names[i], "auto_nbdays" )) { GLOBALS->auto_nbdays = atoi(attribute_values[i]); }
617 }
618 }
619
620
homebank_load_xml_cat(ParseContext * ctx,const gchar ** attribute_names,const gchar ** attribute_values)621 static void homebank_load_xml_cat(ParseContext *ctx, const gchar **attribute_names, const gchar **attribute_values)
622 {
623 Category *entry = da_cat_malloc();
624 gboolean budget;
625 gint i, j;
626
627 for (i = 0; attribute_names[i] != NULL; i++)
628 {
629 //DB( g_print(" att='%s' val='%s'\n", attribute_names[i], attribute_values[i]) );
630
631 if(!strcmp (attribute_names[i], "key" )) { entry->key = atoi(attribute_values[i]); }
632 else if(!strcmp (attribute_names[i], "parent")) { entry->parent = atoi(attribute_values[i]); }
633 else if(!strcmp (attribute_names[i], "flags" )) { entry->flags = atoi(attribute_values[i]); }
634 else if(!strcmp (attribute_names[i], "name" )) { entry->name = g_strdup(attribute_values[i]); }
635
636 budget = FALSE;
637 for(j=0;j<=12;j++)
638 {
639 gchar *tmpname;
640
641 tmpname = g_strdup_printf ("b%d", j);
642 if(!(strcmp (attribute_names[i], tmpname))) { entry->budget[j] = g_ascii_strtod(attribute_values[i], NULL); }
643 g_free(tmpname);
644
645 if(entry->budget[j]) budget = TRUE;
646 }
647 if(budget == TRUE)
648 entry->flags |= GF_BUDGET;
649
650 }
651
652 //all attribute loaded: append
653 da_cat_insert( entry);
654 }
655
656
homebank_load_xml_cur(ParseContext * ctx,const gchar ** attribute_names,const gchar ** attribute_values)657 static void homebank_load_xml_cur(ParseContext *ctx, const gchar **attribute_names, const gchar **attribute_values)
658 {
659 Currency *entry = da_cur_malloc ();
660 gint i;
661
662 for (i = 0; attribute_names[i] != NULL; i++)
663 {
664 //DB( g_print(" att='%s' val='%s'\n", attribute_names[i], attribute_values[i]) );
665
666 if(!strcmp (attribute_names[i], "key" )) { entry->key = atoi(attribute_values[i]); }
667 else if(!strcmp (attribute_names[i], "flags" )) { entry->flags = atoi(attribute_values[i]); }
668 else if(!strcmp (attribute_names[i], "name" )) { entry->name = g_strdup(attribute_values[i]); }
669 else if(!strcmp (attribute_names[i], "iso" )) { entry->iso_code = g_strdup(attribute_values[i]); }
670 else if(!strcmp (attribute_names[i], "symb" )) { entry->symbol = g_strdup(attribute_values[i]); }
671 else if(!strcmp (attribute_names[i], "syprf" )) { entry->sym_prefix = atoi(attribute_values[i]); }
672 else if(!strcmp (attribute_names[i], "dchar" )) { entry->decimal_char = g_strdup(attribute_values[i]); }
673 else if(!strcmp (attribute_names[i], "gchar" )) { entry->grouping_char = g_strdup(attribute_values[i]); }
674 else if(!strcmp (attribute_names[i], "frac" )) { entry->frac_digits = atoi(attribute_values[i]); }
675 else if(!strcmp (attribute_names[i], "rate" )) { entry->rate = g_ascii_strtod(attribute_values[i], NULL); }
676 else if(!strcmp (attribute_names[i], "mdate ")) { entry->mdate = atoi(attribute_values[i]); }
677
678 }
679
680 //all attribute loaded: append
681 da_cur_insert (entry);
682 }
683
684
homebank_load_xml_grp(ParseContext * ctx,const gchar ** attribute_names,const gchar ** attribute_values)685 static void homebank_load_xml_grp(ParseContext *ctx, const gchar **attribute_names, const gchar **attribute_values)
686 {
687 Group *entry = da_grp_malloc();
688 gint i;
689
690 for (i = 0; attribute_names[i] != NULL; i++)
691 {
692 DB( g_print(" att='%s' val='%s'\n", attribute_names[i], attribute_values[i]) );
693
694 if(!strcmp (attribute_names[i], "key" )) { entry->key = atoi(attribute_values[i]); }
695 //else if(!strcmp (attribute_names[i], "type")) { entry->type = atoi(attribute_values[i]); }
696 //else if(!strcmp (attribute_names[i], "flags")) { entry->flags = atoi(attribute_values[i]); }
697 else if(!strcmp (attribute_names[i], "name" )) { entry->name = g_strdup(attribute_values[i]); }
698 }
699
700 //all attribute loaded: append
701 da_grp_insert(entry);
702 }
703
704
705 /*static void homebank_load_xml_tag(ParseContext *ctx, const gchar **attribute_names, const gchar **attribute_values)
706 {
707 Tag *entry = da_tag_malloc();
708 gint i;
709
710 for (i = 0; attribute_names[i] != NULL; i++)
711 {
712 //DB( g_print(" att='%s' val='%s'\n", attribute_names[i], attribute_values[i]) );
713
714 if(!strcmp (attribute_names[i], "key" )) { entry->key = atoi(attribute_values[i]); }
715 //else if(!strcmp (attribute_names[i], "flags")) { entry->flags = atoi(attribute_values[i]); }
716 else if(!strcmp (attribute_names[i], "name" )) { entry->name = g_strdup(attribute_values[i]); }
717 }
718
719 //all attribute loaded: append
720 da_tag_insert(entry);
721 }*/
722
723
homebank_load_xml_fav(ParseContext * ctx,const gchar ** attribute_names,const gchar ** attribute_values)724 static void homebank_load_xml_fav(ParseContext *ctx, const gchar **attribute_names, const gchar **attribute_values)
725 {
726 Archive *entry = da_archive_malloc();
727 gchar *scat = NULL;
728 gchar *samt = NULL;
729 gchar *smem = NULL;
730 gboolean split = FALSE;
731 gint i;
732
733 for (i = 0; attribute_names[i] != NULL; i++)
734 {
735 //DB( g_print(" att='%s' val='%s'\n", attribute_names[i], attribute_values[i]) );
736
737 if(!strcmp (attribute_names[i], "key" )) { entry->key = atoi(attribute_values[i]); }
738 else if(!strcmp (attribute_names[i], "amount" )) { entry->amount = g_ascii_strtod(attribute_values[i], NULL); }
739 else if(!strcmp (attribute_names[i], "account" )) { entry->kacc = atoi(attribute_values[i]); }
740 else if(!strcmp (attribute_names[i], "dst_account")) { entry->kxferacc = atoi(attribute_values[i]); }
741 else if(!strcmp (attribute_names[i], "paymode" )) { entry->paymode = atoi(attribute_values[i]); }
742 else if(!strcmp (attribute_names[i], "st" )) { entry->status = atoi(attribute_values[i]); }
743 else if(!strcmp (attribute_names[i], "flags" )) { entry->flags = atoi(attribute_values[i]); }
744 else if(!strcmp (attribute_names[i], "payee" )) { entry->kpay = atoi(attribute_values[i]); }
745 else if(!strcmp (attribute_names[i], "category" )) { entry->kcat = atoi(attribute_values[i]); }
746 else if(!strcmp (attribute_names[i], "wording" )) { if(strcmp(attribute_values[i],"(null)") && attribute_values[i] != NULL) entry->memo = g_strdup(attribute_values[i]); }
747 else if(!strcmp (attribute_names[i], "info" )) { if(strcmp(attribute_values[i],"(null)") && attribute_values[i] != NULL) entry->info = g_strdup(attribute_values[i]); }
748 else if(!strcmp (attribute_names[i], "tags" ))
749 {
750 if(attribute_values[i] != NULL && strlen(attribute_values[i]) > 0 && strcmp(attribute_values[i],"(null)") != 0 )
751 {
752 entry->tags = tags_parse(attribute_values[i]);
753 }
754 }
755 else if(!strcmp (attribute_names[i], "nextdate" )) { entry->nextdate = atoi(attribute_values[i]); }
756 else if(!strcmp (attribute_names[i], "every" )) { entry->every = atoi(attribute_values[i]); }
757 else if(!strcmp (attribute_names[i], "unit" )) { entry->unit = atoi(attribute_values[i]); }
758 else if(!strcmp (attribute_names[i], "limit" )) { entry->limit = atoi(attribute_values[i]); }
759 else if(!strcmp (attribute_names[i], "weekend" )) { entry->weekend = atoi(attribute_values[i]); }
760 else if(!strcmp (attribute_names[i], "gap" )) { entry->daygap = atoi(attribute_values[i]); }
761 else if(!strcmp (attribute_names[i], "scat" )) { scat = (gchar *)attribute_values[i]; split = TRUE; }
762 else if(!strcmp (attribute_names[i], "samt" )) { samt = (gchar *)attribute_values[i]; split = TRUE; }
763 else if(!strcmp (attribute_names[i], "smem" )) { smem = (gchar *)attribute_values[i]; split = TRUE; }
764
765 }
766
767 if(split == TRUE)
768 {
769 entry->splits = da_split_new ();
770 if (da_splits_parse(entry->splits, scat, samt, smem) > 0)
771 {
772 entry->flags |= OF_SPLIT; //Flag that Splits are active
773 }
774 }
775
776 //all attribute loaded: append
777 //GLOBALS->arc_list = g_list_append(GLOBALS->arc_list, entry);
778 da_archive_append(entry);
779 }
780
781
homebank_load_xml_ope(ParseContext * ctx,const gchar ** attribute_names,const gchar ** attribute_values)782 static void homebank_load_xml_ope(ParseContext *ctx, const gchar **attribute_names, const gchar **attribute_values)
783 {
784 Transaction *entry = da_transaction_malloc();
785 gchar *scat = NULL;
786 gchar *samt = NULL;
787 gchar *smem = NULL;
788 gboolean split = FALSE;
789 gint i;
790
791 for (i = 0; attribute_names[i] != NULL; i++)
792 {
793 //DB( g_print(" att='%s' val='%s'\n", attribute_names[i], attribute_values[i]) );
794
795 if(!strcmp (attribute_names[i], "date" )) { entry->date = atoi(attribute_values[i]); }
796 else if(!strcmp (attribute_names[i], "amount" )) { entry->amount = g_ascii_strtod(attribute_values[i], NULL); }
797 else if(!strcmp (attribute_names[i], "account" )) { entry->kacc = atoi(attribute_values[i]); }
798 else if(!strcmp (attribute_names[i], "dst_account")) { entry->kxferacc = atoi(attribute_values[i]); }
799 else if(!strcmp (attribute_names[i], "paymode" )) { entry->paymode = atoi(attribute_values[i]); }
800 else if(!strcmp (attribute_names[i], "st" )) { entry->status = atoi(attribute_values[i]); }
801 else if(!strcmp (attribute_names[i], "flags" )) { entry->flags = atoi(attribute_values[i]); }
802 else if(!strcmp (attribute_names[i], "payee" )) { entry->kpay = atoi(attribute_values[i]); }
803 else if(!strcmp (attribute_names[i], "category" )) { entry->kcat = atoi(attribute_values[i]); }
804 else if(!strcmp (attribute_names[i], "wording" )) { if(strcmp(attribute_values[i],"(null)") && attribute_values[i] != NULL) entry->memo = g_strdup(attribute_values[i]); }
805 else if(!strcmp (attribute_names[i], "info" )) { if(strcmp(attribute_values[i],"(null)") && attribute_values[i] != NULL) entry->info = g_strdup(attribute_values[i]); }
806 else if(!strcmp (attribute_names[i], "tags" ))
807 {
808 if(attribute_values[i] != NULL && strlen(attribute_values[i]) > 0 && strcmp(attribute_values[i],"(null)") != 0 )
809 {
810 entry->tags = tags_parse(attribute_values[i]);
811 }
812 }
813 else if(!strcmp (attribute_names[i], "kxfer" )) { entry->kxfer = atoi(attribute_values[i]); }
814 else if(!strcmp (attribute_names[i], "scat" )) { scat = (gchar *)attribute_values[i]; split = TRUE; }
815 else if(!strcmp (attribute_names[i], "samt" )) { samt = (gchar *)attribute_values[i]; split = TRUE; }
816 else if(!strcmp (attribute_names[i], "smem" )) { smem = (gchar *)attribute_values[i]; split = TRUE; }
817 }
818
819 //bugfix 303886
820 //if(entry->kcat < 0)
821 // entry->kcat = 0;
822
823 if(split == TRUE)
824 {
825 entry->splits = da_split_new ();
826 if (da_splits_parse(entry->splits, scat, samt, smem) > 0)
827 {
828 entry->flags |= OF_SPLIT; //Flag that Splits are active
829 }
830 }
831
832 //all attribute loaded: append
833 // for perf reason we use prepend here, the list will be reversed later
834 da_transaction_prepend(entry);
835 }
836
837
838
839
840 static void
start_element_handler(GMarkupParseContext * context,const gchar * element_name,const gchar ** attribute_names,const gchar ** attribute_values,gpointer user_data,GError ** error)841 start_element_handler (GMarkupParseContext *context,
842 const gchar *element_name,
843 const gchar **attribute_names,
844 const gchar **attribute_values,
845 gpointer user_data,
846 GError **error)
847 {
848 ParseContext *ctx = user_data;
849 //GtkUIManager *self = ctx->self;
850
851 //DB( g_print("** start element: '%s'\n", element_name) );
852
853 switch(element_name[0])
854 {
855 case 'a':
856 {
857 if(!strcmp (element_name, "account")) //account
858 {
859 homebank_load_xml_acc(ctx, attribute_names, attribute_values);
860 }
861 else if(!strcmp (element_name, "asg")) //assign
862 {
863 homebank_load_xml_asg(ctx, attribute_names, attribute_values);
864 }
865 }
866 break;
867
868 case 'p':
869 {
870 if(!strcmp (element_name, "pay"))
871 {
872 homebank_load_xml_pay(ctx, attribute_names, attribute_values);
873 }
874 else if(!strcmp (element_name, "properties"))
875 {
876 homebank_load_xml_prop(ctx, attribute_names, attribute_values);
877 }
878 }
879 break;
880
881 case 'g':
882 {
883 if(!strcmp (element_name, "grp"))
884 {
885 homebank_load_xml_grp(ctx, attribute_names, attribute_values);
886 }
887 }
888 break;
889
890 case 'c':
891 {
892 if(!strcmp (element_name, "cat"))
893 {
894 homebank_load_xml_cat(ctx, attribute_names, attribute_values);
895 }
896 else if(!strcmp (element_name, "cur"))
897 {
898 homebank_load_xml_cur(ctx, attribute_names, attribute_values);
899 }
900 }
901 break;
902
903 //TODO: < 5.2 misstyped here, should be tag without a s
904 //commented > 5.2 useless not loaded, but no side effect
905 /*case 't':
906 {
907 if(!strcmp (element_name, "tags"))
908 {
909 homebank_load_xml_tag(ctx, attribute_names, attribute_values);
910 }
911 }
912 break;*/
913
914 case 'f':
915 {
916 if(!strcmp (element_name, "fav"))
917 {
918 homebank_load_xml_fav(ctx, attribute_names, attribute_values);
919 }
920 }
921 break;
922
923 case 'o':
924 {
925 if(!strcmp (element_name, "ope"))
926 {
927 homebank_load_xml_ope(ctx, attribute_names, attribute_values);
928 }
929 }
930 break;
931 }
932 }
933
934
935 /*
936 static void
937 end_element_handler (GMarkupParseContext *context,
938 const gchar *element_name,
939 gpointer user_data,
940 GError **error)
941 {
942 ParseContext *ctx = user_data;
943
944 //DB( g_print("-- end element: %s\n", element_name) );
945
946
947 }
948 */
949
950 static GMarkupParser hb_parser = {
951 start_element_handler,
952 NULL, //end_element_handler,
953 NULL, //text_handler,
954 NULL,
955 NULL //cleanup
956 };
957
958
hb_xml_get_version(ParseContext * ctx,gchar * buffer)959 static gboolean hb_xml_get_version(ParseContext *ctx, gchar *buffer)
960 {
961 gchar *v_buffer;
962
963 ctx->file_version = 0.0;
964 ctx->data_version = 0;
965
966 /* v3.4 add :: prevent load of future file version */
967 v_buffer = g_strstr_len(buffer, 50, "<homebank v=");
968 if( v_buffer == NULL )
969 return FALSE;
970
971 DB( g_print("- id line: --(%.50s)\n\n", v_buffer) );
972
973 ctx->file_version = g_ascii_strtod(v_buffer+13, NULL); /* a little hacky, but works ! */
974 if( ctx->file_version == 0.0 )
975 ctx->file_version = 0.1;
976 else if( ctx->file_version == 5.0 ) //was a mistake
977 ctx->file_version = 1.0;
978
979 v_buffer = g_strstr_len(buffer+13, 50, "d=");
980 if( v_buffer )
981 {
982 //TODO: beware here of we display all the file...
983 DB( g_print(" d=%.25s)\n\n", v_buffer) );
984
985 ctx->data_version = atoi(v_buffer+3);
986 }
987 return TRUE;
988 }
989
990
991 /*
992 ** XML load homebank file: hbfile
993 */
homebank_load_xml(gchar * filename)994 gint homebank_load_xml(gchar *filename)
995 {
996 gint retval;
997 gchar *buffer;
998 gsize length;
999 GError *error = NULL;
1000 ParseContext ctx;
1001 GMarkupParseContext *context;
1002 gboolean rc, dosanity;
1003
1004 DB( g_print("\n[hb-xml] homebank_load_xml\n") );
1005
1006 retval = XML_OK;
1007 if (!g_file_get_contents (filename, &buffer, &length, &error))
1008 {
1009 if(error)
1010 {
1011 g_warning("unable to load file %s: %s", filename, error->message);
1012 g_error_free(error);
1013 retval = XML_IO_ERROR;
1014 }
1015 }
1016 else
1017 {
1018 if( hb_xml_get_version(&ctx, buffer) == FALSE )
1019 return XML_FILE_ERROR;
1020
1021 if( ctx.file_version > FILE_VERSION )
1022 return XML_VERSION_ERROR;
1023
1024
1025 DB( g_print("- file ok : v=%.1f data_v=%06d\n", ctx.file_version, ctx.data_version) );
1026
1027 /* 1st: validate the file is well in utf-8 */
1028 DB( g_print("- ensure UTF-8\n") );
1029 buffer = homebank_utf8_ensure(buffer);
1030
1031 /* then process the buffer */
1032 #if MYDEBUG == 1
1033 GTimer *t = g_timer_new();
1034 g_print("- start parse\n");
1035 #endif
1036
1037 context = g_markup_parse_context_new (&hb_parser, 0, &ctx, NULL);
1038
1039 error = NULL;
1040 rc = g_markup_parse_context_parse (context, buffer, length, &error);
1041
1042 if( error )
1043 {
1044 g_print("failed: %s\n", error->message);
1045 g_error_free (error);
1046 }
1047
1048
1049 if( rc == FALSE )
1050 {
1051 error = NULL;
1052 g_markup_parse_context_end_parse(context, &error);
1053
1054 if( error )
1055 {
1056 g_print("failed: %s\n", error->message);
1057 g_error_free (error);
1058 }
1059 }
1060
1061 g_markup_parse_context_free (context);
1062 g_free (buffer);
1063
1064 DB( g_print("- end parse : %f sec\n", g_timer_elapsed(t, NULL)) );
1065 DB( g_timer_destroy (t) );
1066
1067 /* file upgrade / bugfix */
1068 dosanity = FALSE;
1069 // group a test for very old version
1070 if( ctx.file_version <= 1.0 )
1071 {
1072 if( ctx.file_version <= 0.1 )
1073 homebank_upgrade_to_v02();
1074 if( ctx.file_version <= 0.2 )
1075 homebank_upgrade_to_v03();
1076 if( ctx.file_version <= 0.3 )
1077 homebank_upgrade_to_v04();
1078 if( ctx.file_version <= 0.4 )
1079 homebank_upgrade_to_v05();
1080 if( ctx.file_version <= 0.5 )
1081 {
1082 homebank_upgrade_to_v06();
1083 homebank_upgrade_lower_v06();
1084 }
1085 if( ctx.file_version <= 0.6 )
1086 {
1087 homebank_upgrade_to_v07();
1088 hbfile_sanity_check();
1089 }
1090 if( ctx.file_version <= 0.7 ) // <= 4.5
1091 {
1092 homebank_upgrade_to_v08();
1093 }
1094 if( ctx.file_version <= 0.8 ) // <= 4.6
1095 {
1096 dosanity = TRUE;
1097 }
1098 if( ctx.file_version <= 0.9 ) // <= 4.6.3 - 2014-08-09
1099 {
1100 homebank_upgrade_to_v10();
1101 dosanity = TRUE;
1102 }
1103 if( ctx.file_version <= 1.0 ) // <= 5.0.0
1104 {
1105 homebank_upgrade_to_v11();
1106 dosanity = TRUE;
1107 }
1108 }
1109
1110 //starting 5.0.4 data upgrade is done without changing file_version
1111 //file version is changed only when the structure change
1112 //don't start number below with 0 to avoid octal interpretation
1113 if( ctx.data_version <= 50005 ) // <= 5.0.5
1114 {
1115 dosanity = TRUE;
1116 }
1117 if( ctx.file_version <= 1.1 ) // <= 5.1.0
1118 {
1119 homebank_upgrade_to_v12();
1120 dosanity = TRUE;
1121 }
1122 if( ctx.data_version <= 50106 ) // < 5.1.6
1123 {
1124 homebank_upgrade_to_v12_7();
1125 }
1126 if( ctx.file_version < 1.3 ) // <= 5.2
1127 {
1128 homebank_upgrade_to_v13();
1129 dosanity = TRUE;
1130 }
1131 if( ctx.data_version <= 50203 )
1132 {
1133 //fix payee defaut payment to int xfer from 5.1
1134 dosanity = TRUE;
1135 }
1136 if( ctx.file_version < 1.4 ) // <= 5.3
1137 {
1138 homebank_upgrade_to_v14();
1139 dosanity = TRUE;
1140 }
1141 if( ctx.data_version < 50402 )
1142 {
1143 //fix income txn flag that may be incorrect (multiple edit)
1144 dosanity = TRUE;
1145 }
1146 // next ?
1147
1148
1149 // sanity check at last
1150 if( dosanity == TRUE )
1151 hbfile_sanity_check();
1152
1153 }
1154
1155 return retval;
1156 }
1157
1158
1159 /* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */
1160
1161 /*
1162 ** misc xml attributes methods
1163 */
hb_xml_append_txt(GString * gstring,gchar * attrname,gchar * value)1164 static void hb_xml_append_txt(GString *gstring, gchar *attrname, gchar *value)
1165 {
1166 if(value != NULL && *value != 0)
1167 {
1168 gchar *escaped = g_markup_escape_text(value, -1);
1169 g_string_append_printf(gstring, " %s=\"%s\"", attrname, escaped);
1170 g_free(escaped);
1171 }
1172 }
1173
1174 static void
append_escaped_text(GString * str,const gchar * text,gssize length)1175 append_escaped_text (GString *str,
1176 const gchar *text,
1177 gssize length)
1178 {
1179 const gchar *p;
1180 const gchar *end;
1181 gunichar c;
1182
1183 p = text;
1184 end = text + length;
1185
1186 while (p < end)
1187 {
1188 const gchar *next;
1189 next = g_utf8_next_char (p);
1190
1191 switch (*p)
1192 {
1193 case '&':
1194 g_string_append (str, "&");
1195 break;
1196
1197 case '<':
1198 g_string_append (str, "<");
1199 break;
1200
1201 case '>':
1202 g_string_append (str, ">");
1203 break;
1204
1205 case '\'':
1206 g_string_append (str, "'");
1207 break;
1208
1209 case '"':
1210 g_string_append (str, """);
1211 break;
1212
1213 default:
1214 c = g_utf8_get_char (p);
1215 if ((0x1 <= c && c <= 0x8) ||
1216 (0xa <= c && c <= 0xd) || //chnaged here from b<->c to a<->d
1217 (0xe <= c && c <= 0x1f) ||
1218 (0x7f <= c && c <= 0x84) ||
1219 (0x86 <= c && c <= 0x9f))
1220 g_string_append_printf (str, "&#x%x;", c);
1221 else
1222 g_string_append_len (str, p, next - p);
1223 break;
1224 }
1225
1226 p = next;
1227 }
1228 }
1229
1230 // we override g_markup_escape_text from glib to encode \n (LF) & \r (CR)
hb_xml_append_txt_crlf(GString * gstring,gchar * attrname,gchar * value)1231 static void hb_xml_append_txt_crlf(GString *gstring, gchar *attrname, gchar *value)
1232 {
1233 if(value != NULL && *value != 0)
1234 {
1235 gssize length;
1236 GString *escaped;
1237
1238 //gchar *escaped = g_markup_escape_text(value, -1);
1239 length = strlen (value);
1240 escaped = g_string_sized_new (length);
1241 append_escaped_text (escaped, value, length);
1242 g_string_append_printf(gstring, " %s=\"%s\"", attrname, escaped->str);
1243 g_string_free (escaped, TRUE);
1244 }
1245 }
1246
hb_xml_append_int0(GString * gstring,gchar * attrname,guint32 value)1247 static void hb_xml_append_int0(GString *gstring, gchar *attrname, guint32 value)
1248 {
1249 g_string_append_printf(gstring, " %s=\"%d\"", attrname, value);
1250 }
1251
hb_xml_append_int(GString * gstring,gchar * attrname,guint32 value)1252 static void hb_xml_append_int(GString *gstring, gchar *attrname, guint32 value)
1253 {
1254 if(value != 0)
1255 {
1256 hb_xml_append_int0(gstring, attrname, value);
1257 }
1258 }
1259
hb_xml_append_amt(GString * gstring,gchar * attrname,gdouble amount)1260 static void hb_xml_append_amt(GString *gstring, gchar *attrname, gdouble amount)
1261 {
1262 char buf[G_ASCII_DTOSTR_BUF_SIZE];
1263
1264 //we must use this, as fprintf use locale decimal settings and not '.'
1265 g_ascii_dtostr (buf, sizeof (buf), amount);
1266 g_string_append_printf(gstring, " %s=\"%s\"", attrname, buf);
1267 }
1268
1269
1270 /* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */
1271
1272
1273 /*
1274 ** XML properties save
1275 */
homebank_save_xml_prop(GIOChannel * io)1276 static gint homebank_save_xml_prop(GIOChannel *io)
1277 {
1278 gchar *title;
1279 GString *node;
1280 gint retval = XML_OK;
1281 GError *error = NULL;
1282
1283 title = GLOBALS->owner == NULL ? "" : GLOBALS->owner;
1284
1285 node = g_string_sized_new(255);
1286
1287 g_string_assign(node, "<properties");
1288
1289 hb_xml_append_txt(node, "title", title);
1290 hb_xml_append_int(node, "curr", GLOBALS->kcur);
1291 hb_xml_append_int(node, "car_category", GLOBALS->vehicle_category);
1292 hb_xml_append_int0(node, "auto_smode", GLOBALS->auto_smode);
1293 hb_xml_append_int(node, "auto_weekday", GLOBALS->auto_weekday);
1294 hb_xml_append_int(node, "auto_nbdays", GLOBALS->auto_nbdays);
1295
1296 g_string_append(node, "/>\n");
1297
1298 error = NULL;
1299 g_io_channel_write_chars(io, node->str, -1, NULL, &error);
1300 if(error)
1301 {
1302 retval = XML_IO_ERROR;
1303 g_error_free(error);
1304 }
1305
1306 g_string_free(node, TRUE);
1307 return retval;
1308 }
1309
1310
1311 /*
1312 ** XML currency save
1313 */
homebank_save_xml_cur(GIOChannel * io)1314 static gint homebank_save_xml_cur(GIOChannel *io)
1315 {
1316 GList *list;
1317 gchar *tmpstr;
1318 char buf1[G_ASCII_DTOSTR_BUF_SIZE];
1319 gint retval = XML_OK;
1320
1321 list = g_hash_table_get_values(GLOBALS->h_cur);
1322 while (list != NULL)
1323 {
1324 Currency *item = list->data;
1325
1326 tmpstr = g_markup_printf_escaped(
1327 "<cur key=\"%d\" flags=\"%d\" iso=\"%s\" name=\"%s\" symb=\"%s\" syprf=\"%d\" dchar=\"%s\" gchar=\"%s\" frac=\"%d\" rate=\"%s\" mdate=\"%d\"/>\n",
1328 item->key,
1329 item->flags,
1330 item->iso_code,
1331 item->name,
1332 item->symbol,
1333 item->sym_prefix,
1334 item->decimal_char,
1335 item->grouping_char,
1336 item->frac_digits,
1337 g_ascii_dtostr (buf1, sizeof (buf1), item->rate),
1338 item->mdate
1339 );
1340
1341 g_io_channel_write_chars(io, tmpstr, -1, NULL, NULL);
1342 g_free(tmpstr);
1343
1344 list = g_list_next(list);
1345 }
1346 g_list_free(list);
1347 return retval;
1348 }
1349
1350
1351 /*
1352 ** XML account save
1353 */
homebank_save_xml_acc(GIOChannel * io)1354 static gint homebank_save_xml_acc(GIOChannel *io)
1355 {
1356 GList *lacc, *list;
1357 GString *node;
1358 gint retval = XML_OK;
1359 GError *error = NULL;
1360
1361 node = g_string_sized_new(255);
1362
1363 lacc = list = account_glist_sorted(0);
1364 while (list != NULL)
1365 {
1366 Account *item = list->data;
1367
1368 item->flags &= ~(AF_ADDED|AF_CHANGED); //delete flag
1369
1370 g_string_assign(node, "<account");
1371
1372 hb_xml_append_int(node, "key", item->key);
1373 hb_xml_append_int(node, "flags", item->flags);
1374 hb_xml_append_int(node, "pos", item->pos);
1375 hb_xml_append_int(node, "type", item->type);
1376 hb_xml_append_int(node, "curr", item->kcur);
1377 hb_xml_append_txt(node, "name", item->name);
1378 hb_xml_append_txt(node, "number", item->number);
1379 hb_xml_append_txt(node, "bankname", item->bankname);
1380 hb_xml_append_amt(node, "initial", item->initial);
1381
1382 hb_xml_append_amt(node, "minimum", item->minimum);
1383 hb_xml_append_amt(node, "maximum", item->maximum);
1384 hb_xml_append_int(node, "cheque1", item->cheque1);
1385 hb_xml_append_int(node, "cheque2", item->cheque2);
1386 hb_xml_append_txt_crlf(node, "notes", item->notes);
1387 hb_xml_append_int(node, "tpl", item->karc);
1388 hb_xml_append_int(node, "grp", item->kgrp);
1389 //5.5
1390 hb_xml_append_int(node, "ccday", item->cccday);
1391 hb_xml_append_int(node, "rdate", item->rdate);
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 list = g_list_next(list);
1405 }
1406 g_list_free(lacc);
1407 g_string_free(node, TRUE);
1408 return retval;
1409 }
1410
1411 /*
1412 ** XML payee save
1413 */
homebank_save_xml_pay(GIOChannel * io)1414 static gint homebank_save_xml_pay(GIOChannel *io)
1415 {
1416 GList *lpay, *list;
1417 GString *node;
1418 gint retval = XML_OK;
1419 GError *error = NULL;
1420
1421 node = g_string_sized_new(255);
1422
1423 lpay = list = payee_glist_sorted(0);
1424 while (list != NULL)
1425 {
1426 Payee *item = list->data;
1427
1428 if(item->key != 0)
1429 {
1430 g_string_assign(node, "<pay");
1431
1432 hb_xml_append_int(node, "key", item->key);
1433 hb_xml_append_txt(node, "name", item->name);
1434 hb_xml_append_int(node, "category", item->kcat);
1435 hb_xml_append_int(node, "paymode" , item->paymode);
1436
1437 g_string_append(node, "/>\n");
1438
1439 error = NULL;
1440 g_io_channel_write_chars(io, node->str, -1, NULL, &error);
1441
1442 if(error)
1443 {
1444 retval = XML_IO_ERROR;
1445 g_error_free(error);
1446 }
1447
1448 }
1449 list = g_list_next(list);
1450 }
1451 g_list_free(lpay);
1452 g_string_free(node, TRUE);
1453 return retval;
1454 }
1455
1456 /*
1457 ** XML category save
1458 */
homebank_save_xml_cat(GIOChannel * io)1459 static gint homebank_save_xml_cat(GIOChannel *io)
1460 {
1461 GList *lcat, *list;
1462 GString *node;
1463 char buf[G_ASCII_DTOSTR_BUF_SIZE];
1464 guint i;
1465 gint retval = XML_OK;
1466 GError *error = NULL;
1467
1468 node = g_string_sized_new(255);
1469
1470 lcat = list = category_glist_sorted(0);
1471 while (list != NULL)
1472 {
1473 Category *item = list->data;
1474
1475 if(item->key != 0)
1476 {
1477 g_string_assign(node, "<cat");
1478
1479 hb_xml_append_int(node, "key", item->key);
1480 hb_xml_append_int(node, "parent", item->parent);
1481 hb_xml_append_int(node, "flags", item->flags);
1482 hb_xml_append_txt(node, "name", item->name);
1483
1484 for(i=0;i<=12;i++)
1485 {
1486 if(item->budget[i] != 0)
1487 {
1488 g_string_append_printf(node," b%d=\"%s\"", i, g_ascii_dtostr (buf, sizeof (buf), item->budget[i]));
1489 }
1490 }
1491
1492 g_string_append(node, "/>\n");
1493
1494 error = NULL;
1495 g_io_channel_write_chars(io, node->str, -1, NULL, &error);
1496
1497 if(error)
1498 {
1499 retval = XML_IO_ERROR;
1500 g_error_free(error);
1501 }
1502
1503 }
1504 list = g_list_next(list);
1505 }
1506 g_list_free(lcat);
1507 g_string_free(node, TRUE);
1508 return retval;
1509 }
1510
1511
1512 /*
1513 ** XML grp save
1514 */
homebank_save_xml_grp(GIOChannel * io)1515 static gint homebank_save_xml_grp(GIOChannel *io)
1516 {
1517 GList *lgrp, *list;
1518 gchar *tmpstr;
1519 gint retval = XML_OK;
1520 GError *error = NULL;
1521
1522 lgrp = list = group_glist_sorted(0);
1523 while (list != NULL)
1524 {
1525 Group *item = list->data;
1526
1527 if(item->key != 0)
1528 {
1529 //tmpstr = g_markup_printf_escaped("<grp key=\"%d\" type=\"%d\" name=\"%s\"/>\n",
1530 tmpstr = g_markup_printf_escaped("<grp key=\"%d\" name=\"%s\"/>\n",
1531 item->key,
1532 //item->type,
1533 item->name
1534 );
1535
1536 error = NULL;
1537 g_io_channel_write_chars(io, tmpstr, -1, NULL, &error);
1538 g_free(tmpstr);
1539
1540 if(error)
1541 {
1542 retval = XML_IO_ERROR;
1543 g_error_free(error);
1544 }
1545 }
1546 list = g_list_next(list);
1547 }
1548 g_list_free(lgrp);
1549 return retval;
1550 }
1551
1552
1553 /*
1554 ** XML tag save
1555 */
1556 /*static gint homebank_save_xml_tag(GIOChannel *io)
1557 {
1558 GList *ltag, *list;
1559 gchar *tmpstr;
1560 gint retval = XML_OK;
1561 GError *error = NULL;
1562
1563 ltag = list = tag_glist_sorted(0);
1564 while (list != NULL)
1565 {
1566 Tag *item = list->data;
1567
1568 if(item->key != 0)
1569 {
1570 tmpstr = g_markup_printf_escaped("<tag key=\"%d\" name=\"%s\"/>\n",
1571 item->key,
1572 item->name
1573 );
1574
1575 error = NULL;
1576 g_io_channel_write_chars(io, tmpstr, -1, NULL, &error);
1577 g_free(tmpstr);
1578
1579 if(error)
1580 {
1581 retval = XML_IO_ERROR;
1582 g_error_free(error);
1583 }
1584 }
1585 list = g_list_next(list);
1586 }
1587 g_list_free(ltag);
1588 return retval;
1589 }*/
1590
1591
1592 /*
1593 ** XML assign save
1594 */
homebank_save_xml_asg(GIOChannel * io)1595 static gint homebank_save_xml_asg(GIOChannel *io)
1596 {
1597 GList *lasg, *list;
1598 GString *node;
1599 gint retval = XML_OK;
1600 GError *error = NULL;
1601
1602 node = g_string_sized_new(255);
1603
1604 lasg = list = assign_glist_sorted(HB_GLIST_SORT_KEY);
1605 while (list != NULL)
1606 {
1607 Assign *item = list->data;
1608
1609 g_string_assign(node, "<asg");
1610
1611 hb_xml_append_int(node, "key" , item->key);
1612 hb_xml_append_int(node, "flags" , item->flags);
1613 hb_xml_append_int(node, "pos" , item->pos);
1614 hb_xml_append_int(node, "field" , item->field);
1615 hb_xml_append_txt(node, "name" , item->search);
1616 hb_xml_append_txt(node, "notes" , item->notes);
1617 hb_xml_append_int(node, "payee" , item->kpay);
1618 hb_xml_append_int(node, "category", item->kcat);
1619 hb_xml_append_int(node, "paymode" , item->paymode);
1620
1621 g_string_append(node, "/>\n");
1622
1623 error = NULL;
1624 g_io_channel_write_chars(io, node->str, -1, NULL, &error);
1625
1626 if(error)
1627 {
1628 retval = XML_IO_ERROR;
1629 g_error_free(error);
1630 }
1631
1632 list = g_list_next(list);
1633 }
1634 g_list_free(lasg);
1635 g_string_free(node, TRUE);
1636 return retval;
1637 }
1638
1639
1640
1641 /*
1642 ** XML archive save
1643 */
homebank_save_xml_arc(GIOChannel * io)1644 static gint homebank_save_xml_arc(GIOChannel *io)
1645 {
1646 GList *list;
1647 GString *node;
1648 gchar *tagstr;
1649 gint retval = XML_OK;
1650 GError *error = NULL;
1651
1652 node = g_string_sized_new(255);
1653
1654 list = da_archive_glist_sorted(0);
1655 while (list != NULL)
1656 {
1657 Archive *item = list->data;
1658
1659 tagstr = tags_tostring(item->tags);
1660
1661 g_string_assign(node, "<fav");
1662
1663 hb_xml_append_int(node, "key", item->key);
1664 hb_xml_append_amt(node, "amount", item->amount);
1665 hb_xml_append_int(node, "account", item->kacc);
1666 hb_xml_append_int(node, "dst_account", item->kxferacc);
1667 hb_xml_append_int(node, "paymode", item->paymode);
1668 hb_xml_append_int(node, "st", item->status);
1669 hb_xml_append_int(node, "flags", item->flags);
1670 hb_xml_append_int(node, "payee", item->kpay);
1671 hb_xml_append_int(node, "category", item->kcat);
1672 hb_xml_append_txt(node, "wording", item->memo);
1673 hb_xml_append_txt(node, "info", item->info);
1674 hb_xml_append_txt(node, "tags", tagstr);
1675 hb_xml_append_int(node, "nextdate", item->nextdate);
1676 hb_xml_append_int(node, "every", item->every);
1677 hb_xml_append_int(node, "unit", item->unit);
1678 hb_xml_append_int(node, "limit", item->limit);
1679 hb_xml_append_int(node, "weekend", item->weekend);
1680 hb_xml_append_int(node, "gap", item->daygap);
1681
1682 if(da_splits_length(item->splits) > 0)
1683 {
1684 gchar *cats, *amounts, *memos;
1685
1686 da_splits_tostring(item->splits, &cats, &amounts, &memos);
1687 g_string_append_printf(node, " scat=\"%s\"", cats);
1688 g_string_append_printf(node, " samt=\"%s\"", amounts);
1689
1690 //fix #1173910
1691 gchar *escaped = g_markup_escape_text(memos, -1);
1692 g_string_append_printf(node, " smem=\"%s\"", escaped);
1693 g_free(escaped);
1694
1695 g_free(cats);
1696 g_free(amounts);
1697 g_free(memos);
1698 }
1699
1700 g_string_append(node, "/>\n");
1701
1702 g_free(tagstr);
1703
1704 error = NULL;
1705 g_io_channel_write_chars(io, node->str, -1, NULL, &error);
1706 if(error)
1707 {
1708 retval = XML_IO_ERROR;
1709 g_error_free(error);
1710 }
1711
1712 list = g_list_next(list);
1713 }
1714 g_string_free(node, TRUE);
1715 return retval;
1716 }
1717
1718
1719 /*
1720 ** XML transaction save
1721 */
homebank_save_xml_ope(GIOChannel * io)1722 static gint homebank_save_xml_ope(GIOChannel *io)
1723 {
1724 GList *lst_acc, *lnk_acc;
1725 GList *list;
1726 GString *node;
1727 gchar *tagstr;
1728 gint retval = XML_OK;
1729 GError *error = NULL;
1730
1731 node = g_string_sized_new(255);
1732
1733 lst_acc = g_hash_table_get_values(GLOBALS->h_acc);
1734 lnk_acc = g_list_first(lst_acc);
1735 while (lnk_acc != NULL)
1736 {
1737 Account *acc = lnk_acc->data;
1738
1739 list = g_queue_peek_head_link(acc->txn_queue);
1740 while (list != NULL)
1741 {
1742 Transaction *item = list->data;
1743
1744 item->flags &= ~(OF_AUTO|OF_ADDED|OF_CHANGED); //delete flag
1745 tagstr = tags_tostring(item->tags);
1746
1747 g_string_assign(node, "<ope");
1748
1749 hb_xml_append_int(node, "date", item->date);
1750 hb_xml_append_amt(node, "amount", item->amount);
1751 hb_xml_append_int(node, "account", item->kacc);
1752 hb_xml_append_int(node, "dst_account", item->kxferacc);
1753 hb_xml_append_int(node, "paymode", item->paymode);
1754 hb_xml_append_int(node, "st", item->status);
1755 hb_xml_append_int(node, "flags", item->flags);
1756 hb_xml_append_int(node, "payee", item->kpay);
1757 hb_xml_append_int(node, "category", item->kcat);
1758 hb_xml_append_txt(node, "wording", item->memo);
1759 hb_xml_append_txt(node, "info", item->info);
1760 hb_xml_append_txt(node, "tags", tagstr);
1761 hb_xml_append_int(node, "kxfer", item->kxfer);
1762
1763 if(da_splits_length(item->splits) > 0)
1764 {
1765 gchar *cats, *amounts, *memos;
1766
1767 da_splits_tostring(item->splits, &cats, &amounts, &memos);
1768 g_string_append_printf(node, " scat=\"%s\"", cats);
1769 g_string_append_printf(node, " samt=\"%s\"", amounts);
1770
1771 //fix #1173910
1772 gchar *escaped = g_markup_escape_text(memos, -1);
1773 g_string_append_printf(node, " smem=\"%s\"", escaped);
1774 g_free(escaped);
1775
1776 g_free(cats);
1777 g_free(amounts);
1778 g_free(memos);
1779 }
1780
1781 g_string_append(node, "/>\n");
1782
1783 g_free(tagstr);
1784
1785 error = NULL;
1786 g_io_channel_write_chars(io, node->str, -1, NULL, &error);
1787
1788 if(error)
1789 {
1790 retval = XML_IO_ERROR;
1791 g_error_free(error);
1792 }
1793
1794 list = g_list_next(list);
1795 }
1796
1797 lnk_acc = g_list_next(lnk_acc);
1798 }
1799 g_list_free(lst_acc);
1800
1801 g_string_free(node, TRUE);
1802 return retval;
1803 }
1804
1805 /*
1806 ** XML save homebank file: hbfile
1807 */
homebank_save_xml(gchar * filename)1808 gint homebank_save_xml(gchar *filename)
1809 {
1810 GIOChannel *io;
1811 char buf1[G_ASCII_DTOSTR_BUF_SIZE];
1812 gchar *outstr;
1813 gint retval = XML_OK;
1814 GError *error = NULL;
1815
1816 io = g_io_channel_new_file(filename, "w", &error);
1817 //The default encoding for the external file is UTF-8.
1818 if(error)
1819 {
1820 g_warning("unable to save file %s: %s", filename, error->message);
1821 g_error_free(error);
1822 return(XML_IO_ERROR);
1823 }
1824
1825 g_io_channel_write_chars(io, "<?xml version=\"1.0\"?>\n", -1, NULL, NULL);
1826
1827 outstr = g_strdup_printf("<homebank v=\"%s\" d=\"%06d\">\n", g_ascii_dtostr (buf1, sizeof (buf1), FILE_VERSION), HB_VERSION_NUM);
1828 g_io_channel_write_chars(io, outstr, -1, NULL, NULL);
1829 g_free(outstr);
1830
1831 retval = homebank_save_xml_prop(io);
1832 retval = homebank_save_xml_cur(io);
1833 retval = homebank_save_xml_grp(io);
1834 retval = homebank_save_xml_acc(io);
1835 retval = homebank_save_xml_pay(io);
1836 retval = homebank_save_xml_cat(io);
1837 //retval = homebank_save_xml_tag(io);
1838 retval = homebank_save_xml_asg(io);
1839 retval = homebank_save_xml_arc(io);
1840 retval = homebank_save_xml_ope(io);
1841
1842 g_io_channel_write_chars(io, "</homebank>\n", -1, NULL, NULL);
1843
1844 g_io_channel_unref (io);
1845
1846 return retval;
1847 }
1848
1849