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