LibOFX

ofxconnect.cpp

Go to the documentation of this file.
00001 /***************************************************************************
00002          ofx_connect.cpp 
00003                              -------------------
00004     copyright            : (C) 2005 by Ace Jones
00005     email                : acejones@users.sourceforge.net
00006 ***************************************************************************/
00023 /***************************************************************************
00024  *                                                                         *
00025  *   This program is free software; you can redistribute it and/or modify  *
00026  *   it under the terms of the GNU General Public License as published by  *
00027  *   the Free Software Foundation; either version 2 of the License, or     *
00028  *   (at your option) any later version.                                   *
00029  *                                                                         *
00030  ***************************************************************************/
00031 #include <iostream>
00032 #include <fstream>
00033 #include <string>
00034 #include "libofx.h"
00035 #include <config.h>             /* Include config constants, e.g., VERSION TF */
00036 #include <stdio.h>
00037 #include <stdlib.h>
00038 #include <unistd.h>
00039 #include <cstring>
00040 #include <cstdlib>
00041 #include <string.h>
00042 #ifdef HAVE_LIBCURL
00043 #include <curl/curl.h>
00044 #endif
00045 
00046 #include "cmdline.h" /* Gengetopt generated parser */
00047 
00048 #include "nodeparser.h"
00049 #include "ofxpartner.h"
00050 
00051 using namespace std;
00052 
00053 #ifdef HAVE_LIBCURL
00054 bool post(const char* request, const char* url, const char* filename)
00055 {
00056   CURL *curl = curl_easy_init();
00057   if(! curl)
00058     return false;
00059 
00060   unlink("tmpout");  
00061   FILE* file = fopen(filename,"wb");
00062   if (! file )
00063   {
00064     curl_easy_cleanup(curl);
00065     return false;
00066   }
00067     
00068   curl_easy_setopt(curl, CURLOPT_URL, url);
00069   curl_easy_setopt(curl, CURLOPT_POSTFIELDS, request);
00070 
00071   struct curl_slist *headerlist=NULL;
00072   headerlist=curl_slist_append(headerlist, "Content-type: application/x-ofx");
00073   headerlist=curl_slist_append(headerlist, "Accept: */*, application/x-ofx");    
00074   
00075   curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headerlist);
00076   curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, fwrite);
00077   curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *)file);
00078     
00079   CURLcode res = curl_easy_perform(curl);
00080 
00081   curl_easy_cleanup(curl);
00082   curl_slist_free_all (headerlist);
00083   
00084   fclose(file);
00085   
00086   return true;
00087 }
00088 #else
00089 bool post(const char*, const char*, const char*)
00090 {
00091   cerr << "ERROR: libox must be configured with libcurl to post this request directly" << endl;
00092   return false;
00093 }
00094 #endif
00095 
00096 ostream& operator<<(ostream& os,const vector<string>& strvect)
00097 {
00098   for( vector<string>::const_iterator it=strvect.begin(); it!=strvect.end(); ++it)
00099   {
00100     os << (*it) << endl;
00101   }
00102   return os;
00103 }
00104 
00105 int main (int argc, char *argv[])
00106 {
00107   gengetopt_args_info args_info;
00108   
00109   if (cmdline_parser (argc, argv, &args_info) != 0)
00110     exit(1) ;
00111 
00112   if ( argc == 1 )
00113   {
00114     cmdline_parser_print_help();
00115     exit(1);
00116   }
00117 
00118   if ( args_info.statement_req_given || args_info.accountinfo_req_given )
00119   {
00120   if ( (args_info.inputs_num > 0) )
00121   {
00122     cout << "file " << args_info.inputs[0] << endl;
00123   }
00124   else
00125   {
00126     cerr << "ERROR: You must specify an output file" << endl;
00127   }
00128   }
00129   else if ( args_info.bank_fipid_given || args_info.bank_services_given )
00130   {
00131   if ( (args_info.inputs_num > 0) )
00132   {
00133     cout << "bank " << args_info.inputs[0] << endl;
00134   }
00135   else
00136   {
00137     cerr << "ERROR: You must specify an bank" << endl;
00138   }
00139   }
00140  
00141   OfxFiLogin fi;
00142   memset(&fi,0,sizeof(OfxFiLogin));
00143   bool ok = true;
00144   string url;
00145  
00146   if ( args_info.statement_req_given || args_info.accountinfo_req_given || args_info.payment_req_given || args_info.paymentinquiry_req_given )
00147   {
00148   // Get the FI Login information
00149   // 
00150  
00151   if ( args_info.fipid_given )
00152   {
00153     cerr << "fipid " <<  args_info.fipid_arg << endl;  
00154     cerr << "contacting partner server..." << endl;
00155     OfxFiServiceInfo svcinfo = OfxPartner::ServiceInfo(args_info.fipid_arg);
00156     cout << "fid " << svcinfo.fid << endl;
00157     strncpy(fi.fid,svcinfo.fid,OFX_FID_LENGTH-1);
00158     cout << "org " << svcinfo.org << endl;
00159     strncpy(fi.org,svcinfo.org,OFX_ORG_LENGTH-1);
00160     cout << "url " << svcinfo.url << endl;
00161     url = svcinfo.url;
00162   }
00163   if ( args_info.fid_given )
00164   {
00165     cerr << "fid " <<  args_info.fid_arg << endl;  
00166     strncpy(fi.fid,args_info.fid_arg,OFX_FID_LENGTH-1);
00167   }
00168   else if ( ! args_info.fipid_given )
00169   {
00170     cerr << "ERROR: --fid is required" << endl;
00171     ok = false;
00172   }
00173   
00174   if ( args_info.org_given )
00175   {
00176     cerr << "org " << args_info.org_arg << endl;  
00177     strncpy(fi.org,args_info.org_arg,OFX_ORG_LENGTH-1);
00178   }
00179   else if ( ! args_info.fipid_given )
00180   {
00181     cerr << "ERROR: --org is required" << endl;
00182     ok = false;
00183   }
00184 
00185   if ( args_info.user_given )
00186   {
00187     cerr << "user " << args_info.user_arg << endl;  
00188     strncpy(fi.userid,args_info.user_arg,OFX_USERID_LENGTH-1);
00189   }
00190   else
00191   {
00192     cerr << "ERROR: --user is required" << endl;
00193     ok = false;
00194   }
00195   
00196   if ( args_info.pass_given )
00197   {
00198     cerr << "pass " << args_info.pass_arg << endl;  
00199     strncpy(fi.userpass,args_info.pass_arg,OFX_USERPASS_LENGTH-1);
00200   }
00201   else
00202   {
00203     cerr << "ERROR: --pass is required" << endl;
00204     ok = false;
00205   }
00206   
00207   if ( args_info.url_given )
00208     url = args_info.url_arg;
00209   }
00210   
00211   if ( args_info.statement_req_given )
00212   {
00213     cerr << "Statement request" << endl;
00214     
00215     OfxAccountData account;
00216     memset(&account,0,sizeof(OfxAccountData));
00217     
00218     if ( args_info.bank_given )
00219     {
00220       cerr << "bank " << args_info.bank_arg << endl;  
00221       strncpy(account.bank_id,args_info.bank_arg,OFX_BANKID_LENGTH-1);
00222     }
00223     else    
00224     {
00225       if ( args_info.type_given && args_info.type_arg == 1 )
00226       {
00227         cerr << "ERROR: --bank is required for a bank request" << endl;
00228         ok = false;
00229       }
00230     }
00231     
00232     if ( args_info.broker_given )
00233     {
00234       cerr << "broker " << args_info.broker_arg << endl;  
00235       strncpy(account.broker_id,args_info.broker_arg,OFX_BROKERID_LENGTH-1);
00236     }
00237     else
00238     {
00239       if ( args_info.type_given && args_info.type_arg == 2 )
00240       {
00241         cerr << "ERROR: --broker is required for an investment statement request" << endl;
00242         ok = false;
00243       }
00244     }
00245     
00246     if ( args_info.acct_given )
00247     {
00248       cerr << "acct " << args_info.acct_arg << endl;  
00249       strncpy(account.account_number,args_info.acct_arg,OFX_ACCTID_LENGTH-1);
00250     }
00251     else
00252     {
00253       cerr << "ERROR: --acct is required for a statement request" << endl;
00254       ok = false;
00255     }
00256     
00257     if ( args_info.type_given )
00258     {
00259       cerr << "type " << args_info.type_arg << endl;
00260       switch (args_info.type_arg) {
00261       case 1: account.account_type = account.OFX_CHECKING;
00262         break;
00263       case 2: account.account_type = account.OFX_INVESTMENT;
00264         break;
00265       case 3: account.account_type = account.OFX_CREDITCARD ;
00266         break;
00267       default:
00268         cerr << "ERROR: --type is not valid.  Must be between 1 and 3" << endl;
00269         ok = false;
00270       }
00271     }
00272     else
00273     {
00274       cerr << "ERROR: --type is required for a statement request" << endl;
00275       ok = false;
00276     }
00277     
00278     if ( args_info.past_given )
00279     {
00280       cerr << "past " << args_info.past_arg << endl;  
00281     }
00282     else
00283     {
00284       cerr << "ERROR: --past is required for a statement request" << endl;
00285       ok = false;
00286     }
00287     
00288     if ( ok )
00289     {
00290       char* request = libofx_request_statement( &fi, &account, time(NULL) - args_info.past_arg * 86400L );
00291     
00292       if ( url.length() ) 
00293         post(request,url.c_str(),args_info.inputs[0]);
00294       else
00295         cout << request;
00296       
00297       free(request);
00298     }
00299   }
00300 
00301   if ( args_info.paymentinquiry_req_given )
00302   {
00303     char tridstr[33];
00304     memset(tridstr,0,33);
00305 
00306     bool ok = true;
00307 
00308     if ( args_info.trid_given )
00309     {
00310       cerr << "trid " << args_info.trid_arg << endl;  
00311       snprintf(tridstr,32,"%i",args_info.trid_arg);
00312     }
00313     else
00314     {
00315       cerr << "ERROR: --trid is required for a payment inquiry request" << endl;
00316       ok = false;
00317     }
00318  
00319     if ( ok )
00320     {
00321       char* request = libofx_request_payment_status( &fi, tridstr );
00322  
00323       filebuf fb;
00324       fb.open ("query",ios::out);
00325       ostream os(&fb);
00326       os << request;
00327       fb.close();
00328       
00329       if ( url.length() ) 
00330         post(request,url.c_str(),args_info.inputs[0]);
00331       else
00332         cout << request;
00333     
00334       free(request);
00335     }
00336   }
00337   
00338   if ( args_info.payment_req_given )
00339   {
00340     OfxAccountData account;
00341     memset(&account,0,sizeof(OfxAccountData));
00342     OfxPayee payee;
00343     memset(&payee,0,sizeof(OfxPayee));
00344     OfxPayment payment;
00345     memset(&payment,0,sizeof(OfxPayment));
00346 
00347     strcpy(payee.name,"MARTIN PREUSS");
00348     strcpy(payee.address1,"1 LAUREL ST");
00349     strcpy(payee.city,"SAN CARLOS");
00350     strcpy(payee.state,"CA");
00351     strcpy(payee.postalcode,"94070");
00352     strcpy(payee.phone,"866-555-1212");
00353         
00354     strcpy(payment.amount,"200.00");
00355     strcpy(payment.account,"1234");
00356     strcpy(payment.datedue,"20060301");
00357     strcpy(payment.memo,"This is a test");
00358 
00359     bool ok = true;
00360 
00361     if ( args_info.bank_given )
00362     {
00363       cerr << "bank " << args_info.bank_arg << endl;  
00364       strncpy(account.bank_id,args_info.bank_arg,OFX_BANKID_LENGTH-1);
00365     }
00366     else    
00367     {
00368       if ( args_info.type_given && args_info.type_arg == 1 )
00369       {
00370         cerr << "ERROR: --bank is required for a bank request" << endl;
00371         ok = false;
00372       }
00373     }
00374     
00375     if ( args_info.broker_given )
00376     {
00377       cerr << "broker " << args_info.broker_arg << endl;  
00378       strncpy(account.broker_id,args_info.broker_arg,OFX_BROKERID_LENGTH-1);
00379     }
00380     else
00381     {
00382       if ( args_info.type_given && args_info.type_arg == 2 )
00383       {
00384         cerr << "ERROR: --broker is required for an investment statement request" << endl;
00385         ok = false;
00386       }
00387     }
00388     
00389     if ( args_info.acct_given )
00390     {
00391       cerr << "acct " << args_info.acct_arg << endl;  
00392       strncpy(account.account_number,args_info.acct_arg,OFX_ACCTID_LENGTH-1);
00393     }
00394     else
00395     {
00396       cerr << "ERROR: --acct is required for a statement request" << endl;
00397       ok = false;
00398     }
00399     
00400     if ( args_info.type_given )
00401     { 
00402       cerr << "type " << args_info.type_arg << endl;
00403       switch (args_info.type_arg) {
00404       case 1: account.account_type = account.OFX_CHECKING;
00405         break;
00406       case 2: account.account_type = account.OFX_INVESTMENT;
00407         break;
00408       case 3: account.account_type = account.OFX_CREDITCARD ;
00409         break;
00410       default:
00411         cerr << "ERROR: --type is not valid.  Must be between 1 and 3" << endl;
00412         ok = false;
00413       }
00414     }
00415     else
00416     {
00417       cerr << "ERROR: --type is required for a statement request" << endl;
00418       ok = false;
00419     }
00420     
00421     if ( ok )
00422     {
00423       char* request = libofx_request_payment( &fi, &account, &payee, &payment );
00424     
00425       filebuf fb;
00426       fb.open ("query",ios::out);
00427       ostream os(&fb);
00428       os << request;
00429       fb.close();
00430       
00431       if ( url.length() ) 
00432         post(request,url.c_str(),args_info.inputs[0]);
00433       else
00434         cout << request;
00435     
00436       free(request);
00437     }
00438         
00439   }
00440   
00441   if ( args_info.accountinfo_req_given )
00442   {
00443     if ( ok )
00444     {
00445       char* request = libofx_request_accountinfo( &fi );
00446     
00447       if ( url.length() ) 
00448         post(request,url.c_str(),args_info.inputs[0]);
00449       else
00450         cout << request;
00451     
00452       free(request);
00453     }
00454   }
00455         
00456   if ( args_info.bank_list_given )
00457   {
00458     cout << OfxPartner::BankNames();
00459   }
00460   
00461   if ( args_info.bank_fipid_given )
00462   {
00463     cout << OfxPartner::FipidForBank(args_info.inputs[0]);
00464   }
00465   
00466   if ( args_info.bank_services_given )
00467   {
00468     OfxFiServiceInfo svcinfo = OfxPartner::ServiceInfo(args_info.inputs[0]);
00469     cout << "Account List? " << (svcinfo.accountlist?"Yes":"No") << endl;
00470     cout << "Statements? " << (svcinfo.statements?"Yes":"No") << endl;
00471     cout << "Billpay? " << (svcinfo.billpay?"Yes":"No") << endl;
00472     cout << "Investments? " << (svcinfo.investments?"Yes":"No") << endl;
00473   }
00474  
00475   if ( args_info.allsupport_given )
00476   {
00477     vector<string> banks = OfxPartner::BankNames();
00478     vector<string>::const_iterator it_bank = banks.begin();
00479     while ( it_bank != banks.end() )
00480     {
00481       vector<string> fipids = OfxPartner::FipidForBank(*it_bank);
00482       vector<string>::const_iterator it_fipid = fipids.begin();
00483       while ( it_fipid != fipids.end() )
00484       {
00485         if ( OfxPartner::ServiceInfo(*it_fipid).accountlist )
00486           cout << *it_bank << endl;
00487         ++it_fipid;
00488       }
00489       ++it_bank;
00490     }
00491   }
00492   
00493   return 0;
00494 }
00495 
00496 
00497 // vim:cin:si:ai:et:ts=2:sw=2:
00498