bio.cc

Go to the documentation of this file.
00001 ///
00002 /// \file       bio.cc
00003 ///             Barry Input / Output
00004 ///
00005 
00006 /*
00007     Copyright (C) 2010-2011, Net Direct Inc. (http://www.netdirect.ca/)
00008 
00009     This program is free software; you can redistribute it and/or modify
00010     it under the terms of the GNU General Public License as published by
00011     the Free Software Foundation; either version 2 of the License, or
00012     (at your option) any later version.
00013 
00014     This program is distributed in the hope that it will be useful,
00015     but WITHOUT ANY WARRANTY; without even the implied warranty of
00016     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
00017 
00018     See the GNU General Public License in the COPYING file at the
00019     root directory of this project for more details.
00020 */
00021 
00022 #include <barry/barry.h>
00023 #include <barry/barrysync.h>
00024 #include <barry/barrybackup.h>
00025 
00026 #include "mimedump.h"
00027 #include "brecsum.h"
00028 
00029 #include <iomanip>
00030 #include <iostream>
00031 #include <sstream>
00032 #include <fstream>
00033 #include <string>
00034 #include <vector>
00035 #include <algorithm>
00036 #include <stdexcept>
00037 #include <tr1/memory>
00038 #include <getopt.h>
00039 #include <strings.h>
00040 
00041 using namespace std;
00042 using namespace std::tr1;
00043 using namespace Barry;
00044 
00045 void Usage()
00046 {
00047    int major, minor;
00048    const char *Version = Barry::Version(major, minor);
00049 
00050    cerr
00051    << "bio - Barry Input / Output\n"
00052    << "      Copyright 2010-2011, Net Direct Inc. (http://www.netdirect.ca/)\n"
00053    << "      Using: " << Version << "\n"
00054    << "      Compiled "
00055 #ifdef __BARRY_BOOST_MODE__
00056    << "with"
00057 #else
00058    << "without"
00059 #endif
00060    << " Boost support\n"
00061    << "\n"
00062    << " Usage:  bio -i <type> [options...]   -o <type> [options...]\n"
00063    << "\n"
00064    << "   -i type   The input type (Builder) to use for producing records\n"
00065    << "             Can be one of: device, tar"
00066 #ifdef __BARRY_BOOST_MODE__
00067    << ", boost"
00068 #endif
00069    << ", ldif, mime\n"
00070    << "   -o type   The output type (Parser) to use for processing records.\n"
00071    << "             Multiple outputs are allowed, as long as they don't\n"
00072    << "             conflict (such as two outputs writing to the same file\n"
00073    << "             or device).\n"
00074    << "             Can be one of: device, tar"
00075 #ifdef __BARRY_BOOST_MODE__
00076    << ", boost"
00077 #endif
00078    << ", ldif, mime, dump, sha1, cstore\n"
00079    << "\n"
00080    << " Options to use for 'device' type:\n"
00081    << "   -d db     Name of input database. Can be used multiple times.\n"
00082    << "   -A        Add all available device databases, instead of specifying\n"
00083    << "             them manually via -d\n"
00084    << "   -p pin    PIN of device to talk to\n"
00085    << "             If only one device is plugged in, this flag is optional\n"
00086    << "   -P pass   Simplistic method to specify device password\n"
00087    << "   -w mode   Set write mode when using 'device' for output.  Must be\n"
00088    << "             specified, or will not write anything.\n"
00089    << "             Can be one of: erase, overwrite, addonly, addnew\n"
00090 /*
00091 // FIXME - modifiers not yet implemented
00092    << "\n"
00093    << " Input database modifiers:  (can be used multiple times for more than 1 record)\n"
00094    << "\n"
00095    << "   -r #      Record index number as seen in the -T state table.\n"
00096    << "             This overrides the default -d behaviour, and only\n"
00097    << "             downloads the one specified record, sending to stdout.\n"
00098    << "   -R #      Same as -r, but also clears the record's dirty flags.\n"
00099    << "   -D #      Record index number as seen in the -T state table,\n"
00100    << "             which indicates the record to delete.  Used with the -d\n"
00101    << "             command to specify the database.\n"
00102 */
00103    << "\n"
00104    << " Options to use for 'tar' backup type:\n"
00105    << "   -d db     Name of input database. Can be used multiple times.\n"
00106    << "             Not available in output mode.  Note that by default,\n"
00107    << "             all databases in the backup are selected, when reading,\n"
00108    << "             unless at least one -d is specified.\n"
00109    << "   -f file   Tar backup file to read from or write to\n"
00110 #ifdef __BARRY_BOOST_MODE__
00111    << "\n"
00112    << " Options to use for 'boost' type:\n"
00113    << "   -f file   Boost serialization filename to read from or write to\n"
00114    << "             Can use - to specify stdin/stdout\n"
00115 #endif
00116    << "\n"
00117    << " Options to use for 'ldif' type:\n"
00118    << "   -c dn     Convert address book database to LDIF format, using the\n"
00119    << "             specified baseDN\n"
00120    << "   -C dnattr LDIF attribute name to use when building the FQDN\n"
00121    << "             Defaults to 'cn'\n"
00122 /*
00123 LDIF options?
00124 
00125    << "   -L        List Contact field names\n"
00126    << "   -m        Map LDIF name to Contact field / Unmap LDIF name\n"
00127    << "                Map: ldif,read,write - maps ldif to read/write Contact fields\n"
00128    << "                Unmap: ldif name alone\n"
00129    << "   -M        List current LDIF mapping\n"
00130 */
00131    << "\n"
00132    << " Options to use for 'mime' type:\n"
00133    << "   -f file   Filename to read from or write to.  Use - to explicitly\n"
00134    << "             specify stdin/stdout, which is default.\n"
00135    << "\n"
00136    << " Options to use for 'dump' to stdout output type:\n"
00137    << "   -n        Use hex dump parser on all databases.\n"
00138    << "\n"
00139    << " Options to use for 'sha1' sum stdout output type:\n"
00140    << "   -t        Include DB Name, Type, and Unique record IDs in the checksums\n"
00141    << "\n"
00142    << " Options to use for 'cstore' output type:\n"
00143    << "   -l        List filenames only\n"
00144    << "   -f file   Filename from the above list, including path.\n"
00145    << "             If found, the file will be written to the current\n"
00146    << "             directory, using the base filename from the device.\n"
00147    << "\n"
00148    << " Standalone options:\n"
00149    << "   -h        This help\n"
00150    << "   -I cs     International charset for string conversions\n"
00151    << "             Valid values here are available with 'iconv --list'\n"
00152    << "   -S        Show list of supported database parsers and builders\n"
00153    << "   -v        Dump protocol data during operation\n"
00154    << "\n"
00155    << endl;
00156 }
00157 
00158 class ModeBase
00159 {
00160 public:
00161         virtual ~ModeBase() {}
00162 
00163         virtual bool ProbeNeeded() const { return false; }
00164 
00165         virtual void SetFilename(const std::string &name)
00166         {
00167                 throw runtime_error("Filename not applicable for this mode");
00168         }
00169 
00170         virtual void AddDB(const std::string &dbname)
00171         {
00172                 throw runtime_error("DB not applicable for this mode");
00173         }
00174 
00175         virtual void AddAllDBs()
00176         {
00177                 throw runtime_error("DBs not applicable for this mode");
00178         }
00179 
00180         virtual void SetPIN(const std::string &pin)
00181         {
00182                 throw runtime_error("PIN not applicable for this mode");
00183         }
00184 
00185         virtual void SetPassword(const std::string &password)
00186         {
00187                 throw runtime_error("Password not applicable for this mode");
00188         }
00189 
00190         virtual void SetWriteMode(DeviceParser::WriteMode mode)
00191         {
00192                 throw runtime_error("Device write behaviour not applicable for this mode");
00193         }
00194 
00195         virtual void SetDN(const std::string &dn)
00196         {
00197                 throw runtime_error("DN not applicable for this mode");
00198         }
00199 
00200         virtual void SetAttribute(const std::string &attr)
00201         {
00202                 throw runtime_error("Attribute not applicable for this mode");
00203         }
00204 
00205         virtual void SetHexDump()
00206         {
00207                 throw runtime_error("No hex dump option in this mode");
00208         }
00209 
00210         virtual void IncludeIDs()
00211         {
00212                 throw runtime_error("Including record IDs in the SHA1 sum is not applicable in this mode");
00213         }
00214 
00215         virtual void SetList()
00216         {
00217                 throw runtime_error("List option not applicable for this mode");
00218         }
00219 };
00220 
00221 class DeviceBase : public virtual ModeBase
00222 {
00223 protected:
00224         Barry::Pin m_pin;
00225         std::string m_password;
00226 
00227 public:
00228         bool ProbeNeeded() const { return true; }
00229 
00230         void SetPIN(const std::string &pin)
00231         {
00232                 istringstream iss(pin);
00233                 iss >> m_pin;
00234                 if( !m_pin.Valid() )
00235                         throw runtime_error("Invalid PIN: " + pin);
00236         }
00237 
00238         void SetPassword(const std::string &password)
00239         {
00240                 m_password = password;
00241         }
00242 };
00243 
00244 //////////////////////////////////////////////////////////////////////////////
00245 // Base class for Input Mode
00246 
00247 class InputBase : public virtual ModeBase
00248 {
00249 public:
00250         virtual Builder& GetBuilder(Barry::Probe *probe, IConverter &ic) = 0;
00251 };
00252 
00253 class DeviceInputBase : public DeviceBase, public InputBase
00254 {
00255 };
00256 
00257 //////////////////////////////////////////////////////////////////////////////
00258 // Mode: Input, Type: device
00259 
00260 class DeviceInput : public DeviceInputBase
00261 {
00262         auto_ptr<Controller> m_con;
00263         auto_ptr<Mode::Desktop> m_desktop;
00264         auto_ptr<DeviceBuilder> m_builder;
00265         vector<string> m_dbnames;
00266         bool m_add_all;
00267 
00268 public:
00269         DeviceInput()
00270                 : m_add_all(false)
00271         {
00272         }
00273 
00274         void AddDB(const std::string &dbname)
00275         {
00276                 m_dbnames.push_back(dbname);
00277         }
00278 
00279         void AddAllDBs()
00280         {
00281                 m_add_all = true;
00282         }
00283 
00284         Builder& GetBuilder(Barry::Probe *probe, IConverter &ic)
00285         {
00286                 int i = probe->FindActive(m_pin);
00287                 if( i == -1 ) {
00288                         if( m_pin.Valid() )
00289                                 throw runtime_error("PIN not found: " + m_pin.Str());
00290                         else
00291                                 throw runtime_error("PIN not specified, and more than one device exists.");
00292                 }
00293 
00294                 m_con.reset( new Controller(probe->Get(i)) );
00295                 m_desktop.reset( new Mode::Desktop(*m_con, ic) );
00296                 m_desktop->Open(m_password.c_str());
00297                 m_builder.reset( new DeviceBuilder(*m_desktop) );
00298 
00299                 if( m_add_all ) {
00300                         m_builder->Add(m_desktop->GetDBDB());
00301                 }
00302                 else {
00303                         for( size_t i = 0; i < m_dbnames.size(); i++ ) {
00304                                 m_builder->Add(m_dbnames[i]);
00305                         }
00306                 }
00307 
00308                 return *m_builder;
00309         }
00310 };
00311 
00312 //////////////////////////////////////////////////////////////////////////////
00313 // Mode: Input, Type: tar
00314 
00315 class TarInput : public InputBase
00316 {
00317         auto_ptr<Restore> m_restore;
00318         string m_tarpath;
00319         vector<string> m_dbnames;
00320 
00321 public:
00322         void SetFilename(const std::string &name)
00323         {
00324                 m_tarpath = name;
00325                 if( name == "-" )
00326                         throw runtime_error("Cannot use stdin as tar source file, sorry.");
00327         }
00328 
00329         void AddDB(const std::string &dbname)
00330         {
00331                 m_dbnames.push_back(dbname);
00332         }
00333 
00334         Builder& GetBuilder(Barry::Probe *probe, IConverter &ic)
00335         {
00336                 m_restore.reset( new Restore(m_tarpath, true) );
00337                 for( size_t i = 0; i < m_dbnames.size(); i++ ) {
00338                         m_restore->AddDB(m_dbnames[i]);
00339                 }
00340 
00341                 return *m_restore;
00342         }
00343 };
00344 
00345 //////////////////////////////////////////////////////////////////////////////
00346 // Mode: Input, Type: boost
00347 
00348 #ifdef __BARRY_BOOST_MODE__
00349 class BoostInput : public InputBase
00350 {
00351         auto_ptr<BoostBuilder> m_builder;
00352         string m_filename;
00353 
00354 public:
00355         BoostInput()
00356                 : m_filename("-")       // default to stdin/stdout
00357         {
00358         }
00359 
00360         void SetFilename(const std::string &name)
00361         {
00362                 m_filename = name;
00363         }
00364 
00365         Builder& GetBuilder(Barry::Probe *probe, IConverter &ic)
00366         {
00367                 if( m_filename == "-" ) {
00368                         // use stdin
00369                         m_builder.reset( new BoostBuilder(cin) );
00370                 }
00371                 else {
00372                         m_builder.reset( new BoostBuilder(m_filename) );
00373                 }
00374                 return *m_builder;
00375         }
00376 
00377 };
00378 #endif
00379 
00380 //////////////////////////////////////////////////////////////////////////////
00381 // Mode: Input, Type: ldif
00382 
00383 class LdifInput : public InputBase
00384 {
00385         auto_ptr<Builder> m_builder;
00386         string m_filename;
00387 
00388 public:
00389         LdifInput()
00390                 : m_filename("-")
00391         {
00392         }
00393 
00394         void SetFilename(const std::string &name)
00395         {
00396                 m_filename = name;
00397         }
00398 
00399         Builder& GetBuilder(Barry::Probe *probe, IConverter &ic)
00400         {
00401                 if( m_filename == "-" ) {
00402                         // use stdin
00403                         m_builder.reset(
00404                                 new RecordBuilder<Contact, LdifStore>(
00405                                         new LdifStore(cin)) );
00406                 }
00407                 else {
00408                         m_builder.reset(
00409                                 new RecordBuilder<Contact, LdifStore>(
00410                                         new LdifStore(m_filename)) );
00411                 }
00412                 return *m_builder;
00413         }
00414 
00415 };
00416 
00417 
00418 //////////////////////////////////////////////////////////////////////////////
00419 // Mode: Input, Type: mime
00420 
00421 class MimeInput : public InputBase
00422 {
00423         auto_ptr<MimeBuilder> m_builder;
00424         string m_filename;
00425 
00426 public:
00427         MimeInput()
00428                 : m_filename("-")
00429         {
00430         }
00431 
00432         void SetFilename(const std::string &name)
00433         {
00434                 m_filename = name;
00435         }
00436 
00437         Builder& GetBuilder(Barry::Probe *probe, IConverter &ic)
00438         {
00439                 if( m_filename == "-" ) {
00440                         // use stdin
00441                         m_builder.reset( new MimeBuilder(cin) );
00442                 }
00443                 else {
00444                         m_builder.reset( new MimeBuilder(m_filename) );
00445                 }
00446                 return *m_builder;
00447         }
00448 
00449 };
00450 
00451 //////////////////////////////////////////////////////////////////////////////
00452 // Base class for Output Mode
00453 
00454 class OutputBase : public virtual ModeBase
00455 {
00456 public:
00457         virtual Parser& GetParser(Barry::Probe *probe, IConverter &ic) = 0;
00458 };
00459 
00460 class DeviceOutputBase : public DeviceBase, public OutputBase
00461 {
00462 };
00463 
00464 //////////////////////////////////////////////////////////////////////////////
00465 // Mode: Output, Type: device
00466 
00467 class DeviceOutput : public DeviceOutputBase
00468 {
00469         auto_ptr<Controller> m_con;
00470         auto_ptr<Mode::Desktop> m_desktop;
00471         auto_ptr<DeviceParser> m_parser;
00472         DeviceParser::WriteMode m_mode;
00473 
00474 public:
00475         DeviceOutput()
00476                 : m_mode(DeviceParser::DROP_RECORD)
00477         {
00478         }
00479 
00480         void SetWriteMode(DeviceParser::WriteMode mode)
00481         {
00482                 m_mode = mode;
00483         }
00484 
00485         Parser& GetParser(Barry::Probe *probe, IConverter &ic)
00486         {
00487                 int i = probe->FindActive(m_pin);
00488                 if( i == -1 ) {
00489                         if( m_pin.Valid() )
00490                                 throw runtime_error("PIN not found: " + m_pin.Str());
00491                         else
00492                                 throw runtime_error("PIN not specified, and more than one device exists.");
00493                 }
00494 
00495                 m_con.reset( new Controller(probe->Get(i)) );
00496                 m_desktop.reset( new Mode::Desktop(*m_con, ic) );
00497                 m_desktop->Open(m_password.c_str());
00498                 m_parser.reset( new DeviceParser(*m_desktop, m_mode) );
00499 
00500                 return *m_parser;
00501         }
00502 };
00503 
00504 //////////////////////////////////////////////////////////////////////////////
00505 // Mode: Output, Type: tar
00506 
00507 class TarOutput : public OutputBase
00508 {
00509         auto_ptr<Backup> m_backup;
00510         string m_tarpath;
00511 
00512 public:
00513         void SetFilename(const std::string &name)
00514         {
00515                 m_tarpath = name;
00516                 if( name == "-" )
00517                         throw runtime_error("Cannot use stdout as tar backup file, sorry.");
00518         }
00519 
00520         Parser& GetParser(Barry::Probe *probe, IConverter &ic)
00521         {
00522                 m_backup.reset( new Backup(m_tarpath) );
00523                 return *m_backup;
00524         }
00525 };
00526 
00527 //////////////////////////////////////////////////////////////////////////////
00528 // Mode: Output, Type: boost
00529 
00530 #ifdef __BARRY_BOOST_MODE__
00531 class BoostOutput : public OutputBase
00532 {
00533         auto_ptr<BoostParser> m_parser;
00534         string m_filename;
00535 
00536 public:
00537         void SetFilename(const std::string &name)
00538         {
00539                 m_filename = name;
00540         }
00541 
00542         Parser& GetParser(Barry::Probe *probe, IConverter &ic)
00543         {
00544                 if( !m_filename.size() )
00545                         throw runtime_error("Boost output requires a specific output file (-f switch)");
00546 
00547                 if( m_filename == "-" ) {
00548                         // use stdout
00549                         m_parser.reset( new BoostParser(cout) );
00550                 }
00551                 else {
00552                         m_parser.reset( new BoostParser(m_filename) );
00553                 }
00554                 return *m_parser;
00555         }
00556 
00557 };
00558 #endif
00559 
00560 //////////////////////////////////////////////////////////////////////////////
00561 // Mode: Output, Type: ldif
00562 
00563 class LdifOutput : public OutputBase
00564 {
00565         auto_ptr<Parser> m_parser;
00566         string m_filename;
00567         string m_baseDN;
00568         string m_dnattr;
00569 
00570 public:
00571         LdifOutput()
00572                 : m_filename("-")
00573         {
00574         }
00575 
00576         void SetFilename(const std::string &name)
00577         {
00578                 m_filename = name;
00579         }
00580 
00581         void SetDN(const std::string &dn)
00582         {
00583                 m_baseDN = dn;
00584         }
00585 
00586         void SetAttribute(const std::string &attr)
00587         {
00588                 m_dnattr = attr;
00589         }
00590 
00591         Parser& GetParser(Barry::Probe *probe, IConverter &ic)
00592         {
00593                 if( m_filename == "-" ) {
00594                         // use stdin
00595                         m_parser.reset(
00596                                 new RecordParser<Contact, LdifStore>(
00597                                         new LdifStore(cout, m_baseDN,
00598                                                 m_dnattr)) );
00599                 }
00600                 else {
00601                         m_parser.reset(
00602                                 new RecordParser<Contact, LdifStore>(
00603                                         new LdifStore(m_filename, m_baseDN,
00604                                                 m_dnattr)) );
00605                 }
00606                 return *m_parser;
00607         }
00608 };
00609 
00610 //////////////////////////////////////////////////////////////////////////////
00611 // Mode: Output, Type: mime
00612 
00613 class MimeStore : public AllRecordStore
00614 {
00615         std::ostream &m_os;
00616 
00617 public:
00618         MimeStore(std::ostream &os)
00619                 : m_os(os)
00620         {
00621         }
00622 
00623 #undef HANDLE_PARSER
00624 #define HANDLE_PARSER(tname) \
00625         void operator() (const Barry::tname &r) \
00626         { \
00627                 MimeDump<tname>::Dump(m_os, r); \
00628         }
00629 
00630         ALL_KNOWN_PARSER_TYPES
00631 };
00632 
00633 class MimeOutput : public OutputBase
00634 {
00635         auto_ptr<std::ofstream> m_file;
00636         auto_ptr<Parser> m_parser;
00637         std::string m_filename;
00638 
00639 public:
00640         MimeOutput()
00641                 : m_filename("-")       // default to stdout
00642         {
00643         }
00644 
00645         void SetFilename(const std::string &name)
00646         {
00647                 m_filename = name;
00648         }
00649 
00650         Parser& GetParser(Barry::Probe *probe, IConverter &ic)
00651         {
00652                 if( m_filename == "-" ) {
00653                         m_parser.reset( new AllRecordParser(cout,
00654                                 new HexDumpParser(cout),
00655                                 new MimeStore(cout)) );
00656                 }
00657                 else {
00658                         m_file.reset( new std::ofstream(m_filename.c_str()) );
00659                         m_parser.reset( new AllRecordParser(*m_file,
00660                                 new HexDumpParser(*m_file),
00661                                 new MimeStore(*m_file)) );
00662                 }
00663                 return *m_parser;
00664         }
00665 };
00666 
00667 //////////////////////////////////////////////////////////////////////////////
00668 // Mode: Output, Type: dump
00669 
00670 class DumpOutput : public OutputBase
00671 {
00672         auto_ptr<Parser> m_parser;
00673         bool m_hex_only;
00674 
00675 public:
00676         DumpOutput()
00677                 : m_hex_only(false)
00678         {
00679         }
00680 
00681         void SetHexDump()
00682         {
00683                 m_hex_only = true;
00684         }
00685 
00686         Parser& GetParser(Barry::Probe *probe, IConverter &ic)
00687         {
00688                 if( m_hex_only ) {
00689                         m_parser.reset( new HexDumpParser(cout) );
00690                 }
00691                 else {
00692                         m_parser.reset( new AllRecordParser(cout,
00693                                 new HexDumpParser(cout),
00694                                 new AllRecordDumpStore(cout)) );
00695                 }
00696                 return *m_parser;
00697         }
00698 };
00699 
00700 //////////////////////////////////////////////////////////////////////////////
00701 // Mode: Output, Type: sha1
00702 
00703 class Sha1Output : public OutputBase
00704 {
00705         auto_ptr<Parser> m_parser;
00706         bool m_include_ids;
00707 
00708 public:
00709         Sha1Output()
00710                 : m_include_ids(false)
00711         {
00712         }
00713 
00714         void IncludeIDs()
00715         {
00716                 m_include_ids = true;
00717         }
00718 
00719         Parser& GetParser(Barry::Probe *probe, IConverter &ic)
00720         {
00721                 m_parser.reset( new ChecksumParser(m_include_ids) );
00722                 return *m_parser;
00723         }
00724 };
00725 
00726 //////////////////////////////////////////////////////////////////////////////
00727 // Mode: Output, Type: cstore
00728 
00729 class ContentStoreOutput : public OutputBase
00730 {
00731         auto_ptr<Parser> m_parser;
00732         bool m_list_only;
00733         vector<string> m_filenames;
00734 
00735 public:
00736         ContentStoreOutput()
00737                 : m_list_only(false)
00738         {
00739         }
00740 
00741         void SetFilename(const std::string &name)
00742         {
00743                 m_filenames.push_back(name);
00744         }
00745 
00746         void SetList()
00747         {
00748                 m_list_only = true;
00749         }
00750 
00751         Parser& GetParser(Barry::Probe *probe, IConverter &ic)
00752         {
00753                 m_parser.reset( new RecordParser<ContentStore, ContentStoreOutput>(*this) );
00754                 return *m_parser;
00755         }
00756 
00757         // storage operator
00758         void operator() (const ContentStore &rec)
00759         {
00760                 if( m_list_only ) {
00761                         cout << rec.Filename;
00762                         if( rec.FolderFlag ) {
00763                                 cout << " (folder)";
00764                         }
00765                         cout << endl;
00766                 }
00767                 else {
00768                         // check if this record matches one of the filenames
00769                         // in the list
00770                         vector<string>::iterator i = find(m_filenames.begin(),
00771                                 m_filenames.end(), rec.Filename);
00772                         if( i != m_filenames.end() ) {
00773                                 SaveFile(rec);
00774                         }
00775                 }
00776         }
00777 
00778         void SaveFile(const ContentStore &rec)
00779         {
00780                 size_t slash = rec.Filename.rfind('/');
00781                 string filename;
00782                 if( slash == string::npos )
00783                         filename = rec.Filename;
00784                 else
00785                         filename = rec.Filename.substr(slash + 1);
00786 
00787                 // modify filename until we find one that doesn't
00788                 // already exist
00789                 string freshname = filename;
00790                 int count = 0;
00791                 while( access(freshname.c_str(), F_OK) == 0 ) {
00792                         ostringstream oss;
00793                         oss << filename << count++;
00794                         freshname = oss.str();
00795                 }
00796 
00797                 // open and write!
00798                 cout << "Saving: " << rec.Filename
00799                         << " as " << freshname << endl;
00800                 ofstream ofs(freshname.c_str());
00801                 ofs << rec.FileContent;
00802                 ofs.flush();
00803                 if( !ofs ) {
00804                         cout << "Error during write!" << endl;
00805                 }
00806         }
00807 };
00808 
00809 
00810 
00811 //////////////////////////////////////////////////////////////////////////////
00812 // Main application class
00813 
00814 class App
00815 {
00816 public:
00817         typedef shared_ptr<OutputBase> OutputPtr;
00818         typedef vector<OutputPtr> OutputsType;
00819 
00820 private:
00821         auto_ptr<InputBase> Input;
00822         OutputsType Outputs;
00823 
00824 public:
00825 
00826         bool ParseInMode(const string &mode);
00827         bool ParseOutMode(const string &mode);
00828         DeviceParser::WriteMode ParseWriteMode(const std::string &mode);
00829         static void ShowParsers();
00830         // returns true if any of the items in Outputs needs a probe
00831         bool OutputsProbeNeeded();
00832         int main(int argc, char *argv[]);
00833 };
00834 
00835 bool App::ParseInMode(const string &mode)
00836 {
00837         if( mode == "device" ) {
00838                 Input.reset( new DeviceInput );
00839                 return true;
00840         }
00841         else if( mode == "tar" ) {
00842                 Input.reset( new TarInput );
00843                 return true;
00844         }
00845 #ifdef __BARRY_BOOST_MODE__
00846         else if( mode == "boost" ) {
00847                 Input.reset( new BoostInput );
00848                 return true;
00849         }
00850 #endif
00851         else if( mode == "ldif" ) {
00852                 Input.reset( new LdifInput );
00853                 return true;
00854         }
00855         else if( mode == "mime" ) {
00856                 Input.reset( new MimeInput );
00857                 return true;
00858         }
00859         else
00860                 return false;
00861 }
00862 
00863 bool App::ParseOutMode(const string &mode)
00864 {
00865         if( mode == "device" ) {
00866                 Outputs.push_back( OutputPtr(new DeviceOutput) );
00867                 return true;
00868         }
00869         else if( mode == "tar" ) {
00870                 Outputs.push_back( OutputPtr(new TarOutput) );
00871                 return true;
00872         }
00873 #ifdef __BARRY_BOOST_MODE__
00874         else if( mode == "boost" ) {
00875                 Outputs.push_back( OutputPtr(new BoostOutput) );
00876                 return true;
00877         }
00878 #endif
00879         else if( mode == "ldif" ) {
00880                 Outputs.push_back( OutputPtr(new LdifOutput) );
00881                 return true;
00882         }
00883         else if( mode == "mime" ) {
00884                 Outputs.push_back( OutputPtr(new MimeOutput) );
00885                 return true;
00886         }
00887         else if( mode == "dump" ) {
00888                 Outputs.push_back( OutputPtr(new DumpOutput) );
00889                 return true;
00890         }
00891         else if( mode == "sha1" ) {
00892                 Outputs.push_back( OutputPtr(new Sha1Output) );
00893                 return true;
00894         }
00895         else if( mode == "cstore" ) {
00896                 Outputs.push_back( OutputPtr(new ContentStoreOutput) );
00897                 return true;
00898         }
00899         else
00900                 return false;
00901 }
00902 
00903 DeviceParser::WriteMode App::ParseWriteMode(const std::string &mode)
00904 {
00905         if( mode == "erase" )
00906                 return DeviceParser::ERASE_ALL_WRITE_ALL;
00907         else if( mode == "overwrite" )
00908                 return DeviceParser::INDIVIDUAL_OVERWRITE;
00909         else if( mode == "addonly" )
00910                 return DeviceParser::ADD_BUT_NO_OVERWRITE;
00911         else if( mode == "addnew" )
00912                 return DeviceParser::ADD_WITH_NEW_ID;
00913         else
00914                 throw runtime_error("Unknown device output mode. Must be one of: erase, overwrite, addonly, addnew");
00915 }
00916 
00917 void App::ShowParsers()
00918 {
00919         cout << "Supported Database parsers:\n"
00920         << " (* = can display in vformat MIME mode)\n"
00921 
00922 #undef HANDLE_PARSER
00923 #define HANDLE_PARSER(tname) \
00924         << "   " << tname::GetDBName() \
00925                 << (MimeDump<tname>::Supported() ? " *" : "") << "\n"
00926 
00927         ALL_KNOWN_PARSER_TYPES
00928 
00929         << "\n"
00930         << "Supported Database builders:\n"
00931 
00932 #undef HANDLE_BUILDER
00933 #define HANDLE_BUILDER(tname) \
00934         << "   " << tname::GetDBName() << "\n"
00935 
00936         ALL_KNOWN_BUILDER_TYPES
00937 
00938         << endl;
00939 }
00940 
00941 bool App::OutputsProbeNeeded()
00942 {
00943         for( OutputsType::iterator i = Outputs.begin();
00944                 i != Outputs.end();
00945                 ++i )
00946         {
00947                 if( (*i)->ProbeNeeded() )
00948                         return true;
00949         }
00950         return false;
00951 }
00952 
00953 int App::main(int argc, char *argv[])
00954 {
00955         bool verbose = false;
00956         string iconvCharset;
00957 
00958         // process command line options
00959         ModeBase *current = 0;
00960         for(;;) {
00961                 int cmd = getopt(argc, argv, "hi:o:nvI:f:p:P:d:c:C:ASw:tl");
00962                 if( cmd == -1 )
00963                         break;
00964 
00965                 // first option must be in or out, or a global option
00966                 if( !current ) {
00967                         if( cmd != 'i' && \
00968                             cmd != 'o' && \
00969                             cmd != 'S' && \
00970                             cmd != 'I' && \
00971                             cmd != 'v' )
00972                         {
00973                                 Usage();
00974                                 return 1;
00975                         }
00976                 }
00977 
00978                 switch( cmd )
00979                 {
00980                 case 'i':       // set input mode
00981                         // must be first time used
00982                         if( Input.get() || !ParseInMode(optarg) ) {
00983                                 Usage();
00984                                 return 1;
00985                         }
00986                         current = Input.get();
00987                         break;
00988 
00989                 case 'o':       // set output mode
00990                         // can be used multiple times
00991                         if( !ParseOutMode(optarg) ) {
00992                                 Usage();
00993                                 return 1;
00994                         }
00995                         current = Outputs[Outputs.size() - 1].get();
00996                         break;
00997 
00998 
00999                 case 'c':       // set ldif dn
01000                         current->SetDN(optarg);
01001                         break;
01002 
01003                 case 'C':       // set ldif attr
01004                         current->SetAttribute(optarg);
01005                         break;
01006 
01007                 case 'd':       // database name
01008                         current->AddDB(optarg);
01009                         break;
01010 
01011                 case 'f':       // filename
01012                         current->SetFilename(optarg);
01013                         break;
01014 
01015                 case 'p':       // device PIN
01016                         current->SetPIN(optarg);
01017                         break;
01018 
01019                 case 'P':       // password
01020                         current->SetPassword(optarg);
01021                         break;
01022 
01023                 case 'w':       // device write mode
01024                         current->SetWriteMode(ParseWriteMode(optarg));
01025                         break;
01026 
01027                 case 'A':       // add all DB names to the device builder
01028                         current->AddAllDBs();
01029                         break;
01030 
01031                 case 't':       // include type and IDs in sha1 mode
01032                         current->IncludeIDs();
01033                         break;
01034 
01035                 case 'l':       // list only
01036                         current->SetList();
01037                         break;
01038 
01039                 case 'S':       // show parsers and builders
01040                         ShowParsers();
01041                         return 0;
01042 
01043                 case 'I':       // international charset (iconv)
01044                         iconvCharset = optarg;
01045                         break;
01046 
01047                 case 'n':       // use null hex dump parser only
01048                         current->SetHexDump();
01049                         break;
01050 
01051                 case 'v':       // verbose
01052                         verbose = true;
01053                         break;
01054 
01055                 case 'h':       // help
01056                 default:
01057                         Usage();
01058                         return 0;
01059                 }
01060         }
01061 
01062         if( !Input.get() || !Outputs.size() ) {
01063                 Usage();
01064                 return 0;
01065         }
01066 
01067         // Initialize the Barry library
01068         Barry::Init(verbose);
01069 
01070         // Create an IConverter object if needed
01071         auto_ptr<IConverter> ic;
01072         if( iconvCharset.size() ) {
01073                 ic.reset( new IConverter(iconvCharset.c_str(), true) );
01074         }
01075 
01076         // Probe for devices only if needed
01077         auto_ptr<Probe> probe;
01078         if( Input->ProbeNeeded() || OutputsProbeNeeded() ) {
01079                 // Probe for available devices
01080                 probe.reset( new Probe );
01081         }
01082 
01083         // Setup the input first (builder)
01084         Builder &builder = Input->GetBuilder(probe.get(), *ic);
01085 
01086         // Setup a TeeParser with all Outputs
01087         TeeParser tee;
01088         for( OutputsType::iterator i = Outputs.begin(); i != Outputs.end(); ++i ) {
01089                 Parser &parser = (*i)->GetParser(probe.get(), *ic);
01090                 tee.Add(parser);
01091         }
01092 
01093         // Setup the pipe
01094         Pipe pipe(builder);
01095         pipe.PumpFile(tee, ic.get());
01096 
01097         return 0;
01098 }
01099 
01100 int main(int argc, char *argv[])
01101 {
01102         try {
01103                 App app;
01104                 return app.main(argc, argv);
01105         }
01106         catch( std::exception &e ) {
01107                 cerr << "Exception: " << e.what() << endl;
01108                 return 1;
01109         }
01110 }
01111 

Generated on Tue Mar 1 17:50:14 2011 for Barry by  doxygen 1.5.6