LibOFX
ofxpartner.cpp
Go to the documentation of this file.
1/***************************************************************************
2 ofx_partner.cpp
3 -------------------
4 copyright : (C) 2005 by Ace Jones
5 email : acejones@users.sourceforge.net
6***************************************************************************/
11/***************************************************************************
12 * *
13 * This program is free software; you can redistribute it and/or modify *
14 * it under the terms of the GNU General Public License as published by *
15 * the Free Software Foundation; either version 2 of the License, or *
16 * (at your option) any later version. *
17 * *
18 ***************************************************************************/
19
20#ifdef HAVE_CONFIG_H
21#include <config.h>
22#endif
23
24#include <libofx.h>
25
26//#ifdef HAVE_LIBCURL
27#include <curl/curl.h>
28//#endif
29
30#include "ofxpartner.h"
31#include "nodeparser.h"
32
33#include <sys/stat.h>
34
35#include <iostream>
36#include <string>
37#include <vector>
38#include <algorithm>
39#include <string.h>
40
41using std::string;
42using std::vector;
43using std::cout;
44using std::endl;
45
46namespace OfxPartner
47{
48bool post(const string& request, const string& url, const string& filename);
49
50const string kBankFilename = "ofx-bank-index.xml";
51const string kCcFilename = "ofx-cc-index.xml";
52const string kInvFilename = "ofx-inv-index.xml";
53
54void ValidateIndexCache(void)
55{
56 // TODO Check whether these files exist and are recent enough before getting them again
57
58 struct stat filestats;
59 if ( stat( kBankFilename.c_str(), &filestats ) || difftime(time(0), filestats.st_mtime) > 7.0 * 24.0 * 60.0 * 60.0 )
60 post("T=1&S=*&R=1&O=0&TEST=0", "http://moneycentral.msn.com/money/2005/mnynet/service/ols/filist.aspx?SKU=3&VER=6", kBankFilename);
61 if ( stat( kCcFilename.c_str(), &filestats ) || difftime(time(0), filestats.st_mtime) > 7.0 * 24.0 * 60.0 * 60.0 )
62 post("T=2&S=*&R=1&O=0&TEST=0", "http://moneycentral.msn.com/money/2005/mnynet/service/ols/filist.aspx?SKU=3&VER=6", kCcFilename);
63 if ( stat( kInvFilename.c_str(), &filestats ) || difftime(time(0), filestats.st_mtime) > 7.0 * 24.0 * 60.0 * 60.0 )
64 post("T=3&S=*&R=1&O=0&TEST=0", "http://moneycentral.msn.com/money/2005/mnynet/service/ols/filist.aspx?SKU=3&VER=6", kInvFilename);
65}
66
67vector<string> BankNames(void)
68{
69 vector<string> result;
70
71 // Make sure the index files are up to date
72 ValidateIndexCache();
73
74 xmlpp::DomParser parser;
75 parser.set_substitute_entities();
76 parser.parse_file(kBankFilename);
77 if ( parser )
78 {
79 vector<string> names = NodeParser(parser).Path("fi/prov/name").Text();
80 result.insert(result.end(), names.begin(), names.end());
81 }
82 parser.parse_file(kCcFilename);
83 if ( parser )
84 {
85 vector<string> names = NodeParser(parser).Path("fi/prov/name").Text();
86 result.insert(result.end(), names.begin(), names.end());
87 }
88 parser.parse_file(kInvFilename);
89 if ( parser )
90 {
91 vector<string> names = NodeParser(parser).Path("fi/prov/name").Text();
92 result.insert(result.end(), names.begin(), names.end());
93 }
94
95 // Add Innovision
96 result.push_back("Innovision");
97
98 // sort the list and remove duplicates, to return one unified list of all supported banks
99 sort(result.begin(), result.end());
100 result.erase(unique(result.begin(), result.end()), result.end());
101 return result;
102}
103
104vector<string> FipidForBank(const string& bank)
105{
106 vector<string> result;
107
108 xmlpp::DomParser parser;
109 parser.set_substitute_entities();
110 parser.parse_file(kBankFilename);
111 if ( parser )
112 {
113 vector<string> fipids = NodeParser(parser).Path("fi/prov").Select("name", bank).Path("guid").Text();
114 if ( ! fipids.back().empty() )
115 result.insert(result.end(), fipids.begin(), fipids.end());
116 }
117 parser.parse_file(kCcFilename);
118 if ( parser )
119 {
120 vector<string> fipids = NodeParser(parser).Path("fi/prov").Select("name", bank).Path("guid").Text();
121 if ( ! fipids.back().empty() )
122 result.insert(result.end(), fipids.begin(), fipids.end());
123 }
124 parser.parse_file(kInvFilename);
125 if ( parser )
126 {
127 vector<string> fipids = NodeParser(parser).Path("fi/prov").Select("name", bank).Path("guid").Text();
128 if ( ! fipids.back().empty() )
129 result.insert(result.end(), fipids.begin(), fipids.end());
130 }
131
132 // the fipid for Innovision is 1.
133 if ( bank == "Innovision" )
134 result.push_back("1");
135
136 sort(result.begin(), result.end());
137 result.erase(unique(result.begin(), result.end()), result.end());
138
139 return result;
140}
141
142OfxFiServiceInfo ServiceInfo(const std::string& fipid)
143{
144 OfxFiServiceInfo result;
145 memset(&result, 0, sizeof(OfxFiServiceInfo));
146
147 // Hard-coded values for Innovision test server
148 if ( fipid == "1" )
149 {
150 strncpy(result.fid, "00000", OFX_FID_LENGTH - 1);
151 strncpy(result.org, "ReferenceFI", OFX_ORG_LENGTH - 1);
152 strncpy(result.url, "http://ofx.innovision.com", OFX_URL_LENGTH - 1);
153 result.accountlist = 1;
154 result.statements = 1;
155 result.billpay = 1;
156 result.investments = 1;
157
158 return result;
159 }
160
161 string url = "http://moneycentral.msn.com/money/2005/mnynet/service/olsvcupd/OnlSvcBrandInfo.aspx?MSNGUID=&GUID=%1&SKU=3&VER=6";
162 url.replace(url.find("%1"), 2, fipid);
163
164 // TODO: Check whether this file exists and is recent enough before getting it again
165 string guidfile = "fipid-%1.xml";
166 guidfile.replace(guidfile.find("%1"), 2, fipid);
167
168 struct stat filestats;
169 if ( stat( guidfile.c_str(), &filestats ) || difftime(time(0), filestats.st_mtime) > 7.0 * 24.0 * 60.0 * 60.0 )
170 post("", url.c_str(), guidfile.c_str());
171
172 // Print the FI details
173 xmlpp::DomParser parser;
174 parser.set_substitute_entities();
175 parser.parse_file(guidfile);
176 if ( parser )
177 {
178 NodeParser nodes(parser);
179
180 strncpy(result.fid, nodes.Path("ProviderSettings/FID").Text().back().c_str(), OFX_FID_LENGTH - 1);
181 strncpy(result.org, nodes.Path("ProviderSettings/Org").Text().back().c_str(), OFX_ORG_LENGTH - 1);
182 strncpy(result.url, nodes.Path("ProviderSettings/ProviderURL").Text().back().c_str(), OFX_URL_LENGTH - 1);
183 result.accountlist = (nodes.Path("ProviderSettings/AcctListAvail").Text().back() == "1");
184 result.statements = (nodes.Path("BankingCapabilities/Bank").Text().back() == "1");
185 result.billpay = (nodes.Path("BillPayCapabilities/Pay").Text().back() == "1");
186 result.investments = (nodes.Path("InvestmentCapabilities/BrkStmt").Text().back() == "1");
187 }
188 return result;
189}
190
191bool post(const string& request, const string& url, const string& filename)
192{
193#if 1 //#ifdef HAVE_LIBCURL
194 CURL *curl = curl_easy_init();
195 if (! curl)
196 return false;
197
198 remove(filename.c_str());
199 FILE* file = fopen(filename.c_str(), "wb");
200 if (! file )
201 {
202 curl_easy_cleanup(curl);
203 return false;
204 }
205
206 curl_easy_setopt(curl, CURLOPT_URL, url.c_str());
207 if ( request.length() )
208 curl_easy_setopt(curl, CURLOPT_POSTFIELDS, request.c_str());
209 curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, fwrite);
210 curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *)file);
211
212 /*CURLcode res =*/
213 curl_easy_perform(curl);
214
215 curl_easy_cleanup(curl);
216
217 fclose(file);
218
219 return true;
220#else
221 request;
222 url;
223 filename;
224 cerr << "ERROR: libox must be configured with libcurl to post this request" << endl;
225 return false;
226#endif
227}
228
229} // namespace OfxPartner
230
231
232// vim:cin:si:ai:et:ts=2:sw=2:
Main header file containing the LibOfx API.
Declaration of nodeparser object, which facilitates searching for nodes in an XML file using a notati...
Methods for connecting to the OFX partner server to retrieve OFX server information.
Information returned by the OFX Partner Server about a financial institution.
Definition libofx.h:1353