lib: added GetPath() to GlobalConfigPath class
[barry.git] / tools / bio.cc
blob13d32f59b09502d74e779755ed2308471e7e7228
1 ///
2 /// \file bio.cc
3 /// Barry Input / Output
4 ///
6 /*
7 Copyright (C) 2010-2012, 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 <strings.h>
40 #include "barrygetopt.h"
42 using namespace std;
43 using namespace std::tr1;
44 using namespace Barry;
46 // keeping a record of all the -i device / -o device pin numbers, so
47 // we can warn the poor user appropriately
48 std::vector<Barry::Pin> m_device_pins;
50 bool IsPinUsed(const Barry::Pin &pin)
52 for( std::vector<Barry::Pin>::const_iterator b = m_device_pins.begin();
53 b != m_device_pins.end(); ++b )
55 if( *b == pin )
56 return true;
58 return false;
61 void Usage()
63 int logical, major, minor;
64 const char *Version = Barry::Version(logical, major, minor);
66 cerr
67 << "bio - Barry Input / Output\n"
68 << " Copyright 2010-2012, Net Direct Inc. (http://www.netdirect.ca/)\n"
69 << " Using: " << Version << "\n"
70 << " Compiled "
71 #ifdef __BARRY_BOOST_MODE__
72 << "with"
73 #else
74 << "without"
75 #endif
76 << " Boost support\n"
77 << "\n"
78 << " Usage: bio -i <type> [options...] -o <type> [options...]\n"
79 << "\n"
80 << " -i type The input type (Builder) to use for producing records\n"
81 << " Can be one of: device, tar"
82 #ifdef __BARRY_BOOST_MODE__
83 << ", boost"
84 #endif
85 << ", ldif, mime\n"
86 << " -o type The output type (Parser) to use for processing records.\n"
87 << " Multiple outputs are allowed, as long as they don't\n"
88 << " conflict (such as two outputs writing to the same file\n"
89 << " or device).\n"
90 << " Can be one of: device, tar"
91 #ifdef __BARRY_BOOST_MODE__
92 << ", boost"
93 #endif
94 << ", ldif, mime, dump, sha1, cstore\n"
95 << "\n"
96 << " Options to use for 'device' type:\n"
97 << " -d db Name of input database. Can be used multiple times.\n"
98 << " -A Add all available device databases, instead of specifying\n"
99 << " them manually via -d\n"
100 << " -p pin PIN of device to talk to\n"
101 << " If only one device is plugged in, this flag is optional\n"
102 << " -P pass Simplistic method to specify device password\n"
103 << " -w mode Set write mode when using 'device' for output. Must be\n"
104 << " specified, or will not write anything.\n"
105 << " Can be one of: erase, overwrite, addonly, addnew\n"
107 // FIXME - modifiers not yet implemented
108 << "\n"
109 << " Input database modifiers: (can be used multiple times for more than 1 record)\n"
110 << "\n"
111 << " -r # Record index number as seen in the -T state table.\n"
112 << " This overrides the default -d behaviour, and only\n"
113 << " downloads the one specified record, sending to stdout.\n"
114 << " -R # Same as -r, but also clears the record's dirty flags.\n"
115 << " -D # Record index number as seen in the -T state table,\n"
116 << " which indicates the record to delete. Used with the -d\n"
117 << " command to specify the database.\n"
119 << "\n"
120 << " Options to use for 'tar' backup type:\n"
121 << " -d db Name of input database. Can be used multiple times.\n"
122 << " Not available in output mode. Note that by default,\n"
123 << " all databases in the backup are selected, when reading,\n"
124 << " unless at least one -d is specified.\n"
125 << " -f file Tar backup file to read from or write to\n"
126 #ifdef __BARRY_BOOST_MODE__
127 << "\n"
128 << " Options to use for 'boost' type:\n"
129 << " -f file Boost serialization filename to read from or write to\n"
130 << " Can use - to specify stdin/stdout\n"
131 #endif
132 << "\n"
133 << " Options to use for 'ldif' type:\n"
134 << " -c dn Convert address book database to LDIF format, using the\n"
135 << " specified baseDN\n"
136 << " -C dnattr LDIF attribute name to use when building the FQDN\n"
137 << " Defaults to 'cn'\n"
139 LDIF options?
141 << " -L List Contact field names\n"
142 << " -m Map LDIF name to Contact field / Unmap LDIF name\n"
143 << " Map: ldif,read,write - maps ldif to read/write Contact fields\n"
144 << " Unmap: ldif name alone\n"
145 << " -M List current LDIF mapping\n"
147 << "\n"
148 << " Options to use for 'mime' type:\n"
149 << " -f file Filename to read from or write to. Use - to explicitly\n"
150 << " specify stdin/stdout, which is default.\n"
151 << "\n"
152 << " Options to use for 'dump' to stdout output type:\n"
153 << " -n Use hex dump parser on all databases.\n"
154 << "\n"
155 << " Options to use for 'sha1' sum stdout output type:\n"
156 << " -t Include DB Name, Type, and Unique record IDs in the checksums\n"
157 << "\n"
158 << " Options to use for 'cstore' output type:\n"
159 << " -l List filenames only\n"
160 << " -f file Filename from the above list, including path.\n"
161 << " If found, the file will be written to the current\n"
162 << " directory, using the base filename from the device.\n"
163 << "\n"
164 << " Standalone options:\n"
165 << " -h This help\n"
166 << " -I cs International charset for string conversions\n"
167 << " Valid values here are available with 'iconv --list'\n"
168 << " -S Show list of supported database parsers and builders\n"
169 << " -v Dump protocol data during operation\n"
170 << "\n"
171 << endl;
174 class ModeBase
176 public:
177 virtual ~ModeBase() {}
179 virtual bool ProbeNeeded() const { return false; }
181 virtual void SetFilename(const std::string &name)
183 throw runtime_error("Filename not applicable for this mode");
186 virtual void AddDB(const std::string &dbname)
188 throw runtime_error("DB not applicable for this mode");
191 virtual void AddAllDBs()
193 throw runtime_error("DBs not applicable for this mode");
196 virtual void SetPIN(const std::string &pin)
198 throw runtime_error("PIN not applicable for this mode");
201 virtual void SetPassword(const std::string &password)
203 throw runtime_error("Password not applicable for this mode");
206 virtual void SetWriteMode(DeviceParser::WriteMode mode)
208 throw runtime_error("Device write behaviour not applicable for this mode");
211 virtual void SetDN(const std::string &dn)
213 throw runtime_error("DN not applicable for this mode");
216 virtual void SetAttribute(const std::string &attr)
218 throw runtime_error("Attribute not applicable for this mode");
221 virtual void SetHexDump()
223 throw runtime_error("No hex dump option in this mode");
226 virtual void IncludeIDs()
228 throw runtime_error("Including record IDs in the SHA1 sum is not applicable in this mode");
231 virtual void SetList()
233 throw runtime_error("List option not applicable for this mode");
237 class DeviceBase : public virtual ModeBase
239 protected:
240 Barry::Pin m_pin;
241 std::string m_password;
243 public:
244 bool ProbeNeeded() const { return true; }
246 void SetPIN(const std::string &pin)
248 istringstream iss(pin);
249 iss >> m_pin;
250 if( !m_pin.Valid() )
251 throw runtime_error("Invalid PIN: " + pin);
254 void SetPassword(const std::string &password)
256 m_password = password;
260 //////////////////////////////////////////////////////////////////////////////
261 // Base class for Input Mode
263 class InputBase : public virtual ModeBase
265 public:
266 virtual Builder& GetBuilder(Barry::Probe *probe, IConverter &ic) = 0;
269 class DeviceInputBase : public DeviceBase, public InputBase
273 //////////////////////////////////////////////////////////////////////////////
274 // Mode: Input, Type: device
276 class DeviceInput : public DeviceInputBase
278 auto_ptr<Controller> m_con;
279 auto_ptr<Mode::Desktop> m_desktop;
280 auto_ptr<DeviceBuilder> m_builder;
281 vector<string> m_dbnames;
282 bool m_add_all;
284 public:
285 DeviceInput()
286 : m_add_all(false)
290 void AddDB(const std::string &dbname)
292 m_dbnames.push_back(dbname);
295 void AddAllDBs()
297 m_add_all = true;
300 Builder& GetBuilder(Barry::Probe *probe, IConverter &ic)
302 int i = probe->FindActive(m_pin);
303 if( i == -1 ) {
304 if( m_pin.Valid() )
305 throw runtime_error("PIN not found: " + m_pin.Str());
306 else
307 throw runtime_error("PIN not specified, and more than one device exists.");
310 if( IsPinUsed(probe->Get(i).m_pin) ) {
311 throw runtime_error("It seems you are trying to use the same device for multiple input or outputs.");
313 m_device_pins.push_back(probe->Get(i).m_pin);
315 m_con.reset( new Controller(probe->Get(i)) );
316 m_desktop.reset( new Mode::Desktop(*m_con, ic) );
317 m_desktop->Open(m_password.c_str());
318 m_builder.reset( new DeviceBuilder(*m_desktop) );
320 if( m_add_all ) {
321 m_builder->Add(m_desktop->GetDBDB());
323 else {
324 for( size_t i = 0; i < m_dbnames.size(); i++ ) {
325 if( !m_builder->Add(m_dbnames[i]) )
326 throw runtime_error("Database not found: " + m_dbnames[i]);
330 return *m_builder;
334 //////////////////////////////////////////////////////////////////////////////
335 // Mode: Input, Type: tar
337 class TarInput : public InputBase
339 auto_ptr<Restore> m_restore;
340 string m_tarpath;
341 vector<string> m_dbnames;
343 public:
344 void SetFilename(const std::string &name)
346 m_tarpath = name;
347 if( name == "-" )
348 throw runtime_error("Cannot use stdin as tar source file, sorry.");
351 void AddDB(const std::string &dbname)
353 m_dbnames.push_back(dbname);
356 Builder& GetBuilder(Barry::Probe *probe, IConverter &ic)
358 m_restore.reset( new Restore(m_tarpath, true) );
359 for( size_t i = 0; i < m_dbnames.size(); i++ ) {
360 m_restore->AddDB(m_dbnames[i]);
363 return *m_restore;
367 //////////////////////////////////////////////////////////////////////////////
368 // Mode: Input, Type: boost
370 #ifdef __BARRY_BOOST_MODE__
371 class BoostInput : public InputBase
373 auto_ptr<BoostBuilder> m_builder;
374 string m_filename;
376 public:
377 BoostInput()
378 : m_filename("-") // default to stdin/stdout
382 void SetFilename(const std::string &name)
384 m_filename = name;
387 Builder& GetBuilder(Barry::Probe *probe, IConverter &ic)
389 if( m_filename == "-" ) {
390 // use stdin
391 m_builder.reset( new BoostBuilder(cin) );
393 else {
394 m_builder.reset( new BoostBuilder(m_filename) );
396 return *m_builder;
400 #endif
402 //////////////////////////////////////////////////////////////////////////////
403 // Mode: Input, Type: ldif
405 class LdifInput : public InputBase
407 auto_ptr<Builder> m_builder;
408 string m_filename;
410 public:
411 LdifInput()
412 : m_filename("-")
416 void SetFilename(const std::string &name)
418 m_filename = name;
421 Builder& GetBuilder(Barry::Probe *probe, IConverter &ic)
423 if( m_filename == "-" ) {
424 // use stdin
425 m_builder.reset(
426 new RecordBuilder<Contact, LdifStore>(
427 new LdifStore(cin)) );
429 else {
430 m_builder.reset(
431 new RecordBuilder<Contact, LdifStore>(
432 new LdifStore(m_filename)) );
434 return *m_builder;
440 //////////////////////////////////////////////////////////////////////////////
441 // Mode: Input, Type: mime
443 class MimeInput : public InputBase
445 auto_ptr<MimeBuilder> m_builder;
446 string m_filename;
448 public:
449 MimeInput()
450 : m_filename("-")
454 void SetFilename(const std::string &name)
456 m_filename = name;
459 Builder& GetBuilder(Barry::Probe *probe, IConverter &ic)
461 if( m_filename == "-" ) {
462 // use stdin
463 m_builder.reset( new MimeBuilder(cin) );
465 else {
466 m_builder.reset( new MimeBuilder(m_filename) );
468 return *m_builder;
473 //////////////////////////////////////////////////////////////////////////////
474 // Base class for Output Mode
476 class OutputBase : public virtual ModeBase
478 public:
479 virtual Parser& GetParser(Barry::Probe *probe, IConverter &ic) = 0;
482 class DeviceOutputBase : public DeviceBase, public OutputBase
486 //////////////////////////////////////////////////////////////////////////////
487 // Mode: Output, Type: device
489 class DeviceOutput : public DeviceOutputBase
491 auto_ptr<Controller> m_con;
492 auto_ptr<Mode::Desktop> m_desktop;
493 auto_ptr<DeviceParser> m_parser;
494 DeviceParser::WriteMode m_mode;
496 public:
497 DeviceOutput()
498 : m_mode(DeviceParser::DROP_RECORD)
502 void SetWriteMode(DeviceParser::WriteMode mode)
504 m_mode = mode;
507 Parser& GetParser(Barry::Probe *probe, IConverter &ic)
509 if( m_mode == DeviceParser::DROP_RECORD ) {
510 cerr << "Warning: the -w switch was not specified: no data will be written to the device." << endl;
513 int i = probe->FindActive(m_pin);
514 if( i == -1 ) {
515 if( m_pin.Valid() )
516 throw runtime_error("PIN not found: " + m_pin.Str());
517 else
518 throw runtime_error("PIN not specified, and more than one device exists.");
521 if( IsPinUsed(probe->Get(i).m_pin) ) {
522 throw runtime_error("It seems you are trying to use the same device for multiple input or outputs.");
524 m_device_pins.push_back(probe->Get(i).m_pin);
526 m_con.reset( new Controller(probe->Get(i)) );
527 m_desktop.reset( new Mode::Desktop(*m_con, ic) );
528 m_desktop->Open(m_password.c_str());
529 m_parser.reset( new DeviceParser(*m_desktop, m_mode) );
531 return *m_parser;
535 //////////////////////////////////////////////////////////////////////////////
536 // Mode: Output, Type: tar
538 class TarOutput : public OutputBase
540 auto_ptr<Backup> m_backup;
541 string m_tarpath;
543 public:
544 void SetFilename(const std::string &name)
546 m_tarpath = name;
547 if( name == "-" )
548 throw runtime_error("Cannot use stdout as tar backup file, sorry.");
551 Parser& GetParser(Barry::Probe *probe, IConverter &ic)
553 m_backup.reset( new Backup(m_tarpath) );
554 return *m_backup;
558 //////////////////////////////////////////////////////////////////////////////
559 // Mode: Output, Type: boost
561 #ifdef __BARRY_BOOST_MODE__
562 class BoostOutput : public OutputBase
564 auto_ptr<BoostParser> m_parser;
565 string m_filename;
567 public:
568 void SetFilename(const std::string &name)
570 m_filename = name;
573 Parser& GetParser(Barry::Probe *probe, IConverter &ic)
575 if( !m_filename.size() )
576 throw runtime_error("Boost output requires a specific output file (-f switch)");
578 if( m_filename == "-" ) {
579 // use stdout
580 m_parser.reset( new BoostParser(cout) );
582 else {
583 m_parser.reset( new BoostParser(m_filename) );
585 return *m_parser;
589 #endif
591 //////////////////////////////////////////////////////////////////////////////
592 // Mode: Output, Type: ldif
594 class LdifOutput : public OutputBase
596 auto_ptr<Parser> m_parser;
597 string m_filename;
598 string m_baseDN;
599 string m_dnattr;
601 public:
602 LdifOutput()
603 : m_filename("-")
607 void SetFilename(const std::string &name)
609 m_filename = name;
612 void SetDN(const std::string &dn)
614 m_baseDN = dn;
617 void SetAttribute(const std::string &attr)
619 m_dnattr = attr;
622 Parser& GetParser(Barry::Probe *probe, IConverter &ic)
624 if( m_filename == "-" ) {
625 // use stdin
626 m_parser.reset(
627 new RecordParser<Contact, LdifStore>(
628 new LdifStore(cout, m_baseDN,
629 m_dnattr)) );
631 else {
632 m_parser.reset(
633 new RecordParser<Contact, LdifStore>(
634 new LdifStore(m_filename, m_baseDN,
635 m_dnattr)) );
637 return *m_parser;
641 //////////////////////////////////////////////////////////////////////////////
642 // Mode: Output, Type: mime
644 class MimeStore : public AllRecordStore
646 std::ostream &m_os;
648 public:
649 MimeStore(std::ostream &os)
650 : m_os(os)
654 #undef HANDLE_PARSER
655 #define HANDLE_PARSER(tname) \
656 void operator() (const Barry::tname &r) \
658 MimeDump<tname>::Dump(m_os, r); \
661 ALL_KNOWN_PARSER_TYPES
664 class MimeOutput : public OutputBase
666 auto_ptr<std::ofstream> m_file;
667 auto_ptr<Parser> m_parser;
668 std::string m_filename;
670 public:
671 MimeOutput()
672 : m_filename("-") // default to stdout
676 void SetFilename(const std::string &name)
678 m_filename = name;
681 Parser& GetParser(Barry::Probe *probe, IConverter &ic)
683 if( m_filename == "-" ) {
684 m_parser.reset( new AllRecordParser(cout,
685 new HexDumpParser(cout),
686 new MimeStore(cout)) );
688 else {
689 m_file.reset( new std::ofstream(m_filename.c_str()) );
690 m_parser.reset( new AllRecordParser(*m_file,
691 new HexDumpParser(*m_file),
692 new MimeStore(*m_file)) );
694 return *m_parser;
698 //////////////////////////////////////////////////////////////////////////////
699 // Mode: Output, Type: dump
701 class DumpOutput : public OutputBase
703 auto_ptr<Parser> m_parser;
704 bool m_hex_only;
706 public:
707 DumpOutput()
708 : m_hex_only(false)
712 void SetHexDump()
714 m_hex_only = true;
717 Parser& GetParser(Barry::Probe *probe, IConverter &ic)
719 if( m_hex_only ) {
720 m_parser.reset( new HexDumpParser(cout) );
722 else {
723 m_parser.reset( new AllRecordParser(cout,
724 new HexDumpParser(cout),
725 new AllRecordDumpStore(cout)) );
727 return *m_parser;
731 //////////////////////////////////////////////////////////////////////////////
732 // Mode: Output, Type: sha1
734 class Sha1Output : public OutputBase
736 auto_ptr<Parser> m_parser;
737 bool m_include_ids;
739 public:
740 Sha1Output()
741 : m_include_ids(false)
745 void IncludeIDs()
747 m_include_ids = true;
750 Parser& GetParser(Barry::Probe *probe, IConverter &ic)
752 m_parser.reset( new ChecksumParser(m_include_ids) );
753 return *m_parser;
757 //////////////////////////////////////////////////////////////////////////////
758 // Mode: Output, Type: cstore
760 class ContentStoreOutput : public OutputBase
762 auto_ptr<Parser> m_parser;
763 bool m_list_only;
764 vector<string> m_filenames;
766 public:
767 ContentStoreOutput()
768 : m_list_only(false)
772 void SetFilename(const std::string &name)
774 m_filenames.push_back(name);
777 void SetList()
779 m_list_only = true;
782 Parser& GetParser(Barry::Probe *probe, IConverter &ic)
784 m_parser.reset( new RecordParser<ContentStore, ContentStoreOutput>(*this) );
785 return *m_parser;
788 // storage operator
789 void operator() (const ContentStore &rec)
791 if( m_list_only ) {
792 cout << rec.Filename;
793 if( rec.FolderFlag ) {
794 cout << " (folder)";
796 cout << endl;
798 else {
799 // check if this record matches one of the filenames
800 // in the list
801 vector<string>::iterator i = find(m_filenames.begin(),
802 m_filenames.end(), rec.Filename);
803 if( i != m_filenames.end() ) {
804 SaveFile(rec);
809 void SaveFile(const ContentStore &rec)
811 size_t slash = rec.Filename.rfind('/');
812 string filename;
813 if( slash == string::npos )
814 filename = rec.Filename;
815 else
816 filename = rec.Filename.substr(slash + 1);
818 // modify filename until we find one that doesn't
819 // already exist
820 string freshname = filename;
821 int count = 0;
822 while( access(freshname.c_str(), F_OK) == 0 ) {
823 ostringstream oss;
824 oss << filename << count++;
825 freshname = oss.str();
828 // open and write!
829 cout << "Saving: " << rec.Filename
830 << " as " << freshname << endl;
831 ofstream ofs(freshname.c_str());
832 ofs << rec.FileContent;
833 ofs.flush();
834 if( !ofs ) {
835 cout << "Error during write!" << endl;
842 //////////////////////////////////////////////////////////////////////////////
843 // Main application class
845 class App
847 public:
848 typedef shared_ptr<OutputBase> OutputPtr;
849 typedef vector<OutputPtr> OutputsType;
851 private:
852 auto_ptr<InputBase> Input;
853 OutputsType Outputs;
855 public:
857 bool ParseInMode(const string &mode);
858 bool ParseOutMode(const string &mode);
859 DeviceParser::WriteMode ParseWriteMode(const std::string &mode);
860 static void ShowParsers();
861 // returns true if any of the items in Outputs needs a probe
862 bool OutputsProbeNeeded();
863 int main(int argc, char *argv[]);
866 bool App::ParseInMode(const string &mode)
868 if( mode == "device" ) {
869 Input.reset( new DeviceInput );
870 return true;
872 else if( mode == "tar" ) {
873 Input.reset( new TarInput );
874 return true;
876 #ifdef __BARRY_BOOST_MODE__
877 else if( mode == "boost" ) {
878 Input.reset( new BoostInput );
879 return true;
881 #endif
882 else if( mode == "ldif" ) {
883 Input.reset( new LdifInput );
884 return true;
886 else if( mode == "mime" ) {
887 Input.reset( new MimeInput );
888 return true;
890 else
891 return false;
894 bool App::ParseOutMode(const string &mode)
896 if( mode == "device" ) {
897 Outputs.push_back( OutputPtr(new DeviceOutput) );
898 return true;
900 else if( mode == "tar" ) {
901 Outputs.push_back( OutputPtr(new TarOutput) );
902 return true;
904 #ifdef __BARRY_BOOST_MODE__
905 else if( mode == "boost" ) {
906 Outputs.push_back( OutputPtr(new BoostOutput) );
907 return true;
909 #endif
910 else if( mode == "ldif" ) {
911 Outputs.push_back( OutputPtr(new LdifOutput) );
912 return true;
914 else if( mode == "mime" ) {
915 Outputs.push_back( OutputPtr(new MimeOutput) );
916 return true;
918 else if( mode == "dump" ) {
919 Outputs.push_back( OutputPtr(new DumpOutput) );
920 return true;
922 else if( mode == "sha1" ) {
923 Outputs.push_back( OutputPtr(new Sha1Output) );
924 return true;
926 else if( mode == "cstore" ) {
927 Outputs.push_back( OutputPtr(new ContentStoreOutput) );
928 return true;
930 else
931 return false;
934 DeviceParser::WriteMode App::ParseWriteMode(const std::string &mode)
936 if( mode == "erase" )
937 return DeviceParser::ERASE_ALL_WRITE_ALL;
938 else if( mode == "overwrite" )
939 return DeviceParser::INDIVIDUAL_OVERWRITE;
940 else if( mode == "addonly" )
941 return DeviceParser::ADD_BUT_NO_OVERWRITE;
942 else if( mode == "addnew" )
943 return DeviceParser::ADD_WITH_NEW_ID;
944 else
945 throw runtime_error("Unknown device output mode. Must be one of: erase, overwrite, addonly, addnew");
948 void App::ShowParsers()
950 cout << "Supported Database parsers:\n"
951 << " (* = can display in vformat MIME mode)\n"
953 #undef HANDLE_PARSER
954 #define HANDLE_PARSER(tname) \
955 << " " << tname::GetDBName() \
956 << (MimeDump<tname>::Supported() ? " *" : "") << "\n"
958 ALL_KNOWN_PARSER_TYPES
960 << "\n"
961 << "Supported Database builders:\n"
963 #undef HANDLE_BUILDER
964 #define HANDLE_BUILDER(tname) \
965 << " " << tname::GetDBName() << "\n"
967 ALL_KNOWN_BUILDER_TYPES
969 << endl;
972 bool App::OutputsProbeNeeded()
974 for( OutputsType::iterator i = Outputs.begin();
975 i != Outputs.end();
976 ++i )
978 if( (*i)->ProbeNeeded() )
979 return true;
981 return false;
984 int App::main(int argc, char *argv[])
986 bool verbose = false;
987 string iconvCharset;
989 // process command line options
990 ModeBase *current = 0;
991 for(;;) {
992 int cmd = getopt(argc, argv, "hi:o:nvI:f:p:P:d:c:C:ASw:tl");
993 if( cmd == -1 )
994 break;
996 // first option must be in or out, or a global option
997 if( !current ) {
998 if( cmd != 'i' && \
999 cmd != 'o' && \
1000 cmd != 'S' && \
1001 cmd != 'I' && \
1002 cmd != 'v' )
1004 Usage();
1005 return 1;
1009 switch( cmd )
1011 case 'i': // set input mode
1012 // must be first time used
1013 if( Input.get() || !ParseInMode(optarg) ) {
1014 Usage();
1015 return 1;
1017 current = Input.get();
1018 break;
1020 case 'o': // set output mode
1021 // can be used multiple times
1022 if( !ParseOutMode(optarg) ) {
1023 Usage();
1024 return 1;
1026 current = Outputs[Outputs.size() - 1].get();
1027 break;
1030 case 'c': // set ldif dn
1031 current->SetDN(optarg);
1032 break;
1034 case 'C': // set ldif attr
1035 current->SetAttribute(optarg);
1036 break;
1038 case 'd': // database name
1039 current->AddDB(optarg);
1040 break;
1042 case 'f': // filename
1043 current->SetFilename(optarg);
1044 break;
1046 case 'p': // device PIN
1047 current->SetPIN(optarg);
1048 break;
1050 case 'P': // password
1051 current->SetPassword(optarg);
1052 break;
1054 case 'w': // device write mode
1055 current->SetWriteMode(ParseWriteMode(optarg));
1056 break;
1058 case 'A': // add all DB names to the device builder
1059 current->AddAllDBs();
1060 break;
1062 case 't': // include type and IDs in sha1 mode
1063 current->IncludeIDs();
1064 break;
1066 case 'l': // list only
1067 current->SetList();
1068 break;
1070 case 'S': // show parsers and builders
1071 ShowParsers();
1072 return 0;
1074 case 'I': // international charset (iconv)
1075 iconvCharset = optarg;
1076 break;
1078 case 'n': // use null hex dump parser only
1079 current->SetHexDump();
1080 break;
1082 case 'v': // verbose
1083 verbose = true;
1084 break;
1086 case 'h': // help
1087 default:
1088 Usage();
1089 return 0;
1093 if( !Input.get() || !Outputs.size() ) {
1094 Usage();
1095 return 0;
1098 // Initialize the Barry library
1099 Barry::Init(verbose);
1101 // Create an IConverter object if needed
1102 auto_ptr<IConverter> ic;
1103 if( iconvCharset.size() ) {
1104 ic.reset( new IConverter(iconvCharset.c_str(), true) );
1107 // Probe for devices only if needed
1108 auto_ptr<Probe> probe;
1109 if( Input->ProbeNeeded() || OutputsProbeNeeded() ) {
1110 // Probe for available devices
1111 probe.reset( new Probe );
1114 // Setup the input first (builder)
1115 Builder &builder = Input->GetBuilder(probe.get(), *ic);
1117 // Setup a TeeParser with all Outputs
1118 TeeParser tee;
1119 for( OutputsType::iterator i = Outputs.begin(); i != Outputs.end(); ++i ) {
1120 Parser &parser = (*i)->GetParser(probe.get(), *ic);
1121 tee.Add(parser);
1124 // Setup the pipe
1125 Pipe pipe(builder);
1126 pipe.PumpFile(tee, ic.get());
1128 return 0;
1131 int main(int argc, char *argv[])
1133 try {
1134 App app;
1135 return app.main(argc, argv);
1137 catch( std::exception &e ) {
1138 cerr << "Exception: " << e.what() << endl;
1139 return 1;