LibOFX
ofxconnect.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  ofx_connect.cpp
3  -------------------
4  copyright : (C) 2005 by Ace Jones
5  email : acejones@users.sourceforge.net
6 ***************************************************************************/
23 /***************************************************************************
24  * *
25  * This program is free software; you can redistribute it and/or modify *
26  * it under the terms of the GNU General Public License as published by *
27  * the Free Software Foundation; either version 2 of the License, or *
28  * (at your option) any later version. *
29  * *
30  ***************************************************************************/
31 #include <iostream>
32 #include <fstream>
33 #include <string>
34 #include "libofx.h"
35 #include <config.h> /* Include config constants, e.g., VERSION TF */
36 #include <stdio.h>
37 #include <stdlib.h>
38 #include <unistd.h>
39 #include <cstring>
40 #include <cstdlib>
41 #include <string.h>
42 #ifdef HAVE_LIBCURL
43 #include <curl/curl.h>
44 #endif
45 
46 #include "cmdline.h" /* Gengetopt generated parser */
47 
48 #include "nodeparser.h"
49 #include "ofxpartner.h"
50 
51 using namespace std;
52 
53 #ifdef HAVE_LIBCURL
54 bool post(const char* request, const char* url, const char* filename)
55 {
56  CURL *curl = curl_easy_init();
57  if (! curl)
58  return false;
59 
60  remove("tmpout");
61  FILE* file = fopen(filename, "wb");
62  if (! file )
63  {
64  curl_easy_cleanup(curl);
65  return false;
66  }
67 
68  curl_easy_setopt(curl, CURLOPT_URL, url);
69  curl_easy_setopt(curl, CURLOPT_POSTFIELDS, request);
70 
71  struct curl_slist *headerlist = NULL;
72  headerlist = curl_slist_append(headerlist, "Content-type: application/x-ofx");
73  headerlist = curl_slist_append(headerlist, "Accept: */*, application/x-ofx");
74 
75  curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headerlist);
76  curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, fwrite);
77  curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *)file);
78 
79  CURLcode res = curl_easy_perform(curl);
80 
81  curl_easy_cleanup(curl);
82  curl_slist_free_all (headerlist);
83 
84  fclose(file);
85 
86  return true;
87 }
88 #else
89 bool post(const char*, const char*, const char*)
90 {
91  cerr << "ERROR: libox must be configured with libcurl to post this request directly" << endl;
92  return false;
93 }
94 #endif
95 
96 ostream& operator<<(ostream& os, const vector<string>& strvect)
97 {
98  for ( vector<string>::const_iterator it = strvect.begin(); it != strvect.end(); ++it)
99  {
100  os << (*it) << endl;
101  }
102  return os;
103 }
104 
105 int main (int argc, char *argv[])
106 {
107  gengetopt_args_info args_info;
108 
109  if (cmdline_parser (argc, argv, &args_info) != 0)
110  exit(1) ;
111 
112  if ( argc == 1 )
113  {
115  exit(1);
116  }
117 
118  if ( args_info.statement_req_given || args_info.accountinfo_req_given )
119  {
120  if ( (args_info.inputs_num > 0) )
121  {
122  cout << "file " << args_info.inputs[0] << endl;
123  }
124  else
125  {
126  cerr << "ERROR: You must specify an output file" << endl;
127  exit(1);
128  }
129  }
130  else if ( args_info.bank_fipid_given || args_info.bank_services_given )
131  {
132  if ( (args_info.inputs_num > 0) )
133  {
134  cout << "bank " << args_info.inputs[0] << endl;
135  }
136  else
137  {
138  cerr << "ERROR: You must specify an bank" << endl;
139  exit(1);
140  }
141  }
142 
143  OfxFiLogin fi;
144  memset(&fi, 0, sizeof(OfxFiLogin));
145  bool ok = true;
146  string url;
147 
148  if ( args_info.statement_req_given || args_info.accountinfo_req_given || args_info.payment_req_given || args_info.paymentinquiry_req_given )
149  {
150  // Get the FI Login information
151  //
152 
153  if ( args_info.fipid_given )
154  {
155  cerr << "fipid " << args_info.fipid_arg << endl;
156  cerr << "contacting partner server..." << endl;
157  OfxFiServiceInfo svcinfo = OfxPartner::ServiceInfo(args_info.fipid_arg);
158  cout << "fid " << svcinfo.fid << endl;
159  strncpy(fi.fid, svcinfo.fid, OFX_FID_LENGTH - 1);
160  cout << "org " << svcinfo.org << endl;
161  strncpy(fi.org, svcinfo.org, OFX_ORG_LENGTH - 1);
162  cout << "url " << svcinfo.url << endl;
163  url = svcinfo.url;
164  }
165  if ( args_info.fid_given )
166  {
167  cerr << "fid " << args_info.fid_arg << endl;
168  strncpy(fi.fid, args_info.fid_arg, OFX_FID_LENGTH - 1);
169  }
170  else if ( ! args_info.fipid_given )
171  {
172  cerr << "ERROR: --fid is required" << endl;
173  ok = false;
174  }
175 
176  if ( args_info.org_given )
177  {
178  cerr << "org " << args_info.org_arg << endl;
179  strncpy(fi.org, args_info.org_arg, OFX_ORG_LENGTH - 1);
180  }
181  else if ( ! args_info.fipid_given )
182  {
183  cerr << "ERROR: --org is required" << endl;
184  ok = false;
185  }
186 
187  if ( args_info.user_given )
188  {
189  cerr << "user " << args_info.user_arg << endl;
190  strncpy(fi.userid, args_info.user_arg, OFX_USERID_LENGTH - 1);
191  }
192  else
193  {
194  cerr << "ERROR: --user is required" << endl;
195  ok = false;
196  }
197 
198  if ( args_info.pass_given )
199  {
200  cerr << "pass " << args_info.pass_arg << endl;
201  strncpy(fi.userpass, args_info.pass_arg, OFX_USERPASS_LENGTH - 1);
202  }
203  else
204  {
205  cerr << "ERROR: --pass is required" << endl;
206  ok = false;
207  }
208 
209  if ( args_info.url_given )
210  url = args_info.url_arg;
211  }
212 
213  if ( args_info.statement_req_given )
214  {
215  cerr << "Statement request" << endl;
216 
217  OfxAccountData account;
218  memset(&account, 0, sizeof(OfxAccountData));
219 
220  if ( args_info.bank_given )
221  {
222  cerr << "bank " << args_info.bank_arg << endl;
223  strncpy(account.bank_id, args_info.bank_arg, OFX_BANKID_LENGTH - 1);
224  }
225  else
226  {
227  if ( args_info.type_given && args_info.type_arg == 1 )
228  {
229  cerr << "ERROR: --bank is required for a bank request" << endl;
230  ok = false;
231  }
232  }
233 
234  if ( args_info.broker_given )
235  {
236  cerr << "broker " << args_info.broker_arg << endl;
237  strncpy(account.broker_id, args_info.broker_arg, OFX_BROKERID_LENGTH - 1);
238  }
239  else
240  {
241  if ( args_info.type_given && args_info.type_arg == 2 )
242  {
243  cerr << "ERROR: --broker is required for an investment statement request" << endl;
244  ok = false;
245  }
246  }
247 
248  if ( args_info.acct_given )
249  {
250  cerr << "acct " << args_info.acct_arg << endl;
251  strncpy(account.account_number, args_info.acct_arg, OFX_ACCTID_LENGTH - 1);
252  }
253  else
254  {
255  cerr << "ERROR: --acct is required for a statement request" << endl;
256  ok = false;
257  }
258 
259  if ( args_info.type_given )
260  {
261  cerr << "type " << args_info.type_arg << endl;
262  switch (args_info.type_arg)
263  {
264  case 1:
265  account.account_type = account.OFX_CHECKING;
266  break;
267  case 2:
268  account.account_type = account.OFX_INVESTMENT;
269  break;
270  case 3:
271  account.account_type = account.OFX_CREDITCARD ;
272  break;
273  default:
274  cerr << "ERROR: --type is not valid. Must be between 1 and 3" << endl;
275  ok = false;
276  }
277  }
278  else
279  {
280  cerr << "ERROR: --type is required for a statement request" << endl;
281  ok = false;
282  }
283 
284  if ( args_info.past_given )
285  {
286  cerr << "past " << args_info.past_arg << endl;
287  }
288  else
289  {
290  cerr << "ERROR: --past is required for a statement request" << endl;
291  ok = false;
292  }
293 
294  if ( ok )
295  {
296  char* request = libofx_request_statement( &fi, &account, time(NULL) - args_info.past_arg * 86400L );
297 
298  if ( url.length() && args_info.inputs_num > 0 )
299  post(request, url.c_str(), args_info.inputs[0]);
300  else
301  cout << request;
302 
303  free(request);
304  }
305  }
306 
307  if ( args_info.paymentinquiry_req_given )
308  {
309  char tridstr[33];
310  memset(tridstr, 0, 33);
311 
312  bool ok = true;
313 
314  if ( args_info.trid_given )
315  {
316  cerr << "trid " << args_info.trid_arg << endl;
317  snprintf(tridstr, 32, "%i", args_info.trid_arg);
318  }
319  else
320  {
321  cerr << "ERROR: --trid is required for a payment inquiry request" << endl;
322  ok = false;
323  }
324 
325  if ( ok )
326  {
327  char* request = libofx_request_payment_status( &fi, tridstr );
328 
329  filebuf fb;
330  fb.open ("query", ios::out);
331  ostream os(&fb);
332  os << request;
333  fb.close();
334 
335  if ( url.length() && args_info.inputs_num > 0 )
336  post(request, url.c_str(), args_info.inputs[0]);
337  else
338  cout << request;
339 
340  free(request);
341  }
342  }
343 
344  if ( args_info.payment_req_given )
345  {
346  OfxAccountData account;
347  memset(&account, 0, sizeof(OfxAccountData));
348  OfxPayee payee;
349  memset(&payee, 0, sizeof(OfxPayee));
350  OfxPayment payment;
351  memset(&payment, 0, sizeof(OfxPayment));
352 
353  strcpy(payee.name, "MARTIN PREUSS");
354  strcpy(payee.address1, "1 LAUREL ST");
355  strcpy(payee.city, "SAN CARLOS");
356  strcpy(payee.state, "CA");
357  strcpy(payee.postalcode, "94070");
358  strcpy(payee.phone, "866-555-1212");
359 
360  strcpy(payment.amount, "200.00");
361  strcpy(payment.account, "1234");
362  strcpy(payment.datedue, "20060301");
363  strcpy(payment.memo, "This is a test");
364 
365  bool ok = true;
366 
367  if ( args_info.bank_given )
368  {
369  cerr << "bank " << args_info.bank_arg << endl;
370  strncpy(account.bank_id, args_info.bank_arg, OFX_BANKID_LENGTH - 1);
371  }
372  else
373  {
374  if ( args_info.type_given && args_info.type_arg == 1 )
375  {
376  cerr << "ERROR: --bank is required for a bank request" << endl;
377  ok = false;
378  }
379  }
380 
381  if ( args_info.broker_given )
382  {
383  cerr << "broker " << args_info.broker_arg << endl;
384  strncpy(account.broker_id, args_info.broker_arg, OFX_BROKERID_LENGTH - 1);
385  }
386  else
387  {
388  if ( args_info.type_given && args_info.type_arg == 2 )
389  {
390  cerr << "ERROR: --broker is required for an investment statement request" << endl;
391  ok = false;
392  }
393  }
394 
395  if ( args_info.acct_given )
396  {
397  cerr << "acct " << args_info.acct_arg << endl;
398  strncpy(account.account_number, args_info.acct_arg, OFX_ACCTID_LENGTH - 1);
399  }
400  else
401  {
402  cerr << "ERROR: --acct is required for a statement request" << endl;
403  ok = false;
404  }
405 
406  if ( args_info.type_given )
407  {
408  cerr << "type " << args_info.type_arg << endl;
409  switch (args_info.type_arg)
410  {
411  case 1:
412  account.account_type = account.OFX_CHECKING;
413  break;
414  case 2:
415  account.account_type = account.OFX_INVESTMENT;
416  break;
417  case 3:
418  account.account_type = account.OFX_CREDITCARD ;
419  break;
420  default:
421  cerr << "ERROR: --type is not valid. Must be between 1 and 3" << endl;
422  ok = false;
423  }
424  }
425  else
426  {
427  cerr << "ERROR: --type is required for a statement request" << endl;
428  ok = false;
429  }
430 
431  if ( ok )
432  {
433  char* request = libofx_request_payment( &fi, &account, &payee, &payment );
434 
435  filebuf fb;
436  fb.open ("query", ios::out);
437  ostream os(&fb);
438  os << request;
439  fb.close();
440 
441  if ( url.length() && args_info.inputs_num > 0 )
442  post(request, url.c_str(), args_info.inputs[0]);
443  else
444  cout << request;
445 
446  free(request);
447  }
448 
449  }
450 
451  if ( args_info.accountinfo_req_given )
452  {
453  if ( ok )
454  {
455  char* request = libofx_request_accountinfo( &fi );
456 
457  if ( url.length() && args_info.inputs_num > 0 )
458  post(request, url.c_str(), args_info.inputs[0]);
459  else
460  cout << request;
461 
462  free(request);
463  }
464  }
465 
466  if ( args_info.bank_list_given )
467  {
468  cout << OfxPartner::BankNames();
469  }
470 
471  if ( args_info.bank_fipid_given && args_info.inputs_num > 0 )
472  {
473  cout << OfxPartner::FipidForBank(args_info.inputs[0]);
474  }
475 
476  if ( args_info.bank_services_given && args_info.inputs_num > 0 )
477  {
478  OfxFiServiceInfo svcinfo = OfxPartner::ServiceInfo(args_info.inputs[0]);
479  cout << "Account List? " << (svcinfo.accountlist ? "Yes" : "No") << endl;
480  cout << "Statements? " << (svcinfo.statements ? "Yes" : "No") << endl;
481  cout << "Billpay? " << (svcinfo.billpay ? "Yes" : "No") << endl;
482  cout << "Investments? " << (svcinfo.investments ? "Yes" : "No") << endl;
483  }
484 
485  if ( args_info.allsupport_given )
486  {
487  vector<string> banks = OfxPartner::BankNames();
488  vector<string>::const_iterator it_bank = banks.begin();
489  while ( it_bank != banks.end() )
490  {
491  vector<string> fipids = OfxPartner::FipidForBank(*it_bank);
492  vector<string>::const_iterator it_fipid = fipids.begin();
493  while ( it_fipid != fipids.end() )
494  {
495  if ( OfxPartner::ServiceInfo(*it_fipid).accountlist )
496  cout << *it_bank << endl;
497  ++it_fipid;
498  }
499  ++it_bank;
500  }
501  }
502 
503  return 0;
504 }
505 
506 
507 // vim:cin:si:ai:et:ts=2:sw=2:
508 
gengetopt_args_info::fipid_given
unsigned int fipid_given
Whether fipid was given.
Definition: ofxconnect/cmdline.h:93
gengetopt_args_info::type_arg
int type_arg
Account Type 1=checking 2=invest 3=ccard.
Definition: ofxconnect/cmdline.h:70
nodeparser.h
Declaration of nodeparser object, which facilitiates searching for nodes in an XML file using a notat...
gengetopt_args_info::user_arg
char * user_arg
User name.
Definition: ofxconnect/cmdline.h:61
gengetopt_args_info::org_given
unsigned int org_given
Whether org was given.
Definition: ofxconnect/cmdline.h:95
OfxAccountData::OFX_INVESTMENT
@ OFX_INVESTMENT
Definition: libofx.h:305
OfxFiServiceInfo::investments
int investments
Definition: libofx.h:794
gengetopt_args_info::broker_given
unsigned int broker_given
Whether broker was given.
Definition: ofxconnect/cmdline.h:97
gengetopt_args_info::org_arg
char * org_arg
FI org tag.
Definition: ofxconnect/cmdline.h:52
OfxAccountData
An abstraction of an account.
Definition: libofx.h:271
gengetopt_args_info::payment_req_given
unsigned int payment_req_given
Whether payment-req was given.
Definition: ofxconnect/cmdline.h:107
gengetopt_args_info::fid_given
unsigned int fid_given
Whether fid was given.
Definition: ofxconnect/cmdline.h:94
OfxFiServiceInfo
Information returned by the OFX Partner Server about a financial institution.
Definition: libofx.h:786
OfxPayee
Definition: libofx.h:832
gengetopt_args_info::type_given
unsigned int type_given
Whether type was given.
Definition: ofxconnect/cmdline.h:101
gengetopt_args_info::accountinfo_req_given
unsigned int accountinfo_req_given
Whether accountinfo-req was given.
Definition: ofxconnect/cmdline.h:106
OfxPayment
Definition: libofx.h:824
gengetopt_args_info::broker_arg
char * broker_arg
Broker identifier.
Definition: ofxconnect/cmdline.h:58
gengetopt_args_info::inputs
char ** inputs
unnamed options (options without names)
Definition: ofxconnect/cmdline.h:114
OfxFiServiceInfo::billpay
int billpay
Definition: libofx.h:793
OfxAccountData::bank_id
char bank_id[OFX_BANKID_LENGTH]
Definition: libofx.h:318
ofxpartner.h
Methods for connecting to the OFX partner server to retrieve OFX server information.
cmdline.h
The header file for the command line option parser generated by GNU Gengetopt version 2....
cmdline_parser_print_help
void cmdline_parser_print_help(void)
Definition: ofxconnect/cmdline.c:201
OfxFiLogin
Information sufficient to log into an financial institution.
Definition: libofx.h:806
OfxFiServiceInfo::accountlist
int accountlist
Definition: libofx.h:791
gengetopt_args_info::url_arg
char * url_arg
Url to POST the data to (otherwise goes to stdout).
Definition: ofxconnect/cmdline.h:76
gengetopt_args_info::trid_arg
int trid_arg
Transaction id.
Definition: ofxconnect/cmdline.h:79
gengetopt_args_info::bank_fipid_given
unsigned int bank_fipid_given
Whether bank-fipid was given.
Definition: ofxconnect/cmdline.h:110
operator<<
ostream & operator<<(ostream &os, SGMLApplication::CharString s)
Convert OpenSP CharString to a C++ stream.
gengetopt_args_info::bank_list_given
unsigned int bank_list_given
Whether bank-list was given.
Definition: ofxconnect/cmdline.h:109
gengetopt_args_info::trid_given
unsigned int trid_given
Whether trid was given.
Definition: ofxconnect/cmdline.h:104
libofx.h
Main header file containing the LibOfx API.
gengetopt_args_info::bank_given
unsigned int bank_given
Whether bank was given.
Definition: ofxconnect/cmdline.h:96
gengetopt_args_info::bank_services_given
unsigned int bank_services_given
Whether bank-services was given.
Definition: ofxconnect/cmdline.h:111
OfxAccountData::OFX_CREDITCARD
@ OFX_CREDITCARD
Definition: libofx.h:304
gengetopt_args_info::acct_arg
char * acct_arg
Account ID.
Definition: ofxconnect/cmdline.h:67
gengetopt_args_info::acct_given
unsigned int acct_given
Whether acct was given.
Definition: ofxconnect/cmdline.h:100
gengetopt_args_info::bank_arg
char * bank_arg
IBAN bank identifier.
Definition: ofxconnect/cmdline.h:55
gengetopt_args_info::pass_arg
char * pass_arg
Password.
Definition: ofxconnect/cmdline.h:64
libofx_request_accountinfo
char * libofx_request_accountinfo(const struct OfxFiLogin *login)
Creates an OFX account info (list) request in string form.
gengetopt_args_info::url_given
unsigned int url_given
Whether url was given.
Definition: ofxconnect/cmdline.h:103
gengetopt_args_info::pass_given
unsigned int pass_given
Whether pass was given.
Definition: ofxconnect/cmdline.h:99
OfxAccountData::account_number
char account_number[OFX_ACCTID_LENGTH]
Definition: libofx.h:314
main
int main(int argc, char *argv[])
Definition: ofxdump.cpp:434
gengetopt_args_info::past_given
unsigned int past_given
Whether past was given.
Definition: ofxconnect/cmdline.h:102
gengetopt_args_info::inputs_num
unsigned inputs_num
unnamed options number
Definition: ofxconnect/cmdline.h:115
cmdline_parser
int cmdline_parser(int argc, char **argv, struct gengetopt_args_info *args_info)
Definition: ofxconnect/cmdline.c:423
gengetopt_args_info::allsupport_given
unsigned int allsupport_given
Whether allsupport was given.
Definition: ofxconnect/cmdline.h:112
gengetopt_args_info::fipid_arg
char * fipid_arg
FI partner identifier (looks up fid, org & url from partner server).
Definition: ofxconnect/cmdline.h:46
OfxAccountData::OFX_CHECKING
@ OFX_CHECKING
Definition: libofx.h:299
gengetopt_args_info
Where the command line options are stored.
Definition: ofxconnect/cmdline.h:42
gengetopt_args_info::past_arg
long past_arg
How far back to look from today (in days).
Definition: ofxconnect/cmdline.h:73
libofx_request_statement
char * libofx_request_statement(const struct OfxFiLogin *fi, const struct OfxAccountData *account, time_t date_from)
Creates an OFX statement request in string form.
gengetopt_args_info::fid_arg
char * fid_arg
FI identifier.
Definition: ofxconnect/cmdline.h:49
gengetopt_args_info::statement_req_given
unsigned int statement_req_given
Whether statement-req was given.
Definition: ofxconnect/cmdline.h:105
gengetopt_args_info::user_given
unsigned int user_given
Whether user was given.
Definition: ofxconnect/cmdline.h:98
gengetopt_args_info::paymentinquiry_req_given
unsigned int paymentinquiry_req_given
Whether paymentinquiry-req was given.
Definition: ofxconnect/cmdline.h:108
OfxFiServiceInfo::statements
int statements
Definition: libofx.h:792