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