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