tools: grouped common tool code into tools/util.{h,cc}
[barry/progweb.git] / tools / bio.cc
blobed7ab7dba46d820a18bad4b9dc0a3433fa280a8a
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"
28 #include "util.h"
30 #include <iomanip>
31 #include <iostream>
32 #include <sstream>
33 #include <fstream>
34 #include <string>
35 #include <vector>
36 #include <algorithm>
37 #include <stdexcept>
38 #include <tr1/memory>
39 #include <strings.h>
41 #include "barrygetopt.h"
43 using namespace std;
44 using namespace std::tr1;
45 using namespace Barry;
47 // keeping a record of all the -i device / -o device pin numbers, so
48 // we can warn the poor user appropriately
49 std::vector<Barry::Pin> m_device_pins;
51 bool IsPinUsed(const Barry::Pin &pin)
53 for( std::vector<Barry::Pin>::const_iterator b = m_device_pins.begin();
54 b != m_device_pins.end(); ++b )
56 if( *b == pin )
57 return true;
59 return false;
62 void Usage()
64 int logical, major, minor;
65 const char *Version = Barry::Version(logical, major, minor);
67 cerr
68 << "bio - Barry Input / Output\n"
69 << " Copyright 2010-2012, Net Direct Inc. (http://www.netdirect.ca/)\n"
70 << " Using: " << Version << "\n"
71 << " Compiled "
72 #ifdef __BARRY_BOOST_MODE__
73 << "with"
74 #else
75 << "without"
76 #endif
77 << " Boost support\n"
78 << "\n"
79 << " Usage: bio -i <type> [options...] -o <type> [options...]\n"
80 << "\n"
81 << " -i type The input type (Builder) to use for producing records\n"
82 << " Can be one of: device, tar"
83 #ifdef __BARRY_BOOST_MODE__
84 << ", boost"
85 #endif
86 << ", ldif, mime\n"
87 << " -o type The output type (Parser) to use for processing records.\n"
88 << " Multiple outputs are allowed, as long as they don't\n"
89 << " conflict (such as two outputs writing to the same file\n"
90 << " or device).\n"
91 << " Can be one of: device, tar"
92 #ifdef __BARRY_BOOST_MODE__
93 << ", boost"
94 #endif
95 << ", ldif, mime, dump, sha1, cstore\n"
96 << "\n"
97 << " Options to use for 'device' type:\n"
98 << " -d db Name of input database. Can be used multiple times.\n"
99 << " -A Add all available device databases, instead of specifying\n"
100 << " them manually via -d\n"
101 << " -p pin PIN of device to talk to\n"
102 << " If only one device is plugged in, this flag is optional\n"
103 << " -P pass Simplistic method to specify device password\n"
104 << " -w mode Set write mode when using 'device' for output. Must be\n"
105 << " specified, or will not write anything.\n"
106 << " Can be one of: erase, overwrite, addonly, addnew\n"
108 // FIXME - modifiers not yet implemented
109 << "\n"
110 << " Input database modifiers: (can be used multiple times for more than 1 record)\n"
111 << "\n"
112 << " -r # Record index number as seen in the -T state table.\n"
113 << " This overrides the default -d behaviour, and only\n"
114 << " downloads the one specified record, sending to stdout.\n"
115 << " -R # Same as -r, but also clears the record's dirty flags.\n"
116 << " -D # Record index number as seen in the -T state table,\n"
117 << " which indicates the record to delete. Used with the -d\n"
118 << " command to specify the database.\n"
120 << "\n"
121 << " Options to use for 'tar' backup type:\n"
122 << " -d db Name of input database. Can be used multiple times.\n"
123 << " Not available in output mode. Note that by default,\n"
124 << " all databases in the backup are selected, when reading,\n"
125 << " unless at least one -d is specified.\n"
126 << " -f file Tar backup file to read from or write to\n"
127 #ifdef __BARRY_BOOST_MODE__
128 << "\n"
129 << " Options to use for 'boost' type:\n"
130 << " -f file Boost serialization filename to read from or write to\n"
131 << " Can use - to specify stdin/stdout\n"
132 #endif
133 << "\n"
134 << " Options to use for 'ldif' type:\n"
135 << " -c dn Convert address book database to LDIF format, using the\n"
136 << " specified baseDN\n"
137 << " -C dnattr LDIF attribute name to use when building the FQDN\n"
138 << " Defaults to 'cn'\n"
140 LDIF options?
142 << " -L List Contact field names\n"
143 << " -m Map LDIF name to Contact field / Unmap LDIF name\n"
144 << " Map: ldif,read,write - maps ldif to read/write Contact fields\n"
145 << " Unmap: ldif name alone\n"
146 << " -M List current LDIF mapping\n"
148 << "\n"
149 << " Options to use for 'mime' type:\n"
150 << " -f file Filename to read from or write to. Use - to explicitly\n"
151 << " specify stdin/stdout, which is default.\n"
152 << "\n"
153 << " Options to use for 'dump' to stdout output type:\n"
154 << " -n Use hex dump parser on all databases.\n"
155 << "\n"
156 << " Options to use for 'sha1' sum stdout output type:\n"
157 << " -t Include DB Name, Type, and Unique record IDs in the checksums\n"
158 << "\n"
159 << " Options to use for 'cstore' output type:\n"
160 << " -l List filenames only\n"
161 << " -f file Filename from the above list, including path.\n"
162 << " If found, the file will be written to the current\n"
163 << " directory, using the base filename from the device.\n"
164 << "\n"
165 << " Standalone options:\n"
166 << " -h This help\n"
167 << " -I cs International charset for string conversions\n"
168 << " Valid values here are available with 'iconv --list'\n"
169 << " -S Show list of supported database parsers and builders.\n"
170 << " Use twice to show field names as well.\n"
171 << " -v Dump protocol data during operation\n"
172 << "\n"
173 << endl;
176 class ModeBase
178 public:
179 virtual ~ModeBase() {}
181 virtual bool ProbeNeeded() const { return false; }
183 virtual void SetFilename(const std::string &name)
185 throw runtime_error("Filename not applicable for this mode");
188 virtual void AddDB(const std::string &dbname)
190 throw runtime_error("DB not applicable for this mode");
193 virtual void AddAllDBs()
195 throw runtime_error("DBs not applicable for this mode");
198 virtual void SetPIN(const std::string &pin)
200 throw runtime_error("PIN not applicable for this mode");
203 virtual void SetPassword(const std::string &password)
205 throw runtime_error("Password not applicable for this mode");
208 virtual void SetWriteMode(DeviceParser::WriteMode mode)
210 throw runtime_error("Device write behaviour not applicable for this mode");
213 virtual void SetDN(const std::string &dn)
215 throw runtime_error("DN not applicable for this mode");
218 virtual void SetAttribute(const std::string &attr)
220 throw runtime_error("Attribute not applicable for this mode");
223 virtual void SetHexDump()
225 throw runtime_error("No hex dump option in this mode");
228 virtual void IncludeIDs()
230 throw runtime_error("Including record IDs in the SHA1 sum is not applicable in this mode");
233 virtual void SetList()
235 throw runtime_error("List option not applicable for this mode");
239 class DeviceBase : public virtual ModeBase
241 protected:
242 Barry::Pin m_pin;
243 std::string m_password;
245 public:
246 bool ProbeNeeded() const { return true; }
248 void SetPIN(const std::string &pin)
250 istringstream iss(pin);
251 iss >> m_pin;
252 if( !m_pin.Valid() )
253 throw runtime_error("Invalid PIN: " + pin);
256 void SetPassword(const std::string &password)
258 m_password = password;
262 //////////////////////////////////////////////////////////////////////////////
263 // Base class for Input Mode
265 class InputBase : public virtual ModeBase
267 public:
268 virtual Builder& GetBuilder(Barry::Probe *probe, IConverter &ic) = 0;
271 class DeviceInputBase : public DeviceBase, public InputBase
275 //////////////////////////////////////////////////////////////////////////////
276 // Mode: Input, Type: device
278 class DeviceInput : public DeviceInputBase
280 auto_ptr<Controller> m_con;
281 auto_ptr<Mode::Desktop> m_desktop;
282 auto_ptr<DeviceBuilder> m_builder;
283 vector<string> m_dbnames;
284 bool m_add_all;
286 public:
287 DeviceInput()
288 : m_add_all(false)
292 void AddDB(const std::string &dbname)
294 m_dbnames.push_back(dbname);
297 void AddAllDBs()
299 m_add_all = true;
302 Builder& GetBuilder(Barry::Probe *probe, IConverter &ic)
304 int i = probe->FindActive(m_pin);
305 if( i == -1 ) {
306 if( m_pin.Valid() )
307 throw runtime_error("PIN not found: " + m_pin.Str());
308 else
309 throw runtime_error("PIN not specified, and more than one device exists.");
312 if( IsPinUsed(probe->Get(i).m_pin) ) {
313 throw runtime_error("It seems you are trying to use the same device for multiple input or outputs.");
315 m_device_pins.push_back(probe->Get(i).m_pin);
317 m_con.reset( new Controller(probe->Get(i)) );
318 m_desktop.reset( new Mode::Desktop(*m_con, ic) );
319 m_desktop->Open(m_password.c_str());
320 m_builder.reset( new DeviceBuilder(*m_desktop) );
322 if( m_add_all ) {
323 m_builder->Add(m_desktop->GetDBDB());
325 else {
326 for( size_t i = 0; i < m_dbnames.size(); i++ ) {
327 if( !m_builder->Add(m_dbnames[i]) )
328 throw runtime_error("Database not found: " + m_dbnames[i]);
332 return *m_builder;
336 //////////////////////////////////////////////////////////////////////////////
337 // Mode: Input, Type: tar
339 class TarInput : public InputBase
341 auto_ptr<Restore> m_restore;
342 string m_tarpath;
343 vector<string> m_dbnames;
345 public:
346 void SetFilename(const std::string &name)
348 m_tarpath = name;
349 if( name == "-" )
350 throw runtime_error("Cannot use stdin as tar source file, sorry.");
353 void AddDB(const std::string &dbname)
355 m_dbnames.push_back(dbname);
358 Builder& GetBuilder(Barry::Probe *probe, IConverter &ic)
360 m_restore.reset( new Restore(m_tarpath, true) );
361 for( size_t i = 0; i < m_dbnames.size(); i++ ) {
362 m_restore->AddDB(m_dbnames[i]);
365 return *m_restore;
369 //////////////////////////////////////////////////////////////////////////////
370 // Mode: Input, Type: boost
372 #ifdef __BARRY_BOOST_MODE__
373 class BoostInput : public InputBase
375 auto_ptr<BoostBuilder> m_builder;
376 string m_filename;
378 public:
379 BoostInput()
380 : m_filename("-") // default to stdin/stdout
384 void SetFilename(const std::string &name)
386 m_filename = name;
389 Builder& GetBuilder(Barry::Probe *probe, IConverter &ic)
391 if( m_filename == "-" ) {
392 // use stdin
393 m_builder.reset( new BoostBuilder(cin) );
395 else {
396 m_builder.reset( new BoostBuilder(m_filename) );
398 return *m_builder;
402 #endif
404 //////////////////////////////////////////////////////////////////////////////
405 // Mode: Input, Type: ldif
407 class LdifInput : public InputBase
409 auto_ptr<Builder> m_builder;
410 string m_filename;
412 public:
413 LdifInput()
414 : m_filename("-")
418 void SetFilename(const std::string &name)
420 m_filename = name;
423 Builder& GetBuilder(Barry::Probe *probe, IConverter &ic)
425 if( m_filename == "-" ) {
426 // use stdin
427 m_builder.reset(
428 new RecordBuilder<Contact, LdifStore>(
429 new LdifStore(cin)) );
431 else {
432 m_builder.reset(
433 new RecordBuilder<Contact, LdifStore>(
434 new LdifStore(m_filename)) );
436 return *m_builder;
442 //////////////////////////////////////////////////////////////////////////////
443 // Mode: Input, Type: mime
445 class MimeInput : public InputBase
447 auto_ptr<MimeBuilder> m_builder;
448 string m_filename;
450 public:
451 MimeInput()
452 : m_filename("-")
456 void SetFilename(const std::string &name)
458 m_filename = name;
461 Builder& GetBuilder(Barry::Probe *probe, IConverter &ic)
463 if( m_filename == "-" ) {
464 // use stdin
465 m_builder.reset( new MimeBuilder(cin) );
467 else {
468 m_builder.reset( new MimeBuilder(m_filename) );
470 return *m_builder;
475 //////////////////////////////////////////////////////////////////////////////
476 // Base class for Output Mode
478 class OutputBase : public virtual ModeBase
480 public:
481 virtual Parser& GetParser(Barry::Probe *probe, IConverter &ic) = 0;
484 class DeviceOutputBase : public DeviceBase, public OutputBase
488 //////////////////////////////////////////////////////////////////////////////
489 // Mode: Output, Type: device
491 class DeviceOutput : public DeviceOutputBase
493 auto_ptr<Controller> m_con;
494 auto_ptr<Mode::Desktop> m_desktop;
495 auto_ptr<DeviceParser> m_parser;
496 DeviceParser::WriteMode m_mode;
498 public:
499 DeviceOutput()
500 : m_mode(DeviceParser::DROP_RECORD)
504 void SetWriteMode(DeviceParser::WriteMode mode)
506 m_mode = mode;
509 Parser& GetParser(Barry::Probe *probe, IConverter &ic)
511 if( m_mode == DeviceParser::DROP_RECORD ) {
512 cerr << "Warning: the -w switch was not specified: no data will be written to the device." << endl;
515 int i = probe->FindActive(m_pin);
516 if( i == -1 ) {
517 if( m_pin.Valid() )
518 throw runtime_error("PIN not found: " + m_pin.Str());
519 else
520 throw runtime_error("PIN not specified, and more than one device exists.");
523 if( IsPinUsed(probe->Get(i).m_pin) ) {
524 throw runtime_error("It seems you are trying to use the same device for multiple input or outputs.");
526 m_device_pins.push_back(probe->Get(i).m_pin);
528 m_con.reset( new Controller(probe->Get(i)) );
529 m_desktop.reset( new Mode::Desktop(*m_con, ic) );
530 m_desktop->Open(m_password.c_str());
531 m_parser.reset( new DeviceParser(*m_desktop, m_mode) );
533 return *m_parser;
537 //////////////////////////////////////////////////////////////////////////////
538 // Mode: Output, Type: tar
540 class TarOutput : public OutputBase
542 auto_ptr<Backup> m_backup;
543 string m_tarpath;
545 public:
546 void SetFilename(const std::string &name)
548 m_tarpath = name;
549 if( name == "-" )
550 throw runtime_error("Cannot use stdout as tar backup file, sorry.");
553 Parser& GetParser(Barry::Probe *probe, IConverter &ic)
555 m_backup.reset( new Backup(m_tarpath) );
556 return *m_backup;
560 //////////////////////////////////////////////////////////////////////////////
561 // Mode: Output, Type: boost
563 #ifdef __BARRY_BOOST_MODE__
564 class BoostOutput : public OutputBase
566 auto_ptr<BoostParser> m_parser;
567 string m_filename;
569 public:
570 void SetFilename(const std::string &name)
572 m_filename = name;
575 Parser& GetParser(Barry::Probe *probe, IConverter &ic)
577 if( !m_filename.size() )
578 throw runtime_error("Boost output requires a specific output file (-f switch)");
580 if( m_filename == "-" ) {
581 // use stdout
582 m_parser.reset( new BoostParser(cout) );
584 else {
585 m_parser.reset( new BoostParser(m_filename) );
587 return *m_parser;
591 #endif
593 //////////////////////////////////////////////////////////////////////////////
594 // Mode: Output, Type: ldif
596 class LdifOutput : public OutputBase
598 auto_ptr<Parser> m_parser;
599 string m_filename;
600 string m_baseDN;
601 string m_dnattr;
603 public:
604 LdifOutput()
605 : m_filename("-")
609 void SetFilename(const std::string &name)
611 m_filename = name;
614 void SetDN(const std::string &dn)
616 m_baseDN = dn;
619 void SetAttribute(const std::string &attr)
621 m_dnattr = attr;
624 Parser& GetParser(Barry::Probe *probe, IConverter &ic)
626 if( m_filename == "-" ) {
627 // use stdin
628 m_parser.reset(
629 new RecordParser<Contact, LdifStore>(
630 new LdifStore(cout, m_baseDN,
631 m_dnattr)) );
633 else {
634 m_parser.reset(
635 new RecordParser<Contact, LdifStore>(
636 new LdifStore(m_filename, m_baseDN,
637 m_dnattr)) );
639 return *m_parser;
643 //////////////////////////////////////////////////////////////////////////////
644 // Mode: Output, Type: mime
646 class MimeStore : public AllRecordStore
648 std::ostream &m_os;
650 public:
651 MimeStore(std::ostream &os)
652 : m_os(os)
656 #undef HANDLE_PARSER
657 #define HANDLE_PARSER(tname) \
658 void operator() (const Barry::tname &r) \
660 MimeDump<tname>::Dump(m_os, r); \
663 ALL_KNOWN_PARSER_TYPES
666 class MimeOutput : public OutputBase
668 auto_ptr<std::ofstream> m_file;
669 auto_ptr<Parser> m_parser;
670 std::string m_filename;
672 public:
673 MimeOutput()
674 : m_filename("-") // default to stdout
678 void SetFilename(const std::string &name)
680 m_filename = name;
683 Parser& GetParser(Barry::Probe *probe, IConverter &ic)
685 if( m_filename == "-" ) {
686 m_parser.reset( new AllRecordParser(cout,
687 new HexDumpParser(cout),
688 new MimeStore(cout)) );
690 else {
691 m_file.reset( new std::ofstream(m_filename.c_str()) );
692 m_parser.reset( new AllRecordParser(*m_file,
693 new HexDumpParser(*m_file),
694 new MimeStore(*m_file)) );
696 return *m_parser;
700 //////////////////////////////////////////////////////////////////////////////
701 // Mode: Output, Type: dump
703 class DumpOutput : public OutputBase
705 auto_ptr<Parser> m_parser;
706 bool m_hex_only;
708 public:
709 DumpOutput()
710 : m_hex_only(false)
714 void SetHexDump()
716 m_hex_only = true;
719 Parser& GetParser(Barry::Probe *probe, IConverter &ic)
721 if( m_hex_only ) {
722 m_parser.reset( new HexDumpParser(cout) );
724 else {
725 m_parser.reset( new AllRecordParser(cout,
726 new HexDumpParser(cout),
727 new AllRecordDumpStore(cout)) );
729 return *m_parser;
733 //////////////////////////////////////////////////////////////////////////////
734 // Mode: Output, Type: sha1
736 class Sha1Output : public OutputBase
738 auto_ptr<Parser> m_parser;
739 bool m_include_ids;
741 public:
742 Sha1Output()
743 : m_include_ids(false)
747 void IncludeIDs()
749 m_include_ids = true;
752 Parser& GetParser(Barry::Probe *probe, IConverter &ic)
754 m_parser.reset( new ChecksumParser(m_include_ids) );
755 return *m_parser;
759 //////////////////////////////////////////////////////////////////////////////
760 // Mode: Output, Type: cstore
762 class ContentStoreOutput : public OutputBase
764 auto_ptr<Parser> m_parser;
765 bool m_list_only;
766 vector<string> m_filenames;
768 public:
769 ContentStoreOutput()
770 : m_list_only(false)
774 void SetFilename(const std::string &name)
776 m_filenames.push_back(name);
779 void SetList()
781 m_list_only = true;
784 Parser& GetParser(Barry::Probe *probe, IConverter &ic)
786 m_parser.reset( new RecordParser<ContentStore, ContentStoreOutput>(*this) );
787 return *m_parser;
790 // storage operator
791 void operator() (const ContentStore &rec)
793 if( m_list_only ) {
794 cout << rec.Filename;
795 if( rec.FolderFlag ) {
796 cout << " (folder)";
798 cout << endl;
800 else {
801 // check if this record matches one of the filenames
802 // in the list
803 vector<string>::iterator i = find(m_filenames.begin(),
804 m_filenames.end(), rec.Filename);
805 if( i != m_filenames.end() ) {
806 SaveFile(rec);
811 void SaveFile(const ContentStore &rec)
813 size_t slash = rec.Filename.rfind('/');
814 string filename;
815 if( slash == string::npos )
816 filename = rec.Filename;
817 else
818 filename = rec.Filename.substr(slash + 1);
820 // modify filename until we find one that doesn't
821 // already exist
822 string freshname = filename;
823 int count = 0;
824 while( access(freshname.c_str(), F_OK) == 0 ) {
825 ostringstream oss;
826 oss << filename << count++;
827 freshname = oss.str();
830 // open and write!
831 cout << "Saving: " << rec.Filename
832 << " as " << freshname << endl;
833 ofstream ofs(freshname.c_str());
834 ofs << rec.FileContent;
835 ofs.flush();
836 if( !ofs ) {
837 cout << "Error during write!" << endl;
844 //////////////////////////////////////////////////////////////////////////////
845 // Main application class
847 class App
849 public:
850 typedef shared_ptr<OutputBase> OutputPtr;
851 typedef vector<OutputPtr> OutputsType;
853 private:
854 auto_ptr<InputBase> Input;
855 OutputsType Outputs;
857 public:
859 bool ParseInMode(const string &mode);
860 bool ParseOutMode(const string &mode);
861 DeviceParser::WriteMode ParseWriteMode(const std::string &mode);
862 // returns true if any of the items in Outputs needs a probe
863 bool OutputsProbeNeeded();
864 int main(int argc, char *argv[]);
867 bool App::ParseInMode(const string &mode)
869 if( mode == "device" ) {
870 Input.reset( new DeviceInput );
871 return true;
873 else if( mode == "tar" ) {
874 Input.reset( new TarInput );
875 return true;
877 #ifdef __BARRY_BOOST_MODE__
878 else if( mode == "boost" ) {
879 Input.reset( new BoostInput );
880 return true;
882 #endif
883 else if( mode == "ldif" ) {
884 Input.reset( new LdifInput );
885 return true;
887 else if( mode == "mime" ) {
888 Input.reset( new MimeInput );
889 return true;
891 else
892 return false;
895 bool App::ParseOutMode(const string &mode)
897 if( mode == "device" ) {
898 Outputs.push_back( OutputPtr(new DeviceOutput) );
899 return true;
901 else if( mode == "tar" ) {
902 Outputs.push_back( OutputPtr(new TarOutput) );
903 return true;
905 #ifdef __BARRY_BOOST_MODE__
906 else if( mode == "boost" ) {
907 Outputs.push_back( OutputPtr(new BoostOutput) );
908 return true;
910 #endif
911 else if( mode == "ldif" ) {
912 Outputs.push_back( OutputPtr(new LdifOutput) );
913 return true;
915 else if( mode == "mime" ) {
916 Outputs.push_back( OutputPtr(new MimeOutput) );
917 return true;
919 else if( mode == "dump" ) {
920 Outputs.push_back( OutputPtr(new DumpOutput) );
921 return true;
923 else if( mode == "sha1" ) {
924 Outputs.push_back( OutputPtr(new Sha1Output) );
925 return true;
927 else if( mode == "cstore" ) {
928 Outputs.push_back( OutputPtr(new ContentStoreOutput) );
929 return true;
931 else
932 return false;
935 DeviceParser::WriteMode App::ParseWriteMode(const std::string &mode)
937 if( mode == "erase" )
938 return DeviceParser::ERASE_ALL_WRITE_ALL;
939 else if( mode == "overwrite" )
940 return DeviceParser::INDIVIDUAL_OVERWRITE;
941 else if( mode == "addonly" )
942 return DeviceParser::ADD_BUT_NO_OVERWRITE;
943 else if( mode == "addnew" )
944 return DeviceParser::ADD_WITH_NEW_ID;
945 else
946 throw runtime_error("Unknown device output mode. Must be one of: erase, overwrite, addonly, addnew");
949 bool App::OutputsProbeNeeded()
951 for( OutputsType::iterator i = Outputs.begin();
952 i != Outputs.end();
953 ++i )
955 if( (*i)->ProbeNeeded() )
956 return true;
958 return false;
961 int App::main(int argc, char *argv[])
963 bool verbose = false;
964 bool show_parsers = false, show_fields = false;
965 string iconvCharset;
967 // process command line options
968 ModeBase *current = 0;
969 for(;;) {
970 int cmd = getopt(argc, argv, "hi:o:nvI:f:p:P:d:c:C:ASw:tl");
971 if( cmd == -1 )
972 break;
974 // first option must be in or out, or a global option
975 if( !current ) {
976 if( cmd != 'i' && \
977 cmd != 'o' && \
978 cmd != 'S' && \
979 cmd != 'I' && \
980 cmd != 'v' )
982 Usage();
983 return 1;
987 switch( cmd )
989 case 'i': // set input mode
990 // must be first time used
991 if( Input.get() || !ParseInMode(optarg) ) {
992 Usage();
993 return 1;
995 current = Input.get();
996 break;
998 case 'o': // set output mode
999 // can be used multiple times
1000 if( !ParseOutMode(optarg) ) {
1001 Usage();
1002 return 1;
1004 current = Outputs[Outputs.size() - 1].get();
1005 break;
1008 case 'c': // set ldif dn
1009 current->SetDN(optarg);
1010 break;
1012 case 'C': // set ldif attr
1013 current->SetAttribute(optarg);
1014 break;
1016 case 'd': // database name
1017 current->AddDB(optarg);
1018 break;
1020 case 'f': // filename
1021 current->SetFilename(optarg);
1022 break;
1024 case 'p': // device PIN
1025 current->SetPIN(optarg);
1026 break;
1028 case 'P': // password
1029 current->SetPassword(optarg);
1030 break;
1032 case 'w': // device write mode
1033 current->SetWriteMode(ParseWriteMode(optarg));
1034 break;
1036 case 'A': // add all DB names to the device builder
1037 current->AddAllDBs();
1038 break;
1040 case 't': // include type and IDs in sha1 mode
1041 current->IncludeIDs();
1042 break;
1044 case 'l': // list only
1045 current->SetList();
1046 break;
1048 case 'S': // show parsers and builders
1049 if( show_parsers )
1050 show_fields = true;
1051 else
1052 show_parsers = true;
1053 break;
1055 case 'I': // international charset (iconv)
1056 iconvCharset = optarg;
1057 break;
1059 case 'n': // use null hex dump parser only
1060 current->SetHexDump();
1061 break;
1063 case 'v': // verbose
1064 verbose = true;
1065 break;
1067 case 'h': // help
1068 default:
1069 Usage();
1070 return 0;
1074 if( show_parsers ) {
1075 ShowParsers(show_fields, true);
1076 ShowBuilders();
1077 return 0;
1080 if( !Input.get() || !Outputs.size() ) {
1081 Usage();
1082 return 0;
1085 // Initialize the Barry library
1086 Barry::Init(verbose);
1088 // Create an IConverter object if needed
1089 auto_ptr<IConverter> ic;
1090 if( iconvCharset.size() ) {
1091 ic.reset( new IConverter(iconvCharset.c_str(), true) );
1094 // Probe for devices only if needed
1095 auto_ptr<Probe> probe;
1096 if( Input->ProbeNeeded() || OutputsProbeNeeded() ) {
1097 // Probe for available devices
1098 probe.reset( new Probe );
1101 // Setup the input first (builder)
1102 Builder &builder = Input->GetBuilder(probe.get(), *ic);
1104 // Setup a TeeParser with all Outputs
1105 TeeParser tee;
1106 for( OutputsType::iterator i = Outputs.begin(); i != Outputs.end(); ++i ) {
1107 Parser &parser = (*i)->GetParser(probe.get(), *ic);
1108 tee.Add(parser);
1111 // Setup the pipe
1112 Pipe pipe(builder);
1113 pipe.PumpFile(tee, ic.get());
1115 return 0;
1118 int main(int argc, char *argv[])
1120 try {
1121 App app;
1122 return app.main(argc, argv);
1124 catch( std::exception &e ) {
1125 cerr << "Exception: " << e.what() << endl;
1126 return 1;