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  {
114  cmdline_parser_print_help();
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 
unsigned int allsupport_given
Whether allsupport was given.
unsigned int org_given
Whether org was given.
An abstraction of an account.
Definition: inc/libofx.h:276
long past_arg
How far back to look from today (in days).
unsigned int payment_req_given
Whether payment-req was given.
unsigned int fid_given
Whether fid was given.
Where the command line options are stored.
char * libofx_request_statement(const struct OfxFiLogin *fi, const struct OfxAccountData *account, time_t date_from)
Creates an OFX statement request in string form.
unsigned int type_given
Whether type was given.
char * fid_arg
FI identifier.
unsigned int bank_given
Whether bank was given.
unsigned int bank_fipid_given
Whether bank-fipid was given.
Methods for connecting to the OFX partner server to retrieve OFX server information.
char * libofx_request_accountinfo(const struct OfxFiLogin *login)
Creates an OFX account info (list) request in string form.
char * url_arg
Url to POST the data to (otherwise goes to stdout).
unsigned int bank_services_given
Whether bank-services was given.
char * fipid_arg
FI partner identifier (looks up fid, org & url from partner server).
unsigned int url_given
Whether url was given.
char bank_id[OFX_BANKID_LENGTH]
Definition: inc/libofx.h:324
unsigned int fipid_given
Whether fipid was given.
char * acct_arg
Account ID.
char * user_arg
User name.
unsigned int bank_list_given
Whether bank-list was given.
unsigned int pass_given
Whether pass was given.
unsigned inputs_num
unamed options number
int trid_arg
Transaction id.
unsigned int statement_req_given
Whether statement-req was given.
Information returned by the OFX Partner Server about a financial institution.
Definition: inc/libofx.h:1352
unsigned int trid_given
Whether trid was given.
unsigned int past_given
Whether past was given.
unsigned int acct_given
Whether acct was given.
int main(int argc, char *argv[])
Definition: ofxdump.cpp:1146
char ** inputs
unamed options (options without names)
char account_number[OFX_ACCTID_LENGTH]
Definition: inc/libofx.h:320
Declaration of nodeparser object, which facilitiates searching for nodes in an XML file using a notat...
unsigned int user_given
Whether user was given.
unsigned int paymentinquiry_req_given
Whether paymentinquiry-req was given.
unsigned int accountinfo_req_given
Whether accountinfo-req was given.
char * bank_arg
IBAN bank identifier.
unsigned int broker_given
Whether broker was given.
char * org_arg
FI org tag.
char * broker_arg
Broker identifier.
int type_arg
Account Type 1=checking 2=invest 3=ccard.
char * pass_arg
Password.
Information sufficient to log into an financial institution.
Definition: inc/libofx.h:1372