3 /// Barry library tester
7 Copyright (C) 2005-2007, 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/barry.h>
32 using namespace Barry
;
37 << "btool - Command line USB Blackberry Test Tool\n"
38 << " Copyright 2005-2007, 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 #ifdef __BARRY_BOOST_MODE__
44 << " -f file Filename to save or load handheld data to/from\n"
47 << " -l List devices\n"
48 << " -p pin PIN of device to talk with\n"
49 << " If only one device plugged in, this flag is optional\n"
50 << " -s db Save database 'db' from data loaded from -f file\n"
51 << " -t Show database database table\n"
52 << " -T db Show record state table for given database\n"
53 << " -v Dump protocol data during operation\n"
55 << " -d Command modifiers: (can be used multiple times for more than 1 record)\n"
57 << " -r # Record index number as seen in the -T state table.\n"
58 << " This overrides the default -d behaviour, and only\n"
59 << " downloads the one specified record, sending to stdout.\n"
60 << " -R # Same as -r, but also clears the record's dirty flags.\n"
61 << " -D # Record index number as seen in the -T state table,\n"
62 << " which indicates the record to delete. Used with the -d\n"
63 << " command to specify the database.\n"
71 Contact2Ldif(const std::string
&baseDN
) : m_baseDN(baseDN
) {}
72 void operator()(const Contact
&rec
)
74 rec
.DumpLdif(cout
, m_baseDN
);
78 template <class Record
>
81 std::vector
<Record
> records
;
82 mutable typename
std::vector
<Record
>::const_iterator rec_it
;
87 Store(const string
&filename
, bool load
)
88 : rec_it(records
.end()),
93 #ifdef __BARRY_BOOST_MODE__
96 if( load
&& filename
.size() ) {
97 // filename is available, attempt to load
98 cout
<< "Loading: " << filename
<< endl
;
99 ifstream
ifs(filename
.c_str());
100 boost::archive::text_iarchive
ia(ifs
);
102 cout
<< records
.size()
103 << " records loaded from '"
104 << filename
<< "'" << endl
;
105 sort(records
.begin(), records
.end());
106 rec_it
= records
.begin();
109 typename
std::vector
<Record
>::const_iterator beg
= records
.begin(), end
= records
.end();
110 for( ; beg
!= end
; beg
++ ) {
111 cout
<< (*beg
) << endl
;
115 } catch( boost::archive::archive_exception
&ae
) {
116 cerr
<< "Archive exception in ~Store(): "
117 << ae
.what() << endl
;
123 cout
<< "Store counted " << dec
<< count
<< " records." << endl
;
124 #ifdef __BARRY_BOOST_MODE__
127 if( !load
&& filename
.size() ) {
128 // filename is available, attempt to save
129 cout
<< "Saving: " << filename
<< endl
;
130 const std::vector
<Record
> &r
= records
;
131 ofstream
ofs(filename
.c_str());
132 boost::archive::text_oarchive
oa(ofs
);
134 cout
<< dec
<< r
.size() << " records saved to '"
135 << filename
<< "'" << endl
;
138 } catch( boost::archive::archive_exception
&ae
) {
139 cerr
<< "Archive exception in ~Store(): "
140 << ae
.what() << endl
;
146 void operator()(const Record
&rec
)
149 std::cout
<< rec
<< std::endl
;
150 records
.push_back(rec
);
153 // retrieval operator
154 bool operator()(Record
&rec
, unsigned int databaseId
) const
156 if( rec_it
== records
.end() )
164 class DataDumpParser
: public Barry::Parser
169 virtual void SetUniqueId(uint32_t id
)
174 virtual void ParseFields(const Barry::Data
&data
, size_t &offset
)
176 std::cout
<< "Raw record dump for record: "
177 << std::hex
<< m_id
<< std::endl
;
178 std::cout
<< data
<< std::endl
;
182 auto_ptr
<Parser
> GetParser(const string
&name
, const string
&filename
)
184 // check for recognized database names
185 if( name
== "Address Book" ) {
186 return auto_ptr
<Parser
>(
187 new RecordParser
<Contact
, Store
<Contact
> > (
188 new Store
<Contact
>(filename
, false)));
190 else if( name
== "Messages" ) {
191 return auto_ptr
<Parser
>(
192 new RecordParser
<Message
, Store
<Message
> > (
193 new Store
<Message
>(filename
, false)));
195 else if( name
== "Calendar" ) {
196 return auto_ptr
<Parser
>(
197 new RecordParser
<Calendar
, Store
<Calendar
> > (
198 new Store
<Calendar
>(filename
, false)));
200 else if( name
== "Service Book" ) {
201 return auto_ptr
<Parser
>(
202 new RecordParser
<ServiceBook
, Store
<ServiceBook
> > (
203 new Store
<ServiceBook
>(filename
, false)));
206 // unknown database, use null parser
207 return auto_ptr
<Parser
>( new DataDumpParser
);
211 auto_ptr
<Builder
> GetBuilder(const string
&name
, const string
&filename
)
213 // check for recognized database names
214 if( name
== "Address Book" ) {
215 return auto_ptr
<Builder
>(
216 new RecordBuilder
<Contact
, Store
<Contact
> > (
217 new Store
<Contact
>(filename
, true)));
220 else if( name == "Messages" ) {
221 return auto_ptr<Parser>(
222 new RecordParser<Message, Store<Message> > (
223 new Store<Message>(filename, true)));
225 else if( name == "Calendar" ) {
226 return auto_ptr<Parser>(
227 new RecordParser<Calendar, Store<Calendar> > (
228 new Store<Calendar>(filename, true)));
230 else if( name == "Service Book" ) {
231 return auto_ptr<Parser>(
232 new RecordParser<ServiceBook, Store<ServiceBook> > (
233 new Store<ServiceBook>(filename, true)));
237 throw std::runtime_error("No Builder available for database");
241 struct StateTableCommand
247 StateTableCommand(char f
, bool c
, unsigned int i
)
248 : flag(f
), clear(c
), index(i
) {}
251 int main(int argc
, char *argv
[])
253 cout
.sync_with_stdio(true); // leave this on, since libusb uses
254 // stdio for debug messages
259 bool list_only
= false,
261 ldif_contacts
= false,
263 record_state
= false;
266 vector
<string
> dbNames
, saveDbNames
;
267 vector
<StateTableCommand
> stCommands
;
269 // process command line options
271 int cmd
= getopt(argc
, argv
, "c:d:D:f:hlp:r:R:s:tT:v");
277 case 'c': // contacts to ldap ldif
278 ldif_contacts
= true;
282 case 'd': // show dbname
283 dbNames
.push_back(string(optarg
));
286 case 'D': // delete record
287 stCommands
.push_back(
288 StateTableCommand('D', false, atoi(optarg
)));
291 case 'f': // filename
292 #ifdef __BARRY_BOOST_MODE__
295 cerr
<< "-f option not supported - no Boost "
296 "serialization support available\n";
300 case 'l': // list only
304 case 'p': // Blackberry PIN
305 pin
= strtoul(optarg
, NULL
, 16);
308 case 'r': // get specific record index
309 stCommands
.push_back(
310 StateTableCommand('r', false, atoi(optarg
)));
313 case 'R': // same as 'r', and clears dirty
314 stCommands
.push_back(
315 StateTableCommand('r', true, atoi(optarg
)));
318 case 's': // save dbname
319 saveDbNames
.push_back(string(optarg
));
322 case 't': // display database database
326 case 'T': // show RecordStateTable
328 dbNames
.push_back(string(optarg
));
331 case 'v': // data dump on
342 // Initialize the barry library. Must be called before
344 Barry::Init(data_dump
);
346 // Probe the USB bus for Blackberry devices and display.
347 // If user has specified a PIN, search for it in the
348 // available device list here as well
350 int activeDevice
= -1;
351 cout
<< "Blackberry devices found:" << endl
;
352 for( int i
= 0; i
< probe
.GetCount(); i
++ ) {
353 cout
<< probe
.Get(i
) << endl
;
354 if( probe
.Get(i
).m_pin
== pin
)
361 if( activeDevice
== -1 ) {
363 // can we default to single device?
364 if( probe
.GetCount() == 1 )
367 cerr
<< "No device selected" << endl
;
372 cerr
<< "PIN " << setbase(16) << pin
373 << " not found" << endl
;
378 // Create our controller object
379 Barry::Controller
con(probe
.Get(activeDevice
));
382 // execute each mode that was turned on
386 // Dump list of all databases to stdout
388 // open desktop mode socket
389 con
.OpenMode(Controller::Desktop
);
390 cout
<< con
.GetDBDB() << endl
;
393 // Dump list of contacts to an LDAP LDIF file
394 // This uses the Controller convenience templates
395 if( ldif_contacts
) {
396 // make sure we're in desktop mode
397 con
.OpenMode(Controller::Desktop
);
399 // create a storage functor object that accepts
400 // Barry::Contact objects as input
401 Contact2Ldif
storage(ldifBaseDN
);
403 // load all the Contact records into storage
404 con
.LoadDatabaseByType
<Barry::Contact
>(storage
);
407 // Dump record state table to stdout
409 if( dbNames
.size() == 0 ) {
410 cout
<< "No db names to process" << endl
;
414 vector
<string
>::iterator b
= dbNames
.begin();
415 for( ; b
!= dbNames
.end(); b
++ ) {
416 con
.OpenMode(Controller::Desktop
);
417 unsigned int id
= con
.GetDBID(*b
);
418 RecordStateTable state
;
419 con
.GetRecordStateTable(id
, state
);
420 cout
<< "Record state table for: " << *b
<< endl
;
426 // Get Record mode overrides the default name mode
427 if( stCommands
.size() ) {
428 if( dbNames
.size() != 1 ) {
429 cout
<< "Must have 1 db name to process" << endl
;
433 con
.OpenMode(Controller::Desktop
);
434 unsigned int id
= con
.GetDBID(dbNames
[0]);
435 auto_ptr
<Parser
> parse
= GetParser(dbNames
[0],filename
);
437 for( unsigned int i
= 0; i
< stCommands
.size(); i
++ ) {
438 con
.GetRecord(id
, stCommands
[i
].index
, *parse
.get());
440 if( stCommands
[i
].flag
== 'r' && stCommands
[i
].clear
) {
441 cout
<< "Clearing record's dirty flags..." << endl
;
442 con
.ClearDirty(id
, stCommands
[i
].index
);
445 if( stCommands
[i
].flag
== 'D' ) {
446 con
.DeleteRecord(id
, stCommands
[i
].index
);
453 // Dump contents of selected databases to stdout, or
454 // to file if specified.
455 // This is retrieving data from the Blackberry.
456 if( dbNames
.size() ) {
457 vector
<string
>::iterator b
= dbNames
.begin();
459 for( ; b
!= dbNames
.end(); b
++ ) {
460 con
.OpenMode(Controller::Desktop
);
461 auto_ptr
<Parser
> parse
= GetParser(*b
,filename
);
462 unsigned int id
= con
.GetDBID(*b
);
463 con
.LoadDatabase(id
, *parse
.get());
467 // Save contents of file to specified databases
468 // This is writing data to the Blackberry.
469 if( saveDbNames
.size() ) {
470 vector
<string
>::iterator b
= saveDbNames
.begin();
472 for( ; b
!= saveDbNames
.end(); b
++ ) {
473 con
.OpenMode(Controller::Desktop
);
474 auto_ptr
<Builder
> build
=
475 GetBuilder(*b
, filename
);
476 unsigned int id
= con
.GetDBID(*b
);
477 con
.SaveDatabase(id
, *build
);
482 catch( Barry::BError
&se
) {
483 std::cerr
<< "BError caught: " << se
.what() << endl
;
485 catch( Usb::UsbError
&ue
) {
486 std::cerr
<< "UsbError caught: " << ue
.what() << endl
;
488 catch( std::runtime_error
&re
) {
489 std::cerr
<< "std::runtime_error caught: " << re
.what() << endl
;
492 catch( std::exception
&e
) {
493 std::cerr
<< "std::exception caught: " << e
.what() << endl
;