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 
50 #ifdef HAVE_LIBCURL
51 bool post(const char* request, const char* url, const char* filename)
52 {
53  CURL *curl = curl_easy_init();
54  if (! curl)
55  return false;
56 
57  remove("tmpout");
58  FILE* file = fopen(filename, "wb");
59  if (! file )
60  {
61  curl_easy_cleanup(curl);
62  return false;
63  }
64 
65  curl_easy_setopt(curl, CURLOPT_URL, url);
66  curl_easy_setopt(curl, CURLOPT_POSTFIELDS, request);
67 
68  struct curl_slist *headerlist = NULL;
69  headerlist = curl_slist_append(headerlist, "Content-type: application/x-ofx");
70  headerlist = curl_slist_append(headerlist, "Accept: */*, application/x-ofx");
71 
72  curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headerlist);
73  curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, fwrite);
74  curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *)file);
75 
76  CURLcode res = curl_easy_perform(curl);
77 
78  curl_easy_cleanup(curl);
79  curl_slist_free_all (headerlist);
80 
81  fclose(file);
82 
83  return true;
84 }
85 #else
86 bool post(const char*, const char*, const char*)
87 {
88  std::cerr << "ERROR: libox must be configured with libcurl to post this request directly" << std::endl;
89  return false;
90 }
91 #endif
92 
93 std::ostream& operator<<(std::ostream& os, const std::vector<std::string>& strvect)
94 {
95  for ( std::vector<std::string>::const_iterator it = strvect.begin(); it != strvect.end(); ++it)
96  {
97  os << (*it) << std::endl;
98  }
99  return os;
100 }
101 
102 int main (int argc, char *argv[])
103 {
104  gengetopt_args_info args_info;
105 
106  if (cmdline_parser (argc, argv, &args_info) != 0)
107  exit(1) ;
108 
109  if ( argc == 1 )
110  {
111  cmdline_parser_print_help();
112  exit(1);
113  }
114 
115  if ( args_info.statement_req_given || args_info.accountinfo_req_given )
116  {
117  if ( (args_info.inputs_num > 0) )
118  {
119  std::cout << "file " << args_info.inputs[0] << std::endl;
120  }
121  else
122  {
123  std::cerr << "ERROR: You must specify an output file" << std::endl;
124  exit(1);
125  }
126  }
127 
128  OfxFiLogin fi;
129  memset(&fi, 0, sizeof(OfxFiLogin));
130  bool ok = true;
131  std::string url;
132 
133  if ( args_info.statement_req_given || args_info.accountinfo_req_given || args_info.payment_req_given || args_info.paymentinquiry_req_given )
134  {
135  // Get the FI Login information
136  //
137 
138  if ( args_info.fid_given )
139  {
140  std::cerr << "fid " << args_info.fid_arg << std::endl;
141  strncpy(fi.fid, args_info.fid_arg, OFX_FID_LENGTH - 1);
142  }
143  else
144  {
145  std::cerr << "ERROR: --fid is required" << std::endl;
146  ok = false;
147  }
148 
149  if ( args_info.org_given )
150  {
151  std::cerr << "org " << args_info.org_arg << std::endl;
152  strncpy(fi.org, args_info.org_arg, OFX_ORG_LENGTH - 1);
153  }
154  else
155  {
156  std::cerr << "ERROR: --org is required" << std::endl;
157  ok = false;
158  }
159 
160  if ( args_info.user_given )
161  {
162  std::cerr << "user " << args_info.user_arg << std::endl;
163  strncpy(fi.userid, args_info.user_arg, OFX_USERID_LENGTH - 1);
164  }
165  else
166  {
167  std::cerr << "ERROR: --user is required" << std::endl;
168  ok = false;
169  }
170 
171  if ( args_info.pass_given )
172  {
173  std::cerr << "pass " << args_info.pass_arg << std::endl;
174  strncpy(fi.userpass, args_info.pass_arg, OFX_USERPASS_LENGTH - 1);
175  }
176  else
177  {
178  std::cerr << "ERROR: --pass is required" << std::endl;
179  ok = false;
180  }
181 
182  if ( args_info.url_given )
183  url = args_info.url_arg;
184  }
185 
186  if ( args_info.statement_req_given )
187  {
188  std::cerr << "Statement request" << std::endl;
189 
190  OfxAccountData account;
191  memset(&account, 0, sizeof(OfxAccountData));
192 
193  if ( args_info.bank_given )
194  {
195  std::cerr << "bank " << args_info.bank_arg << std::endl;
196  strncpy(account.bank_id, args_info.bank_arg, OFX_BANKID_LENGTH - 1);
197  }
198  else
199  {
200  if ( args_info.type_given && args_info.type_arg == 1 )
201  {
202  std::cerr << "ERROR: --bank is required for a bank request" << std::endl;
203  ok = false;
204  }
205  }
206 
207  if ( args_info.broker_given )
208  {
209  std::cerr << "broker " << args_info.broker_arg << std::endl;
210  strncpy(account.broker_id, args_info.broker_arg, OFX_BROKERID_LENGTH - 1);
211  }
212  else
213  {
214  if ( args_info.type_given && args_info.type_arg == 2 )
215  {
216  std::cerr << "ERROR: --broker is required for an investment statement request" << std::endl;
217  ok = false;
218  }
219  }
220 
221  if ( args_info.acct_given )
222  {
223  std::cerr << "acct " << args_info.acct_arg << std::endl;
224  strncpy(account.account_number, args_info.acct_arg, OFX_ACCTID_LENGTH - 1);
225  }
226  else
227  {
228  std::cerr << "ERROR: --acct is required for a statement request" << std::endl;
229  ok = false;
230  }
231 
232  if ( args_info.type_given )
233  {
234  std::cerr << "type " << args_info.type_arg << std::endl;
235  switch (args_info.type_arg)
236  {
237  case 1:
238  account.account_type = account.OFX_CHECKING;
239  break;
240  case 2:
241  account.account_type = account.OFX_INVESTMENT;
242  break;
243  case 3:
244  account.account_type = account.OFX_CREDITCARD ;
245  break;
246  default:
247  std::cerr << "ERROR: --type is not valid. Must be between 1 and 3" << std::endl;
248  ok = false;
249  }
250  }
251  else
252  {
253  std::cerr << "ERROR: --type is required for a statement request" << std::endl;
254  ok = false;
255  }
256 
257  if ( args_info.past_given )
258  {
259  std::cerr << "past " << args_info.past_arg << std::endl;
260  }
261  else
262  {
263  std::cerr << "ERROR: --past is required for a statement request" << std::endl;
264  ok = false;
265  }
266 
267  if ( ok )
268  {
269  char* request = libofx_request_statement( &fi, &account, time(NULL) - args_info.past_arg * 86400L );
270 
271  if ( url.length() && args_info.inputs_num > 0 )
272  post(request, url.c_str(), args_info.inputs[0]);
273  else
274  std::cout << request;
275 
276  free(request);
277  }
278  }
279 
280  if ( args_info.paymentinquiry_req_given )
281  {
282  char tridstr[33];
283  memset(tridstr, 0, 33);
284 
285  bool is_trid_given = true;
286 
287  if ( args_info.trid_given )
288  {
289  std::cerr << "trid " << args_info.trid_arg << std::endl;
290  snprintf(tridstr, 32, "%i", args_info.trid_arg);
291  }
292  else
293  {
294  std::cerr << "ERROR: --trid is required for a payment inquiry request" << std::endl;
295  is_trid_given = false;
296  }
297 
298  if ( is_trid_given )
299  {
300  char* request = libofx_request_payment_status( &fi, tridstr );
301 
302  std::filebuf fb;
303  fb.open ("query", std::ios::out);
304  std::ostream os(&fb);
305  os << request;
306  fb.close();
307 
308  if ( url.length() && args_info.inputs_num > 0 )
309  post(request, url.c_str(), args_info.inputs[0]);
310  else
311  std::cout << request;
312 
313  free(request);
314  }
315  }
316 
317  if ( args_info.payment_req_given )
318  {
319  OfxAccountData account;
320  memset(&account, 0, sizeof(OfxAccountData));
321  OfxPayee payee;
322  memset(&payee, 0, sizeof(OfxPayee));
323  OfxPayment payment;
324  memset(&payment, 0, sizeof(OfxPayment));
325 
326  strcpy(payee.name, "MARTIN PREUSS");
327  strcpy(payee.address1, "1 LAUREL ST");
328  strcpy(payee.city, "SAN CARLOS");
329  strcpy(payee.state, "CA");
330  strcpy(payee.postalcode, "94070");
331  strcpy(payee.phone, "866-555-1212");
332 
333  strcpy(payment.amount, "200.00");
334  strcpy(payment.account, "1234");
335  strcpy(payment.datedue, "20060301");
336  strcpy(payment.memo, "This is a test");
337 
338  bool is_payment_args_given = true;
339 
340  if ( args_info.bank_given )
341  {
342  std::cerr << "bank " << args_info.bank_arg << std::endl;
343  strncpy(account.bank_id, args_info.bank_arg, OFX_BANKID_LENGTH - 1);
344  }
345  else
346  {
347  if ( args_info.type_given && args_info.type_arg == 1 )
348  {
349  std::cerr << "ERROR: --bank is required for a bank request" << std::endl;
350  is_payment_args_given = false;
351  }
352  }
353 
354  if ( args_info.broker_given )
355  {
356  std::cerr << "broker " << args_info.broker_arg << std::endl;
357  strncpy(account.broker_id, args_info.broker_arg, OFX_BROKERID_LENGTH - 1);
358  }
359  else
360  {
361  if ( args_info.type_given && args_info.type_arg == 2 )
362  {
363  std::cerr << "ERROR: --broker is required for an investment statement request" << std::endl;
364  is_payment_args_given = false;
365  }
366  }
367 
368  if ( args_info.acct_given )
369  {
370  std::cerr << "acct " << args_info.acct_arg << std::endl;
371  strncpy(account.account_number, args_info.acct_arg, OFX_ACCTID_LENGTH - 1);
372  }
373  else
374  {
375  std::cerr << "ERROR: --acct is required for a statement request" << std::endl;
376  is_payment_args_given = false;
377  }
378 
379  if ( args_info.type_given )
380  {
381  std::cerr << "type " << args_info.type_arg << std::endl;
382  switch (args_info.type_arg)
383  {
384  case 1:
385  account.account_type = account.OFX_CHECKING;
386  break;
387  case 2:
388  account.account_type = account.OFX_INVESTMENT;
389  break;
390  case 3:
391  account.account_type = account.OFX_CREDITCARD ;
392  break;
393  default:
394  std::cerr << "ERROR: --type is not valid. Must be between 1 and 3" << std::endl;
395  ok = false;
396  }
397  }
398  else
399  {
400  std::cerr << "ERROR: --type is required for a statement request" << std::endl;
401  is_payment_args_given = false;
402  }
403 
404  if ( is_payment_args_given )
405  {
406  char* request = libofx_request_payment( &fi, &account, &payee, &payment );
407 
408  std::filebuf fb;
409  fb.open ("query", std::ios::out);
410  std::ostream os(&fb);
411  os << request;
412  fb.close();
413 
414  if ( url.length() && args_info.inputs_num > 0 )
415  post(request, url.c_str(), args_info.inputs[0]);
416  else
417  std::cout << request;
418 
419  free(request);
420  }
421 
422  }
423 
424  if ( args_info.accountinfo_req_given )
425  {
426  if ( ok )
427  {
428  char* request = libofx_request_accountinfo( &fi );
429 
430  if ( url.length() && args_info.inputs_num > 0 )
431  post(request, url.c_str(), args_info.inputs[0]);
432  else
433  std::cout << request;
434 
435  free(request);
436  }
437  }
438 
439  return 0;
440 }
441 
442 
443 // vim:cin:si:ai:et:ts=2:sw=2:
444 
unsigned int org_given
Whether org was given.
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.
unsigned int type_given
Whether type was given.
char * fid_arg
FI identifier.
unsigned int bank_given
Whether bank was given.
char * url_arg
Url to POST the data to (otherwise goes to stdout).
unsigned int url_given
Whether url was given.
char * acct_arg
Account ID.
char * user_arg
User name.
unsigned int pass_given
Whether pass was given.
unsigned inputs_num
unnamed options number
int trid_arg
Transaction id.
unsigned int statement_req_given
Whether statement-req was given.
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:1143
char ** inputs
unnamed options (options without names)
Declaration of nodeparser object, which facilitates searching for nodes in an XML file using a notati...
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.