LibOFX

- Main Page
- Related Pages
- Namespaces
- Data Structures
- Files

- File List
- Globals

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 }
128 }
129 else if ( args_info.bank_fipid_given || args_info.bank_services_given )
130 {
131 if ( (args_info.inputs_num > 0) )
132 {
133 cout << "bank " << args_info.inputs[0] << endl;
134 }
135 else
136 {
137 cerr << "ERROR: You must specify an bank" << endl;
138 }
139 }
140
141 OfxFiLogin fi;
142 memset(&fi, 0, sizeof(OfxFiLogin));
143 bool ok = true;
144 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 cerr << "fipid " << args_info.fipid_arg << endl;
154 cerr << "contacting partner server..." << endl;
155 OfxFiServiceInfo svcinfo = OfxPartner::ServiceInfo(args_info.fipid_arg);
156 cout << "fid " << svcinfo.fid << endl;
157 strncpy(fi.fid, svcinfo.fid, OFX_FID_LENGTH - 1);
158 cout << "org " << svcinfo.org << endl;
159 strncpy(fi.org, svcinfo.org, OFX_ORG_LENGTH - 1);
160 cout << "url " << svcinfo.url << endl;
161 url = svcinfo.url;
162 }
163 if ( args_info.fid_given )
164 {
165 cerr << "fid " << args_info.fid_arg << endl;
166 strncpy(fi.fid, args_info.fid_arg, OFX_FID_LENGTH - 1);
167 }
168 else if ( ! args_info.fipid_given )
169 {
170 cerr << "ERROR: --fid is required" << endl;
171 ok = false;
172 }
173
174 if ( args_info.org_given )
175 {
176 cerr << "org " << args_info.org_arg << endl;
177 strncpy(fi.org, args_info.org_arg, OFX_ORG_LENGTH - 1);
178 }
179 else if ( ! args_info.fipid_given )
180 {
181 cerr << "ERROR: --org is required" << endl;
182 ok = false;
183 }
184
185 if ( args_info.user_given )
186 {
187 cerr << "user " << args_info.user_arg << endl;
188 strncpy(fi.userid, args_info.user_arg, OFX_USERID_LENGTH - 1);
189 }
190 else
191 {
192 cerr << "ERROR: --user is required" << endl;
193 ok = false;
194 }
195
196 if ( args_info.pass_given )
197 {
198 cerr << "pass " << args_info.pass_arg << endl;
199 strncpy(fi.userpass, args_info.pass_arg, OFX_USERPASS_LENGTH - 1);
200 }
201 else
202 {
203 cerr << "ERROR: --pass is required" << 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 cerr << "Statement request" << endl;
214
215 OfxAccountData account;
216 memset(&account, 0, sizeof(OfxAccountData));
217
218 if ( args_info.bank_given )
219 {
220 cerr << "bank " << args_info.bank_arg << 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 cerr << "ERROR: --bank is required for a bank request" << endl;
228 ok = false;
229 }
230 }
231
232 if ( args_info.broker_given )
233 {
234 cerr << "broker " << args_info.broker_arg << 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 cerr << "ERROR: --broker is required for an investment statement request" << endl;
242 ok = false;
243 }
244 }
245
246 if ( args_info.acct_given )
247 {
248 cerr << "acct " << args_info.acct_arg << endl;
249 strncpy(account.account_number, args_info.acct_arg, OFX_ACCTID_LENGTH - 1);
250 }
251 else
252 {
253 cerr << "ERROR: --acct is required for a statement request" << endl;
254 ok = false;
255 }
256
257 if ( args_info.type_given )
258 {
259 cerr << "type " << args_info.type_arg << 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 cerr << "ERROR: --type is not valid. Must be between 1 and 3" << endl;
273 ok = false;
274 }
275 }
276 else
277 {
278 cerr << "ERROR: --type is required for a statement request" << endl;
279 ok = false;
280 }
281
282 if ( args_info.past_given )
283 {
284 cerr << "past " << args_info.past_arg << endl;
285 }
286 else
287 {
288 cerr << "ERROR: --past is required for a statement request" << 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() )
297 post(request, url.c_str(), args_info.inputs[0]);
298 else
299 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 cerr << "trid " << args_info.trid_arg << endl;
315 snprintf(tridstr, 32, "%i", args_info.trid_arg);
316 }
317 else
318 {
319 cerr << "ERROR: --trid is required for a payment inquiry request" << endl;
320 ok = false;
321 }
322
323 if ( ok )
324 {
325 char* request = libofx_request_payment_status( &fi, tridstr );
326
327 filebuf fb;
328 fb.open ("query", ios::out);
329 ostream os(&fb);
330 os << request;
331 fb.close();
332
333 if ( url.length() )
334 post(request, url.c_str(), args_info.inputs[0]);
335 else
336 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 cerr << "bank " << args_info.bank_arg << 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 cerr << "ERROR: --bank is required for a bank request" << endl;
375 ok = false;
376 }
377 }
378
379 if ( args_info.broker_given )
380 {
381 cerr << "broker " << args_info.broker_arg << 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 cerr << "ERROR: --broker is required for an investment statement request" << endl;
389 ok = false;
390 }
391 }
392
393 if ( args_info.acct_given )
394 {
395 cerr << "acct " << args_info.acct_arg << endl;
396 strncpy(account.account_number, args_info.acct_arg, OFX_ACCTID_LENGTH - 1);
397 }
398 else
399 {
400 cerr << "ERROR: --acct is required for a statement request" << endl;
401 ok = false;
402 }
403
404 if ( args_info.type_given )
405 {
406 cerr << "type " << args_info.type_arg << 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 cerr << "ERROR: --type is not valid. Must be between 1 and 3" << endl;
420 ok = false;
421 }
422 }
423 else
424 {
425 cerr << "ERROR: --type is required for a statement request" << endl;
426 ok = false;
427 }
428
429 if ( ok )
430 {
431 char* request = libofx_request_payment( &fi, &account, &payee, &payment );
432
433 filebuf fb;
434 fb.open ("query", ios::out);
435 ostream os(&fb);
436 os << request;
437 fb.close();
438
439 if ( url.length() )
440 post(request, url.c_str(), args_info.inputs[0]);
441 else
442 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() )
456 post(request, url.c_str(), args_info.inputs[0]);
457 else
458 cout << request;
459
460 free(request);
461 }
462 }
463
464 if ( args_info.bank_list_given )
465 {
466 cout << OfxPartner::BankNames();
467 }
468
469 if ( args_info.bank_fipid_given )
470 {
471 cout << OfxPartner::FipidForBank(args_info.inputs[0]);
472 }
473
474 if ( args_info.bank_services_given )
475 {
476 OfxFiServiceInfo svcinfo = OfxPartner::ServiceInfo(args_info.inputs[0]);
477 cout << "Account List? " << (svcinfo.accountlist ? "Yes" : "No") << endl;
478 cout << "Statements? " << (svcinfo.statements ? "Yes" : "No") << endl;
479 cout << "Billpay? " << (svcinfo.billpay ? "Yes" : "No") << endl;
480 cout << "Investments? " << (svcinfo.investments ? "Yes" : "No") << endl;
481 }
482
483 if ( args_info.allsupport_given )
484 {
485 vector<string> banks = OfxPartner::BankNames();
486 vector<string>::const_iterator it_bank = banks.begin();
487 while ( it_bank != banks.end() )
488 {
489 vector<string> fipids = OfxPartner::FipidForBank(*it_bank);
490 vector<string>::const_iterator it_fipid = fipids.begin();
491 while ( it_fipid != fipids.end() )
492 {
493 if ( OfxPartner::ServiceInfo(*it_fipid).accountlist )
494 cout << *it_bank << 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
OfxAccountData
An abstraction of an account.
Definition: inc/libofx.h:270
OfxPayee
Definition: inc/libofx.h:830
gengetopt_args_info
Where the command line options are stored.
Definition: 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.
OfxFiServiceInfo::accountlist
int accountlist
Definition: inc/libofx.h:790
OfxAccountData::OFX_CREDITCARD
Definition: inc/libofx.h:303
OfxFiServiceInfo::investments
int investments
Definition: inc/libofx.h:793
ofxpartner.h
Methods for connecting to the OFX partner server to retrieve OFX server information.
OfxFiServiceInfo::billpay
int billpay
Definition: inc/libofx.h:792
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:822
OfxAccountData::bank_id
char bank_id[OFX_BANKID_LENGTH]
Definition: inc/libofx.h:317
cmdline_parser
int cmdline_parser(int argc, char **argv, struct gengetopt_args_info *args_info)
Definition: cmdline.c:304
cmdline_parser_print_help
void cmdline_parser_print_help(void)
Definition: cmdline.c:143
gengetopt_args_info::inputs_num
unsigned inputs_num
unamed options number
Definition: cmdline.h:75
OfxFiServiceInfo
Information returned by the OFX Partner Server about a financial institution.
Definition: inc/libofx.h:785
main
int main(int argc, char *argv[])
Definition: ofxdump.cpp:434
cmdline.h
The header file for the command line option parser generated by GNU Gengetopt version 2...
OfxAccountData::account_number
char account_number[OFX_ACCTID_LENGTH]
Definition: inc/libofx.h:313
OfxFiServiceInfo::statements
int statements
Definition: inc/libofx.h:791
OfxAccountData::OFX_INVESTMENT
Definition: inc/libofx.h:304
OfxAccountData::OFX_CHECKING
Definition: inc/libofx.h:298
nodeparser.h
Declaration of nodeparser object, which facilitiates searching for nodes in an XML file using a notat...
gengetopt_args_info::inputs
char ** inputs
unamed options (options without names)
Definition: cmdline.h:74
OfxFiLogin
Information sufficient to log into an financial institution.
Definition: inc/libofx.h:805