LibOFX
|
00001 /*************************************************************************** 00002 ofx_partner.cpp 00003 ------------------- 00004 copyright : (C) 2005 by Ace Jones 00005 email : acejones@users.sourceforge.net 00006 ***************************************************************************/ 00011 /*************************************************************************** 00012 * * 00013 * This program is free software; you can redistribute it and/or modify * 00014 * it under the terms of the GNU General Public License as published by * 00015 * the Free Software Foundation; either version 2 of the License, or * 00016 * (at your option) any later version. * 00017 * * 00018 ***************************************************************************/ 00019 00020 #ifdef HAVE_CONFIG_H 00021 #include <config.h> 00022 #endif 00023 00024 #include <libofx.h> 00025 00026 //#ifdef HAVE_LIBCURL 00027 #include <curl/curl.h> 00028 //#endif 00029 00030 #include "ofxpartner.h" 00031 #include "nodeparser.h" 00032 00033 #include <sys/stat.h> 00034 00035 #include <iostream> 00036 #include <string> 00037 #include <vector> 00038 #include <algorithm> 00039 #include <string.h> 00040 00041 using std::string; 00042 using std::vector; 00043 using std::cout; 00044 using std::endl; 00045 00046 namespace OfxPartner 00047 { 00048 bool post(const string& request, const string& url, const string& filename); 00049 00050 const string kBankFilename = "ofx-bank-index.xml"; 00051 const string kCcFilename = "ofx-cc-index.xml"; 00052 const string kInvFilename = "ofx-inv-index.xml"; 00053 00054 void ValidateIndexCache(void) 00055 { 00056 // TODO Check whether these files exist and are recent enough before getting them again 00057 00058 struct stat filestats; 00059 if ( stat( kBankFilename.c_str(), &filestats ) || difftime(time(0),filestats.st_mtime) > 7.0*24.0*60.0*60.0 ) 00060 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); 00061 if ( stat( kCcFilename.c_str(), &filestats ) || difftime(time(0),filestats.st_mtime) > 7.0*24.0*60.0*60.0 ) 00062 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); 00063 if ( stat( kInvFilename.c_str(), &filestats ) || difftime(time(0),filestats.st_mtime) > 7.0*24.0*60.0*60.0 ) 00064 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); 00065 } 00066 00067 vector<string> BankNames(void) 00068 { 00069 vector<string> result; 00070 00071 // Make sure the index files are up to date 00072 ValidateIndexCache(); 00073 00074 xmlpp::DomParser parser; 00075 parser.set_substitute_entities(); 00076 parser.parse_file(kBankFilename); 00077 if ( parser ) 00078 { 00079 vector<string> names = NodeParser(parser).Path("fi/prov/name").Text(); 00080 result.insert(result.end(),names.begin(),names.end()); 00081 } 00082 parser.parse_file(kCcFilename); 00083 if ( parser ) 00084 { 00085 vector<string> names = NodeParser(parser).Path("fi/prov/name").Text(); 00086 result.insert(result.end(),names.begin(),names.end()); 00087 } 00088 parser.parse_file(kInvFilename); 00089 if ( parser ) 00090 { 00091 vector<string> names = NodeParser(parser).Path("fi/prov/name").Text(); 00092 result.insert(result.end(),names.begin(),names.end()); 00093 } 00094 00095 // Add Innovision 00096 result.push_back("Innovision"); 00097 00098 // sort the list and remove duplicates, to return one unified list of all supported banks 00099 sort(result.begin(),result.end()); 00100 result.erase(unique(result.begin(),result.end()),result.end()); 00101 return result; 00102 } 00103 00104 vector<string> FipidForBank(const string& bank) 00105 { 00106 vector<string> result; 00107 00108 xmlpp::DomParser parser; 00109 parser.set_substitute_entities(); 00110 parser.parse_file(kBankFilename); 00111 if ( parser ) 00112 { 00113 vector<string> fipids = NodeParser(parser).Path("fi/prov").Select("name",bank).Path("guid").Text(); 00114 if ( ! fipids.back().empty() ) 00115 result.insert(result.end(),fipids.begin(),fipids.end()); 00116 } 00117 parser.parse_file(kCcFilename); 00118 if ( parser ) 00119 { 00120 vector<string> fipids = NodeParser(parser).Path("fi/prov").Select("name",bank).Path("guid").Text(); 00121 if ( ! fipids.back().empty() ) 00122 result.insert(result.end(),fipids.begin(),fipids.end()); 00123 } 00124 parser.parse_file(kInvFilename); 00125 if ( parser ) 00126 { 00127 vector<string> fipids = NodeParser(parser).Path("fi/prov").Select("name",bank).Path("guid").Text(); 00128 if ( ! fipids.back().empty() ) 00129 result.insert(result.end(),fipids.begin(),fipids.end()); 00130 } 00131 00132 // the fipid for Innovision is 1. 00133 if ( bank == "Innovision" ) 00134 result.push_back("1"); 00135 00136 sort(result.begin(),result.end()); 00137 result.erase(unique(result.begin(),result.end()),result.end()); 00138 00139 return result; 00140 } 00141 00142 OfxFiServiceInfo ServiceInfo(const std::string& fipid) 00143 { 00144 OfxFiServiceInfo result; 00145 memset(&result,0,sizeof(OfxFiServiceInfo)); 00146 00147 // Hard-coded values for Innovision test server 00148 if ( fipid == "1" ) 00149 { 00150 strncpy(result.fid,"00000",OFX_FID_LENGTH-1); 00151 strncpy(result.org,"ReferenceFI",OFX_ORG_LENGTH-1); 00152 strncpy(result.url,"http://ofx.innovision.com",OFX_URL_LENGTH-1); 00153 result.accountlist = 1; 00154 result.statements = 1; 00155 result.billpay = 1; 00156 result.investments = 1; 00157 00158 return result; 00159 } 00160 00161 string url = "http://moneycentral.msn.com/money/2005/mnynet/service/olsvcupd/OnlSvcBrandInfo.aspx?MSNGUID=&GUID=%1&SKU=3&VER=6"; 00162 url.replace(url.find("%1"),2,fipid); 00163 00164 // TODO: Check whether this file exists and is recent enough before getting it again 00165 string guidfile = "fipid-%1.xml"; 00166 guidfile.replace(guidfile.find("%1"),2,fipid); 00167 00168 struct stat filestats; 00169 if ( stat( guidfile.c_str(), &filestats ) || difftime(time(0),filestats.st_mtime) > 7.0*24.0*60.0*60.0 ) 00170 post("",url.c_str(),guidfile.c_str()); 00171 00172 // Print the FI details 00173 xmlpp::DomParser parser; 00174 parser.set_substitute_entities(); 00175 parser.parse_file(guidfile); 00176 if ( parser ) 00177 { 00178 NodeParser nodes(parser); 00179 00180 strncpy(result.fid,nodes.Path("ProviderSettings/FID").Text().back().c_str(),OFX_FID_LENGTH-1); 00181 strncpy(result.org,nodes.Path("ProviderSettings/Org").Text().back().c_str(),OFX_ORG_LENGTH-1); 00182 strncpy(result.url,nodes.Path("ProviderSettings/ProviderURL").Text().back().c_str(),OFX_URL_LENGTH-1); 00183 result.accountlist = (nodes.Path("ProviderSettings/AcctListAvail").Text().back() == "1"); 00184 result.statements = (nodes.Path("BankingCapabilities/Bank").Text().back() == "1"); 00185 result.billpay = (nodes.Path("BillPayCapabilities/Pay").Text().back() == "1"); 00186 result.investments = (nodes.Path("InvestmentCapabilities/BrkStmt").Text().back() == "1"); 00187 } 00188 return result; 00189 } 00190 00191 bool post(const string& request, const string& url, const string& filename) 00192 { 00193 #if 1 //#ifdef HAVE_LIBCURL 00194 CURL *curl = curl_easy_init(); 00195 if(! curl) 00196 return false; 00197 00198 unlink(filename.c_str()); 00199 FILE* file = fopen(filename.c_str(),"wb"); 00200 if (! file ) 00201 { 00202 curl_easy_cleanup(curl); 00203 return false; 00204 } 00205 00206 curl_easy_setopt(curl, CURLOPT_URL, url.c_str()); 00207 if ( request.length() ) 00208 curl_easy_setopt(curl, CURLOPT_POSTFIELDS, request.c_str()); 00209 curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, fwrite); 00210 curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *)file); 00211 00212 /*CURLcode res =*/ curl_easy_perform(curl); 00213 00214 curl_easy_cleanup(curl); 00215 00216 fclose(file); 00217 00218 return true; 00219 #else 00220 request; url; filename; 00221 cerr << "ERROR: libox must be configured with libcurl to post this request" << endl; 00222 return false; 00223 #endif 00224 } 00225 00226 } // namespace OfxPartner 00227 00228 00229 // vim:cin:si:ai:et:ts=2:sw=2: