lib: moved mimedump.h from tools/ into the library (mimeio.h)
[barry/progweb.git] / tools / bio.cc
blob8cefa06a82c5375bac0d369019d6d7a975c601f2
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"
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"
107 << "\n"
108 << " Options to use for 'tar' backup type:\n"
109 << " -d db Name of input database. Can be used multiple times.\n"
110 << " Not available in output mode. Note that by default,\n"
111 << " all databases in the backup are selected, when reading,\n"
112 << " unless at least one -d is specified.\n"
113 << " -D db Name of input database to skip. If no -d options are used,\n"
114 << " then all databases are automatically selected. Using -D\n"
115 << " allows a filtering selection. If -d and -D are used for\n"
116 << " the same database, -D takes precedence.\n"
117 << " -f file Tar backup file to read from or write to\n"
118 #ifdef __BARRY_BOOST_MODE__
119 << "\n"
120 << " Options to use for 'boost' type:\n"
121 << " -f file Boost serialization filename to read from or write to\n"
122 << " Can use - to specify stdin/stdout\n"
123 #endif
124 << "\n"
125 << " Options to use for 'ldif' type:\n"
126 << " -c dn Convert address book database to LDIF format, using the\n"
127 << " specified baseDN\n"
128 << " -C dnattr LDIF attribute name to use when building the FQDN\n"
129 << " Defaults to 'cn'\n"
131 LDIF options?
133 << " -L List Contact field names\n"
134 << " -m Map LDIF name to Contact field / Unmap LDIF name\n"
135 << " Map: ldif,read,write - maps ldif to read/write Contact fields\n"
136 << " Unmap: ldif name alone\n"
137 << " -M List current LDIF mapping\n"
139 << "\n"
140 << " Options to use for 'mime' type:\n"
141 << " -f file Filename to read from or write to. Use - to explicitly\n"
142 << " specify stdin/stdout, which is default.\n"
143 << "\n"
144 << " Options to use for 'dump' to stdout output type:\n"
145 << " -n Use hex dump parser on all databases.\n"
146 << "\n"
147 << " Options to use for 'sha1' sum stdout output type:\n"
148 << " -t Include DB Name, Type, and Unique record IDs in the checksums\n"
149 << "\n"
150 << " Options to use for 'cstore' output type:\n"
151 << " -l List filenames only\n"
152 << " -f file Filename from the above list, including path.\n"
153 << " If found, the file will be written to the current\n"
154 << " directory, using the base filename from the device.\n"
155 << "\n"
156 << " Standalone options:\n"
157 << " -h This help\n"
158 << " -I cs International charset for string conversions\n"
159 << " Valid values here are available with 'iconv --list'\n"
160 << " -S Show list of supported database parsers and builders.\n"
161 << " Use twice to show field names as well.\n"
162 << " -v Dump protocol data during operation\n"
163 << "\n"
164 << endl;
167 class ModeBase
169 public:
170 virtual ~ModeBase() {}
172 virtual bool ProbeNeeded() const { return false; }
174 virtual void SetFilename(const std::string &name)
176 throw runtime_error("Filename not applicable for this mode");
179 virtual void AddDB(const std::string &dbname)
181 throw runtime_error("DB not applicable for this mode");
184 virtual void AddSkipDB(const std::string &dbname)
186 throw runtime_error("DB skipping not applicable for this mode");
189 virtual void AddAllDBs()
191 throw runtime_error("DBs not applicable for this mode");
194 virtual void SetPIN(const std::string &pin)
196 throw runtime_error("PIN not applicable for this mode");
199 virtual void SetPassword(const std::string &password)
201 throw runtime_error("Password not applicable for this mode");
204 virtual void SetWriteMode(DeviceParser::WriteMode mode)
206 throw runtime_error("Device write behaviour not applicable for this mode");
209 virtual void SetDN(const std::string &dn)
211 throw runtime_error("DN not applicable for this mode");
214 virtual void SetAttribute(const std::string &attr)
216 throw runtime_error("Attribute not applicable for this mode");
219 virtual void SetHexDump()
221 throw runtime_error("No hex dump option in this mode");
224 virtual void IncludeIDs()
226 throw runtime_error("Including record IDs in the SHA1 sum is not applicable in this mode");
229 virtual void SetList()
231 throw runtime_error("List option not applicable for this mode");
235 class DeviceBase : public virtual ModeBase
237 protected:
238 Barry::Pin m_pin;
239 std::string m_password;
241 public:
242 bool ProbeNeeded() const { return true; }
244 void SetPIN(const std::string &pin)
246 istringstream iss(pin);
247 iss >> m_pin;
248 if( !m_pin.Valid() )
249 throw runtime_error("Invalid PIN: " + pin);
252 void SetPassword(const std::string &password)
254 m_password = password;
258 //////////////////////////////////////////////////////////////////////////////
259 // Base class for Input Mode
261 class InputBase : public virtual ModeBase
263 public:
264 virtual Builder& GetBuilder(Barry::Probe *probe, IConverter &ic) = 0;
267 class DeviceInputBase : public DeviceBase, public InputBase
271 //////////////////////////////////////////////////////////////////////////////
272 // Mode: Input, Type: device
274 class DeviceInput : public DeviceInputBase
276 auto_ptr<Controller> m_con;
277 auto_ptr<Mode::Desktop> m_desktop;
278 auto_ptr<DeviceBuilder> m_builder;
279 vector<string> m_dbnames;
280 bool m_add_all;
282 public:
283 DeviceInput()
284 : m_add_all(false)
288 void AddDB(const std::string &dbname)
290 m_dbnames.push_back(dbname);
293 void AddAllDBs()
295 m_add_all = true;
298 Builder& GetBuilder(Barry::Probe *probe, IConverter &ic)
300 int i = probe->FindActive(m_pin);
301 if( i == -1 ) {
302 if( m_pin.Valid() )
303 throw runtime_error("PIN not found: " + m_pin.Str());
304 else
305 throw runtime_error("PIN not specified, and more than one device exists.");
308 if( IsPinUsed(probe->Get(i).m_pin) ) {
309 throw runtime_error("It seems you are trying to use the same device for multiple input or outputs.");
311 m_device_pins.push_back(probe->Get(i).m_pin);
313 m_con.reset( new Controller(probe->Get(i)) );
314 m_desktop.reset( new Mode::Desktop(*m_con, ic) );
315 m_desktop->Open(m_password.c_str());
316 m_builder.reset( new DeviceBuilder(*m_desktop) );
318 if( m_add_all ) {
319 m_builder->Add(m_desktop->GetDBDB());
321 else {
322 for( size_t i = 0; i < m_dbnames.size(); i++ ) {
323 if( !m_builder->Add(m_dbnames[i]) )
324 throw runtime_error("Database not found: " + m_dbnames[i]);
328 return *m_builder;
332 //////////////////////////////////////////////////////////////////////////////
333 // Mode: Input, Type: tar
335 class TarInput : public InputBase
337 auto_ptr<Restore> m_restore;
338 string m_tarpath;
339 vector<string> m_dbnames, m_dbskips;
341 public:
342 void SetFilename(const std::string &name)
344 m_tarpath = name;
345 if( name == "-" )
346 throw runtime_error("Cannot use stdin as tar source file, sorry.");
349 void AddDB(const std::string &dbname)
351 m_dbnames.push_back(dbname);
354 void AddSkipDB(const std::string &dbname)
356 m_dbskips.push_back(dbname);
359 Builder& GetBuilder(Barry::Probe *probe, IConverter &ic)
361 m_restore.reset( new Restore(m_tarpath, true) );
362 for( size_t i = 0; i < m_dbnames.size(); i++ ) {
363 m_restore->AddDB(m_dbnames[i]);
365 for( size_t i = 0; i < m_dbskips.size(); i++ ) {
366 m_restore->AddSkipDB(m_dbskips[i]);
369 return *m_restore;
373 //////////////////////////////////////////////////////////////////////////////
374 // Mode: Input, Type: boost
376 #ifdef __BARRY_BOOST_MODE__
377 class BoostInput : public InputBase
379 auto_ptr<BoostBuilder> m_builder;
380 string m_filename;
382 public:
383 BoostInput()
384 : m_filename("-") // default to stdin/stdout
388 void SetFilename(const std::string &name)
390 m_filename = name;
393 Builder& GetBuilder(Barry::Probe *probe, IConverter &ic)
395 if( m_filename == "-" ) {
396 // use stdin
397 m_builder.reset( new BoostBuilder(cin) );
399 else {
400 m_builder.reset( new BoostBuilder(m_filename) );
402 return *m_builder;
406 #endif
408 //////////////////////////////////////////////////////////////////////////////
409 // Mode: Input, Type: ldif
411 class LdifInput : public InputBase
413 auto_ptr<Builder> m_builder;
414 string m_filename;
416 public:
417 LdifInput()
418 : m_filename("-")
422 void SetFilename(const std::string &name)
424 m_filename = name;
427 Builder& GetBuilder(Barry::Probe *probe, IConverter &ic)
429 if( m_filename == "-" ) {
430 // use stdin
431 m_builder.reset(
432 new RecordBuilder<Contact, LdifStore>(
433 new LdifStore(cin)) );
435 else {
436 m_builder.reset(
437 new RecordBuilder<Contact, LdifStore>(
438 new LdifStore(m_filename)) );
440 return *m_builder;
446 //////////////////////////////////////////////////////////////////////////////
447 // Mode: Input, Type: mime
449 class MimeInput : public InputBase
451 auto_ptr<MimeBuilder> m_builder;
452 string m_filename;
454 public:
455 MimeInput()
456 : m_filename("-")
460 void SetFilename(const std::string &name)
462 m_filename = name;
465 Builder& GetBuilder(Barry::Probe *probe, IConverter &ic)
467 if( m_filename == "-" ) {
468 // use stdin
469 m_builder.reset( new MimeBuilder(cin) );
471 else {
472 m_builder.reset( new MimeBuilder(m_filename) );
474 return *m_builder;
479 //////////////////////////////////////////////////////////////////////////////
480 // Base class for Output Mode
482 class OutputBase : public virtual ModeBase
484 public:
485 virtual Parser& GetParser(Barry::Probe *probe, IConverter &ic) = 0;
488 class DeviceOutputBase : public DeviceBase, public OutputBase
492 //////////////////////////////////////////////////////////////////////////////
493 // Mode: Output, Type: device
495 class DeviceOutput : public DeviceOutputBase
497 auto_ptr<Controller> m_con;
498 auto_ptr<Mode::Desktop> m_desktop;
499 auto_ptr<DeviceParser> m_parser;
500 DeviceParser::WriteMode m_mode;
502 public:
503 DeviceOutput()
504 : m_mode(DeviceParser::DROP_RECORD)
508 void SetWriteMode(DeviceParser::WriteMode mode)
510 m_mode = mode;
513 Parser& GetParser(Barry::Probe *probe, IConverter &ic)
515 if( m_mode == DeviceParser::DROP_RECORD ) {
516 cerr << "Warning: the -w switch was not specified: no data will be written to the device." << endl;
519 int i = probe->FindActive(m_pin);
520 if( i == -1 ) {
521 if( m_pin.Valid() )
522 throw runtime_error("PIN not found: " + m_pin.Str());
523 else
524 throw runtime_error("PIN not specified, and more than one device exists.");
527 if( IsPinUsed(probe->Get(i).m_pin) ) {
528 throw runtime_error("It seems you are trying to use the same device for multiple input or outputs.");
530 m_device_pins.push_back(probe->Get(i).m_pin);
532 m_con.reset( new Controller(probe->Get(i)) );
533 m_desktop.reset( new Mode::Desktop(*m_con, ic) );
534 m_desktop->Open(m_password.c_str());
535 m_parser.reset( new DeviceParser(*m_desktop, m_mode) );
537 return *m_parser;
541 //////////////////////////////////////////////////////////////////////////////
542 // Mode: Output, Type: tar
544 class TarOutput : public OutputBase
546 auto_ptr<Backup> m_backup;
547 string m_tarpath;
549 public:
550 void SetFilename(const std::string &name)
552 m_tarpath = name;
553 if( name == "-" )
554 throw runtime_error("Cannot use stdout as tar backup file, sorry.");
557 Parser& GetParser(Barry::Probe *probe, IConverter &ic)
559 m_backup.reset( new Backup(m_tarpath) );
560 return *m_backup;
564 //////////////////////////////////////////////////////////////////////////////
565 // Mode: Output, Type: boost
567 #ifdef __BARRY_BOOST_MODE__
568 class BoostOutput : public OutputBase
570 auto_ptr<BoostParser> m_parser;
571 string m_filename;
573 public:
574 void SetFilename(const std::string &name)
576 m_filename = name;
579 Parser& GetParser(Barry::Probe *probe, IConverter &ic)
581 if( !m_filename.size() )
582 throw runtime_error("Boost output requires a specific output file (-f switch)");
584 if( m_filename == "-" ) {
585 // use stdout
586 m_parser.reset( new BoostParser(cout) );
588 else {
589 m_parser.reset( new BoostParser(m_filename) );
591 return *m_parser;
595 #endif
597 //////////////////////////////////////////////////////////////////////////////
598 // Mode: Output, Type: ldif
600 class LdifOutput : public OutputBase
602 auto_ptr<Parser> m_parser;
603 string m_filename;
604 string m_baseDN;
605 string m_dnattr;
607 public:
608 LdifOutput()
609 : m_filename("-")
613 void SetFilename(const std::string &name)
615 m_filename = name;
618 void SetDN(const std::string &dn)
620 m_baseDN = dn;
623 void SetAttribute(const std::string &attr)
625 m_dnattr = attr;
628 Parser& GetParser(Barry::Probe *probe, IConverter &ic)
630 if( m_filename == "-" ) {
631 // use stdin
632 m_parser.reset(
633 new RecordParser<Contact, LdifStore>(
634 new LdifStore(cout, m_baseDN,
635 m_dnattr)) );
637 else {
638 m_parser.reset(
639 new RecordParser<Contact, LdifStore>(
640 new LdifStore(m_filename, m_baseDN,
641 m_dnattr)) );
643 return *m_parser;
647 //////////////////////////////////////////////////////////////////////////////
648 // Mode: Output, Type: mime
650 class MimeStore : public AllRecordStore
652 std::ostream &m_os;
654 public:
655 MimeStore(std::ostream &os)
656 : m_os(os)
660 #undef HANDLE_PARSER
661 #define HANDLE_PARSER(tname) \
662 void operator() (const Barry::tname &r) \
664 MimeDump<tname>::Dump(m_os, r); \
667 ALL_KNOWN_PARSER_TYPES
670 class MimeOutput : public OutputBase
672 auto_ptr<std::ofstream> m_file;
673 auto_ptr<Parser> m_parser;
674 std::string m_filename;
676 public:
677 MimeOutput()
678 : m_filename("-") // default to stdout
682 void SetFilename(const std::string &name)
684 m_filename = name;
687 Parser& GetParser(Barry::Probe *probe, IConverter &ic)
689 if( m_filename == "-" ) {
690 m_parser.reset( new AllRecordParser(cout,
691 new HexDumpParser(cout),
692 new MimeStore(cout)) );
694 else {
695 m_file.reset( new std::ofstream(m_filename.c_str()) );
696 m_parser.reset( new AllRecordParser(*m_file,
697 new HexDumpParser(*m_file),
698 new MimeStore(*m_file)) );
700 return *m_parser;
704 //////////////////////////////////////////////////////////////////////////////
705 // Mode: Output, Type: dump
707 class DumpOutput : public OutputBase
709 auto_ptr<Parser> m_parser;
710 bool m_hex_only;
712 public:
713 DumpOutput()
714 : m_hex_only(false)
718 void SetHexDump()
720 m_hex_only = true;
723 Parser& GetParser(Barry::Probe *probe, IConverter &ic)
725 if( m_hex_only ) {
726 m_parser.reset( new HexDumpParser(cout) );
728 else {
729 m_parser.reset( new AllRecordParser(cout,
730 new HexDumpParser(cout),
731 new AllRecordDumpStore(cout)) );
733 return *m_parser;
737 //////////////////////////////////////////////////////////////////////////////
738 // Mode: Output, Type: sha1
740 class Sha1Output : public OutputBase
742 auto_ptr<Parser> m_parser;
743 bool m_include_ids;
745 public:
746 Sha1Output()
747 : m_include_ids(false)
751 void IncludeIDs()
753 m_include_ids = true;
756 Parser& GetParser(Barry::Probe *probe, IConverter &ic)
758 m_parser.reset( new ChecksumParser(m_include_ids) );
759 return *m_parser;
763 //////////////////////////////////////////////////////////////////////////////
764 // Mode: Output, Type: cstore
766 class ContentStoreOutput : public OutputBase
768 auto_ptr<Parser> m_parser;
769 bool m_list_only;
770 vector<string> m_filenames;
772 public:
773 ContentStoreOutput()
774 : m_list_only(false)
778 void SetFilename(const std::string &name)
780 m_filenames.push_back(name);
783 void SetList()
785 m_list_only = true;
788 Parser& GetParser(Barry::Probe *probe, IConverter &ic)
790 m_parser.reset( new RecordParser<ContentStore, ContentStoreOutput>(*this) );
791 return *m_parser;
794 // storage operator
795 void operator() (const ContentStore &rec)
797 if( m_list_only ) {
798 cout << rec.Filename;
799 if( rec.FolderFlag ) {
800 cout << " (folder)";
802 cout << endl;
804 else {
805 // check if this record matches one of the filenames
806 // in the list
807 vector<string>::iterator i = find(m_filenames.begin(),
808 m_filenames.end(), rec.Filename);
809 if( i != m_filenames.end() ) {
810 SaveFile(rec);
815 void SaveFile(const ContentStore &rec)
817 size_t slash = rec.Filename.rfind('/');
818 string filename;
819 if( slash == string::npos )
820 filename = rec.Filename;
821 else
822 filename = rec.Filename.substr(slash + 1);
824 // modify filename until we find one that doesn't
825 // already exist
826 string freshname = filename;
827 int count = 0;
828 while( access(freshname.c_str(), F_OK) == 0 ) {
829 ostringstream oss;
830 oss << filename << count++;
831 freshname = oss.str();
834 // open and write!
835 cout << "Saving: " << rec.Filename
836 << " as " << freshname << endl;
837 ofstream ofs(freshname.c_str());
838 ofs << rec.FileContent;
839 ofs.flush();
840 if( !ofs ) {
841 cout << "Error during write!" << endl;
848 //////////////////////////////////////////////////////////////////////////////
849 // Main application class
851 class App
853 public:
854 typedef shared_ptr<OutputBase> OutputPtr;
855 typedef vector<OutputPtr> OutputsType;
857 private:
858 auto_ptr<InputBase> Input;
859 OutputsType Outputs;
861 public:
863 bool ParseInMode(const string &mode);
864 bool ParseOutMode(const string &mode);
865 DeviceParser::WriteMode ParseWriteMode(const std::string &mode);
866 // returns true if any of the items in Outputs needs a probe
867 bool OutputsProbeNeeded();
868 int main(int argc, char *argv[]);
871 bool App::ParseInMode(const string &mode)
873 if( mode == "device" ) {
874 Input.reset( new DeviceInput );
875 return true;
877 else if( mode == "tar" ) {
878 Input.reset( new TarInput );
879 return true;
881 #ifdef __BARRY_BOOST_MODE__
882 else if( mode == "boost" ) {
883 Input.reset( new BoostInput );
884 return true;
886 #endif
887 else if( mode == "ldif" ) {
888 Input.reset( new LdifInput );
889 return true;
891 else if( mode == "mime" ) {
892 Input.reset( new MimeInput );
893 return true;
895 else
896 return false;
899 bool App::ParseOutMode(const string &mode)
901 if( mode == "device" ) {
902 Outputs.push_back( OutputPtr(new DeviceOutput) );
903 return true;
905 else if( mode == "tar" ) {
906 Outputs.push_back( OutputPtr(new TarOutput) );
907 return true;
909 #ifdef __BARRY_BOOST_MODE__
910 else if( mode == "boost" ) {
911 Outputs.push_back( OutputPtr(new BoostOutput) );
912 return true;
914 #endif
915 else if( mode == "ldif" ) {
916 Outputs.push_back( OutputPtr(new LdifOutput) );
917 return true;
919 else if( mode == "mime" ) {
920 Outputs.push_back( OutputPtr(new MimeOutput) );
921 return true;
923 else if( mode == "dump" ) {
924 Outputs.push_back( OutputPtr(new DumpOutput) );
925 return true;
927 else if( mode == "sha1" ) {
928 Outputs.push_back( OutputPtr(new Sha1Output) );
929 return true;
931 else if( mode == "cstore" ) {
932 Outputs.push_back( OutputPtr(new ContentStoreOutput) );
933 return true;
935 else
936 return false;
939 DeviceParser::WriteMode App::ParseWriteMode(const std::string &mode)
941 if( mode == "erase" )
942 return DeviceParser::ERASE_ALL_WRITE_ALL;
943 else if( mode == "overwrite" )
944 return DeviceParser::INDIVIDUAL_OVERWRITE;
945 else if( mode == "addonly" )
946 return DeviceParser::ADD_BUT_NO_OVERWRITE;
947 else if( mode == "addnew" )
948 return DeviceParser::ADD_WITH_NEW_ID;
949 else
950 throw runtime_error("Unknown device output mode. Must be one of: erase, overwrite, addonly, addnew");
953 bool App::OutputsProbeNeeded()
955 for( OutputsType::iterator i = Outputs.begin();
956 i != Outputs.end();
957 ++i )
959 if( (*i)->ProbeNeeded() )
960 return true;
962 return false;
965 int App::main(int argc, char *argv[])
967 bool verbose = false;
968 bool show_parsers = false, show_fields = false;
969 string iconvCharset;
971 // process command line options
972 ModeBase *current = 0;
973 for(;;) {
974 int cmd = getopt(argc, argv, "hi:o:nvI:f:p:P:d:D:c:C:ASw:tl");
975 if( cmd == -1 )
976 break;
978 // first option must be in or out, or a global option
979 if( !current ) {
980 if( cmd != 'i' && \
981 cmd != 'o' && \
982 cmd != 'S' && \
983 cmd != 'I' && \
984 cmd != 'v' )
986 Usage();
987 return 1;
991 switch( cmd )
993 case 'i': // set input mode
994 // must be first time used
995 if( Input.get() || !ParseInMode(optarg) ) {
996 Usage();
997 return 1;
999 current = Input.get();
1000 break;
1002 case 'o': // set output mode
1003 // can be used multiple times
1004 if( !ParseOutMode(optarg) ) {
1005 Usage();
1006 return 1;
1008 current = Outputs[Outputs.size() - 1].get();
1009 break;
1012 case 'c': // set ldif dn
1013 current->SetDN(optarg);
1014 break;
1016 case 'C': // set ldif attr
1017 current->SetAttribute(optarg);
1018 break;
1020 case 'd': // database name
1021 current->AddDB(optarg);
1022 break;
1024 case 'D': // database name to skip
1025 current->AddSkipDB(optarg);
1026 break;
1028 case 'f': // filename
1029 current->SetFilename(optarg);
1030 break;
1032 case 'p': // device PIN
1033 current->SetPIN(optarg);
1034 break;
1036 case 'P': // password
1037 current->SetPassword(optarg);
1038 break;
1040 case 'w': // device write mode
1041 current->SetWriteMode(ParseWriteMode(optarg));
1042 break;
1044 case 'A': // add all DB names to the device builder
1045 current->AddAllDBs();
1046 break;
1048 case 't': // include type and IDs in sha1 mode
1049 current->IncludeIDs();
1050 break;
1052 case 'l': // list only
1053 current->SetList();
1054 break;
1056 case 'S': // show parsers and builders
1057 if( show_parsers )
1058 show_fields = true;
1059 else
1060 show_parsers = true;
1061 break;
1063 case 'I': // international charset (iconv)
1064 iconvCharset = optarg;
1065 break;
1067 case 'n': // use null hex dump parser only
1068 current->SetHexDump();
1069 break;
1071 case 'v': // verbose
1072 verbose = true;
1073 break;
1075 case 'h': // help
1076 default:
1077 Usage();
1078 return 0;
1082 if( show_parsers ) {
1083 ShowParsers(show_fields, true);
1084 ShowBuilders();
1085 return 0;
1088 if( !Input.get() || !Outputs.size() ) {
1089 Usage();
1090 return 0;
1093 // Initialize the Barry library
1094 Barry::Init(verbose);
1096 // Create an IConverter object if needed
1097 auto_ptr<IConverter> ic;
1098 if( iconvCharset.size() ) {
1099 ic.reset( new IConverter(iconvCharset.c_str(), true) );
1102 // Probe for devices only if needed
1103 auto_ptr<Probe> probe;
1104 if( Input->ProbeNeeded() || OutputsProbeNeeded() ) {
1105 // Probe for available devices
1106 probe.reset( new Probe );
1109 // Setup the input first (builder)
1110 Builder &builder = Input->GetBuilder(probe.get(), *ic);
1112 // Setup a TeeParser with all Outputs
1113 TeeParser tee;
1114 for( OutputsType::iterator i = Outputs.begin(); i != Outputs.end(); ++i ) {
1115 Parser &parser = (*i)->GetParser(probe.get(), *ic);
1116 tee.Add(parser);
1119 // Setup the pipe
1120 Pipe pipe(builder);
1121 pipe.PumpFile(tee, ic.get());
1123 return 0;
1126 int main(int argc, char *argv[])
1128 try {
1129 App app;
1130 return app.main(argc, argv);
1132 catch( std::exception &e ) {
1133 cerr << "Exception: " << e.what() << endl;
1134 return 1;