Cleaned up Orange UK file formatting to match the others
[barry/progweb.git] / tools / bio.cc
blobe984408c5e730eff07549ae47f4bcd4c55530fb8
1 ///
2 /// \file bio.cc
3 /// Barry Input / Output
4 ///
6 /*
7 Copyright (C) 2010-2011, 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 // keeping a record of all the -i device / -o device pin numbers, so
46 // we can warn the poor user appropriately
47 std::vector<Barry::Pin> m_device_pins;
49 bool IsPinUsed(const Barry::Pin &pin)
51 for( std::vector<Barry::Pin>::const_iterator b = m_device_pins.begin();
52 b != m_device_pins.end(); ++b )
54 if( *b == pin )
55 return true;
57 return false;
60 void Usage()
62 int logical, major, minor;
63 const char *Version = Barry::Version(logical, major, minor);
65 cerr
66 << "bio - Barry Input / Output\n"
67 << " Copyright 2010-2011, Net Direct Inc. (http://www.netdirect.ca/)\n"
68 << " Using: " << Version << "\n"
69 << " Compiled "
70 #ifdef __BARRY_BOOST_MODE__
71 << "with"
72 #else
73 << "without"
74 #endif
75 << " Boost support\n"
76 << "\n"
77 << " Usage: bio -i <type> [options...] -o <type> [options...]\n"
78 << "\n"
79 << " -i type The input type (Builder) to use for producing records\n"
80 << " Can be one of: device, tar"
81 #ifdef __BARRY_BOOST_MODE__
82 << ", boost"
83 #endif
84 << ", ldif, mime\n"
85 << " -o type The output type (Parser) to use for processing records.\n"
86 << " Multiple outputs are allowed, as long as they don't\n"
87 << " conflict (such as two outputs writing to the same file\n"
88 << " or device).\n"
89 << " Can be one of: device, tar"
90 #ifdef __BARRY_BOOST_MODE__
91 << ", boost"
92 #endif
93 << ", ldif, mime, dump, sha1, cstore\n"
94 << "\n"
95 << " Options to use for 'device' type:\n"
96 << " -d db Name of input database. Can be used multiple times.\n"
97 << " -A Add all available device databases, instead of specifying\n"
98 << " them manually via -d\n"
99 << " -p pin PIN of device to talk to\n"
100 << " If only one device is plugged in, this flag is optional\n"
101 << " -P pass Simplistic method to specify device password\n"
102 << " -w mode Set write mode when using 'device' for output. Must be\n"
103 << " specified, or will not write anything.\n"
104 << " Can be one of: erase, overwrite, addonly, addnew\n"
106 // FIXME - modifiers not yet implemented
107 << "\n"
108 << " Input database modifiers: (can be used multiple times for more than 1 record)\n"
109 << "\n"
110 << " -r # Record index number as seen in the -T state table.\n"
111 << " This overrides the default -d behaviour, and only\n"
112 << " downloads the one specified record, sending to stdout.\n"
113 << " -R # Same as -r, but also clears the record's dirty flags.\n"
114 << " -D # Record index number as seen in the -T state table,\n"
115 << " which indicates the record to delete. Used with the -d\n"
116 << " command to specify the database.\n"
118 << "\n"
119 << " Options to use for 'tar' backup type:\n"
120 << " -d db Name of input database. Can be used multiple times.\n"
121 << " Not available in output mode. Note that by default,\n"
122 << " all databases in the backup are selected, when reading,\n"
123 << " unless at least one -d is specified.\n"
124 << " -f file Tar backup file to read from or write to\n"
125 #ifdef __BARRY_BOOST_MODE__
126 << "\n"
127 << " Options to use for 'boost' type:\n"
128 << " -f file Boost serialization filename to read from or write to\n"
129 << " Can use - to specify stdin/stdout\n"
130 #endif
131 << "\n"
132 << " Options to use for 'ldif' type:\n"
133 << " -c dn Convert address book database to LDIF format, using the\n"
134 << " specified baseDN\n"
135 << " -C dnattr LDIF attribute name to use when building the FQDN\n"
136 << " Defaults to 'cn'\n"
138 LDIF options?
140 << " -L List Contact field names\n"
141 << " -m Map LDIF name to Contact field / Unmap LDIF name\n"
142 << " Map: ldif,read,write - maps ldif to read/write Contact fields\n"
143 << " Unmap: ldif name alone\n"
144 << " -M List current LDIF mapping\n"
146 << "\n"
147 << " Options to use for 'mime' type:\n"
148 << " -f file Filename to read from or write to. Use - to explicitly\n"
149 << " specify stdin/stdout, which is default.\n"
150 << "\n"
151 << " Options to use for 'dump' to stdout output type:\n"
152 << " -n Use hex dump parser on all databases.\n"
153 << "\n"
154 << " Options to use for 'sha1' sum stdout output type:\n"
155 << " -t Include DB Name, Type, and Unique record IDs in the checksums\n"
156 << "\n"
157 << " Options to use for 'cstore' output type:\n"
158 << " -l List filenames only\n"
159 << " -f file Filename from the above list, including path.\n"
160 << " If found, the file will be written to the current\n"
161 << " directory, using the base filename from the device.\n"
162 << "\n"
163 << " Standalone options:\n"
164 << " -h This help\n"
165 << " -I cs International charset for string conversions\n"
166 << " Valid values here are available with 'iconv --list'\n"
167 << " -S Show list of supported database parsers and builders\n"
168 << " -v Dump protocol data during operation\n"
169 << "\n"
170 << endl;
173 class ModeBase
175 public:
176 virtual ~ModeBase() {}
178 virtual bool ProbeNeeded() const { return false; }
180 virtual void SetFilename(const std::string &name)
182 throw runtime_error("Filename not applicable for this mode");
185 virtual void AddDB(const std::string &dbname)
187 throw runtime_error("DB not applicable for this mode");
190 virtual void AddAllDBs()
192 throw runtime_error("DBs not applicable for this mode");
195 virtual void SetPIN(const std::string &pin)
197 throw runtime_error("PIN not applicable for this mode");
200 virtual void SetPassword(const std::string &password)
202 throw runtime_error("Password not applicable for this mode");
205 virtual void SetWriteMode(DeviceParser::WriteMode mode)
207 throw runtime_error("Device write behaviour not applicable for this mode");
210 virtual void SetDN(const std::string &dn)
212 throw runtime_error("DN not applicable for this mode");
215 virtual void SetAttribute(const std::string &attr)
217 throw runtime_error("Attribute not applicable for this mode");
220 virtual void SetHexDump()
222 throw runtime_error("No hex dump option in this mode");
225 virtual void IncludeIDs()
227 throw runtime_error("Including record IDs in the SHA1 sum is not applicable in this mode");
230 virtual void SetList()
232 throw runtime_error("List option not applicable for this mode");
236 class DeviceBase : public virtual ModeBase
238 protected:
239 Barry::Pin m_pin;
240 std::string m_password;
242 public:
243 bool ProbeNeeded() const { return true; }
245 void SetPIN(const std::string &pin)
247 istringstream iss(pin);
248 iss >> m_pin;
249 if( !m_pin.Valid() )
250 throw runtime_error("Invalid PIN: " + pin);
253 void SetPassword(const std::string &password)
255 m_password = password;
259 //////////////////////////////////////////////////////////////////////////////
260 // Base class for Input Mode
262 class InputBase : public virtual ModeBase
264 public:
265 virtual Builder& GetBuilder(Barry::Probe *probe, IConverter &ic) = 0;
268 class DeviceInputBase : public DeviceBase, public InputBase
272 //////////////////////////////////////////////////////////////////////////////
273 // Mode: Input, Type: device
275 class DeviceInput : public DeviceInputBase
277 auto_ptr<Controller> m_con;
278 auto_ptr<Mode::Desktop> m_desktop;
279 auto_ptr<DeviceBuilder> m_builder;
280 vector<string> m_dbnames;
281 bool m_add_all;
283 public:
284 DeviceInput()
285 : m_add_all(false)
289 void AddDB(const std::string &dbname)
291 m_dbnames.push_back(dbname);
294 void AddAllDBs()
296 m_add_all = true;
299 Builder& GetBuilder(Barry::Probe *probe, IConverter &ic)
301 int i = probe->FindActive(m_pin);
302 if( i == -1 ) {
303 if( m_pin.Valid() )
304 throw runtime_error("PIN not found: " + m_pin.Str());
305 else
306 throw runtime_error("PIN not specified, and more than one device exists.");
309 if( IsPinUsed(probe->Get(i).m_pin) ) {
310 throw runtime_error("It seems you are trying to use the same device for multiple input or outputs.");
312 m_device_pins.push_back(probe->Get(i).m_pin);
314 m_con.reset( new Controller(probe->Get(i)) );
315 m_desktop.reset( new Mode::Desktop(*m_con, ic) );
316 m_desktop->Open(m_password.c_str());
317 m_builder.reset( new DeviceBuilder(*m_desktop) );
319 if( m_add_all ) {
320 m_builder->Add(m_desktop->GetDBDB());
322 else {
323 for( size_t i = 0; i < m_dbnames.size(); i++ ) {
324 if( !m_builder->Add(m_dbnames[i]) )
325 throw runtime_error("Database not found: " + m_dbnames[i]);
329 return *m_builder;
333 //////////////////////////////////////////////////////////////////////////////
334 // Mode: Input, Type: tar
336 class TarInput : public InputBase
338 auto_ptr<Restore> m_restore;
339 string m_tarpath;
340 vector<string> m_dbnames;
342 public:
343 void SetFilename(const std::string &name)
345 m_tarpath = name;
346 if( name == "-" )
347 throw runtime_error("Cannot use stdin as tar source file, sorry.");
350 void AddDB(const std::string &dbname)
352 m_dbnames.push_back(dbname);
355 Builder& GetBuilder(Barry::Probe *probe, IConverter &ic)
357 m_restore.reset( new Restore(m_tarpath, true) );
358 for( size_t i = 0; i < m_dbnames.size(); i++ ) {
359 m_restore->AddDB(m_dbnames[i]);
362 return *m_restore;
366 //////////////////////////////////////////////////////////////////////////////
367 // Mode: Input, Type: boost
369 #ifdef __BARRY_BOOST_MODE__
370 class BoostInput : public InputBase
372 auto_ptr<BoostBuilder> m_builder;
373 string m_filename;
375 public:
376 BoostInput()
377 : m_filename("-") // default to stdin/stdout
381 void SetFilename(const std::string &name)
383 m_filename = name;
386 Builder& GetBuilder(Barry::Probe *probe, IConverter &ic)
388 if( m_filename == "-" ) {
389 // use stdin
390 m_builder.reset( new BoostBuilder(cin) );
392 else {
393 m_builder.reset( new BoostBuilder(m_filename) );
395 return *m_builder;
399 #endif
401 //////////////////////////////////////////////////////////////////////////////
402 // Mode: Input, Type: ldif
404 class LdifInput : public InputBase
406 auto_ptr<Builder> m_builder;
407 string m_filename;
409 public:
410 LdifInput()
411 : m_filename("-")
415 void SetFilename(const std::string &name)
417 m_filename = name;
420 Builder& GetBuilder(Barry::Probe *probe, IConverter &ic)
422 if( m_filename == "-" ) {
423 // use stdin
424 m_builder.reset(
425 new RecordBuilder<Contact, LdifStore>(
426 new LdifStore(cin)) );
428 else {
429 m_builder.reset(
430 new RecordBuilder<Contact, LdifStore>(
431 new LdifStore(m_filename)) );
433 return *m_builder;
439 //////////////////////////////////////////////////////////////////////////////
440 // Mode: Input, Type: mime
442 class MimeInput : public InputBase
444 auto_ptr<MimeBuilder> m_builder;
445 string m_filename;
447 public:
448 MimeInput()
449 : m_filename("-")
453 void SetFilename(const std::string &name)
455 m_filename = name;
458 Builder& GetBuilder(Barry::Probe *probe, IConverter &ic)
460 if( m_filename == "-" ) {
461 // use stdin
462 m_builder.reset( new MimeBuilder(cin) );
464 else {
465 m_builder.reset( new MimeBuilder(m_filename) );
467 return *m_builder;
472 //////////////////////////////////////////////////////////////////////////////
473 // Base class for Output Mode
475 class OutputBase : public virtual ModeBase
477 public:
478 virtual Parser& GetParser(Barry::Probe *probe, IConverter &ic) = 0;
481 class DeviceOutputBase : public DeviceBase, public OutputBase
485 //////////////////////////////////////////////////////////////////////////////
486 // Mode: Output, Type: device
488 class DeviceOutput : public DeviceOutputBase
490 auto_ptr<Controller> m_con;
491 auto_ptr<Mode::Desktop> m_desktop;
492 auto_ptr<DeviceParser> m_parser;
493 DeviceParser::WriteMode m_mode;
495 public:
496 DeviceOutput()
497 : m_mode(DeviceParser::DROP_RECORD)
501 void SetWriteMode(DeviceParser::WriteMode mode)
503 m_mode = mode;
506 Parser& GetParser(Barry::Probe *probe, IConverter &ic)
508 int i = probe->FindActive(m_pin);
509 if( i == -1 ) {
510 if( m_pin.Valid() )
511 throw runtime_error("PIN not found: " + m_pin.Str());
512 else
513 throw runtime_error("PIN not specified, and more than one device exists.");
516 if( IsPinUsed(probe->Get(i).m_pin) ) {
517 throw runtime_error("It seems you are trying to use the same device for multiple input or outputs.");
519 m_device_pins.push_back(probe->Get(i).m_pin);
521 m_con.reset( new Controller(probe->Get(i)) );
522 m_desktop.reset( new Mode::Desktop(*m_con, ic) );
523 m_desktop->Open(m_password.c_str());
524 m_parser.reset( new DeviceParser(*m_desktop, m_mode) );
526 return *m_parser;
530 //////////////////////////////////////////////////////////////////////////////
531 // Mode: Output, Type: tar
533 class TarOutput : public OutputBase
535 auto_ptr<Backup> m_backup;
536 string m_tarpath;
538 public:
539 void SetFilename(const std::string &name)
541 m_tarpath = name;
542 if( name == "-" )
543 throw runtime_error("Cannot use stdout as tar backup file, sorry.");
546 Parser& GetParser(Barry::Probe *probe, IConverter &ic)
548 m_backup.reset( new Backup(m_tarpath) );
549 return *m_backup;
553 //////////////////////////////////////////////////////////////////////////////
554 // Mode: Output, Type: boost
556 #ifdef __BARRY_BOOST_MODE__
557 class BoostOutput : public OutputBase
559 auto_ptr<BoostParser> m_parser;
560 string m_filename;
562 public:
563 void SetFilename(const std::string &name)
565 m_filename = name;
568 Parser& GetParser(Barry::Probe *probe, IConverter &ic)
570 if( !m_filename.size() )
571 throw runtime_error("Boost output requires a specific output file (-f switch)");
573 if( m_filename == "-" ) {
574 // use stdout
575 m_parser.reset( new BoostParser(cout) );
577 else {
578 m_parser.reset( new BoostParser(m_filename) );
580 return *m_parser;
584 #endif
586 //////////////////////////////////////////////////////////////////////////////
587 // Mode: Output, Type: ldif
589 class LdifOutput : public OutputBase
591 auto_ptr<Parser> m_parser;
592 string m_filename;
593 string m_baseDN;
594 string m_dnattr;
596 public:
597 LdifOutput()
598 : m_filename("-")
602 void SetFilename(const std::string &name)
604 m_filename = name;
607 void SetDN(const std::string &dn)
609 m_baseDN = dn;
612 void SetAttribute(const std::string &attr)
614 m_dnattr = attr;
617 Parser& GetParser(Barry::Probe *probe, IConverter &ic)
619 if( m_filename == "-" ) {
620 // use stdin
621 m_parser.reset(
622 new RecordParser<Contact, LdifStore>(
623 new LdifStore(cout, m_baseDN,
624 m_dnattr)) );
626 else {
627 m_parser.reset(
628 new RecordParser<Contact, LdifStore>(
629 new LdifStore(m_filename, m_baseDN,
630 m_dnattr)) );
632 return *m_parser;
636 //////////////////////////////////////////////////////////////////////////////
637 // Mode: Output, Type: mime
639 class MimeStore : public AllRecordStore
641 std::ostream &m_os;
643 public:
644 MimeStore(std::ostream &os)
645 : m_os(os)
649 #undef HANDLE_PARSER
650 #define HANDLE_PARSER(tname) \
651 void operator() (const Barry::tname &r) \
653 MimeDump<tname>::Dump(m_os, r); \
656 ALL_KNOWN_PARSER_TYPES
659 class MimeOutput : public OutputBase
661 auto_ptr<std::ofstream> m_file;
662 auto_ptr<Parser> m_parser;
663 std::string m_filename;
665 public:
666 MimeOutput()
667 : m_filename("-") // default to stdout
671 void SetFilename(const std::string &name)
673 m_filename = name;
676 Parser& GetParser(Barry::Probe *probe, IConverter &ic)
678 if( m_filename == "-" ) {
679 m_parser.reset( new AllRecordParser(cout,
680 new HexDumpParser(cout),
681 new MimeStore(cout)) );
683 else {
684 m_file.reset( new std::ofstream(m_filename.c_str()) );
685 m_parser.reset( new AllRecordParser(*m_file,
686 new HexDumpParser(*m_file),
687 new MimeStore(*m_file)) );
689 return *m_parser;
693 //////////////////////////////////////////////////////////////////////////////
694 // Mode: Output, Type: dump
696 class DumpOutput : public OutputBase
698 auto_ptr<Parser> m_parser;
699 bool m_hex_only;
701 public:
702 DumpOutput()
703 : m_hex_only(false)
707 void SetHexDump()
709 m_hex_only = true;
712 Parser& GetParser(Barry::Probe *probe, IConverter &ic)
714 if( m_hex_only ) {
715 m_parser.reset( new HexDumpParser(cout) );
717 else {
718 m_parser.reset( new AllRecordParser(cout,
719 new HexDumpParser(cout),
720 new AllRecordDumpStore(cout)) );
722 return *m_parser;
726 //////////////////////////////////////////////////////////////////////////////
727 // Mode: Output, Type: sha1
729 class Sha1Output : public OutputBase
731 auto_ptr<Parser> m_parser;
732 bool m_include_ids;
734 public:
735 Sha1Output()
736 : m_include_ids(false)
740 void IncludeIDs()
742 m_include_ids = true;
745 Parser& GetParser(Barry::Probe *probe, IConverter &ic)
747 m_parser.reset( new ChecksumParser(m_include_ids) );
748 return *m_parser;
752 //////////////////////////////////////////////////////////////////////////////
753 // Mode: Output, Type: cstore
755 class ContentStoreOutput : public OutputBase
757 auto_ptr<Parser> m_parser;
758 bool m_list_only;
759 vector<string> m_filenames;
761 public:
762 ContentStoreOutput()
763 : m_list_only(false)
767 void SetFilename(const std::string &name)
769 m_filenames.push_back(name);
772 void SetList()
774 m_list_only = true;
777 Parser& GetParser(Barry::Probe *probe, IConverter &ic)
779 m_parser.reset( new RecordParser<ContentStore, ContentStoreOutput>(*this) );
780 return *m_parser;
783 // storage operator
784 void operator() (const ContentStore &rec)
786 if( m_list_only ) {
787 cout << rec.Filename;
788 if( rec.FolderFlag ) {
789 cout << " (folder)";
791 cout << endl;
793 else {
794 // check if this record matches one of the filenames
795 // in the list
796 vector<string>::iterator i = find(m_filenames.begin(),
797 m_filenames.end(), rec.Filename);
798 if( i != m_filenames.end() ) {
799 SaveFile(rec);
804 void SaveFile(const ContentStore &rec)
806 size_t slash = rec.Filename.rfind('/');
807 string filename;
808 if( slash == string::npos )
809 filename = rec.Filename;
810 else
811 filename = rec.Filename.substr(slash + 1);
813 // modify filename until we find one that doesn't
814 // already exist
815 string freshname = filename;
816 int count = 0;
817 while( access(freshname.c_str(), F_OK) == 0 ) {
818 ostringstream oss;
819 oss << filename << count++;
820 freshname = oss.str();
823 // open and write!
824 cout << "Saving: " << rec.Filename
825 << " as " << freshname << endl;
826 ofstream ofs(freshname.c_str());
827 ofs << rec.FileContent;
828 ofs.flush();
829 if( !ofs ) {
830 cout << "Error during write!" << endl;
837 //////////////////////////////////////////////////////////////////////////////
838 // Main application class
840 class App
842 public:
843 typedef shared_ptr<OutputBase> OutputPtr;
844 typedef vector<OutputPtr> OutputsType;
846 private:
847 auto_ptr<InputBase> Input;
848 OutputsType Outputs;
850 public:
852 bool ParseInMode(const string &mode);
853 bool ParseOutMode(const string &mode);
854 DeviceParser::WriteMode ParseWriteMode(const std::string &mode);
855 static void ShowParsers();
856 // returns true if any of the items in Outputs needs a probe
857 bool OutputsProbeNeeded();
858 int main(int argc, char *argv[]);
861 bool App::ParseInMode(const string &mode)
863 if( mode == "device" ) {
864 Input.reset( new DeviceInput );
865 return true;
867 else if( mode == "tar" ) {
868 Input.reset( new TarInput );
869 return true;
871 #ifdef __BARRY_BOOST_MODE__
872 else if( mode == "boost" ) {
873 Input.reset( new BoostInput );
874 return true;
876 #endif
877 else if( mode == "ldif" ) {
878 Input.reset( new LdifInput );
879 return true;
881 else if( mode == "mime" ) {
882 Input.reset( new MimeInput );
883 return true;
885 else
886 return false;
889 bool App::ParseOutMode(const string &mode)
891 if( mode == "device" ) {
892 Outputs.push_back( OutputPtr(new DeviceOutput) );
893 return true;
895 else if( mode == "tar" ) {
896 Outputs.push_back( OutputPtr(new TarOutput) );
897 return true;
899 #ifdef __BARRY_BOOST_MODE__
900 else if( mode == "boost" ) {
901 Outputs.push_back( OutputPtr(new BoostOutput) );
902 return true;
904 #endif
905 else if( mode == "ldif" ) {
906 Outputs.push_back( OutputPtr(new LdifOutput) );
907 return true;
909 else if( mode == "mime" ) {
910 Outputs.push_back( OutputPtr(new MimeOutput) );
911 return true;
913 else if( mode == "dump" ) {
914 Outputs.push_back( OutputPtr(new DumpOutput) );
915 return true;
917 else if( mode == "sha1" ) {
918 Outputs.push_back( OutputPtr(new Sha1Output) );
919 return true;
921 else if( mode == "cstore" ) {
922 Outputs.push_back( OutputPtr(new ContentStoreOutput) );
923 return true;
925 else
926 return false;
929 DeviceParser::WriteMode App::ParseWriteMode(const std::string &mode)
931 if( mode == "erase" )
932 return DeviceParser::ERASE_ALL_WRITE_ALL;
933 else if( mode == "overwrite" )
934 return DeviceParser::INDIVIDUAL_OVERWRITE;
935 else if( mode == "addonly" )
936 return DeviceParser::ADD_BUT_NO_OVERWRITE;
937 else if( mode == "addnew" )
938 return DeviceParser::ADD_WITH_NEW_ID;
939 else
940 throw runtime_error("Unknown device output mode. Must be one of: erase, overwrite, addonly, addnew");
943 void App::ShowParsers()
945 cout << "Supported Database parsers:\n"
946 << " (* = can display in vformat MIME mode)\n"
948 #undef HANDLE_PARSER
949 #define HANDLE_PARSER(tname) \
950 << " " << tname::GetDBName() \
951 << (MimeDump<tname>::Supported() ? " *" : "") << "\n"
953 ALL_KNOWN_PARSER_TYPES
955 << "\n"
956 << "Supported Database builders:\n"
958 #undef HANDLE_BUILDER
959 #define HANDLE_BUILDER(tname) \
960 << " " << tname::GetDBName() << "\n"
962 ALL_KNOWN_BUILDER_TYPES
964 << endl;
967 bool App::OutputsProbeNeeded()
969 for( OutputsType::iterator i = Outputs.begin();
970 i != Outputs.end();
971 ++i )
973 if( (*i)->ProbeNeeded() )
974 return true;
976 return false;
979 int App::main(int argc, char *argv[])
981 bool verbose = false;
982 string iconvCharset;
984 // process command line options
985 ModeBase *current = 0;
986 for(;;) {
987 int cmd = getopt(argc, argv, "hi:o:nvI:f:p:P:d:c:C:ASw:tl");
988 if( cmd == -1 )
989 break;
991 // first option must be in or out, or a global option
992 if( !current ) {
993 if( cmd != 'i' && \
994 cmd != 'o' && \
995 cmd != 'S' && \
996 cmd != 'I' && \
997 cmd != 'v' )
999 Usage();
1000 return 1;
1004 switch( cmd )
1006 case 'i': // set input mode
1007 // must be first time used
1008 if( Input.get() || !ParseInMode(optarg) ) {
1009 Usage();
1010 return 1;
1012 current = Input.get();
1013 break;
1015 case 'o': // set output mode
1016 // can be used multiple times
1017 if( !ParseOutMode(optarg) ) {
1018 Usage();
1019 return 1;
1021 current = Outputs[Outputs.size() - 1].get();
1022 break;
1025 case 'c': // set ldif dn
1026 current->SetDN(optarg);
1027 break;
1029 case 'C': // set ldif attr
1030 current->SetAttribute(optarg);
1031 break;
1033 case 'd': // database name
1034 current->AddDB(optarg);
1035 break;
1037 case 'f': // filename
1038 current->SetFilename(optarg);
1039 break;
1041 case 'p': // device PIN
1042 current->SetPIN(optarg);
1043 break;
1045 case 'P': // password
1046 current->SetPassword(optarg);
1047 break;
1049 case 'w': // device write mode
1050 current->SetWriteMode(ParseWriteMode(optarg));
1051 break;
1053 case 'A': // add all DB names to the device builder
1054 current->AddAllDBs();
1055 break;
1057 case 't': // include type and IDs in sha1 mode
1058 current->IncludeIDs();
1059 break;
1061 case 'l': // list only
1062 current->SetList();
1063 break;
1065 case 'S': // show parsers and builders
1066 ShowParsers();
1067 return 0;
1069 case 'I': // international charset (iconv)
1070 iconvCharset = optarg;
1071 break;
1073 case 'n': // use null hex dump parser only
1074 current->SetHexDump();
1075 break;
1077 case 'v': // verbose
1078 verbose = true;
1079 break;
1081 case 'h': // help
1082 default:
1083 Usage();
1084 return 0;
1088 if( !Input.get() || !Outputs.size() ) {
1089 Usage();
1090 return 0;
1093 // Initialize the Barry library
1094 Barry::Init(verbose);
1096 // Create an IConverter object if needed
1097 auto_ptr<IConverter> ic;
1098 if( iconvCharset.size() ) {
1099 ic.reset( new IConverter(iconvCharset.c_str(), true) );
1102 // Probe for devices only if needed
1103 auto_ptr<Probe> probe;
1104 if( Input->ProbeNeeded() || OutputsProbeNeeded() ) {
1105 // Probe for available devices
1106 probe.reset( new Probe );
1109 // Setup the input first (builder)
1110 Builder &builder = Input->GetBuilder(probe.get(), *ic);
1112 // Setup a TeeParser with all Outputs
1113 TeeParser tee;
1114 for( OutputsType::iterator i = Outputs.begin(); i != Outputs.end(); ++i ) {
1115 Parser &parser = (*i)->GetParser(probe.get(), *ic);
1116 tee.Add(parser);
1119 // Setup the pipe
1120 Pipe pipe(builder);
1121 pipe.PumpFile(tee, ic.get());
1123 return 0;
1126 int main(int argc, char *argv[])
1128 try {
1129 App app;
1130 return app.main(argc, argv);
1132 catch( std::exception &e ) {
1133 cerr << "Exception: " << e.what() << endl;
1134 return 1;