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