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
gengetopt_args_info::allsupport_given
unsigned int allsupport_given
Whether allsupport was given.
Definition: ofxconnect/cmdline.h:112
gengetopt_args_info::org_given
unsigned int org_given
Whether org was given.
Definition: ofxconnect/cmdline.h:95
OfxAccountData
An abstraction of an account.
Definition: inc/libofx.h:271
OfxPayee
Definition: inc/libofx.h:832
gengetopt_args_info::past_arg
long past_arg
How far back to look from today (in days).
Definition: ofxconnect/cmdline.h:73
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
gengetopt_args_info
Where the command line options are stored.
Definition: ofxconnect/cmdline.h:42
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::type_given
unsigned int type_given
Whether type was given.
Definition: ofxconnect/cmdline.h:101
OfxFiServiceInfo::accountlist
int accountlist
Definition: inc/libofx.h:791
gengetopt_args_info::fid_arg
char * fid_arg
FI identifier.
Definition: ofxconnect/cmdline.h:49
gengetopt_args_info::bank_given
unsigned int bank_given
Whether bank was given.
Definition: ofxconnect/cmdline.h:96
OfxAccountData::OFX_CREDITCARD
Definition: inc/libofx.h:304
std
OfxFiServiceInfo::investments
int investments
Definition: inc/libofx.h:794
gengetopt_args_info::bank_fipid_given
unsigned int bank_fipid_given
Whether bank-fipid was given.
Definition: ofxconnect/cmdline.h:110
ofxpartner.h
Methods for connecting to the OFX partner server to retrieve OFX server information.
OfxFiServiceInfo::billpay
int billpay
Definition: inc/libofx.h:793
libofx_request_accountinfo
char * libofx_request_accountinfo(const struct OfxFiLogin *login)
Creates an OFX account info (list) request in string form.
OfxPayment
Definition: inc/libofx.h:824
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::bank_services_given
unsigned int bank_services_given
Whether bank-services was given.
Definition: ofxconnect/cmdline.h:111
gengetopt_args_info::fipid_arg
char * fipid_arg
FI partner identifier (looks up fid, org & url from partner server).
Definition: ofxconnect/cmdline.h:46
gengetopt_args_info::url_given
unsigned int url_given
Whether url was given.
Definition: ofxconnect/cmdline.h:103
OfxAccountData::bank_id
char bank_id[OFX_BANKID_LENGTH]
Definition: inc/libofx.h:318
gengetopt_args_info::fipid_given
unsigned int fipid_given
Whether fipid was given.
Definition: ofxconnect/cmdline.h:93
gengetopt_args_info::acct_arg
char * acct_arg
Account ID.
Definition: ofxconnect/cmdline.h:67
gengetopt_args_info::user_arg
char * user_arg
User name.
Definition: ofxconnect/cmdline.h:61
gengetopt_args_info::bank_list_given
unsigned int bank_list_given
Whether bank-list was given.
Definition: ofxconnect/cmdline.h:109
gengetopt_args_info::pass_given
unsigned int pass_given
Whether pass was given.
Definition: ofxconnect/cmdline.h:99
gengetopt_args_info::inputs_num
unsigned inputs_num
unamed options number
Definition: ofxconnect/cmdline.h:115
gengetopt_args_info::trid_arg
int trid_arg
Transaction id.
Definition: ofxconnect/cmdline.h:79
gengetopt_args_info::statement_req_given
unsigned int statement_req_given
Whether statement-req was given.
Definition: ofxconnect/cmdline.h:105
OfxFiServiceInfo
Information returned by the OFX Partner Server about a financial institution.
Definition: inc/libofx.h:786
gengetopt_args_info::trid_given
unsigned int trid_given
Whether trid was given.
Definition: ofxconnect/cmdline.h:104
gengetopt_args_info::past_given
unsigned int past_given
Whether past was given.
Definition: ofxconnect/cmdline.h:102
gengetopt_args_info::acct_given
unsigned int acct_given
Whether acct was given.
Definition: ofxconnect/cmdline.h:100
main
int main(int argc, char *argv[])
Definition: ofxdump.cpp:434
gengetopt_args_info::inputs
char ** inputs
unamed options (options without names)
Definition: ofxconnect/cmdline.h:114
OfxAccountData::account_number
char account_number[OFX_ACCTID_LENGTH]
Definition: inc/libofx.h:314
OfxFiServiceInfo::statements
int statements
Definition: inc/libofx.h:792
OfxAccountData::OFX_INVESTMENT
Definition: inc/libofx.h:305
OfxAccountData::OFX_CHECKING
Definition: inc/libofx.h:299
nodeparser.h
Declaration of nodeparser object, which facilitiates searching for nodes in an XML file using a notat...
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
gengetopt_args_info::accountinfo_req_given
unsigned int accountinfo_req_given
Whether accountinfo-req was given.
Definition: ofxconnect/cmdline.h:106
gengetopt_args_info::bank_arg
char * bank_arg
IBAN bank identifier.
Definition: ofxconnect/cmdline.h:55
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
gengetopt_args_info::broker_arg
char * broker_arg
Broker identifier.
Definition: ofxconnect/cmdline.h:58
gengetopt_args_info::type_arg
int type_arg
Account Type 1=checking 2=invest 3=ccard.
Definition: ofxconnect/cmdline.h:70
gengetopt_args_info::pass_arg
char * pass_arg
Password.
Definition: ofxconnect/cmdline.h:64
OfxFiLogin
Information sufficient to log into an financial institution.
Definition: inc/libofx.h:806