ofxpartner.cpp
Go to the documentation of this file.

    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: