- added src/endian.h... still need to add configure support to
[barry.git] / src / btool.cc
blob74b3d22b32435aedce88e74a13432f1efcfe88e3
1 ///
2 /// \file btool.cc
3 /// Barry library tester
4 ///
6 /*
7 Copyright (C) 2005-2006, Net Direct Inc. (http://www.netdirect.ca/)
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 2 of the License, or
12 (at your option) any later version.
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
18 See the GNU General Public License in the COPYING file at the
19 root directory of this project for more details.
22 #include "barry.h"
23 #include <iomanip>
24 #include <iostream>
25 #include <fstream>
26 #include <vector>
27 #include <string>
28 #include <getopt.h>
31 using namespace std;
32 using namespace Barry;
34 void Usage()
36 cerr
37 << "btool - Command line USB Blackberry Test Tool\n"
38 << " Copyright 2005-2006, Net Direct Inc. (http://www.netdirect.ca/)\n\n"
39 << " -c dn Convert address book database to LDIF format, using the\n"
40 << " specified baseDN\n"
41 << " -d db Load database 'db' and dump to screen\n"
42 << " Can be used multiple times to fetch more than one DB\n"
43 << " -f file Filename to save or load handheld data to/from\n"
44 << " -h This help\n"
45 << " -l List devices\n"
46 << " -p pin PIN of device to talk with\n"
47 << " If only one device plugged in, this flag is optional\n"
48 << " -s db Save database 'db' from data loaded from -f file\n"
49 << " -t Show database database table\n"
50 << " -v Dump protocol data during operation\n"
51 << endl;
54 class Contact2Ldif
56 std::string m_baseDN;
57 public:
58 Contact2Ldif(const std::string &baseDN) : m_baseDN(baseDN) {}
59 void operator()(const Contact &rec)
61 rec.DumpLdif(cout, m_baseDN);
65 template <class Record>
66 struct Store
68 std::vector<Record> records;
69 mutable typename std::vector<Record>::const_iterator rec_it;
70 std::string filename;
71 bool load;
72 int count;
74 Store(const string &filename, bool load)
75 : rec_it(records.end()),
76 filename(filename),
77 load(load),
78 count(0)
80 #ifdef __BOOST_MODE__
81 try {
83 if( load && filename.size() ) {
84 // filename is available, attempt to load
85 cout << "Loading: " << filename << endl;
86 ifstream ifs(filename.c_str());
87 boost::archive::text_iarchive ia(ifs);
88 ia >> records;
89 cout << records.size()
90 << " records loaded from '"
91 << filename << "'" << endl;
92 sort(records.begin(), records.end());
93 rec_it = records.begin();
95 // debugging aid
96 typename std::vector<Record>::const_iterator beg = records.begin(), end = records.end();
97 for( ; beg != end; beg++ ) {
98 dout(*beg);
102 } catch( boost::archive::archive_exception &ae ) {
103 cerr << "Archive exception in ~Store(): "
104 << ae.what() << endl;
106 #endif
108 ~Store()
110 cout << "Store counted " << dec << count << " records." << endl;
111 #ifdef __BOOST_MODE__
112 try {
114 if( !load && filename.size() ) {
115 // filename is available, attempt to save
116 cout << "Saving: " << filename << endl;
117 const std::vector<Record> &r = records;
118 ofstream ofs(filename.c_str());
119 boost::archive::text_oarchive oa(ofs);
120 oa << r;
121 cout << dec << r.size() << " records saved to '"
122 << filename << "'" << endl;
125 } catch( boost::archive::archive_exception &ae ) {
126 cerr << "Archive exception in ~Store(): "
127 << ae.what() << endl;
129 #endif
132 // storage operator
133 void operator()(const Record &rec)
135 count++;
136 std::cout << rec << std::endl;
137 records.push_back(rec);
140 // retrieval operator
141 bool operator()(Record &rec, unsigned int databaseId) const
143 if( rec_it == records.end() )
144 return false;
145 rec = *rec_it;
146 rec_it++;
147 return true;
151 auto_ptr<Parser> GetParser(const string &name, const string &filename)
153 // check for recognized database names
154 if( name == "Address Book" ) {
155 return auto_ptr<Parser>(
156 new RecordParser<Contact, Store<Contact> > (
157 new Store<Contact>(filename, false)));
159 else if( name == "Messages" ) {
160 return auto_ptr<Parser>(
161 new RecordParser<Message, Store<Message> > (
162 new Store<Message>(filename, false)));
164 else if( name == "Calendar" ) {
165 return auto_ptr<Parser>(
166 new RecordParser<Calendar, Store<Calendar> > (
167 new Store<Calendar>(filename, false)));
169 else if( name == "Service Book" ) {
170 return auto_ptr<Parser>(
171 new RecordParser<ServiceBook, Store<ServiceBook> > (
172 new Store<ServiceBook>(filename, false)));
174 else {
175 // unknown database, use null parser
176 return auto_ptr<Parser>( new Parser );
180 auto_ptr<Builder> GetBuilder(const string &name, const string &filename)
182 // check for recognized database names
183 if( name == "Address Book" ) {
184 return auto_ptr<Builder>(
185 new RecordBuilder<Contact, Store<Contact> > (
186 new Store<Contact>(filename, true)));
189 else if( name == "Messages" ) {
190 return auto_ptr<Parser>(
191 new RecordParser<Message, Store<Message> > (
192 new Store<Message>(filename, true)));
194 else if( name == "Calendar" ) {
195 return auto_ptr<Parser>(
196 new RecordParser<Calendar, Store<Calendar> > (
197 new Store<Calendar>(filename, true)));
199 else if( name == "Service Book" ) {
200 return auto_ptr<Parser>(
201 new RecordParser<ServiceBook, Store<ServiceBook> > (
202 new Store<ServiceBook>(filename, true)));
205 else {
206 throw std::runtime_error("No Builder available for database");
210 int main(int argc, char *argv[])
212 cout.sync_with_stdio(true); // leave this on, since libusb uses
213 // stdio for debug messages
215 try {
217 uint32_t pin = 0;
218 bool list_only = false,
219 show_dbdb = false,
220 ldif_contacts = false,
221 data_dump = false;
222 string ldifBaseDN;
223 string filename;
224 vector<string> dbNames, saveDbNames;
226 // process command line options
227 for(;;) {
228 int cmd = getopt(argc, argv, "c:d:f:hlp:s:tv");
229 if( cmd == -1 )
230 break;
232 switch( cmd )
234 case 'c': // contacts to ldap ldif
235 ldif_contacts = true;
236 ldifBaseDN = optarg;
237 break;
239 case 'd': // show dbname
240 dbNames.push_back(string(optarg));
241 break;
243 case 'f': // filename
244 #ifdef __BOOST_MODE__
245 filename = optarg;
246 #else
247 cerr << "-f option not supported - no Boost "
248 "serialization support available";
249 #endif
250 break;
251 case 'l': // list only
252 list_only = true;
253 break;
255 case 'p': // Blackberry PIN
256 pin = strtoul(optarg, NULL, 16);
257 break;
259 case 's': // save dbname
260 saveDbNames.push_back(string(optarg));
261 break;
263 case 't': // display database database
264 show_dbdb = true;
265 break;
267 case 'v': // data dump on
268 data_dump = true;
269 break;
271 case 'h': // help
272 default:
273 Usage();
274 return 0;
278 // Initialize the barry library. Must be called before
279 // anything else.
280 Barry::Init(data_dump);
282 // Probe the USB bus for Blackberry devices and display.
283 // If user has specified a PIN, search for it in the
284 // available device list here as well
285 Barry::Probe probe;
286 int activeDevice = -1;
287 cout << "Blackberry devices found:" << endl;
288 for( int i = 0; i < probe.GetCount(); i++ ) {
289 cout << probe.Get(i) << endl;
290 if( probe.Get(i).m_pin == pin )
291 activeDevice = i;
294 if( list_only )
295 return 0; // done
297 if( activeDevice == -1 ) {
298 if( pin == 0 ) {
299 // can we default to single device?
300 if( probe.GetCount() == 1 )
301 activeDevice = 0;
302 else {
303 cerr << "No device selected" << endl;
304 return 1;
307 else {
308 cerr << "PIN " << setbase(16) << pin
309 << " not found" << endl;
310 return 1;
314 // Create our controller object
315 Barry::Controller con(probe.Get(activeDevice));
318 // execute each mode that was turned on
322 // Dump list of all databases to stdout
323 if( show_dbdb ) {
324 // open desktop mode socket
325 con.OpenMode(Controller::Desktop);
326 cout << con.GetDBDB() << endl;
329 // Dump list of contacts to an LDAP LDIF file
330 // This uses the Controller convenience templates
331 if( ldif_contacts ) {
332 // make sure we're in desktop mode
333 con.OpenMode(Controller::Desktop);
335 // create a storage functor object that accepts
336 // Barry::Contact objects as input
337 Contact2Ldif storage(ldifBaseDN);
339 // load all the Contact records into storage
340 con.LoadDatabaseByType<Barry::Contact>(storage);
343 // Dump contents of selected databases to stdout, or
344 // to file if specified.
345 // This is retrieving data from the Blackberry.
346 if( dbNames.size() ) {
347 vector<string>::iterator b = dbNames.begin();
349 for( ; b != dbNames.end(); b++ ) {
350 con.OpenMode(Controller::Desktop);
351 auto_ptr<Parser> parse = GetParser(*b,filename);
352 unsigned int id = con.GetDBID(*b);
353 con.LoadDatabase(id, *parse.get());
357 // Save contents of file to specified databases
358 // This is writing data to the Blackberry.
359 if( saveDbNames.size() ) {
360 vector<string>::iterator b = saveDbNames.begin();
362 for( ; b != saveDbNames.end(); b++ ) {
363 con.OpenMode(Controller::Desktop);
364 auto_ptr<Builder> build =
365 GetBuilder(*b, filename);
366 unsigned int id = con.GetDBID(*b);
367 con.SaveDatabase(id, *build);
372 catch( Barry::BError &se ) {
373 std::cerr << "BError caught: " << se.what() << endl;
375 catch( Usb::UsbError &ue) {
376 std::cerr << "UsbError caught: " << ue.what() << endl;
378 catch( std::runtime_error &re ) {
379 std::cerr << "std::runtime_error caught: " << re.what() << endl;
380 return 1;
382 catch( std::exception &e ) {
383 std::cerr << "std::exception caught: " << e.what() << endl;
384 return 1;
387 return 0;