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 
41 using std::string;
42 using std::vector;
43 using std::cout;
44 using std::endl;
45 
46 namespace OfxPartner
47 {
48 bool post(const string& request, const string& url, const string& filename);
49 
50 const string kBankFilename = "ofx-bank-index.xml";
51 const string kCcFilename = "ofx-cc-index.xml";
52 const string kInvFilename = "ofx-inv-index.xml";
53 
54 void 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 
67 vector<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 
104 vector<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 
142 OfxFiServiceInfo 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 
191 bool 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:
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: inc/libofx.h:1352
Declaration of nodeparser object, which facilitiates searching for nodes in an XML file using a notat...