00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022 #include <barry/barry.h>
00023 #include <barry/barrysync.h>
00024 #include <barry/barrybackup.h>
00025
00026 #include "mimedump.h"
00027 #include "brecsum.h"
00028
00029 #include <iomanip>
00030 #include <iostream>
00031 #include <sstream>
00032 #include <fstream>
00033 #include <string>
00034 #include <vector>
00035 #include <algorithm>
00036 #include <stdexcept>
00037 #include <tr1/memory>
00038 #include <getopt.h>
00039 #include <strings.h>
00040
00041 using namespace std;
00042 using namespace std::tr1;
00043 using namespace Barry;
00044
00045 void Usage()
00046 {
00047 int major, minor;
00048 const char *Version = Barry::Version(major, minor);
00049
00050 cerr
00051 << "bio - Barry Input / Output\n"
00052 << " Copyright 2010-2011, Net Direct Inc. (http://www.netdirect.ca/)\n"
00053 << " Using: " << Version << "\n"
00054 << " Compiled "
00055 #ifdef __BARRY_BOOST_MODE__
00056 << "with"
00057 #else
00058 << "without"
00059 #endif
00060 << " Boost support\n"
00061 << "\n"
00062 << " Usage: bio -i <type> [options...] -o <type> [options...]\n"
00063 << "\n"
00064 << " -i type The input type (Builder) to use for producing records\n"
00065 << " Can be one of: device, tar"
00066 #ifdef __BARRY_BOOST_MODE__
00067 << ", boost"
00068 #endif
00069 << ", ldif, mime\n"
00070 << " -o type The output type (Parser) to use for processing records.\n"
00071 << " Multiple outputs are allowed, as long as they don't\n"
00072 << " conflict (such as two outputs writing to the same file\n"
00073 << " or device).\n"
00074 << " Can be one of: device, tar"
00075 #ifdef __BARRY_BOOST_MODE__
00076 << ", boost"
00077 #endif
00078 << ", ldif, mime, dump, sha1, cstore\n"
00079 << "\n"
00080 << " Options to use for 'device' type:\n"
00081 << " -d db Name of input database. Can be used multiple times.\n"
00082 << " -A Add all available device databases, instead of specifying\n"
00083 << " them manually via -d\n"
00084 << " -p pin PIN of device to talk to\n"
00085 << " If only one device is plugged in, this flag is optional\n"
00086 << " -P pass Simplistic method to specify device password\n"
00087 << " -w mode Set write mode when using 'device' for output. Must be\n"
00088 << " specified, or will not write anything.\n"
00089 << " Can be one of: erase, overwrite, addonly, addnew\n"
00090
00091
00092
00093
00094
00095
00096
00097
00098
00099
00100
00101
00102
00103 << "\n"
00104 << " Options to use for 'tar' backup type:\n"
00105 << " -d db Name of input database. Can be used multiple times.\n"
00106 << " Not available in output mode. Note that by default,\n"
00107 << " all databases in the backup are selected, when reading,\n"
00108 << " unless at least one -d is specified.\n"
00109 << " -f file Tar backup file to read from or write to\n"
00110 #ifdef __BARRY_BOOST_MODE__
00111 << "\n"
00112 << " Options to use for 'boost' type:\n"
00113 << " -f file Boost serialization filename to read from or write to\n"
00114 << " Can use - to specify stdin/stdout\n"
00115 #endif
00116 << "\n"
00117 << " Options to use for 'ldif' type:\n"
00118 << " -c dn Convert address book database to LDIF format, using the\n"
00119 << " specified baseDN\n"
00120 << " -C dnattr LDIF attribute name to use when building the FQDN\n"
00121 << " Defaults to 'cn'\n"
00122
00123
00124
00125
00126
00127
00128
00129
00130
00131 << "\n"
00132 << " Options to use for 'mime' type:\n"
00133 << " -f file Filename to read from or write to. Use - to explicitly\n"
00134 << " specify stdin/stdout, which is default.\n"
00135 << "\n"
00136 << " Options to use for 'dump' to stdout output type:\n"
00137 << " -n Use hex dump parser on all databases.\n"
00138 << "\n"
00139 << " Options to use for 'sha1' sum stdout output type:\n"
00140 << " -t Include DB Name, Type, and Unique record IDs in the checksums\n"
00141 << "\n"
00142 << " Options to use for 'cstore' output type:\n"
00143 << " -l List filenames only\n"
00144 << " -f file Filename from the above list, including path.\n"
00145 << " If found, the file will be written to the current\n"
00146 << " directory, using the base filename from the device.\n"
00147 << "\n"
00148 << " Standalone options:\n"
00149 << " -h This help\n"
00150 << " -I cs International charset for string conversions\n"
00151 << " Valid values here are available with 'iconv --list'\n"
00152 << " -S Show list of supported database parsers and builders\n"
00153 << " -v Dump protocol data during operation\n"
00154 << "\n"
00155 << endl;
00156 }
00157
00158 class ModeBase
00159 {
00160 public:
00161 virtual ~ModeBase() {}
00162
00163 virtual bool ProbeNeeded() const { return false; }
00164
00165 virtual void SetFilename(const std::string &name)
00166 {
00167 throw runtime_error("Filename not applicable for this mode");
00168 }
00169
00170 virtual void AddDB(const std::string &dbname)
00171 {
00172 throw runtime_error("DB not applicable for this mode");
00173 }
00174
00175 virtual void AddAllDBs()
00176 {
00177 throw runtime_error("DBs not applicable for this mode");
00178 }
00179
00180 virtual void SetPIN(const std::string &pin)
00181 {
00182 throw runtime_error("PIN not applicable for this mode");
00183 }
00184
00185 virtual void SetPassword(const std::string &password)
00186 {
00187 throw runtime_error("Password not applicable for this mode");
00188 }
00189
00190 virtual void SetWriteMode(DeviceParser::WriteMode mode)
00191 {
00192 throw runtime_error("Device write behaviour not applicable for this mode");
00193 }
00194
00195 virtual void SetDN(const std::string &dn)
00196 {
00197 throw runtime_error("DN not applicable for this mode");
00198 }
00199
00200 virtual void SetAttribute(const std::string &attr)
00201 {
00202 throw runtime_error("Attribute not applicable for this mode");
00203 }
00204
00205 virtual void SetHexDump()
00206 {
00207 throw runtime_error("No hex dump option in this mode");
00208 }
00209
00210 virtual void IncludeIDs()
00211 {
00212 throw runtime_error("Including record IDs in the SHA1 sum is not applicable in this mode");
00213 }
00214
00215 virtual void SetList()
00216 {
00217 throw runtime_error("List option not applicable for this mode");
00218 }
00219 };
00220
00221 class DeviceBase : public virtual ModeBase
00222 {
00223 protected:
00224 Barry::Pin m_pin;
00225 std::string m_password;
00226
00227 public:
00228 bool ProbeNeeded() const { return true; }
00229
00230 void SetPIN(const std::string &pin)
00231 {
00232 istringstream iss(pin);
00233 iss >> m_pin;
00234 if( !m_pin.Valid() )
00235 throw runtime_error("Invalid PIN: " + pin);
00236 }
00237
00238 void SetPassword(const std::string &password)
00239 {
00240 m_password = password;
00241 }
00242 };
00243
00244
00245
00246
00247 class InputBase : public virtual ModeBase
00248 {
00249 public:
00250 virtual Builder& GetBuilder(Barry::Probe *probe, IConverter &ic) = 0;
00251 };
00252
00253 class DeviceInputBase : public DeviceBase, public InputBase
00254 {
00255 };
00256
00257
00258
00259
00260 class DeviceInput : public DeviceInputBase
00261 {
00262 auto_ptr<Controller> m_con;
00263 auto_ptr<Mode::Desktop> m_desktop;
00264 auto_ptr<DeviceBuilder> m_builder;
00265 vector<string> m_dbnames;
00266 bool m_add_all;
00267
00268 public:
00269 DeviceInput()
00270 : m_add_all(false)
00271 {
00272 }
00273
00274 void AddDB(const std::string &dbname)
00275 {
00276 m_dbnames.push_back(dbname);
00277 }
00278
00279 void AddAllDBs()
00280 {
00281 m_add_all = true;
00282 }
00283
00284 Builder& GetBuilder(Barry::Probe *probe, IConverter &ic)
00285 {
00286 int i = probe->FindActive(m_pin);
00287 if( i == -1 ) {
00288 if( m_pin.Valid() )
00289 throw runtime_error("PIN not found: " + m_pin.Str());
00290 else
00291 throw runtime_error("PIN not specified, and more than one device exists.");
00292 }
00293
00294 m_con.reset( new Controller(probe->Get(i)) );
00295 m_desktop.reset( new Mode::Desktop(*m_con, ic) );
00296 m_desktop->Open(m_password.c_str());
00297 m_builder.reset( new DeviceBuilder(*m_desktop) );
00298
00299 if( m_add_all ) {
00300 m_builder->Add(m_desktop->GetDBDB());
00301 }
00302 else {
00303 for( size_t i = 0; i < m_dbnames.size(); i++ ) {
00304 m_builder->Add(m_dbnames[i]);
00305 }
00306 }
00307
00308 return *m_builder;
00309 }
00310 };
00311
00312
00313
00314
00315 class TarInput : public InputBase
00316 {
00317 auto_ptr<Restore> m_restore;
00318 string m_tarpath;
00319 vector<string> m_dbnames;
00320
00321 public:
00322 void SetFilename(const std::string &name)
00323 {
00324 m_tarpath = name;
00325 if( name == "-" )
00326 throw runtime_error("Cannot use stdin as tar source file, sorry.");
00327 }
00328
00329 void AddDB(const std::string &dbname)
00330 {
00331 m_dbnames.push_back(dbname);
00332 }
00333
00334 Builder& GetBuilder(Barry::Probe *probe, IConverter &ic)
00335 {
00336 m_restore.reset( new Restore(m_tarpath, true) );
00337 for( size_t i = 0; i < m_dbnames.size(); i++ ) {
00338 m_restore->AddDB(m_dbnames[i]);
00339 }
00340
00341 return *m_restore;
00342 }
00343 };
00344
00345
00346
00347
00348 #ifdef __BARRY_BOOST_MODE__
00349 class BoostInput : public InputBase
00350 {
00351 auto_ptr<BoostBuilder> m_builder;
00352 string m_filename;
00353
00354 public:
00355 BoostInput()
00356 : m_filename("-")
00357 {
00358 }
00359
00360 void SetFilename(const std::string &name)
00361 {
00362 m_filename = name;
00363 }
00364
00365 Builder& GetBuilder(Barry::Probe *probe, IConverter &ic)
00366 {
00367 if( m_filename == "-" ) {
00368
00369 m_builder.reset( new BoostBuilder(cin) );
00370 }
00371 else {
00372 m_builder.reset( new BoostBuilder(m_filename) );
00373 }
00374 return *m_builder;
00375 }
00376
00377 };
00378 #endif
00379
00380
00381
00382
00383 class LdifInput : public InputBase
00384 {
00385 auto_ptr<Builder> m_builder;
00386 string m_filename;
00387
00388 public:
00389 LdifInput()
00390 : m_filename("-")
00391 {
00392 }
00393
00394 void SetFilename(const std::string &name)
00395 {
00396 m_filename = name;
00397 }
00398
00399 Builder& GetBuilder(Barry::Probe *probe, IConverter &ic)
00400 {
00401 if( m_filename == "-" ) {
00402
00403 m_builder.reset(
00404 new RecordBuilder<Contact, LdifStore>(
00405 new LdifStore(cin)) );
00406 }
00407 else {
00408 m_builder.reset(
00409 new RecordBuilder<Contact, LdifStore>(
00410 new LdifStore(m_filename)) );
00411 }
00412 return *m_builder;
00413 }
00414
00415 };
00416
00417
00418
00419
00420
00421 class MimeInput : public InputBase
00422 {
00423 auto_ptr<MimeBuilder> m_builder;
00424 string m_filename;
00425
00426 public:
00427 MimeInput()
00428 : m_filename("-")
00429 {
00430 }
00431
00432 void SetFilename(const std::string &name)
00433 {
00434 m_filename = name;
00435 }
00436
00437 Builder& GetBuilder(Barry::Probe *probe, IConverter &ic)
00438 {
00439 if( m_filename == "-" ) {
00440
00441 m_builder.reset( new MimeBuilder(cin) );
00442 }
00443 else {
00444 m_builder.reset( new MimeBuilder(m_filename) );
00445 }
00446 return *m_builder;
00447 }
00448
00449 };
00450
00451
00452
00453
00454 class OutputBase : public virtual ModeBase
00455 {
00456 public:
00457 virtual Parser& GetParser(Barry::Probe *probe, IConverter &ic) = 0;
00458 };
00459
00460 class DeviceOutputBase : public DeviceBase, public OutputBase
00461 {
00462 };
00463
00464
00465
00466
00467 class DeviceOutput : public DeviceOutputBase
00468 {
00469 auto_ptr<Controller> m_con;
00470 auto_ptr<Mode::Desktop> m_desktop;
00471 auto_ptr<DeviceParser> m_parser;
00472 DeviceParser::WriteMode m_mode;
00473
00474 public:
00475 DeviceOutput()
00476 : m_mode(DeviceParser::DROP_RECORD)
00477 {
00478 }
00479
00480 void SetWriteMode(DeviceParser::WriteMode mode)
00481 {
00482 m_mode = mode;
00483 }
00484
00485 Parser& GetParser(Barry::Probe *probe, IConverter &ic)
00486 {
00487 int i = probe->FindActive(m_pin);
00488 if( i == -1 ) {
00489 if( m_pin.Valid() )
00490 throw runtime_error("PIN not found: " + m_pin.Str());
00491 else
00492 throw runtime_error("PIN not specified, and more than one device exists.");
00493 }
00494
00495 m_con.reset( new Controller(probe->Get(i)) );
00496 m_desktop.reset( new Mode::Desktop(*m_con, ic) );
00497 m_desktop->Open(m_password.c_str());
00498 m_parser.reset( new DeviceParser(*m_desktop, m_mode) );
00499
00500 return *m_parser;
00501 }
00502 };
00503
00504
00505
00506
00507 class TarOutput : public OutputBase
00508 {
00509 auto_ptr<Backup> m_backup;
00510 string m_tarpath;
00511
00512 public:
00513 void SetFilename(const std::string &name)
00514 {
00515 m_tarpath = name;
00516 if( name == "-" )
00517 throw runtime_error("Cannot use stdout as tar backup file, sorry.");
00518 }
00519
00520 Parser& GetParser(Barry::Probe *probe, IConverter &ic)
00521 {
00522 m_backup.reset( new Backup(m_tarpath) );
00523 return *m_backup;
00524 }
00525 };
00526
00527
00528
00529
00530 #ifdef __BARRY_BOOST_MODE__
00531 class BoostOutput : public OutputBase
00532 {
00533 auto_ptr<BoostParser> m_parser;
00534 string m_filename;
00535
00536 public:
00537 void SetFilename(const std::string &name)
00538 {
00539 m_filename = name;
00540 }
00541
00542 Parser& GetParser(Barry::Probe *probe, IConverter &ic)
00543 {
00544 if( !m_filename.size() )
00545 throw runtime_error("Boost output requires a specific output file (-f switch)");
00546
00547 if( m_filename == "-" ) {
00548
00549 m_parser.reset( new BoostParser(cout) );
00550 }
00551 else {
00552 m_parser.reset( new BoostParser(m_filename) );
00553 }
00554 return *m_parser;
00555 }
00556
00557 };
00558 #endif
00559
00560
00561
00562
00563 class LdifOutput : public OutputBase
00564 {
00565 auto_ptr<Parser> m_parser;
00566 string m_filename;
00567 string m_baseDN;
00568 string m_dnattr;
00569
00570 public:
00571 LdifOutput()
00572 : m_filename("-")
00573 {
00574 }
00575
00576 void SetFilename(const std::string &name)
00577 {
00578 m_filename = name;
00579 }
00580
00581 void SetDN(const std::string &dn)
00582 {
00583 m_baseDN = dn;
00584 }
00585
00586 void SetAttribute(const std::string &attr)
00587 {
00588 m_dnattr = attr;
00589 }
00590
00591 Parser& GetParser(Barry::Probe *probe, IConverter &ic)
00592 {
00593 if( m_filename == "-" ) {
00594
00595 m_parser.reset(
00596 new RecordParser<Contact, LdifStore>(
00597 new LdifStore(cout, m_baseDN,
00598 m_dnattr)) );
00599 }
00600 else {
00601 m_parser.reset(
00602 new RecordParser<Contact, LdifStore>(
00603 new LdifStore(m_filename, m_baseDN,
00604 m_dnattr)) );
00605 }
00606 return *m_parser;
00607 }
00608 };
00609
00610
00611
00612
00613 class MimeStore : public AllRecordStore
00614 {
00615 std::ostream &m_os;
00616
00617 public:
00618 MimeStore(std::ostream &os)
00619 : m_os(os)
00620 {
00621 }
00622
00623 #undef HANDLE_PARSER
00624 #define HANDLE_PARSER(tname) \
00625 void operator() (const Barry::tname &r) \
00626 { \
00627 MimeDump<tname>::Dump(m_os, r); \
00628 }
00629
00630 ALL_KNOWN_PARSER_TYPES
00631 };
00632
00633 class MimeOutput : public OutputBase
00634 {
00635 auto_ptr<std::ofstream> m_file;
00636 auto_ptr<Parser> m_parser;
00637 std::string m_filename;
00638
00639 public:
00640 MimeOutput()
00641 : m_filename("-")
00642 {
00643 }
00644
00645 void SetFilename(const std::string &name)
00646 {
00647 m_filename = name;
00648 }
00649
00650 Parser& GetParser(Barry::Probe *probe, IConverter &ic)
00651 {
00652 if( m_filename == "-" ) {
00653 m_parser.reset( new AllRecordParser(cout,
00654 new HexDumpParser(cout),
00655 new MimeStore(cout)) );
00656 }
00657 else {
00658 m_file.reset( new std::ofstream(m_filename.c_str()) );
00659 m_parser.reset( new AllRecordParser(*m_file,
00660 new HexDumpParser(*m_file),
00661 new MimeStore(*m_file)) );
00662 }
00663 return *m_parser;
00664 }
00665 };
00666
00667
00668
00669
00670 class DumpOutput : public OutputBase
00671 {
00672 auto_ptr<Parser> m_parser;
00673 bool m_hex_only;
00674
00675 public:
00676 DumpOutput()
00677 : m_hex_only(false)
00678 {
00679 }
00680
00681 void SetHexDump()
00682 {
00683 m_hex_only = true;
00684 }
00685
00686 Parser& GetParser(Barry::Probe *probe, IConverter &ic)
00687 {
00688 if( m_hex_only ) {
00689 m_parser.reset( new HexDumpParser(cout) );
00690 }
00691 else {
00692 m_parser.reset( new AllRecordParser(cout,
00693 new HexDumpParser(cout),
00694 new AllRecordDumpStore(cout)) );
00695 }
00696 return *m_parser;
00697 }
00698 };
00699
00700
00701
00702
00703 class Sha1Output : public OutputBase
00704 {
00705 auto_ptr<Parser> m_parser;
00706 bool m_include_ids;
00707
00708 public:
00709 Sha1Output()
00710 : m_include_ids(false)
00711 {
00712 }
00713
00714 void IncludeIDs()
00715 {
00716 m_include_ids = true;
00717 }
00718
00719 Parser& GetParser(Barry::Probe *probe, IConverter &ic)
00720 {
00721 m_parser.reset( new ChecksumParser(m_include_ids) );
00722 return *m_parser;
00723 }
00724 };
00725
00726
00727
00728
00729 class ContentStoreOutput : public OutputBase
00730 {
00731 auto_ptr<Parser> m_parser;
00732 bool m_list_only;
00733 vector<string> m_filenames;
00734
00735 public:
00736 ContentStoreOutput()
00737 : m_list_only(false)
00738 {
00739 }
00740
00741 void SetFilename(const std::string &name)
00742 {
00743 m_filenames.push_back(name);
00744 }
00745
00746 void SetList()
00747 {
00748 m_list_only = true;
00749 }
00750
00751 Parser& GetParser(Barry::Probe *probe, IConverter &ic)
00752 {
00753 m_parser.reset( new RecordParser<ContentStore, ContentStoreOutput>(*this) );
00754 return *m_parser;
00755 }
00756
00757
00758 void operator() (const ContentStore &rec)
00759 {
00760 if( m_list_only ) {
00761 cout << rec.Filename;
00762 if( rec.FolderFlag ) {
00763 cout << " (folder)";
00764 }
00765 cout << endl;
00766 }
00767 else {
00768
00769
00770 vector<string>::iterator i = find(m_filenames.begin(),
00771 m_filenames.end(), rec.Filename);
00772 if( i != m_filenames.end() ) {
00773 SaveFile(rec);
00774 }
00775 }
00776 }
00777
00778 void SaveFile(const ContentStore &rec)
00779 {
00780 size_t slash = rec.Filename.rfind('/');
00781 string filename;
00782 if( slash == string::npos )
00783 filename = rec.Filename;
00784 else
00785 filename = rec.Filename.substr(slash + 1);
00786
00787
00788
00789 string freshname = filename;
00790 int count = 0;
00791 while( access(freshname.c_str(), F_OK) == 0 ) {
00792 ostringstream oss;
00793 oss << filename << count++;
00794 freshname = oss.str();
00795 }
00796
00797
00798 cout << "Saving: " << rec.Filename
00799 << " as " << freshname << endl;
00800 ofstream ofs(freshname.c_str());
00801 ofs << rec.FileContent;
00802 ofs.flush();
00803 if( !ofs ) {
00804 cout << "Error during write!" << endl;
00805 }
00806 }
00807 };
00808
00809
00810
00811
00812
00813
00814 class App
00815 {
00816 public:
00817 typedef shared_ptr<OutputBase> OutputPtr;
00818 typedef vector<OutputPtr> OutputsType;
00819
00820 private:
00821 auto_ptr<InputBase> Input;
00822 OutputsType Outputs;
00823
00824 public:
00825
00826 bool ParseInMode(const string &mode);
00827 bool ParseOutMode(const string &mode);
00828 DeviceParser::WriteMode ParseWriteMode(const std::string &mode);
00829 static void ShowParsers();
00830
00831 bool OutputsProbeNeeded();
00832 int main(int argc, char *argv[]);
00833 };
00834
00835 bool App::ParseInMode(const string &mode)
00836 {
00837 if( mode == "device" ) {
00838 Input.reset( new DeviceInput );
00839 return true;
00840 }
00841 else if( mode == "tar" ) {
00842 Input.reset( new TarInput );
00843 return true;
00844 }
00845 #ifdef __BARRY_BOOST_MODE__
00846 else if( mode == "boost" ) {
00847 Input.reset( new BoostInput );
00848 return true;
00849 }
00850 #endif
00851 else if( mode == "ldif" ) {
00852 Input.reset( new LdifInput );
00853 return true;
00854 }
00855 else if( mode == "mime" ) {
00856 Input.reset( new MimeInput );
00857 return true;
00858 }
00859 else
00860 return false;
00861 }
00862
00863 bool App::ParseOutMode(const string &mode)
00864 {
00865 if( mode == "device" ) {
00866 Outputs.push_back( OutputPtr(new DeviceOutput) );
00867 return true;
00868 }
00869 else if( mode == "tar" ) {
00870 Outputs.push_back( OutputPtr(new TarOutput) );
00871 return true;
00872 }
00873 #ifdef __BARRY_BOOST_MODE__
00874 else if( mode == "boost" ) {
00875 Outputs.push_back( OutputPtr(new BoostOutput) );
00876 return true;
00877 }
00878 #endif
00879 else if( mode == "ldif" ) {
00880 Outputs.push_back( OutputPtr(new LdifOutput) );
00881 return true;
00882 }
00883 else if( mode == "mime" ) {
00884 Outputs.push_back( OutputPtr(new MimeOutput) );
00885 return true;
00886 }
00887 else if( mode == "dump" ) {
00888 Outputs.push_back( OutputPtr(new DumpOutput) );
00889 return true;
00890 }
00891 else if( mode == "sha1" ) {
00892 Outputs.push_back( OutputPtr(new Sha1Output) );
00893 return true;
00894 }
00895 else if( mode == "cstore" ) {
00896 Outputs.push_back( OutputPtr(new ContentStoreOutput) );
00897 return true;
00898 }
00899 else
00900 return false;
00901 }
00902
00903 DeviceParser::WriteMode App::ParseWriteMode(const std::string &mode)
00904 {
00905 if( mode == "erase" )
00906 return DeviceParser::ERASE_ALL_WRITE_ALL;
00907 else if( mode == "overwrite" )
00908 return DeviceParser::INDIVIDUAL_OVERWRITE;
00909 else if( mode == "addonly" )
00910 return DeviceParser::ADD_BUT_NO_OVERWRITE;
00911 else if( mode == "addnew" )
00912 return DeviceParser::ADD_WITH_NEW_ID;
00913 else
00914 throw runtime_error("Unknown device output mode. Must be one of: erase, overwrite, addonly, addnew");
00915 }
00916
00917 void App::ShowParsers()
00918 {
00919 cout << "Supported Database parsers:\n"
00920 << " (* = can display in vformat MIME mode)\n"
00921
00922 #undef HANDLE_PARSER
00923 #define HANDLE_PARSER(tname) \
00924 << " " << tname::GetDBName() \
00925 << (MimeDump<tname>::Supported() ? " *" : "") << "\n"
00926
00927 ALL_KNOWN_PARSER_TYPES
00928
00929 << "\n"
00930 << "Supported Database builders:\n"
00931
00932 #undef HANDLE_BUILDER
00933 #define HANDLE_BUILDER(tname) \
00934 << " " << tname::GetDBName() << "\n"
00935
00936 ALL_KNOWN_BUILDER_TYPES
00937
00938 << endl;
00939 }
00940
00941 bool App::OutputsProbeNeeded()
00942 {
00943 for( OutputsType::iterator i = Outputs.begin();
00944 i != Outputs.end();
00945 ++i )
00946 {
00947 if( (*i)->ProbeNeeded() )
00948 return true;
00949 }
00950 return false;
00951 }
00952
00953 int App::main(int argc, char *argv[])
00954 {
00955 bool verbose = false;
00956 string iconvCharset;
00957
00958
00959 ModeBase *current = 0;
00960 for(;;) {
00961 int cmd = getopt(argc, argv, "hi:o:nvI:f:p:P:d:c:C:ASw:tl");
00962 if( cmd == -1 )
00963 break;
00964
00965
00966 if( !current ) {
00967 if( cmd != 'i' && \
00968 cmd != 'o' && \
00969 cmd != 'S' && \
00970 cmd != 'I' && \
00971 cmd != 'v' )
00972 {
00973 Usage();
00974 return 1;
00975 }
00976 }
00977
00978 switch( cmd )
00979 {
00980 case 'i':
00981
00982 if( Input.get() || !ParseInMode(optarg) ) {
00983 Usage();
00984 return 1;
00985 }
00986 current = Input.get();
00987 break;
00988
00989 case 'o':
00990
00991 if( !ParseOutMode(optarg) ) {
00992 Usage();
00993 return 1;
00994 }
00995 current = Outputs[Outputs.size() - 1].get();
00996 break;
00997
00998
00999 case 'c':
01000 current->SetDN(optarg);
01001 break;
01002
01003 case 'C':
01004 current->SetAttribute(optarg);
01005 break;
01006
01007 case 'd':
01008 current->AddDB(optarg);
01009 break;
01010
01011 case 'f':
01012 current->SetFilename(optarg);
01013 break;
01014
01015 case 'p':
01016 current->SetPIN(optarg);
01017 break;
01018
01019 case 'P':
01020 current->SetPassword(optarg);
01021 break;
01022
01023 case 'w':
01024 current->SetWriteMode(ParseWriteMode(optarg));
01025 break;
01026
01027 case 'A':
01028 current->AddAllDBs();
01029 break;
01030
01031 case 't':
01032 current->IncludeIDs();
01033 break;
01034
01035 case 'l':
01036 current->SetList();
01037 break;
01038
01039 case 'S':
01040 ShowParsers();
01041 return 0;
01042
01043 case 'I':
01044 iconvCharset = optarg;
01045 break;
01046
01047 case 'n':
01048 current->SetHexDump();
01049 break;
01050
01051 case 'v':
01052 verbose = true;
01053 break;
01054
01055 case 'h':
01056 default:
01057 Usage();
01058 return 0;
01059 }
01060 }
01061
01062 if( !Input.get() || !Outputs.size() ) {
01063 Usage();
01064 return 0;
01065 }
01066
01067
01068 Barry::Init(verbose);
01069
01070
01071 auto_ptr<IConverter> ic;
01072 if( iconvCharset.size() ) {
01073 ic.reset( new IConverter(iconvCharset.c_str(), true) );
01074 }
01075
01076
01077 auto_ptr<Probe> probe;
01078 if( Input->ProbeNeeded() || OutputsProbeNeeded() ) {
01079
01080 probe.reset( new Probe );
01081 }
01082
01083
01084 Builder &builder = Input->GetBuilder(probe.get(), *ic);
01085
01086
01087 TeeParser tee;
01088 for( OutputsType::iterator i = Outputs.begin(); i != Outputs.end(); ++i ) {
01089 Parser &parser = (*i)->GetParser(probe.get(), *ic);
01090 tee.Add(parser);
01091 }
01092
01093
01094 Pipe pipe(builder);
01095 pipe.PumpFile(tee, ic.get());
01096
01097 return 0;
01098 }
01099
01100 int main(int argc, char *argv[])
01101 {
01102 try {
01103 App app;
01104 return app.main(argc, argv);
01105 }
01106 catch( std::exception &e ) {
01107 cerr << "Exception: " << e.what() << endl;
01108 return 1;
01109 }
01110 }
01111