- renamed Changelog to ChangeLog in preparation for autoconf
[barry.git] / src / btool.cc
blob75723d47e6411adbd94163621af6500e89f1903b
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 " << 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 << 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 {
170 // unknown database, use null parser
171 return auto_ptr<Parser>( new Parser );
175 auto_ptr<Builder> GetBuilder(const string &name, const string &filename)
177 // check for recognized database names
178 if( name == "Address Book" ) {
179 return auto_ptr<Builder>(
180 new RecordBuilder<Contact, Store<Contact> > (
181 new Store<Contact>(filename, true)));
184 else if( name == "Messages" ) {
185 return auto_ptr<Parser>(
186 new RecordParser<Message, Store<Message> > (
187 new Store<Message>(filename, true)));
189 else if( name == "Calendar" ) {
190 return auto_ptr<Parser>(
191 new RecordParser<Calendar, Store<Calendar> > (
192 new Store<Calendar>(filename, true)));
195 else {
196 throw std::runtime_error("No Builder available for database");
200 int main(int argc, char *argv[])
202 cout.sync_with_stdio(true); // leave this on, since libusb uses
203 // stdio for debug messages
205 try {
207 uint32_t pin = 0;
208 bool list_only = false,
209 show_dbdb = false,
210 ldif_contacts = false,
211 data_dump = false;
212 string ldifBaseDN;
213 string filename;
214 vector<string> dbNames, saveDbNames;
216 // process command line options
217 for(;;) {
218 int cmd = getopt(argc, argv, "c:d:f:hlp:s:tv");
219 if( cmd == -1 )
220 break;
222 switch( cmd )
224 case 'c': // contacts to ldap ldif
225 ldif_contacts = true;
226 ldifBaseDN = optarg;
227 break;
229 case 'd': // show dbname
230 dbNames.push_back(string(optarg));
231 break;
233 case 'f': // filename
234 #ifdef __BOOST_MODE__
235 filename = optarg;
236 #else
237 cerr << "-f option not supported - no Boost "
238 "serialization support available";
239 #endif
240 break;
241 case 'l': // list only
242 list_only = true;
243 break;
245 case 'p': // Blackberry PIN
246 pin = strtoul(optarg, NULL, 16);
247 break;
249 case 's': // save dbname
250 saveDbNames.push_back(string(optarg));
251 break;
253 case 't': // display database database
254 show_dbdb = true;
255 break;
257 case 'v': // data dump on
258 data_dump = true;
259 break;
261 case 'h': // help
262 default:
263 Usage();
264 return 0;
268 // Initialize the barry library. Must be called before
269 // anything else.
270 Barry::Init(data_dump);
272 // Probe the USB bus for Blackberry devices and display.
273 // If user has specified a PIN, search for it in the
274 // available device list here as well
275 Barry::Probe probe;
276 int activeDevice = -1;
277 cout << "Blackberry devices found:" << endl;
278 for( int i = 0; i < probe.GetCount(); i++ ) {
279 cout << probe.Get(i) << endl;
280 if( probe.Get(i).m_pin == pin )
281 activeDevice = i;
284 if( list_only )
285 return 0; // done
287 if( activeDevice == -1 ) {
288 if( pin == 0 ) {
289 // can we default to single device?
290 if( probe.GetCount() == 1 )
291 activeDevice = 0;
292 else {
293 cerr << "No device selected" << endl;
294 return 1;
297 else {
298 cerr << "PIN " << setbase(16) << pin
299 << " not found" << endl;
300 return 1;
304 // Create our controller object
305 Barry::Controller con(probe.Get(activeDevice));
308 // execute each mode that was turned on
312 // Dump list of all databases to stdout
313 if( show_dbdb ) {
314 // open desktop mode socket
315 con.OpenMode(Controller::Desktop);
316 cout << con.GetDBDB() << endl;
319 // Dump list of contacts to an LDAP LDIF file
320 // This uses the Controller convenience templates
321 if( ldif_contacts ) {
322 // make sure we're in desktop mode
323 con.OpenMode(Controller::Desktop);
325 // create a storage functor object that accepts
326 // Barry::Contact objects as input
327 Contact2Ldif storage(ldifBaseDN);
329 // load all the Contact records into storage
330 con.LoadDatabaseByType<Barry::Contact>(storage);
333 // Dump contents of selected databases to stdout, or
334 // to file if specified.
335 // This is retrieving data from the Blackberry.
336 if( dbNames.size() ) {
337 vector<string>::iterator b = dbNames.begin();
339 for( ; b != dbNames.end(); b++ ) {
340 con.OpenMode(Controller::Desktop);
341 auto_ptr<Parser> parse = GetParser(*b,filename);
342 unsigned int id = con.GetDBID(*b);
343 con.LoadDatabase(id, *parse.get());
347 // Save contents of file to specified databases
348 // This is writing data to the Blackberry.
349 if( saveDbNames.size() ) {
350 vector<string>::iterator b = saveDbNames.begin();
352 for( ; b != saveDbNames.end(); b++ ) {
353 con.OpenMode(Controller::Desktop);
354 auto_ptr<Builder> build =
355 GetBuilder(*b, filename);
356 unsigned int id = con.GetDBID(*b);
357 con.SaveDatabase(id, *build);
362 catch( Barry::BError &se ) {
363 std::cerr << "BError caught: " << se.what() << endl;
365 catch( Usb::UsbError &ue) {
366 std::cerr << "UsbError caught: " << ue.what() << endl;
368 catch( std::runtime_error &re ) {
369 std::cerr << "std::runtime_error caught: " << re.what() << endl;
370 return 1;
372 catch( std::exception &e ) {
373 std::cerr << "std::exception caught: " << e.what() << endl;
374 return 1;
377 return 0;