Updated TODO
[barry.git] / tools / bio.cc
blob04d1decfccd31a4507d32259dcd477aab2c08841
1 ///
2 /// \file bio.cc
3 /// Barry Input / Output
4 ///
6 /*
7 Copyright (C) 2010, 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>
23 #include <barry/barrysync.h>
24 #include <barry/barrybackup.h>
26 #include "mimedump.h"
27 #include "brecsum.h"
29 #include <iomanip>
30 #include <iostream>
31 #include <sstream>
32 #include <fstream>
33 #include <string>
34 #include <vector>
35 #include <algorithm>
36 #include <stdexcept>
37 #include <tr1/memory>
38 #include <getopt.h>
39 #include <strings.h>
41 using namespace std;
42 using namespace std::tr1;
43 using namespace Barry;
45 void Usage()
47 int major, minor;
48 const char *Version = Barry::Version(major, minor);
50 cerr
51 << "bio - Barry Input / Output\n"
52 << " Copyright 2010, Net Direct Inc. (http://www.netdirect.ca/)\n"
53 << " Using: " << Version << "\n"
54 << " Compiled "
55 #ifdef __BARRY_BOOST_MODE__
56 << "with"
57 #else
58 << "without"
59 #endif
60 << " Boost support\n"
61 << "\n"
62 << " Usage: bio -i <type> [options...] -o <type> [options...]\n"
63 << "\n"
64 << " -i type The input type (Builder) to use for producing records\n"
65 << " Can be one of: device, tar"
66 #ifdef __BARRY_BOOST_MODE__
67 << ", boost"
68 #endif
69 << ", ldif, mime\n"
70 << " -o type The output type (Parser) to use for processing records.\n"
71 << " Multiple outputs are allowed, as long as they don't\n"
72 << " conflict (such as two outputs writing to the same file\n"
73 << " or device).\n"
74 << " Can be one of: device, tar"
75 #ifdef __BARRY_BOOST_MODE__
76 << ", boost"
77 #endif
78 << ", ldif, mime, dump, sha1, cstore\n"
79 << "\n"
80 << " Options to use for 'device' type:\n"
81 << " -d db Name of input database. Can be used multiple times.\n"
82 << " -A Add all available device databases, instead of specifying\n"
83 << " them manually via -d\n"
84 << " -p pin PIN of device to talk to\n"
85 << " If only one device is plugged in, this flag is optional\n"
86 << " -P pass Simplistic method to specify device password\n"
87 << " -w mode Set write mode when using 'device' for output. Must be\n"
88 << " specified, or will not write anything.\n"
89 << " Can be one of: erase, overwrite, addonly, addnew\n"
91 // FIXME - modifiers not yet implemented
92 << "\n"
93 << " Input database modifiers: (can be used multiple times for more than 1 record)\n"
94 << "\n"
95 << " -r # Record index number as seen in the -T state table.\n"
96 << " This overrides the default -d behaviour, and only\n"
97 << " downloads the one specified record, sending to stdout.\n"
98 << " -R # Same as -r, but also clears the record's dirty flags.\n"
99 << " -D # Record index number as seen in the -T state table,\n"
100 << " which indicates the record to delete. Used with the -d\n"
101 << " command to specify the database.\n"
103 << "\n"
104 << " Options to use for 'tar' backup type:\n"
105 << " -d db Name of input database. Can be used multiple times.\n"
106 << " Not available in output mode. Note that by default,\n"
107 << " all databases in the backup are selected, when reading,\n"
108 << " unless at least one -d is specified.\n"
109 << " -f file Tar backup file to read from or write to\n"
110 #ifdef __BARRY_BOOST_MODE__
111 << "\n"
112 << " Options to use for 'boost' type:\n"
113 << " -f file Boost serialization filename to read from or write to\n"
114 << " Can use - to specify stdin/stdout\n"
115 #endif
116 << "\n"
117 << " Options to use for 'ldif' type:\n"
118 << " -c dn Convert address book database to LDIF format, using the\n"
119 << " specified baseDN\n"
120 << " -C dnattr LDIF attribute name to use when building the FQDN\n"
121 << " Defaults to 'cn'\n"
123 LDIF options?
125 << " -L List Contact field names\n"
126 << " -m Map LDIF name to Contact field / Unmap LDIF name\n"
127 << " Map: ldif,read,write - maps ldif to read/write Contact fields\n"
128 << " Unmap: ldif name alone\n"
129 << " -M List current LDIF mapping\n"
131 << "\n"
132 << " Options to use for 'mime' type:\n"
133 << " -f file Filename to read from or write to. Use - to explicitly\n"
134 << " specify stdin/stdout, which is default.\n"
135 << "\n"
136 << " Options to use for 'dump' to stdout output type:\n"
137 << " -n Use hex dump parser on all databases.\n"
138 << "\n"
139 << " Options to use for 'sha1' sum stdout output type:\n"
140 << " -t Include DB Name, Type, and Unique record IDs in the checksums\n"
141 << "\n"
142 << " Options to use for 'cstore' output type:\n"
143 << " -l List filenames only\n"
144 << " -f file Filename from the above list, including path.\n"
145 << " If found, the file will be written to the current\n"
146 << " directory, using the base filename from the device.\n"
147 << "\n"
148 << " Standalone options:\n"
149 << " -h This help\n"
150 << " -I cs International charset for string conversions\n"
151 << " Valid values here are available with 'iconv --list'\n"
152 << " -S Show list of supported database parsers and builders\n"
153 << " -v Dump protocol data during operation\n"
154 << "\n"
155 << endl;
158 class ModeBase
160 public:
161 virtual ~ModeBase() {}
163 virtual bool ProbeNeeded() const { return false; }
165 virtual void SetFilename(const std::string &name)
167 throw runtime_error("Filename not applicable for this mode");
170 virtual void AddDB(const std::string &dbname)
172 throw runtime_error("DB not applicable for this mode");
175 virtual void AddAllDBs()
177 throw runtime_error("DBs not applicable for this mode");
180 virtual void SetPIN(const std::string &pin)
182 throw runtime_error("PIN not applicable for this mode");
185 virtual void SetPassword(const std::string &password)
187 throw runtime_error("Password not applicable for this mode");
190 virtual void SetWriteMode(DeviceParser::WriteMode mode)
192 throw runtime_error("Device write behaviour not applicable for this mode");
195 virtual void SetDN(const std::string &dn)
197 throw runtime_error("DN not applicable for this mode");
200 virtual void SetAttribute(const std::string &attr)
202 throw runtime_error("Attribute not applicable for this mode");
205 virtual void SetHexDump()
207 throw runtime_error("No hex dump option in this mode");
210 virtual void IncludeIDs()
212 throw runtime_error("Including record IDs in the SHA1 sum is not applicable in this mode");
215 virtual void SetList()
217 throw runtime_error("List option not applicable for this mode");
221 class DeviceBase : public virtual ModeBase
223 protected:
224 Barry::Pin m_pin;
225 std::string m_password;
227 public:
228 bool ProbeNeeded() const { return true; }
230 void SetPIN(const std::string &pin)
232 istringstream iss(pin);
233 iss >> m_pin;
234 if( !m_pin.Valid() )
235 throw runtime_error("Invalid PIN: " + pin);
238 void SetPassword(const std::string &password)
240 m_password = password;
244 //////////////////////////////////////////////////////////////////////////////
245 // Base class for Input Mode
247 class InputBase : public virtual ModeBase
249 public:
250 virtual Builder& GetBuilder(Barry::Probe *probe, IConverter &ic) = 0;
253 class DeviceInputBase : public DeviceBase, public InputBase
257 //////////////////////////////////////////////////////////////////////////////
258 // Mode: Input, Type: device
260 class DeviceInput : public DeviceInputBase
262 auto_ptr<Controller> m_con;
263 auto_ptr<Mode::Desktop> m_desktop;
264 auto_ptr<DeviceBuilder> m_builder;
265 vector<string> m_dbnames;
266 bool m_add_all;
268 public:
269 DeviceInput()
270 : m_add_all(false)
274 void AddDB(const std::string &dbname)
276 m_dbnames.push_back(dbname);
279 void AddAllDBs()
281 m_add_all = true;
284 Builder& GetBuilder(Barry::Probe *probe, IConverter &ic)
286 int i = probe->FindActive(m_pin);
287 if( i == -1 ) {
288 if( m_pin.Valid() )
289 throw runtime_error("PIN not found: " + m_pin.Str());
290 else
291 throw runtime_error("PIN not specified, and more than one device exists.");
294 m_con.reset( new Controller(probe->Get(i)) );
295 m_desktop.reset( new Mode::Desktop(*m_con, ic) );
296 m_desktop->Open(m_password.c_str());
297 m_builder.reset( new DeviceBuilder(*m_desktop) );
299 if( m_add_all ) {
300 m_builder->Add(m_desktop->GetDBDB());
302 else {
303 for( size_t i = 0; i < m_dbnames.size(); i++ ) {
304 m_builder->Add(m_dbnames[i]);
308 return *m_builder;
312 //////////////////////////////////////////////////////////////////////////////
313 // Mode: Input, Type: tar
315 class TarInput : public InputBase
317 auto_ptr<Restore> m_restore;
318 string m_tarpath;
319 vector<string> m_dbnames;
321 public:
322 void SetFilename(const std::string &name)
324 m_tarpath = name;
325 if( name == "-" )
326 throw runtime_error("Cannot use stdin as tar source file, sorry.");
329 void AddDB(const std::string &dbname)
331 m_dbnames.push_back(dbname);
334 Builder& GetBuilder(Barry::Probe *probe, IConverter &ic)
336 m_restore.reset( new Restore(m_tarpath, true) );
337 for( size_t i = 0; i < m_dbnames.size(); i++ ) {
338 m_restore->AddDB(m_dbnames[i]);
341 return *m_restore;
345 //////////////////////////////////////////////////////////////////////////////
346 // Mode: Input, Type: boost
348 #ifdef __BARRY_BOOST_MODE__
349 class BoostInput : public InputBase
351 auto_ptr<BoostBuilder> m_builder;
352 string m_filename;
354 public:
355 BoostInput()
356 : m_filename("-") // default to stdin/stdout
360 void SetFilename(const std::string &name)
362 m_filename = name;
365 Builder& GetBuilder(Barry::Probe *probe, IConverter &ic)
367 if( m_filename == "-" ) {
368 // use stdin
369 m_builder.reset( new BoostBuilder(cin) );
371 else {
372 m_builder.reset( new BoostBuilder(m_filename) );
374 return *m_builder;
378 #endif
380 //////////////////////////////////////////////////////////////////////////////
381 // Mode: Input, Type: ldif
383 class LdifInput : public InputBase
385 auto_ptr<Builder> m_builder;
386 string m_filename;
388 public:
389 LdifInput()
390 : m_filename("-")
394 void SetFilename(const std::string &name)
396 m_filename = name;
399 Builder& GetBuilder(Barry::Probe *probe, IConverter &ic)
401 if( m_filename == "-" ) {
402 // use stdin
403 m_builder.reset(
404 new RecordBuilder<Contact, LdifStore>(
405 new LdifStore(cin)) );
407 else {
408 m_builder.reset(
409 new RecordBuilder<Contact, LdifStore>(
410 new LdifStore(m_filename)) );
412 return *m_builder;
418 //////////////////////////////////////////////////////////////////////////////
419 // Mode: Input, Type: mime
421 class MimeInput : public InputBase
423 auto_ptr<MimeBuilder> m_builder;
424 string m_filename;
426 public:
427 MimeInput()
428 : m_filename("-")
432 void SetFilename(const std::string &name)
434 m_filename = name;
437 Builder& GetBuilder(Barry::Probe *probe, IConverter &ic)
439 if( m_filename == "-" ) {
440 // use stdin
441 m_builder.reset( new MimeBuilder(cin) );
443 else {
444 m_builder.reset( new MimeBuilder(m_filename) );
446 return *m_builder;
451 //////////////////////////////////////////////////////////////////////////////
452 // Base class for Output Mode
454 class OutputBase : public virtual ModeBase
456 public:
457 virtual Parser& GetParser(Barry::Probe *probe, IConverter &ic) = 0;
460 class DeviceOutputBase : public DeviceBase, public OutputBase
464 //////////////////////////////////////////////////////////////////////////////
465 // Mode: Output, Type: device
467 class DeviceOutput : public DeviceOutputBase
469 auto_ptr<Controller> m_con;
470 auto_ptr<Mode::Desktop> m_desktop;
471 auto_ptr<DeviceParser> m_parser;
472 DeviceParser::WriteMode m_mode;
474 public:
475 DeviceOutput()
476 : m_mode(DeviceParser::DROP_RECORD)
480 void SetWriteMode(DeviceParser::WriteMode mode)
482 m_mode = mode;
485 Parser& GetParser(Barry::Probe *probe, IConverter &ic)
487 int i = probe->FindActive(m_pin);
488 if( i == -1 ) {
489 if( m_pin.Valid() )
490 throw runtime_error("PIN not found: " + m_pin.Str());
491 else
492 throw runtime_error("PIN not specified, and more than one device exists.");
495 m_con.reset( new Controller(probe->Get(i)) );
496 m_desktop.reset( new Mode::Desktop(*m_con, ic) );
497 m_desktop->Open(m_password.c_str());
498 m_parser.reset( new DeviceParser(*m_desktop, m_mode) );
500 return *m_parser;
504 //////////////////////////////////////////////////////////////////////////////
505 // Mode: Output, Type: tar
507 class TarOutput : public OutputBase
509 auto_ptr<Backup> m_backup;
510 string m_tarpath;
512 public:
513 void SetFilename(const std::string &name)
515 m_tarpath = name;
516 if( name == "-" )
517 throw runtime_error("Cannot use stdout as tar backup file, sorry.");
520 Parser& GetParser(Barry::Probe *probe, IConverter &ic)
522 m_backup.reset( new Backup(m_tarpath) );
523 return *m_backup;
527 //////////////////////////////////////////////////////////////////////////////
528 // Mode: Output, Type: boost
530 #ifdef __BARRY_BOOST_MODE__
531 class BoostOutput : public OutputBase
533 auto_ptr<BoostParser> m_parser;
534 string m_filename;
536 public:
537 void SetFilename(const std::string &name)
539 m_filename = name;
542 Parser& GetParser(Barry::Probe *probe, IConverter &ic)
544 if( !m_filename.size() )
545 throw runtime_error("Boost output requires a specific output file (-f switch)");
547 if( m_filename == "-" ) {
548 // use stdout
549 m_parser.reset( new BoostParser(cout) );
551 else {
552 m_parser.reset( new BoostParser(m_filename) );
554 return *m_parser;
558 #endif
560 //////////////////////////////////////////////////////////////////////////////
561 // Mode: Output, Type: ldif
563 class LdifOutput : public OutputBase
565 auto_ptr<Parser> m_parser;
566 string m_filename;
567 string m_baseDN;
568 string m_dnattr;
570 public:
571 LdifOutput()
572 : m_filename("-")
576 void SetFilename(const std::string &name)
578 m_filename = name;
581 void SetDN(const std::string &dn)
583 m_baseDN = dn;
586 void SetAttribute(const std::string &attr)
588 m_dnattr = attr;
591 Parser& GetParser(Barry::Probe *probe, IConverter &ic)
593 if( m_filename == "-" ) {
594 // use stdin
595 m_parser.reset(
596 new RecordParser<Contact, LdifStore>(
597 new LdifStore(cout, m_baseDN,
598 m_dnattr)) );
600 else {
601 m_parser.reset(
602 new RecordParser<Contact, LdifStore>(
603 new LdifStore(m_filename, m_baseDN,
604 m_dnattr)) );
606 return *m_parser;
610 //////////////////////////////////////////////////////////////////////////////
611 // Mode: Output, Type: mime
613 class MimeStore : public AllRecordStore
615 std::ostream &m_os;
617 public:
618 MimeStore(std::ostream &os)
619 : m_os(os)
623 #undef HANDLE_PARSER
624 #define HANDLE_PARSER(tname) \
625 void operator() (const Barry::tname &r) \
627 MimeDump<tname>::Dump(m_os, r); \
630 ALL_KNOWN_PARSER_TYPES
633 class MimeOutput : public OutputBase
635 auto_ptr<std::ofstream> m_file;
636 auto_ptr<Parser> m_parser;
637 std::string m_filename;
639 public:
640 MimeOutput()
641 : m_filename("-") // default to stdout
645 void SetFilename(const std::string &name)
647 m_filename = name;
650 Parser& GetParser(Barry::Probe *probe, IConverter &ic)
652 if( m_filename == "-" ) {
653 m_parser.reset( new AllRecordParser(cout,
654 new HexDumpParser(cout),
655 new MimeStore(cout)) );
657 else {
658 m_file.reset( new std::ofstream(m_filename.c_str()) );
659 m_parser.reset( new AllRecordParser(*m_file,
660 new HexDumpParser(*m_file),
661 new MimeStore(*m_file)) );
663 return *m_parser;
667 //////////////////////////////////////////////////////////////////////////////
668 // Mode: Output, Type: dump
670 class DumpOutput : public OutputBase
672 auto_ptr<Parser> m_parser;
673 bool m_hex_only;
675 public:
676 DumpOutput()
677 : m_hex_only(false)
681 void SetHexDump()
683 m_hex_only = true;
686 Parser& GetParser(Barry::Probe *probe, IConverter &ic)
688 if( m_hex_only ) {
689 m_parser.reset( new HexDumpParser(cout) );
691 else {
692 m_parser.reset( new AllRecordParser(cout,
693 new HexDumpParser(cout),
694 new AllRecordDumpStore(cout)) );
696 return *m_parser;
700 //////////////////////////////////////////////////////////////////////////////
701 // Mode: Output, Type: sha1
703 class Sha1Output : public OutputBase
705 auto_ptr<Parser> m_parser;
706 bool m_include_ids;
708 public:
709 Sha1Output()
710 : m_include_ids(false)
714 void IncludeIDs()
716 m_include_ids = true;
719 Parser& GetParser(Barry::Probe *probe, IConverter &ic)
721 m_parser.reset( new ChecksumParser(m_include_ids) );
722 return *m_parser;
726 //////////////////////////////////////////////////////////////////////////////
727 // Mode: Output, Type: cstore
729 class ContentStoreOutput : public OutputBase
731 auto_ptr<Parser> m_parser;
732 bool m_list_only;
733 vector<string> m_filenames;
735 public:
736 ContentStoreOutput()
737 : m_list_only(false)
741 void SetFilename(const std::string &name)
743 m_filenames.push_back(name);
746 void SetList()
748 m_list_only = true;
751 Parser& GetParser(Barry::Probe *probe, IConverter &ic)
753 m_parser.reset( new RecordParser<ContentStore, ContentStoreOutput>(*this) );
754 return *m_parser;
757 // storage operator
758 void operator() (const ContentStore &rec)
760 if( m_list_only ) {
761 cout << rec.Filename;
762 if( rec.FolderFlag ) {
763 cout << " (folder)";
765 cout << endl;
767 else {
768 // check if this record matches one of the filenames
769 // in the list
770 vector<string>::iterator i = find(m_filenames.begin(),
771 m_filenames.end(), rec.Filename);
772 if( i != m_filenames.end() ) {
773 SaveFile(rec);
778 void SaveFile(const ContentStore &rec)
780 size_t slash = rec.Filename.rfind('/');
781 string filename;
782 if( slash == string::npos )
783 filename = rec.Filename;
784 else
785 filename = rec.Filename.substr(slash + 1);
787 // modify filename until we find one that doesn't
788 // already exist
789 string freshname = filename;
790 int count = 0;
791 while( access(freshname.c_str(), F_OK) == 0 ) {
792 ostringstream oss;
793 oss << filename << count++;
794 freshname = oss.str();
797 // open and write!
798 cout << "Saving: " << rec.Filename
799 << " as " << freshname << endl;
800 ofstream ofs(freshname.c_str());
801 ofs << rec.FileContent;
802 ofs.flush();
803 if( !ofs ) {
804 cout << "Error during write!" << endl;
811 //////////////////////////////////////////////////////////////////////////////
812 // Main application class
814 class App
816 public:
817 typedef shared_ptr<OutputBase> OutputPtr;
818 typedef vector<OutputPtr> OutputsType;
820 private:
821 auto_ptr<InputBase> Input;
822 OutputsType Outputs;
824 public:
826 bool ParseInMode(const string &mode);
827 bool ParseOutMode(const string &mode);
828 DeviceParser::WriteMode ParseWriteMode(const std::string &mode);
829 static void ShowParsers();
830 // returns true if any of the items in Outputs needs a probe
831 bool OutputsProbeNeeded();
832 int main(int argc, char *argv[]);
835 bool App::ParseInMode(const string &mode)
837 if( mode == "device" ) {
838 Input.reset( new DeviceInput );
839 return true;
841 else if( mode == "tar" ) {
842 Input.reset( new TarInput );
843 return true;
845 #ifdef __BARRY_BOOST_MODE__
846 else if( mode == "boost" ) {
847 Input.reset( new BoostInput );
848 return true;
850 #endif
851 else if( mode == "ldif" ) {
852 Input.reset( new LdifInput );
853 return true;
855 else if( mode == "mime" ) {
856 Input.reset( new MimeInput );
857 return true;
859 else
860 return false;
863 bool App::ParseOutMode(const string &mode)
865 if( mode == "device" ) {
866 Outputs.push_back( OutputPtr(new DeviceOutput) );
867 return true;
869 else if( mode == "tar" ) {
870 Outputs.push_back( OutputPtr(new TarOutput) );
871 return true;
873 #ifdef __BARRY_BOOST_MODE__
874 else if( mode == "boost" ) {
875 Outputs.push_back( OutputPtr(new BoostOutput) );
876 return true;
878 #endif
879 else if( mode == "ldif" ) {
880 Outputs.push_back( OutputPtr(new LdifOutput) );
881 return true;
883 else if( mode == "mime" ) {
884 Outputs.push_back( OutputPtr(new MimeOutput) );
885 return true;
887 else if( mode == "dump" ) {
888 Outputs.push_back( OutputPtr(new DumpOutput) );
889 return true;
891 else if( mode == "sha1" ) {
892 Outputs.push_back( OutputPtr(new Sha1Output) );
893 return true;
895 else if( mode == "cstore" ) {
896 Outputs.push_back( OutputPtr(new ContentStoreOutput) );
897 return true;
899 else
900 return false;
903 DeviceParser::WriteMode App::ParseWriteMode(const std::string &mode)
905 if( mode == "erase" )
906 return DeviceParser::ERASE_ALL_WRITE_ALL;
907 else if( mode == "overwrite" )
908 return DeviceParser::INDIVIDUAL_OVERWRITE;
909 else if( mode == "addonly" )
910 return DeviceParser::ADD_BUT_NO_OVERWRITE;
911 else if( mode == "addnew" )
912 return DeviceParser::ADD_WITH_NEW_ID;
913 else
914 throw runtime_error("Unknown device output mode. Must be one of: erase, overwrite, addonly, addnew");
917 void App::ShowParsers()
919 cout << "Supported Database parsers:\n"
920 << " (* = can display in vformat MIME mode)\n"
922 #undef HANDLE_PARSER
923 #define HANDLE_PARSER(tname) \
924 << " " << tname::GetDBName() \
925 << (MimeDump<tname>::Supported() ? " *" : "") << "\n"
927 ALL_KNOWN_PARSER_TYPES
929 << "\n"
930 << "Supported Database builders:\n"
932 #undef HANDLE_BUILDER
933 #define HANDLE_BUILDER(tname) \
934 << " " << tname::GetDBName() << "\n"
936 ALL_KNOWN_BUILDER_TYPES
938 << endl;
941 bool App::OutputsProbeNeeded()
943 for( OutputsType::iterator i = Outputs.begin();
944 i != Outputs.end();
945 ++i )
947 if( (*i)->ProbeNeeded() )
948 return true;
950 return false;
953 int App::main(int argc, char *argv[])
955 bool verbose = false;
956 string iconvCharset;
958 // process command line options
959 ModeBase *current = 0;
960 for(;;) {
961 int cmd = getopt(argc, argv, "hi:o:nvI:f:p:P:d:c:C:ASw:tl");
962 if( cmd == -1 )
963 break;
965 // first option must be in or out, or a global option
966 if( !current ) {
967 if( cmd != 'i' && \
968 cmd != 'o' && \
969 cmd != 'S' && \
970 cmd != 'I' && \
971 cmd != 'v' )
973 Usage();
974 return 1;
978 switch( cmd )
980 case 'i': // set input mode
981 // must be first time used
982 if( Input.get() || !ParseInMode(optarg) ) {
983 Usage();
984 return 1;
986 current = Input.get();
987 break;
989 case 'o': // set output mode
990 // can be used multiple times
991 if( !ParseOutMode(optarg) ) {
992 Usage();
993 return 1;
995 current = Outputs[Outputs.size() - 1].get();
996 break;
999 case 'c': // set ldif dn
1000 current->SetDN(optarg);
1001 break;
1003 case 'C': // set ldif attr
1004 current->SetAttribute(optarg);
1005 break;
1007 case 'd': // database name
1008 current->AddDB(optarg);
1009 break;
1011 case 'f': // filename
1012 current->SetFilename(optarg);
1013 break;
1015 case 'p': // device PIN
1016 current->SetPIN(optarg);
1017 break;
1019 case 'P': // password
1020 current->SetPassword(optarg);
1021 break;
1023 case 'w': // device write mode
1024 current->SetWriteMode(ParseWriteMode(optarg));
1025 break;
1027 case 'A': // add all DB names to the device builder
1028 current->AddAllDBs();
1029 break;
1031 case 't': // include type and IDs in sha1 mode
1032 current->IncludeIDs();
1033 break;
1035 case 'l': // list only
1036 current->SetList();
1037 break;
1039 case 'S': // show parsers and builders
1040 ShowParsers();
1041 return 0;
1043 case 'I': // international charset (iconv)
1044 iconvCharset = optarg;
1045 break;
1047 case 'n': // use null hex dump parser only
1048 current->SetHexDump();
1049 break;
1051 case 'v': // verbose
1052 verbose = true;
1053 break;
1055 case 'h': // help
1056 default:
1057 Usage();
1058 return 0;
1062 if( !Input.get() || !Outputs.size() ) {
1063 Usage();
1064 return 0;
1067 // Initialize the Barry library
1068 Barry::Init(verbose);
1070 // Create an IConverter object if needed
1071 auto_ptr<IConverter> ic;
1072 if( iconvCharset.size() ) {
1073 ic.reset( new IConverter(iconvCharset.c_str(), true) );
1076 // Probe for devices only if needed
1077 auto_ptr<Probe> probe;
1078 if( Input->ProbeNeeded() || OutputsProbeNeeded() ) {
1079 // Probe for available devices
1080 probe.reset( new Probe );
1083 // Setup the input first (builder)
1084 Builder &builder = Input->GetBuilder(probe.get(), *ic);
1086 // Setup a TeeParser with all Outputs
1087 TeeParser tee;
1088 for( OutputsType::iterator i = Outputs.begin(); i != Outputs.end(); ++i ) {
1089 Parser &parser = (*i)->GetParser(probe.get(), *ic);
1090 tee.Add(parser);
1093 // Setup the pipe
1094 Pipe pipe(builder);
1095 pipe.PumpFile(tee, ic.get());
1097 return 0;
1100 int main(int argc, char *argv[])
1102 try {
1103 App app;
1104 return app.main(argc, argv);
1106 catch( std::exception &e ) {
1107 cerr << "Exception: " << e.what() << endl;
1108 return 1;