1 /***************************************************************************
2 begin : Mon Jan 07 2008
3 copyright : (C) 2008 by Martin Preuss
4 email : martin@libchipcard.de
5
6 comments :Stephen R. Besch
7 email :sbesch@acsu.buffalo.edu
8
9 ***************************************************************************
10 * Please see toplevel file COPYING for license details *
11 ***************************************************************************/
12
13
14 #ifdef HAVE_CONFIG_H
15 # include <config.h>
16 #endif
17
18 #include "g_invstmtrs_p.h"
19 #include "ofxxmlctx_l.h"
20 #include "aqbanking/i18n_l.h"
21
22 #include "g_generic_l.h"
23 #include "g_ignore_l.h"
24
25 #include "g_invacc_l.h" /*SRB 4/22/09*/
26 #include "g_invposlist_l.h"
27 #include "g_invtranlist_l.h" /*SRB 4/22/09*/
28 #include <aqbanking/types/balance.h>
29
30 #include <gwenhywfar/misc.h>
31 #include <gwenhywfar/debug.h>
32 #include <gwenhywfar/buffer.h>
33 #include <gwenhywfar/gui.h>
34
35
36
GWEN_INHERIT(AIO_OFX_GROUP,AIO_OFX_GROUP_INVSTMTRS)37 GWEN_INHERIT(AIO_OFX_GROUP, AIO_OFX_GROUP_INVSTMTRS)
38
39 /*This code parallels the code in g_stmtrs with the exception that there are quite a few more items to
40 ignore and more items to handle. Since there are data items that we want to use, we need to define
41 virtual functions for adding data items. And, since some of the subgroups return data, we will need
42 to watch for end-tags so we can dispose of the data when the group closes.*/
43
44 AIO_OFX_GROUP *AIO_OfxGroup_INVSTMTRS_new(const char *groupName,
45 AIO_OFX_GROUP *parent,
46 GWEN_XML_CONTEXT *ctx)
47 {
48 AIO_OFX_GROUP *g;
49 AIO_OFX_GROUP_INVSTMTRS *xg;
50
51 /* create base group */
52 g=AIO_OfxGroup_Generic_new(groupName, parent, ctx);
53 assert(g);
54
55 GWEN_NEW_OBJECT(AIO_OFX_GROUP_INVSTMTRS, xg);
56 assert(xg);
57 GWEN_INHERIT_SETDATA(AIO_OFX_GROUP, AIO_OFX_GROUP_INVSTMTRS, g, xg,
58 AIO_OfxGroup_INVSTMTRS_FreeData);
59
60 /* set virtual functions */
61 AIO_OfxGroup_SetStartTagFn(g, AIO_OfxGroup_INVSTMTRS_StartTag);
62 AIO_OfxGroup_SetAddDataFn(g, AIO_OfxGroup_INVSTMTRS_AddData);
63 AIO_OfxGroup_SetEndSubGroupFn(g, AIO_OfxGroup_INVSTMTRS_EndSubGroup);
64 return g;
65 }
66
67 GWENHYWFAR_CB
AIO_OfxGroup_INVSTMTRS_FreeData(void * bp,void * p)68 void AIO_OfxGroup_INVSTMTRS_FreeData(void *bp, void *p)
69 {
70 AIO_OFX_GROUP_INVSTMTRS *xg;
71
72 xg=(AIO_OFX_GROUP_INVSTMTRS *)p;
73 assert(xg);
74 free(xg->currency);
75 free(xg->currentElement);
76 GWEN_FREE_OBJECT(xg);
77 }
78
79 /*There are 2 data items and 7 subgroups (INVACCTFROM, INVACCTTO, INVTRANLIST, INVPOSLIST, INVOOLIST, INCOME, INVBAL)
80 Original code handled 3 of the 7 groups. I've added the INVTRANLIST group to the mix.*/
81
AIO_OfxGroup_INVSTMTRS_StartTag(AIO_OFX_GROUP * g,const char * tagName)82 int AIO_OfxGroup_INVSTMTRS_StartTag(AIO_OFX_GROUP *g,
83 const char *tagName)
84 {
85 AIO_OFX_GROUP_INVSTMTRS *xg;
86 GWEN_XML_CONTEXT *ctx;
87 AIO_OFX_GROUP *gNew=NULL;
88
89 /*First, get the data and context.*/
90
91 assert(g);
92 xg=GWEN_INHERIT_GETDATA(AIO_OFX_GROUP, AIO_OFX_GROUP_INVSTMTRS, g);
93 assert(xg);
94 ctx=AIO_OfxGroup_GetXmlContext(g);
95
96 free(xg->currentElement); /*Get rid of the old contents*/
97 xg->currentElement=NULL;
98
99 /*Handle the data tags first We only need to make the current element's value match the tag.*/
100
101 if (strcasecmp(tagName, "CURDEF")==0 ||
102 strcasecmp(tagName, "DTASOF")==0) {
103 xg->currentElement=strdup(tagName);
104 }
105
106 /*Then handle the groups.*/
107
108 else if (strcasecmp(tagName, "INVACCTFROM")==0 ||
109 strcasecmp(tagName, "INVACCTTO")==0)
110 gNew=AIO_OfxGroup_INVACC_new(tagName, g, ctx);
111 else if (strcasecmp(tagName, "INVTRANLIST")==0)
112 gNew=AIO_OfxGroup_INVTRANLIST_new(tagName, g, ctx); /*SRB 4/22/09*/
113 else if (strcasecmp(tagName, "INVPOSLIST")==0)
114 gNew=AIO_OfxGroup_INVPOSLIST_new(tagName, g, ctx);
115 else {
116 DBG_WARN(AQBANKING_LOGDOMAIN, "Ignoring group [%s]", tagName);
117 gNew=AIO_OfxGroup_Ignore_new(tagName, g, ctx);
118 }
119 if (gNew) {
120 AIO_OfxXmlCtx_SetCurrentGroup(ctx, gNew);
121 GWEN_XmlCtx_IncDepth(ctx);
122 }
123 return 0;
124 }
125
126
127
128 /*Even though we look for the DTASOF tag above (we must, so that it can be distinguished from a group),
129 nothing is done with the data. The only tag we preocess is the currency definition.*/
130
AIO_OfxGroup_INVSTMTRS_AddData(AIO_OFX_GROUP * g,const char * data)131 int AIO_OfxGroup_INVSTMTRS_AddData(AIO_OFX_GROUP *g, const char *data)
132 {
133 AIO_OFX_GROUP_INVSTMTRS *xg;
134 assert(g);
135 xg=GWEN_INHERIT_GETDATA(AIO_OFX_GROUP, AIO_OFX_GROUP_INVSTMTRS, g);
136 assert(xg);
137
138 /*If the last start tag defined a "currentElement", then see if we recognize it.*/
139
140 if (xg->currentElement) {
141 GWEN_BUFFER *buf;
142 int rv;
143 const char *s;
144
145 /*Always make sure that there are no weird or extra characters in the string data.*/
146
147 buf=GWEN_Buffer_new(0, strlen(data), 0, 1);
148 rv=AIO_OfxXmlCtx_SanitizeData(AIO_OfxGroup_GetXmlContext(g), data, buf);
149 if (rv<0) {
150 DBG_INFO(AQBANKING_LOGDOMAIN, "here (%d)", rv);
151 GWEN_Buffer_free(buf);
152 return rv;
153 }
154 s=GWEN_Buffer_GetStart(buf);
155 if (*s) { /*If there is actually a string there, then*/
156 DBG_INFO(AQBANKING_LOGDOMAIN, "AddData: %s=[%s]", xg->currentElement, s);
157 if (strcasecmp(xg->currentElement, "CURDEF")==0) { /*See if it was following a CURDEF*/
158 free(xg->currency); /*If so, then remove any debris*/
159 xg->currency=strdup(s); /*and dup the string into xg->currency*/
160 }
161 else { /*All other tags are ignored!*/
162 DBG_INFO(AQBANKING_LOGDOMAIN,
163 "Ignoring data for unknown element [%s]",
164 xg->currentElement);
165 }
166 }
167 GWEN_Buffer_free(buf);
168 }
169 return 0;
170 }
171
172 /*We need to watch for the ending of our 3 groups. Ignore INVACCTTO for now.*/
173
AIO_OfxGroup_INVSTMTRS_EndSubGroup(AIO_OFX_GROUP * g,AIO_OFX_GROUP * sg)174 int AIO_OfxGroup_INVSTMTRS_EndSubGroup(AIO_OFX_GROUP *g, AIO_OFX_GROUP *sg)
175 {
176 AIO_OFX_GROUP_INVSTMTRS *xg;
177 const char *s;
178 GWEN_XML_CONTEXT *ctx;
179
180 /*Set up pointers to INVSTMTRS group data*/
181
182 assert(g);
183 xg=GWEN_INHERIT_GETDATA(AIO_OFX_GROUP, AIO_OFX_GROUP_INVSTMTRS, g);
184 assert(xg);
185 ctx=AIO_OfxGroup_GetXmlContext(g);
186 assert(ctx);
187
188 s=AIO_OfxGroup_GetGroupName(sg); /*Pointer to the group name*/
189
190 /*First look for the INVACCTFROM group. This is quite simple and is in fact nearly identical to the code for
191 BANKACCTFROM in g_stmtrn.c. ....What about INVACCTTO? */
192
193 if (strcasecmp(s, "INVACCTFROM")==0) {
194 AB_IMEXPORTER_ACCOUNTINFO *ai;
195 const char *s;
196 DBG_INFO(AQBANKING_LOGDOMAIN, "Importing account %s/%s", AIO_OfxGroup_INVACC_GetBrokerId(sg),
197 AIO_OfxGroup_INVACC_GetAccId(sg));
198 ai=AB_ImExporterAccountInfo_new(); /*Create the AccountInfo Structure*/
199 assert(ai); /*Validate creation*/
200 s=AIO_OfxGroup_INVACC_GetBrokerId(sg);
201 if (s)
202 AB_ImExporterAccountInfo_SetBankCode(ai, s); /*Install Broker ID*/
203 s=AIO_OfxGroup_INVACC_GetAccId(sg);
204 if (s)
205 AB_ImExporterAccountInfo_SetAccountNumber(ai, s); /*And account number*/
206
207 /* and set currency if there is one */
208
209 if (xg->currency)
210 AB_ImExporterAccountInfo_SetCurrency(ai, xg->currency);
211
212 /* set account type, if known */
213
214 s=AIO_OfxGroup_INVACC_GetAccType(sg);
215 if (!s)
216 s="INVESTMENT"; /* Investment is a real code now?--- SRB 4/22/09*/
217 if (s) {
218 AB_ACCOUNT_TYPE t;
219 t=AIO_OfxGroup_Generic_AccountTypeFromString(s);
220 AB_ImExporterAccountInfo_SetAccountType(ai, t);
221 }
222
223 DBG_INFO(AQBANKING_LOGDOMAIN, "Adding investment account");
224 AB_ImExporterContext_AddAccountInfo(AIO_OfxXmlCtx_GetIoContext(ctx), ai);
225 xg->accountInfo=ai;
226 }
227
228 else if (strcasecmp(s, "INVTRANLIST") == 0) {
229 /*Here when we finish an Investment transaction list. Uncommented and extended by SRB*/
230 AB_TRANSACTION_LIST2 *tl;
231 AB_TRANSACTION_LIST2_ITERATOR *it;
232
233 tl=AIO_OfxGroup_INVTRANLIST_TakeTransactionList(sg);
234 if (!tl)
235 return 0; /*No list - just return*/
236
237 it=AB_Transaction_List2_First(tl);
238
239 if (it) {
240 AB_TRANSACTION *t;
241
242 t=AB_Transaction_List2Iterator_Data(it);
243 /* int transactionCount=0;
244 char st[20]; */
245
246 while (t) {
247 DBG_INFO(AQBANKING_LOGDOMAIN, "Importing investment transaction");
248 if (xg->currency) { /* set currency using xg->currency if missing from transaction */
249 const AB_VALUE *v;
250 v=AB_Transaction_GetValue(t); /*Returns pointer to actual data item*/
251 if (v && AB_Value_GetCurrency(v)==NULL) { /*If v is valid, check for currency valid*/
252 AB_VALUE *v2; /*We're duplicating here (why??)*/
253 v2=AB_Value_dup(v); /*Can do AB_Value_SetCurrency(v, xg->currency) for whole mess*/
254 AB_Value_SetCurrency(v2, xg->currency); /*Install the currency*/
255 AB_Transaction_SetValue(t, v2); /*This destroys v, duplicates v2 and uses duplicate*/
256 AB_Value_free(v2);
257 }
258 }
259
260 /* sprintf(st,"%d",transactionCount);
261 AB_Transaction_SetCustomerReference(t,st);
262 transactionCount++; */
263
264 AB_ImExporterAccountInfo_AddTransaction(xg->accountInfo, t);
265 t=AB_Transaction_List2Iterator_Next(it);
266 }
267 AB_Transaction_List2Iterator_free(it);
268 }
269
270 /* don't call AB_Transaction_List2_freeAll(), because the transactions
271 from the list have been taken over by the AccountInfo object */
272
273 AB_Transaction_List2_free(tl);
274 }
275 return 0;
276 }
277
278