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