lib+tools: updated strings to support i18n translations
[barry.git] / tools / bio.cc
blob92b2bab624bb687a543722b43422a5a30da5c47b
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 "brecsum.h"
27 #include "util.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>
39 #include <unistd.h>
41 #include "barrygetopt.h"
42 #include "i18n.h"
44 using namespace std;
45 using namespace std::tr1;
46 using namespace Barry;
48 // keeping a record of all the -i device / -o device pin numbers, so
49 // we can warn the poor user appropriately
50 std::vector<Barry::Pin> m_device_pins;
52 bool IsPinUsed(const Barry::Pin &pin)
54 for( std::vector<Barry::Pin>::const_iterator b = m_device_pins.begin();
55 b != m_device_pins.end(); ++b )
57 if( *b == pin )
58 return true;
60 return false;
63 void Usage()
65 int logical, major, minor;
66 const char *Version = Barry::Version(logical, major, minor);
67 #ifdef __BARRY_BOOST_MODE__
68 string boost_mode = _("Compiled with Boost support");
69 string boost_feature = "boost, ";
70 string boost_options = _("\n"
71 " Options to use for 'boost' type:\n"
72 " -f file Boost serialization filename to read from or write to\n"
73 " Can use - to specify stdin/stdout\n");
74 #else
75 string boost_mode = _("Compiled without Boost support");
76 string boost_feature;
77 string boost_options;
78 #endif
80 cerr << string_vprintf(
81 // TRANSLATORS: the i/o types, such as device, tar, mime, etc. must
82 // be exact. They are commands that the code tests for. Do not
83 // translate those particular words. Same with the -w write mode
84 // options.
85 _("bio - Barry Input / Output\n"
86 " Copyright 2010-2012, Net Direct Inc. (http://www.netdirect.ca/)\n"
87 " Using: %s\n"
88 " %s\n"
89 "\n"
90 " Usage: bio -i <type> [options...] -o <type> [options...]\n"
91 "\n"
92 " -i type The input type (Builder) to use for producing records\n"
93 " Can be one of: device, tar, %sldif, mime\n"
94 " -o type The output type (Parser) to use for processing records.\n"
95 " Multiple outputs are allowed, as long as they don't\n"
96 " conflict (such as two outputs writing to the same file\n"
97 " or device).\n"
98 " Can be one of: device, tar, %sldif, mime, dump, sha1, cstore\n"
99 "\n"
100 " Options to use for 'device' type:\n"
101 " -d db Name of input database. Can be used multiple times.\n"
102 " -A Add all available device databases, instead of specifying\n"
103 " them manually via -d\n"
104 " -p pin PIN of device to talk to\n"
105 " If only one device is plugged in, this flag is optional\n"
106 " -P pass Simplistic method to specify device password\n"
107 " -w mode Set write mode when using 'device' for output. Must be\n"
108 " specified, or will not write anything.\n"
109 " Can be one of: erase, overwrite, addonly, addnew\n"
110 "\n"
111 " Options to use for 'tar' backup type:\n"
112 " -d db Name of input database. Can be used multiple times.\n"
113 " Not available in output mode. Note that by default,\n"
114 " all databases in the backup are selected, when reading,\n"
115 " unless at least one -d is specified.\n"
116 " -D db Name of input database to skip. If no -d options are used,\n"
117 " then all databases are automatically selected. Using -D\n"
118 " allows a filtering selection. If -d and -D are used for\n"
119 " the same database, -D takes precedence.\n"
120 " -f file Tar backup file to read from or write to\n"
121 "%s"
122 "\n"
123 " Options to use for 'ldif' type:\n"
124 " -c dn Convert address book database to LDIF format, using the\n"
125 " specified baseDN\n"
126 " -C dnattr LDIF attribute name to use when building the FQDN\n"
127 " Defaults to 'cn'\n"
129 LDIF options?
131 " -L List Contact field names\n"
132 " -m Map LDIF name to Contact field / Unmap LDIF name\n"
133 " Map: ldif,read,write - maps ldif to read/write Contact fields\n"
134 " Unmap: ldif name alone\n"
135 " -M List current LDIF mapping\n"
137 "\n"
138 " Options to use for 'mime' type:\n"
139 " -f file Filename to read from or write to. Use - to explicitly\n"
140 " specify stdin/stdout, which is default.\n"
141 "\n"
142 " Options to use for 'dump' to stdout output type:\n"
143 " -n Use hex dump parser on all databases.\n"
144 "\n"
145 " Options to use for 'sha1' sum stdout output type:\n"
146 " -t Include DB Name, Type, and Unique record IDs in the checksums\n"
147 "\n"
148 " Options to use for 'cstore' output type:\n"
149 " -l List filenames only\n"
150 " -f file Filename from the above list, including path.\n"
151 " If found, the file will be written to the current\n"
152 " directory, using the base filename from the device.\n"
153 "\n"
154 " Standalone options:\n"
155 " -h This help\n"
156 " -I cs International charset for string conversions\n"
157 " Valid values here are available with 'iconv --list'\n"
158 " -S Show list of supported database parsers and builders.\n"
159 " Use twice to show field names as well.\n"
160 " -v Dump protocol data during operation\n"
161 "\n"),
162 Version, boost_mode.c_str(),
163 boost_feature.c_str(), boost_feature.c_str(),
164 boost_options.c_str())
165 << endl;
168 class ModeBase
170 public:
171 virtual ~ModeBase() {}
173 virtual bool ProbeNeeded() const { return false; }
175 virtual void SetFilename(const std::string &name)
177 throw runtime_error(_("Filename not applicable for this mode"));
180 virtual void AddDB(const std::string &dbname)
182 throw runtime_error(_("DB not applicable for this mode"));
185 virtual void AddSkipDB(const std::string &dbname)
187 throw runtime_error(_("DB skipping 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, m_dbskips;
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 void AddSkipDB(const std::string &dbname)
357 m_dbskips.push_back(dbname);
360 Builder& GetBuilder(Barry::Probe *probe, IConverter &ic)
362 m_restore.reset( new Restore(m_tarpath, true) );
363 for( size_t i = 0; i < m_dbnames.size(); i++ ) {
364 m_restore->AddDB(m_dbnames[i]);
366 for( size_t i = 0; i < m_dbskips.size(); i++ ) {
367 m_restore->AddSkipDB(m_dbskips[i]);
370 return *m_restore;
374 //////////////////////////////////////////////////////////////////////////////
375 // Mode: Input, Type: boost
377 #ifdef __BARRY_BOOST_MODE__
378 class BoostInput : public InputBase
380 auto_ptr<BoostBuilder> m_builder;
381 string m_filename;
383 public:
384 BoostInput()
385 : m_filename("-") // default to stdin/stdout
389 void SetFilename(const std::string &name)
391 m_filename = name;
394 Builder& GetBuilder(Barry::Probe *probe, IConverter &ic)
396 if( m_filename == "-" ) {
397 // use stdin
398 m_builder.reset( new BoostBuilder(cin) );
400 else {
401 m_builder.reset( new BoostBuilder(m_filename) );
403 return *m_builder;
407 #endif
409 //////////////////////////////////////////////////////////////////////////////
410 // Mode: Input, Type: ldif
412 class LdifInput : public InputBase
414 auto_ptr<Builder> m_builder;
415 string m_filename;
417 public:
418 LdifInput()
419 : m_filename("-")
423 void SetFilename(const std::string &name)
425 m_filename = name;
428 Builder& GetBuilder(Barry::Probe *probe, IConverter &ic)
430 if( m_filename == "-" ) {
431 // use stdin
432 m_builder.reset(
433 new RecordBuilder<Contact, LdifStore>(
434 new LdifStore(cin)) );
436 else {
437 m_builder.reset(
438 new RecordBuilder<Contact, LdifStore>(
439 new LdifStore(m_filename)) );
441 return *m_builder;
447 //////////////////////////////////////////////////////////////////////////////
448 // Mode: Input, Type: mime
450 class MimeInput : public InputBase
452 auto_ptr<MimeBuilder> m_builder;
453 string m_filename;
455 public:
456 MimeInput()
457 : m_filename("-")
461 void SetFilename(const std::string &name)
463 m_filename = name;
466 Builder& GetBuilder(Barry::Probe *probe, IConverter &ic)
468 if( m_filename == "-" ) {
469 // use stdin
470 m_builder.reset( new MimeBuilder(cin) );
472 else {
473 m_builder.reset( new MimeBuilder(m_filename) );
475 return *m_builder;
480 //////////////////////////////////////////////////////////////////////////////
481 // Base class for Output Mode
483 class OutputBase : public virtual ModeBase
485 public:
486 virtual Parser& GetParser(Barry::Probe *probe, IConverter &ic) = 0;
489 class DeviceOutputBase : public DeviceBase, public OutputBase
493 //////////////////////////////////////////////////////////////////////////////
494 // Mode: Output, Type: device
496 class DeviceOutput : public DeviceOutputBase
498 auto_ptr<Controller> m_con;
499 auto_ptr<Mode::Desktop> m_desktop;
500 auto_ptr<DeviceParser> m_parser;
501 DeviceParser::WriteMode m_mode;
503 public:
504 DeviceOutput()
505 : m_mode(DeviceParser::DROP_RECORD)
509 void SetWriteMode(DeviceParser::WriteMode mode)
511 m_mode = mode;
514 Parser& GetParser(Barry::Probe *probe, IConverter &ic)
516 if( m_mode == DeviceParser::DROP_RECORD ) {
517 cerr << _("Warning: the -w switch was not specified: no data will be written to the device.") << endl;
520 int i = probe->FindActive(m_pin);
521 if( i == -1 ) {
522 if( m_pin.Valid() )
523 throw runtime_error(_("PIN not found: ") + m_pin.Str());
524 else
525 throw runtime_error(_("PIN not specified, and more than one device exists."));
528 if( IsPinUsed(probe->Get(i).m_pin) ) {
529 throw runtime_error(_("It seems you are trying to use the same device for multiple input or outputs."));
531 m_device_pins.push_back(probe->Get(i).m_pin);
533 m_con.reset( new Controller(probe->Get(i)) );
534 m_desktop.reset( new Mode::Desktop(*m_con, ic) );
535 m_desktop->Open(m_password.c_str());
536 m_parser.reset( new DeviceParser(*m_desktop, m_mode) );
538 return *m_parser;
542 //////////////////////////////////////////////////////////////////////////////
543 // Mode: Output, Type: tar
545 class TarOutput : public OutputBase
547 auto_ptr<Backup> m_backup;
548 string m_tarpath;
550 public:
551 void SetFilename(const std::string &name)
553 m_tarpath = name;
554 if( name == "-" )
555 throw runtime_error(_("Cannot use stdout as tar backup file, sorry."));
558 Parser& GetParser(Barry::Probe *probe, IConverter &ic)
560 m_backup.reset( new Backup(m_tarpath) );
561 return *m_backup;
565 //////////////////////////////////////////////////////////////////////////////
566 // Mode: Output, Type: boost
568 #ifdef __BARRY_BOOST_MODE__
569 class BoostOutput : public OutputBase
571 auto_ptr<BoostParser> m_parser;
572 string m_filename;
574 public:
575 void SetFilename(const std::string &name)
577 m_filename = name;
580 Parser& GetParser(Barry::Probe *probe, IConverter &ic)
582 if( !m_filename.size() )
583 throw runtime_error(_("Boost output requires a specific output file (-f switch)"));
585 if( m_filename == "-" ) {
586 // use stdout
587 m_parser.reset( new BoostParser(cout) );
589 else {
590 m_parser.reset( new BoostParser(m_filename) );
592 return *m_parser;
596 #endif
598 //////////////////////////////////////////////////////////////////////////////
599 // Mode: Output, Type: ldif
601 class LdifOutput : public OutputBase
603 auto_ptr<Parser> m_parser;
604 string m_filename;
605 string m_baseDN;
606 string m_dnattr;
608 public:
609 LdifOutput()
610 : m_filename("-")
614 void SetFilename(const std::string &name)
616 m_filename = name;
619 void SetDN(const std::string &dn)
621 m_baseDN = dn;
624 void SetAttribute(const std::string &attr)
626 m_dnattr = attr;
629 Parser& GetParser(Barry::Probe *probe, IConverter &ic)
631 if( m_filename == "-" ) {
632 // use stdin
633 m_parser.reset(
634 new RecordParser<Contact, LdifStore>(
635 new LdifStore(cout, m_baseDN,
636 m_dnattr)) );
638 else {
639 m_parser.reset(
640 new RecordParser<Contact, LdifStore>(
641 new LdifStore(m_filename, m_baseDN,
642 m_dnattr)) );
644 return *m_parser;
648 //////////////////////////////////////////////////////////////////////////////
649 // Mode: Output, Type: mime
651 class MimeStore : public AllRecordStore
653 std::ostream &m_os;
655 public:
656 MimeStore(std::ostream &os)
657 : m_os(os)
661 #undef HANDLE_PARSER
662 #define HANDLE_PARSER(tname) \
663 void operator() (const Barry::tname &r) \
665 MimeDump<tname>::Dump(m_os, r); \
668 ALL_KNOWN_PARSER_TYPES
671 class MimeOutput : public OutputBase
673 auto_ptr<std::ofstream> m_file;
674 auto_ptr<Parser> m_parser;
675 std::string m_filename;
677 public:
678 MimeOutput()
679 : m_filename("-") // default to stdout
683 void SetFilename(const std::string &name)
685 m_filename = name;
688 Parser& GetParser(Barry::Probe *probe, IConverter &ic)
690 if( m_filename == "-" ) {
691 m_parser.reset( new AllRecordParser(cout,
692 new HexDumpParser(cout),
693 new MimeStore(cout)) );
695 else {
696 m_file.reset( new std::ofstream(m_filename.c_str()) );
697 m_parser.reset( new AllRecordParser(*m_file,
698 new HexDumpParser(*m_file),
699 new MimeStore(*m_file)) );
701 return *m_parser;
705 //////////////////////////////////////////////////////////////////////////////
706 // Mode: Output, Type: dump
708 class DumpOutput : public OutputBase
710 auto_ptr<Parser> m_parser;
711 bool m_hex_only;
713 public:
714 DumpOutput()
715 : m_hex_only(false)
719 void SetHexDump()
721 m_hex_only = true;
724 Parser& GetParser(Barry::Probe *probe, IConverter &ic)
726 if( m_hex_only ) {
727 m_parser.reset( new HexDumpParser(cout) );
729 else {
730 m_parser.reset( new AllRecordParser(cout,
731 new HexDumpParser(cout),
732 new AllRecordDumpStore(cout)) );
734 return *m_parser;
738 //////////////////////////////////////////////////////////////////////////////
739 // Mode: Output, Type: sha1
741 class Sha1Output : public OutputBase
743 auto_ptr<Parser> m_parser;
744 bool m_include_ids;
746 public:
747 Sha1Output()
748 : m_include_ids(false)
752 void IncludeIDs()
754 m_include_ids = true;
757 Parser& GetParser(Barry::Probe *probe, IConverter &ic)
759 m_parser.reset( new ChecksumParser(m_include_ids) );
760 return *m_parser;
764 //////////////////////////////////////////////////////////////////////////////
765 // Mode: Output, Type: cstore
767 class ContentStoreOutput : public OutputBase
769 auto_ptr<Parser> m_parser;
770 bool m_list_only;
771 vector<string> m_filenames;
773 public:
774 ContentStoreOutput()
775 : m_list_only(false)
779 void SetFilename(const std::string &name)
781 m_filenames.push_back(name);
784 void SetList()
786 m_list_only = true;
789 Parser& GetParser(Barry::Probe *probe, IConverter &ic)
791 m_parser.reset( new RecordParser<ContentStore, ContentStoreOutput>(*this) );
792 return *m_parser;
795 // storage operator
796 void operator() (const ContentStore &rec)
798 if( m_list_only ) {
799 cout << rec.Filename;
800 if( rec.FolderFlag ) {
801 cout << _(" (folder)");
803 cout << endl;
805 else {
806 // check if this record matches one of the filenames
807 // in the list
808 vector<string>::iterator i = find(m_filenames.begin(),
809 m_filenames.end(), rec.Filename);
810 if( i != m_filenames.end() ) {
811 SaveFile(rec);
816 void SaveFile(const ContentStore &rec)
818 size_t slash = rec.Filename.rfind('/');
819 string filename;
820 if( slash == string::npos )
821 filename = rec.Filename;
822 else
823 filename = rec.Filename.substr(slash + 1);
825 // modify filename until we find one that doesn't
826 // already exist
827 string freshname = filename;
828 int count = 0;
829 while( access(freshname.c_str(), F_OK) == 0 ) {
830 ostringstream oss;
831 oss << filename << count++;
832 freshname = oss.str();
835 // open and write!
836 cout << string_vprintf(_("Saving: %s as %s"),
837 rec.Filename.c_str(), freshname.c_str())
838 << endl;
839 ofstream ofs(freshname.c_str());
840 ofs << rec.FileContent;
841 ofs.flush();
842 if( !ofs ) {
843 cout << _("Error during write!") << endl;
850 //////////////////////////////////////////////////////////////////////////////
851 // Main application class
853 class App
855 public:
856 typedef shared_ptr<OutputBase> OutputPtr;
857 typedef vector<OutputPtr> OutputsType;
859 private:
860 auto_ptr<InputBase> Input;
861 OutputsType Outputs;
863 public:
865 bool ParseInMode(const string &mode);
866 bool ParseOutMode(const string &mode);
867 DeviceParser::WriteMode ParseWriteMode(const std::string &mode);
868 // returns true if any of the items in Outputs needs a probe
869 bool OutputsProbeNeeded();
870 int main(int argc, char *argv[]);
873 bool App::ParseInMode(const string &mode)
875 if( mode == "device" ) {
876 Input.reset( new DeviceInput );
877 return true;
879 else if( mode == "tar" ) {
880 Input.reset( new TarInput );
881 return true;
883 #ifdef __BARRY_BOOST_MODE__
884 else if( mode == "boost" ) {
885 Input.reset( new BoostInput );
886 return true;
888 #endif
889 else if( mode == "ldif" ) {
890 Input.reset( new LdifInput );
891 return true;
893 else if( mode == "mime" ) {
894 Input.reset( new MimeInput );
895 return true;
897 else
898 return false;
901 bool App::ParseOutMode(const string &mode)
903 if( mode == "device" ) {
904 Outputs.push_back( OutputPtr(new DeviceOutput) );
905 return true;
907 else if( mode == "tar" ) {
908 Outputs.push_back( OutputPtr(new TarOutput) );
909 return true;
911 #ifdef __BARRY_BOOST_MODE__
912 else if( mode == "boost" ) {
913 Outputs.push_back( OutputPtr(new BoostOutput) );
914 return true;
916 #endif
917 else if( mode == "ldif" ) {
918 Outputs.push_back( OutputPtr(new LdifOutput) );
919 return true;
921 else if( mode == "mime" ) {
922 Outputs.push_back( OutputPtr(new MimeOutput) );
923 return true;
925 else if( mode == "dump" ) {
926 Outputs.push_back( OutputPtr(new DumpOutput) );
927 return true;
929 else if( mode == "sha1" ) {
930 Outputs.push_back( OutputPtr(new Sha1Output) );
931 return true;
933 else if( mode == "cstore" ) {
934 Outputs.push_back( OutputPtr(new ContentStoreOutput) );
935 return true;
937 else
938 return false;
941 DeviceParser::WriteMode App::ParseWriteMode(const std::string &mode)
943 if( mode == "erase" )
944 return DeviceParser::ERASE_ALL_WRITE_ALL;
945 else if( mode == "overwrite" )
946 return DeviceParser::INDIVIDUAL_OVERWRITE;
947 else if( mode == "addonly" )
948 return DeviceParser::ADD_BUT_NO_OVERWRITE;
949 else if( mode == "addnew" )
950 return DeviceParser::ADD_WITH_NEW_ID;
951 else
952 throw runtime_error(_("Unknown device output mode. Must be one of: erase, overwrite, addonly, addnew"));
955 bool App::OutputsProbeNeeded()
957 for( OutputsType::iterator i = Outputs.begin();
958 i != Outputs.end();
959 ++i )
961 if( (*i)->ProbeNeeded() )
962 return true;
964 return false;
967 int App::main(int argc, char *argv[])
969 bool verbose = false;
970 bool show_parsers = false, show_fields = false;
971 string iconvCharset;
973 // process command line options
974 ModeBase *current = 0;
975 for(;;) {
976 int cmd = getopt(argc, argv, "hi:o:nvI:f:p:P:d:D:c:C:ASw:tl");
977 if( cmd == -1 )
978 break;
980 // first option must be in or out, or a global option
981 if( !current ) {
982 if( cmd != 'i' && \
983 cmd != 'o' && \
984 cmd != 'S' && \
985 cmd != 'I' && \
986 cmd != 'v' )
988 Usage();
989 return 1;
993 switch( cmd )
995 case 'i': // set input mode
996 // must be first time used
997 if( Input.get() || !ParseInMode(optarg) ) {
998 Usage();
999 return 1;
1001 current = Input.get();
1002 break;
1004 case 'o': // set output mode
1005 // can be used multiple times
1006 if( !ParseOutMode(optarg) ) {
1007 Usage();
1008 return 1;
1010 current = Outputs[Outputs.size() - 1].get();
1011 break;
1014 case 'c': // set ldif dn
1015 current->SetDN(optarg);
1016 break;
1018 case 'C': // set ldif attr
1019 current->SetAttribute(optarg);
1020 break;
1022 case 'd': // database name
1023 current->AddDB(optarg);
1024 break;
1026 case 'D': // database name to skip
1027 current->AddSkipDB(optarg);
1028 break;
1030 case 'f': // filename
1031 current->SetFilename(optarg);
1032 break;
1034 case 'p': // device PIN
1035 current->SetPIN(optarg);
1036 break;
1038 case 'P': // password
1039 current->SetPassword(optarg);
1040 break;
1042 case 'w': // device write mode
1043 current->SetWriteMode(ParseWriteMode(optarg));
1044 break;
1046 case 'A': // add all DB names to the device builder
1047 current->AddAllDBs();
1048 break;
1050 case 't': // include type and IDs in sha1 mode
1051 current->IncludeIDs();
1052 break;
1054 case 'l': // list only
1055 current->SetList();
1056 break;
1058 case 'S': // show parsers and builders
1059 if( show_parsers )
1060 show_fields = true;
1061 else
1062 show_parsers = true;
1063 break;
1065 case 'I': // international charset (iconv)
1066 iconvCharset = optarg;
1067 break;
1069 case 'n': // use null hex dump parser only
1070 current->SetHexDump();
1071 break;
1073 case 'v': // verbose
1074 verbose = true;
1075 break;
1077 case 'h': // help
1078 default:
1079 Usage();
1080 return 0;
1084 if( show_parsers ) {
1085 ShowParsers(show_fields, true);
1086 ShowBuilders();
1087 return 0;
1090 if( !Input.get() || !Outputs.size() ) {
1091 Usage();
1092 return 0;
1095 // Initialize the Barry library
1096 Barry::Init(verbose);
1098 // Create an IConverter object if needed
1099 auto_ptr<IConverter> ic;
1100 if( iconvCharset.size() ) {
1101 ic.reset( new IConverter(iconvCharset.c_str(), true) );
1104 // Probe for devices only if needed
1105 auto_ptr<Probe> probe;
1106 if( Input->ProbeNeeded() || OutputsProbeNeeded() ) {
1107 // Probe for available devices
1108 probe.reset( new Probe );
1111 // Setup the input first (builder)
1112 Builder &builder = Input->GetBuilder(probe.get(), *ic);
1114 // Setup a TeeParser with all Outputs
1115 TeeParser tee;
1116 for( OutputsType::iterator i = Outputs.begin(); i != Outputs.end(); ++i ) {
1117 Parser &parser = (*i)->GetParser(probe.get(), *ic);
1118 tee.Add(parser);
1121 // Setup the pipe
1122 Pipe pipe(builder);
1123 pipe.PumpFile(tee, ic.get());
1125 return 0;
1128 int main(int argc, char *argv[])
1130 try {
1131 App app;
1132 return app.main(argc, argv);
1134 catch( std::exception &e ) {
1135 cerr << _("Exception: ") << e.what() << endl;
1136 return 1;