menu: added new Keywords tag to .desktop files
[barry.git] / tools / bio.cc
blob66274217935c44d567fff61198205ec0e1e4d426
1 ///
2 /// \file bio.cc
3 /// Barry Input / Output
4 ///
6 /*
7 Copyright (C) 2010-2013, 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-2013, 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 " -T Show only the names of the databases.\n"
145 "\n"
146 " Options to use for 'sha1' sum stdout output type:\n"
147 " -t Include DB Name, Type, and Unique record IDs in the checksums\n"
148 "\n"
149 " Options to use for 'cstore' output type:\n"
150 " -l List filenames only\n"
151 " -f file Filename from the above list, including path.\n"
152 " If found, the file will be written to the current\n"
153 " directory, using the base filename from the device.\n"
154 "\n"
155 " Standalone options:\n"
156 " -h This help\n"
157 " -I cs International charset for string conversions\n"
158 " Valid values here are available with 'iconv --list'\n"
159 " -S Show list of supported database parsers and builders.\n"
160 " Use twice to show field names as well.\n"
161 " -v Dump protocol data during operation\n"
162 "\n"),
163 Version, boost_mode.c_str(),
164 boost_feature.c_str(), boost_feature.c_str(),
165 boost_options.c_str())
166 << endl;
169 class ModeBase
171 public:
172 virtual ~ModeBase() {}
174 virtual bool ProbeNeeded() const { return false; }
176 virtual void SetFilename(const std::string &name)
178 throw runtime_error(_("Filename not applicable for this mode"));
181 virtual void AddDB(const std::string &dbname)
183 throw runtime_error(_("DB not applicable for this mode"));
186 virtual void AddSkipDB(const std::string &dbname)
188 throw runtime_error(_("DB skipping 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 SetDBNamesOnly()
228 throw runtime_error(_("No name-only option in this mode"));
231 virtual void IncludeIDs()
233 throw runtime_error(_("Including record IDs in the SHA1 sum is not applicable in this mode"));
236 virtual void SetList()
238 throw runtime_error(_("List option not applicable for this mode"));
242 class DeviceBase : public virtual ModeBase
244 protected:
245 Barry::Pin m_pin;
246 std::string m_password;
248 public:
249 bool ProbeNeeded() const { return true; }
251 void SetPIN(const std::string &pin)
253 istringstream iss(pin);
254 iss >> m_pin;
255 if( !m_pin.Valid() )
256 throw runtime_error(_("Invalid PIN: ") + pin);
259 void SetPassword(const std::string &password)
261 m_password = password;
265 //////////////////////////////////////////////////////////////////////////////
266 // Base class for Input Mode
268 class InputBase : public virtual ModeBase
270 public:
271 virtual Builder& GetBuilder(Barry::Probe *probe, IConverter &ic) = 0;
274 class DeviceInputBase : public DeviceBase, public InputBase
278 //////////////////////////////////////////////////////////////////////////////
279 // Mode: Input, Type: device
281 class DeviceInput : public DeviceInputBase
283 auto_ptr<Controller> m_con;
284 auto_ptr<Mode::Desktop> m_desktop;
285 auto_ptr<DeviceBuilder> m_builder;
286 vector<string> m_dbnames;
287 bool m_add_all;
289 public:
290 DeviceInput()
291 : m_add_all(false)
295 void AddDB(const std::string &dbname)
297 m_dbnames.push_back(dbname);
300 void AddAllDBs()
302 m_add_all = true;
305 Builder& GetBuilder(Barry::Probe *probe, IConverter &ic)
307 int i = probe->FindActive(m_pin);
308 if( i == -1 ) {
309 if( m_pin.Valid() )
310 throw runtime_error(_("PIN not found: ") + m_pin.Str());
311 else
312 throw runtime_error(_("PIN not specified, and more than one device exists."));
315 if( IsPinUsed(probe->Get(i).m_pin) ) {
316 throw runtime_error(_("It seems you are trying to use the same device for multiple input or outputs."));
318 m_device_pins.push_back(probe->Get(i).m_pin);
320 m_con.reset( new Controller(probe->Get(i)) );
321 m_desktop.reset( new Mode::Desktop(*m_con, ic) );
322 m_desktop->Open(m_password.c_str());
323 m_builder.reset( new DeviceBuilder(*m_desktop) );
325 if( m_add_all ) {
326 m_builder->Add(m_desktop->GetDBDB());
328 else {
329 for( size_t i = 0; i < m_dbnames.size(); i++ ) {
330 if( !m_builder->Add(m_dbnames[i]) )
331 throw runtime_error(_("Database not found: ") + m_dbnames[i]);
335 return *m_builder;
339 //////////////////////////////////////////////////////////////////////////////
340 // Mode: Input, Type: tar
342 class TarInput : public InputBase
344 auto_ptr<Restore> m_restore;
345 string m_tarpath;
346 vector<string> m_dbnames, m_dbskips;
348 public:
349 void SetFilename(const std::string &name)
351 m_tarpath = name;
352 if( name == "-" )
353 throw runtime_error(_("Cannot use stdin as tar source file, sorry."));
356 void AddDB(const std::string &dbname)
358 m_dbnames.push_back(dbname);
361 void AddSkipDB(const std::string &dbname)
363 m_dbskips.push_back(dbname);
366 Builder& GetBuilder(Barry::Probe *probe, IConverter &ic)
368 m_restore.reset( new Restore(m_tarpath, true) );
369 for( size_t i = 0; i < m_dbnames.size(); i++ ) {
370 m_restore->AddDB(m_dbnames[i]);
372 for( size_t i = 0; i < m_dbskips.size(); i++ ) {
373 m_restore->AddSkipDB(m_dbskips[i]);
376 return *m_restore;
380 //////////////////////////////////////////////////////////////////////////////
381 // Mode: Input, Type: boost
383 #ifdef __BARRY_BOOST_MODE__
384 class BoostInput : public InputBase
386 auto_ptr<BoostBuilder> m_builder;
387 string m_filename;
389 public:
390 BoostInput()
391 : m_filename("-") // default to stdin/stdout
395 void SetFilename(const std::string &name)
397 m_filename = name;
400 Builder& GetBuilder(Barry::Probe *probe, IConverter &ic)
402 if( m_filename == "-" ) {
403 // use stdin
404 m_builder.reset( new BoostBuilder(cin) );
406 else {
407 m_builder.reset( new BoostBuilder(m_filename) );
409 return *m_builder;
413 #endif
415 //////////////////////////////////////////////////////////////////////////////
416 // Mode: Input, Type: ldif
418 class LdifInput : public InputBase
420 auto_ptr<Builder> m_builder;
421 string m_filename;
423 public:
424 LdifInput()
425 : m_filename("-")
429 void SetFilename(const std::string &name)
431 m_filename = name;
434 Builder& GetBuilder(Barry::Probe *probe, IConverter &ic)
436 if( m_filename == "-" ) {
437 // use stdin
438 m_builder.reset(
439 new RecordBuilder<Contact, LdifStore>(
440 new LdifStore(cin)) );
442 else {
443 m_builder.reset(
444 new RecordBuilder<Contact, LdifStore>(
445 new LdifStore(m_filename)) );
447 return *m_builder;
453 //////////////////////////////////////////////////////////////////////////////
454 // Mode: Input, Type: mime
456 class MimeInput : public InputBase
458 auto_ptr<MimeBuilder> m_builder;
459 string m_filename;
461 public:
462 MimeInput()
463 : m_filename("-")
467 void SetFilename(const std::string &name)
469 m_filename = name;
472 Builder& GetBuilder(Barry::Probe *probe, IConverter &ic)
474 if( m_filename == "-" ) {
475 // use stdin
476 m_builder.reset( new MimeBuilder(cin) );
478 else {
479 m_builder.reset( new MimeBuilder(m_filename) );
481 return *m_builder;
486 //////////////////////////////////////////////////////////////////////////////
487 // Base class for Output Mode
489 class OutputBase : public virtual ModeBase
491 public:
492 virtual Parser& GetParser(Barry::Probe *probe, IConverter &ic) = 0;
495 class DeviceOutputBase : public DeviceBase, public OutputBase
499 //////////////////////////////////////////////////////////////////////////////
500 // Mode: Output, Type: device
502 class DeviceOutput : public DeviceOutputBase
504 auto_ptr<Controller> m_con;
505 auto_ptr<Mode::Desktop> m_desktop;
506 auto_ptr<DeviceParser> m_parser;
507 DeviceParser::WriteMode m_mode;
509 public:
510 DeviceOutput()
511 : m_mode(DeviceParser::DROP_RECORD)
515 void SetWriteMode(DeviceParser::WriteMode mode)
517 m_mode = mode;
520 Parser& GetParser(Barry::Probe *probe, IConverter &ic)
522 if( m_mode == DeviceParser::DROP_RECORD ) {
523 cerr << _("Warning: the -w switch was not specified: no data will be written to the device.") << endl;
526 int i = probe->FindActive(m_pin);
527 if( i == -1 ) {
528 if( m_pin.Valid() )
529 throw runtime_error(_("PIN not found: ") + m_pin.Str());
530 else
531 throw runtime_error(_("PIN not specified, and more than one device exists."));
534 if( IsPinUsed(probe->Get(i).m_pin) ) {
535 throw runtime_error(_("It seems you are trying to use the same device for multiple input or outputs."));
537 m_device_pins.push_back(probe->Get(i).m_pin);
539 m_con.reset( new Controller(probe->Get(i)) );
540 m_desktop.reset( new Mode::Desktop(*m_con, ic) );
541 m_desktop->Open(m_password.c_str());
542 m_parser.reset( new DeviceParser(*m_desktop, m_mode) );
544 return *m_parser;
548 //////////////////////////////////////////////////////////////////////////////
549 // Mode: Output, Type: tar
551 class TarOutput : public OutputBase
553 auto_ptr<Backup> m_backup;
554 string m_tarpath;
556 public:
557 void SetFilename(const std::string &name)
559 m_tarpath = name;
560 if( name == "-" )
561 throw runtime_error(_("Cannot use stdout as tar backup file, sorry."));
564 Parser& GetParser(Barry::Probe *probe, IConverter &ic)
566 m_backup.reset( new Backup(m_tarpath) );
567 return *m_backup;
571 //////////////////////////////////////////////////////////////////////////////
572 // Mode: Output, Type: boost
574 #ifdef __BARRY_BOOST_MODE__
575 class BoostOutput : public OutputBase
577 auto_ptr<BoostParser> m_parser;
578 string m_filename;
580 public:
581 void SetFilename(const std::string &name)
583 m_filename = name;
586 Parser& GetParser(Barry::Probe *probe, IConverter &ic)
588 if( !m_filename.size() )
589 throw runtime_error(_("Boost output requires a specific output file (-f switch)"));
591 if( m_filename == "-" ) {
592 // use stdout
593 m_parser.reset( new BoostParser(cout) );
595 else {
596 m_parser.reset( new BoostParser(m_filename) );
598 return *m_parser;
602 #endif
604 //////////////////////////////////////////////////////////////////////////////
605 // Mode: Output, Type: ldif
607 class LdifOutput : public OutputBase
609 auto_ptr<Parser> m_parser;
610 string m_filename;
611 string m_baseDN;
612 string m_dnattr;
614 public:
615 LdifOutput()
616 : m_filename("-")
620 void SetFilename(const std::string &name)
622 m_filename = name;
625 void SetDN(const std::string &dn)
627 m_baseDN = dn;
630 void SetAttribute(const std::string &attr)
632 m_dnattr = attr;
635 Parser& GetParser(Barry::Probe *probe, IConverter &ic)
637 if( m_filename == "-" ) {
638 // use stdin
639 m_parser.reset(
640 new RecordParser<Contact, LdifStore>(
641 new LdifStore(cout, m_baseDN,
642 m_dnattr)) );
644 else {
645 m_parser.reset(
646 new RecordParser<Contact, LdifStore>(
647 new LdifStore(m_filename, m_baseDN,
648 m_dnattr)) );
650 return *m_parser;
654 //////////////////////////////////////////////////////////////////////////////
655 // Mode: Output, Type: mime
657 class MimeStore : public AllRecordStore
659 std::ostream &m_os;
661 public:
662 MimeStore(std::ostream &os)
663 : m_os(os)
667 #undef HANDLE_PARSER
668 #define HANDLE_PARSER(tname) \
669 void operator() (const Barry::tname &r) \
671 MimeDump<tname>::Dump(m_os, r); \
674 ALL_KNOWN_PARSER_TYPES
677 class MimeOutput : public OutputBase
679 auto_ptr<std::ofstream> m_file;
680 auto_ptr<Parser> m_parser;
681 std::string m_filename;
683 public:
684 MimeOutput()
685 : m_filename("-") // default to stdout
689 void SetFilename(const std::string &name)
691 m_filename = name;
694 Parser& GetParser(Barry::Probe *probe, IConverter &ic)
696 if( m_filename == "-" ) {
697 m_parser.reset( new AllRecordParser(cout,
698 new HexDumpParser(cout),
699 new MimeStore(cout)) );
701 else {
702 m_file.reset( new std::ofstream(m_filename.c_str()) );
703 m_parser.reset( new AllRecordParser(*m_file,
704 new HexDumpParser(*m_file),
705 new MimeStore(*m_file)) );
707 return *m_parser;
711 //////////////////////////////////////////////////////////////////////////////
712 // Mode: Output, Type: dump
714 class DumpOutput : public OutputBase
716 auto_ptr<Parser> m_parser;
717 bool m_hex_only;
718 bool m_dbnames_only;
720 public:
721 DumpOutput()
722 : m_hex_only(false)
723 , m_dbnames_only(false)
727 void SetHexDump()
729 m_hex_only = true;
732 void SetDBNamesOnly()
734 m_dbnames_only = true;
737 Parser& GetParser(Barry::Probe *probe, IConverter &ic)
739 if( m_hex_only ) {
740 m_parser.reset( new HexDumpParser(cout) );
742 else if( m_dbnames_only ) {
743 m_parser.reset( new DBNamesOnlyParser(cout) );
745 else {
746 m_parser.reset( new AllRecordParser(cout,
747 new HexDumpParser(cout),
748 new AllRecordDumpStore(cout)) );
750 return *m_parser;
754 //////////////////////////////////////////////////////////////////////////////
755 // Mode: Output, Type: sha1
757 class Sha1Output : public OutputBase
759 auto_ptr<Parser> m_parser;
760 bool m_include_ids;
762 public:
763 Sha1Output()
764 : m_include_ids(false)
768 void IncludeIDs()
770 m_include_ids = true;
773 Parser& GetParser(Barry::Probe *probe, IConverter &ic)
775 m_parser.reset( new ChecksumParser(m_include_ids) );
776 return *m_parser;
780 //////////////////////////////////////////////////////////////////////////////
781 // Mode: Output, Type: cstore
783 class ContentStoreOutput : public OutputBase
785 auto_ptr<Parser> m_parser;
786 bool m_list_only;
787 vector<string> m_filenames;
789 public:
790 ContentStoreOutput()
791 : m_list_only(false)
795 void SetFilename(const std::string &name)
797 m_filenames.push_back(name);
800 void SetList()
802 m_list_only = true;
805 Parser& GetParser(Barry::Probe *probe, IConverter &ic)
807 m_parser.reset( new RecordParser<ContentStore, ContentStoreOutput>(*this) );
808 return *m_parser;
811 // storage operator
812 void operator() (const ContentStore &rec)
814 if( m_list_only ) {
815 cout << rec.Filename;
816 if( rec.FolderFlag ) {
817 cout << _(" (folder)");
819 cout << endl;
821 else {
822 // check if this record matches one of the filenames
823 // in the list
824 vector<string>::iterator i = find(m_filenames.begin(),
825 m_filenames.end(), rec.Filename);
826 if( i != m_filenames.end() ) {
827 SaveFile(rec);
832 void SaveFile(const ContentStore &rec)
834 size_t slash = rec.Filename.rfind('/');
835 string filename;
836 if( slash == string::npos )
837 filename = rec.Filename;
838 else
839 filename = rec.Filename.substr(slash + 1);
841 // modify filename until we find one that doesn't
842 // already exist
843 string freshname = filename;
844 int count = 0;
845 while( access(freshname.c_str(), F_OK) == 0 ) {
846 ostringstream oss;
847 oss << filename << count++;
848 freshname = oss.str();
851 // open and write!
852 cout << string_vprintf(_("Saving: %s as %s"),
853 rec.Filename.c_str(), freshname.c_str())
854 << endl;
855 ofstream ofs(freshname.c_str());
856 ofs << rec.FileContent;
857 ofs.flush();
858 if( !ofs ) {
859 cout << _("Error during write!") << endl;
866 //////////////////////////////////////////////////////////////////////////////
867 // Main application class
869 class App
871 public:
872 typedef shared_ptr<OutputBase> OutputPtr;
873 typedef vector<OutputPtr> OutputsType;
875 private:
876 auto_ptr<InputBase> Input;
877 OutputsType Outputs;
879 public:
881 bool ParseInMode(const string &mode);
882 bool ParseOutMode(const string &mode);
883 DeviceParser::WriteMode ParseWriteMode(const std::string &mode);
884 // returns true if any of the items in Outputs needs a probe
885 bool OutputsProbeNeeded();
886 int main(int argc, char *argv[]);
889 bool App::ParseInMode(const string &mode)
891 if( mode == "device" ) {
892 Input.reset( new DeviceInput );
893 return true;
895 else if( mode == "tar" ) {
896 Input.reset( new TarInput );
897 return true;
899 #ifdef __BARRY_BOOST_MODE__
900 else if( mode == "boost" ) {
901 Input.reset( new BoostInput );
902 return true;
904 #endif
905 else if( mode == "ldif" ) {
906 Input.reset( new LdifInput );
907 return true;
909 else if( mode == "mime" ) {
910 Input.reset( new MimeInput );
911 return true;
913 else
914 return false;
917 bool App::ParseOutMode(const string &mode)
919 if( mode == "device" ) {
920 Outputs.push_back( OutputPtr(new DeviceOutput) );
921 return true;
923 else if( mode == "tar" ) {
924 Outputs.push_back( OutputPtr(new TarOutput) );
925 return true;
927 #ifdef __BARRY_BOOST_MODE__
928 else if( mode == "boost" ) {
929 Outputs.push_back( OutputPtr(new BoostOutput) );
930 return true;
932 #endif
933 else if( mode == "ldif" ) {
934 Outputs.push_back( OutputPtr(new LdifOutput) );
935 return true;
937 else if( mode == "mime" ) {
938 Outputs.push_back( OutputPtr(new MimeOutput) );
939 return true;
941 else if( mode == "dump" ) {
942 Outputs.push_back( OutputPtr(new DumpOutput) );
943 return true;
945 else if( mode == "sha1" ) {
946 Outputs.push_back( OutputPtr(new Sha1Output) );
947 return true;
949 else if( mode == "cstore" ) {
950 Outputs.push_back( OutputPtr(new ContentStoreOutput) );
951 return true;
953 else
954 return false;
957 DeviceParser::WriteMode App::ParseWriteMode(const std::string &mode)
959 if( mode == "erase" )
960 return DeviceParser::ERASE_ALL_WRITE_ALL;
961 else if( mode == "overwrite" )
962 return DeviceParser::INDIVIDUAL_OVERWRITE;
963 else if( mode == "addonly" )
964 return DeviceParser::ADD_BUT_NO_OVERWRITE;
965 else if( mode == "addnew" )
966 return DeviceParser::ADD_WITH_NEW_ID;
967 else
968 throw runtime_error(_("Unknown device output mode. Must be one of: erase, overwrite, addonly, addnew"));
971 bool App::OutputsProbeNeeded()
973 for( OutputsType::iterator i = Outputs.begin();
974 i != Outputs.end();
975 ++i )
977 if( (*i)->ProbeNeeded() )
978 return true;
980 return false;
983 int App::main(int argc, char *argv[])
985 bool verbose = false;
986 bool show_parsers = false, show_fields = 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:D:c:C:ASw:tTl");
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 'D': // database name to skip
1043 current->AddSkipDB(optarg);
1044 break;
1046 case 'f': // filename
1047 current->SetFilename(optarg);
1048 break;
1050 case 'p': // device PIN
1051 current->SetPIN(optarg);
1052 break;
1054 case 'P': // password
1055 current->SetPassword(optarg);
1056 break;
1058 case 'w': // device write mode
1059 current->SetWriteMode(ParseWriteMode(optarg));
1060 break;
1062 case 'A': // add all DB names to the device builder
1063 current->AddAllDBs();
1064 break;
1066 case 't': // include type and IDs in sha1 mode
1067 current->IncludeIDs();
1068 break;
1070 case 'T': // display database names only instead of recs
1071 current->SetDBNamesOnly();
1072 break;
1074 case 'l': // list only
1075 current->SetList();
1076 break;
1078 case 'S': // show parsers and builders
1079 if( show_parsers )
1080 show_fields = true;
1081 else
1082 show_parsers = true;
1083 break;
1085 case 'I': // international charset (iconv)
1086 iconvCharset = optarg;
1087 break;
1089 case 'n': // use null hex dump parser only
1090 current->SetHexDump();
1091 break;
1093 case 'v': // verbose
1094 verbose = true;
1095 break;
1097 case 'h': // help
1098 default:
1099 Usage();
1100 return 0;
1104 if( show_parsers ) {
1105 ShowParsers(show_fields, true);
1106 ShowBuilders();
1107 return 0;
1110 if( !Input.get() || !Outputs.size() ) {
1111 Usage();
1112 return 0;
1115 // Initialize the Barry library
1116 Barry::Init(verbose);
1118 // Create an IConverter object if needed
1119 auto_ptr<IConverter> ic;
1120 if( iconvCharset.size() ) {
1121 ic.reset( new IConverter(iconvCharset.c_str(), true) );
1124 // Probe for devices only if needed
1125 auto_ptr<Probe> probe;
1126 if( Input->ProbeNeeded() || OutputsProbeNeeded() ) {
1127 // Probe for available devices
1128 probe.reset( new Probe );
1131 // Setup the input first (builder)
1132 Builder &builder = Input->GetBuilder(probe.get(), *ic);
1134 // Setup a TeeParser with all Outputs
1135 TeeParser tee;
1136 for( OutputsType::iterator i = Outputs.begin(); i != Outputs.end(); ++i ) {
1137 Parser &parser = (*i)->GetParser(probe.get(), *ic);
1138 tee.Add(parser);
1141 // Setup the pipe
1142 Pipe pipe(builder);
1143 pipe.PumpFile(tee, ic.get());
1145 return 0;
1148 int main(int argc, char *argv[])
1150 INIT_I18N(PACKAGE);
1152 try {
1153 App app;
1154 return app.main(argc, argv);
1156 catch( std::exception &e ) {
1157 cerr << _("Exception: ") << e.what() << endl;
1158 return 1;