1 /*===========================================================================
2 *
3 *                            PUBLIC DOMAIN NOTICE
4 *               National Center for Biotechnology Information
5 *
6 *  This software/database is a "United States Government Work" under the
7 *  terms of the United States Copyright Act.  It was written as part of
8 *  the author's official duties as a United States Government employee and
9 *  thus cannot be copyrighted.  This software/database is freely available
10 *  to the public for use. The National Library of Medicine and the U.S.
11 *  Government have not placed any restriction on its use or reproduction.
12 *
13 *  Although all reasonable efforts have been taken to ensure the accuracy
14 *  and reliability of the software and data, the NLM and the U.S.
15 *  Government do not and cannot warrant the performance or results that
16 *  may be obtained by using this software or data. The NLM and the U.S.
17 *  Government disclaim all warranties, express or implied, including
18 *  warranties of performance, merchantability or fitness for any particular
19 *  purpose.
20 *
21 *  Please cite the author in any work or product based on this material.
22 *
23 * ===========================================================================
24 *
25 */
26 
27 #include "configure.h" /* configure */
28 #include "interactive.h" /* run_interactive */
29 #include "util.hpp" // CNoncopyable
30 #include "vdb-config-model.hpp" // vdbconf_model
31 
32 #include <klib/rc.h> /* RC */
33 #include <klib/vector.h> /* Vector */
34 
35 #include <sstream> // stringstream
36 
37 #include <climits> /* PATH_MAX */
38 #ifndef PATH_MAX
39 #define PATH_MAX 4096
40 #endif
41 
42 using std::string;
43 
44 ////////////////////////////////////////////////////////////////////////////////
45 class CConfigurator : CNoncopyable {
46     CKConfig m_Cfg;
47     CKDirectory m_Dir;
CheckNcbiHome(bool & updated,bool verbose) const48     rc_t CheckNcbiHome(bool &updated, bool verbose) const {
49         if (verbose) {
50             OUTMSG(("checking NCBI home... "));
51         }
52 
53         const CString ncbi(m_Cfg.ReadNcbiHome());
54 
55         if (verbose) {
56             OUTMSG(("%S\n", ncbi.Get()));
57         }
58 
59         rc_t rc = 0;
60         if (!ncbi.Empty()) {
61             rc = m_Dir.CreateNonExistingPrivateDir(ncbi, verbose);
62             if (rc == 0) {
63                 rc = m_Dir.CheckPrivateAccess(ncbi, updated, verbose);
64             }
65             if (rc == 0) {
66                 rc = m_Dir.CanWriteFile(ncbi, verbose);
67             }
68         }
69 
70         return rc;
71     }
CheckRepositories(bool fix)72     rc_t CheckRepositories(bool fix) {
73         {
74             const string name("/repository/user/default-path");
75             CString node(m_Cfg.ReadString(name.c_str()));
76             if (node.Empty()) {
77                 CString home(m_Cfg.ReadString("HOME"));
78                 if (!home.Empty()) {
79 /* this rc is ignored */ m_Cfg.UpdateNode(name.c_str(),
80                     (home.GetString() + "/ncbi").c_str());
81                 }
82                 else {
83                     m_Cfg.UpdateNode(name.c_str(), "$(HOME)/ncbi");
84                 }
85             }
86             else {
87                 const string canonical
88                     ( m_Dir . Canonical ( node . GetCString () ) );
89                 if ( ! canonical . empty () )
90                     m_Cfg.UpdateNode ( name, canonical );
91             }
92         }
93         rc_t rc = 0;
94         if (fix) {
95             const string name("/repository/site/disabled");
96             if (m_Cfg.NodeExists(name)) {
97                 rc_t r2 = m_Cfg.UpdateNode(name.c_str(), "false");
98                 if (r2 != 0 && rc == 0)
99                     rc = r2;
100             }
101         }
102         const KRepositoryMgr *mgr = NULL;
103         rc = KConfigMakeRepositoryMgrRead(m_Cfg.Get(), &mgr);
104         KRepositoryVector repositories;
105         memset(&repositories, 0, sizeof repositories);
106         if (rc == 0) {
107             rc = KRepositoryMgrRemoteRepositories(mgr, &repositories);
108             if (rc == 0)
109                 KRepositoryVectorWhack(&repositories);
110             else if
111                 (rc == SILENT_RC(rcKFG, rcNode, rcOpening, rcPath, rcNotFound))
112             {
113                 rc = m_Cfg.CreateRemoteRepositories();
114             }
115         }
116         if ( rc == 0 && fix )
117             rc = m_Cfg.CreateRemoteRepositories(fix);
118         if (rc == 0) {
119 
120             m_Cfg . FixResolverCgiNodes ( );
121 
122             bool noUser = false;
123             rc = KRepositoryMgrUserRepositories(mgr, &repositories);
124             if (rc == 0) {
125                 uint32_t len = 0;
126                 if (rc == 0)
127                     len = VectorLength(&repositories);
128                 if (len == 0)
129                     noUser = true;
130                 else {
131                     uint32_t i = 0;
132                     noUser = true;
133                     for (i = 0; i < len; ++i) {
134                         KRepository *repo = static_cast<KRepository*>
135                             (VectorGet(&repositories, i));
136                         if (repo != NULL) {
137                             char name[PATH_MAX] = "";
138                             size_t size = 0;
139                             rc = KRepositoryName(repo,
140                                 name, sizeof name, &size);
141                             if (rc == 0) {
142                                 const char p[] = "public";
143                                 if (strcase_cmp(p, sizeof p - 1, name,
144                                     size, sizeof name) == 0)
145                                 {
146                                     noUser = false;
147                                 }
148                                 if (fix) {
149                                     rc = m_Cfg.CreateUserRepository (name, fix);
150                                 }
151                             }
152 
153                             char root[PATH_MAX] = "";
154                             rc = KRepositoryRoot ( repo,
155                                                    root, sizeof root, &size);
156                             if (rc == 0) {
157                                 const string canonical
158                                     ( m_Dir . Canonical ( root ) );
159                                 if ( ! canonical . empty () ) {
160                                     rc = KRepositorySetRoot ( repo,
161                                         canonical . c_str (),
162                                         canonical . size () );
163                                     if ( rc == 0 )
164                                         m_Cfg . Updated ();
165                                 }
166                             }
167                         }
168                     }
169                     rc = 0;
170                 }
171                 KRepositoryVectorWhack(&repositories);
172             }
173             else if
174                 (rc == SILENT_RC(rcKFG, rcNode, rcOpening, rcPath, rcNotFound))
175             {
176                 noUser = true;
177             }
178             if (noUser) {
179                 rc = m_Cfg.CreateUserRepository();
180             }
181         }
182         RELEASE(KRepositoryMgr, mgr);
183         return rc;
184     }
185 
CheckConfig(bool fix)186     rc_t CheckConfig(bool fix) {
187         rc_t rc = CheckRepositories(fix);
188         if (rc == 0) {
189             const string name("/tools/ascp/max_rate");
190             CString node(m_Cfg.ReadString(name.c_str()));
191             if (node.Empty()) {
192                 rc = m_Cfg.UpdateNode(name.c_str(), "450m");
193             }
194         }
195         if (rc == 0) {
196             CString config_default(m_Cfg.ReadDefaultConfig());
197             if (!config_default.Empty() && !config_default.Equals("false")) {
198                 m_Cfg.UpdateNode("/config/default", "false");
199             }
200         }
201         if (rc == 0) {
202             m_Cfg.Commit();
203         }
204         return rc;
205     }
206 
207 protected:
208     vdbconf_model *m_Config;
209 
210 public:
CConfigurator(bool fix=false,bool verbose=false)211     CConfigurator(bool fix = false, bool verbose = false): m_Config(NULL) {
212 #define TODO 1
213         bool updated = false;
214         rc_t rc = CheckNcbiHome(updated, verbose);
215         if (rc == 0 && updated) {
216             m_Cfg.Reload(verbose);
217         }
218         if (rc == 0) {
219             rc = CheckConfig(fix);
220             if (rc == 0) {
221                 m_Cfg.Reload(verbose);
222             }
223         }
224         if (rc == 0) {
225             m_Config = new vdbconf_model( m_Cfg );
226             if (m_Config == NULL) {
227                 rc = TODO;
228             }
229         }
230         if (rc != 0) {
231             throw rc;
232         }
233     }
~CConfigurator(void)234     virtual ~CConfigurator(void) { delete m_Config; }
Configure(void)235     virtual rc_t Configure(void) {
236         OUTMSG(("Fixed default configuration\n"));
237         return 0;
238     }
239 };
240 struct SUserRepo {
241     bool cacheEnabled;
242 //  bool enabled;
243     string root;
SUserRepoSUserRepo244     SUserRepo(const vdbconf_model *kfg, int32_t id = -1) { Reload (kfg, id); }
ReloadSUserRepo245     void Reload(const vdbconf_model *kfg, int32_t id = -1) {
246         assert(kfg);
247         if (id < 0) {
248             cacheEnabled = kfg->is_user_cache_enabled();
249 //          enabled = kfg->is_user_enabled();
250             root = kfg->get_public_location();
251         }
252         else {
253             cacheEnabled = kfg->is_protected_repo_cached(id);
254 //          enabled = kfg->is_protected_repo_enabled(id);
255             root = kfg->get_repo_location(id);
256         }
257     }
258 };
259 struct SProtectedRepo : SUserRepo {
260 public:
261     const string name;
262     const string description;
SProtectedRepoSProtectedRepo263     SProtectedRepo(const vdbconf_model *kfg,
264             uint32_t id, const string &aName)
265         : SUserRepo(kfg, id)
266         , name(aName), description(kfg->get_repo_description(name))
267     {}
ReloadSProtectedRepo268     void Reload(const vdbconf_model *kfg,
269         uint32_t id, const string &aName)
270     {
271         assert(name == aName);
272         SUserRepo::Reload(kfg, id);
273     }
274 };
275 class CProtectedRepos : public std::map<const string, SProtectedRepo> {
276     typedef std::map<const string, SProtectedRepo>::iterator TI;
277 public:
278     typedef std::map<const string, SProtectedRepo>::const_iterator TCI;
CProtectedRepos(const vdbconf_model * kfg)279     CProtectedRepos(const vdbconf_model *kfg) { Reload(kfg); }
Reload(const vdbconf_model * kfg)280     void Reload(const vdbconf_model *kfg) {
281         assert(kfg);
282         uint32_t n = kfg->get_repo_count();
283         for (uint32_t i = 0; i < n; ++i) {
284             const string name(kfg->get_repo_name(i));
285             TI it = find(name);
286             if (it == end()) {
287                 insert(std::pair<const string, SProtectedRepo>
288                     (name, SProtectedRepo(kfg, i, name)));
289             }
290             else {
291                 (*it).second.Reload(kfg, i, name);
292             }
293         }
294     }
Get(uint32_t id) const295     TCI Get(uint32_t id) const {
296         TCI it = begin();
297         for (uint32_t i = 0; it != end(); ++it, ++i) {
298             if (i == id) {
299                 break;
300             }
301         }
302         return it;
303     }
304 };
305 struct SData {
306     bool done;
307     bool updated;
308     bool site;
309     struct SCrntData {
310     private:
311         const vdbconf_model *m_Kfg;
312     public:
313         bool site_enabled;
314         bool remote_enabled;
315         bool cache_disabled;
316         SUserRepo userR;
317         CProtectedRepos protectedR;
SCrntDataSData::SCrntData318         SCrntData(const vdbconf_model *kfg)
319             : m_Kfg(kfg), userR(kfg), protectedR(kfg)
320         {
321             Reload();
322         }
ReloadSData::SCrntData323         void Reload(void) {
324             assert(m_Kfg);
325             site_enabled = m_Kfg->is_site_enabled();
326             remote_enabled = m_Kfg->is_remote_enabled();
327             cache_disabled = ! m_Kfg->is_global_cache_enabled();
328             userR.Reload(m_Kfg);
329             protectedR.Reload(m_Kfg);
330         }
331     } crnt;
SDataSData332     SData(const vdbconf_model *kfg)
333         : done(false)
334         , updated(false)
335         , site(kfg->does_site_repo_exist())
336         , crnt(kfg)
337     {}
338 };
339 struct STrinity {
340 private:
ToStringSTrinity341     string ToString(int i) { std::stringstream s; s << i; return s.str(); }
342 public:
343 //  const string enabled;
344     const string cached;
345     const string root;
STrinitySTrinity346     STrinity(const string &src)
347 //      : enabled(src.substr(0, 1))
348         : cached (src.substr(0, 1))
349         , root   (src.substr(1, 1))
350     {}
STrinitySTrinity351     STrinity(int i)
352 //      : enabled(ToString(i + 0))
353         : cached (ToString(i + 0))
354         , root   (ToString(i + 1))
355     {}
PrintSTrinity356     void Print(void) const
357     { OUTMSG(("%s %s\n", cached.c_str(), root.c_str())); }
358 };
359 class CTextualConfigurator : public CConfigurator {
360     CStdIn m_Stdin;
Input(const string & prompt,const string & value)361     string Input(const string &prompt, const string &value) {
362         OUTMSG(("\n\n%s:\n%s\n\nEnter the new path and Press <Enter>\n"
363             "Press <Enter> to accept the path\n> ",
364             prompt.c_str(), value.c_str()));
365         char buffer[PATH_MAX] = "";
366         size_t num_read = 0;
367         rc_t rc = m_Stdin.Read(buffer, sizeof buffer, &num_read);
368         if (rc == 0 && num_read > 0) {
369             return string(buffer, num_read);
370         }
371         else {
372             return "";
373         }
374     }
375 
ProcessCancel(SData & d)376     void ProcessCancel(SData &d) {
377         if (!d.updated) {
378             d.done = true;
379             return;
380         }
381         OUTMSG(("\nChanges in your configuration were not saved\n\n"));
382         while (true) {
383             OUTMSG((
384                 "To save changes and exit  : Enter Y and Press <Enter>\n"
385                 "To ignore changes and exit: Enter N and Press <Enter>\n"
386                 "To cancel and continue    : Press <Enter>\n"
387                 "\n"
388                 "Your choice > "));
389             char answer = toupper(m_Stdin.Read1());
390             switch (answer) {
391                 case '\0':
392                     return;
393                 case  'Y':
394                     OUTMSG(("Saving...\n"));
395                     m_Config->commit();
396                 //  no break;
397                 case  'N':
398                     OUTMSG(("Exiting..."));
399                     d.done = true;
400                     return;
401                 default:
402                     OUTMSG(("Unrecognized input\n"));
403             }
404         }
405     }
406     enum EChoice {
407         eCancel,
408         eExit,
409         eRemote,
410         eSite,
411         eUnknown,
412         eUserCacheEnable,
413         eGlobalCacheEnable,
414 //      eUserEnable,
415         eUserRoot,
416     };
417     struct SChoice {
418         EChoice choice;
419         int32_t id;
SChoiceCTextualConfigurator::SChoice420         SChoice(EChoice c, int32_t i = -1) : choice(c), id(i)
421         {}
422     };
423     class CSymGen {
424         static const string magic;
425     public:
Id2Seq(uint32_t id)426         static STrinity Id2Seq(uint32_t id) {
427             int d = id * 2 - (int)magic.size();
428             if (d < 0) {
429                 return STrinity(magic.substr(id * 2, 2));
430             }
431             else {
432                 return STrinity(d + 10);
433             }
434         }
Seq2Choice(string s,uint32_t maxId)435         static SChoice Seq2Choice(string /* copy */ s, uint32_t maxId) {
436             if (s.length() <= 0 || s.length() > 2) {
437                 return SChoice(eUnknown);
438             }
439             else if (s.length() == 1) {
440                 size_t p = magic.find(s[0]);
441                 if (p == string::npos) {
442                     return SChoice(eUnknown);
443                 }
444                 else {
445                     EChoice c = eUnknown;
446                     switch (p % 2) {
447                         case 0: c = eUserCacheEnable; break;
448                         case 1: c = eUserRoot       ; break;
449                         default: assert(0); break;
450                     }
451                     return SChoice(c, (int)p / 2);
452                 }
453             }
454             else {
455                 assert(s.length() == 2);
456                 if (!isdigit(s[0]) || !!isdigit(s[0]) || s[0] == '0') {
457                     return SChoice(eUnknown);
458                 }
459                 int id = (s[0] - '0') * 10 + s[1] - '0' + (int)magic.size();
460                 EChoice c = eUnknown;
461                 switch (id % 2) {
462                     case 0: c = eUserCacheEnable; break;
463                     case 1: c = eUserRoot       ; break;
464                     default: assert(0); break;
465                 }
466                 return SChoice(c, id / 2);
467             }
468         }
Ask(void)469         static void Ask(void) { OUTMSG(("magic.len = %d\n", magic.size())); }
470     };
Inquire(const SData & d)471     SChoice Inquire(const SData &d) {
472         OUTMSG(("     vdb-config interactive\n\n  data source\n\n"));
473         OUTMSG(("   NCBI SRA: "));
474         if (d.crnt.remote_enabled) {
475             OUTMSG(("enabled (recommended) (1)\n\n"));
476         }
477         else {
478             OUTMSG(("disabled (not recommended) (1)\n\n"));
479         }
480         if (d.site) {
481         OUTMSG(("   site    : "));
482             if (d.crnt.site_enabled) {
483                 OUTMSG(("enabled (recommended) (2)\n\n"));
484             }
485             else {
486                 OUTMSG(("disabled (not recommended) (2)\n\n"));
487             }
488         }
489         OUTMSG(("\n  local workspaces: local file caching: "));
490         if (d.crnt.cache_disabled) {
491             OUTMSG(("disabled (not recommended) (6)\n"));
492         }
493         else {
494             OUTMSG(("enabled (recommended) (6)\n"));
495         }
496         OUTMSG(("\n  Open Access Data\n"));
497 /*      if (d.crnt.userR.enabled) {
498             OUTMSG(("enabled (recommended) (6)\n"));
499         }
500         else {
501             OUTMSG(("disabled (not recommended) (6)\n"));
502         }*/
503         if (d.crnt.userR.cacheEnabled) {
504             OUTMSG(("cached (recommended) (3)\n"));
505         }
506         else {
507             OUTMSG(("not cached (not recommended) (3)\n"));
508         }
509         OUTMSG(("location: '%s' (4)\n", d.crnt.userR.root.c_str()));
510 
511         uint32_t id = 0;
512         for (CProtectedRepos::TCI it = d.crnt.protectedR.begin();
513             it != d.crnt.protectedR.end(); ++it, ++id)
514         {
515             const SProtectedRepo r((*it).second);
516             OUTMSG(("\n   %s:\n", r.name.c_str()));
517             if (r.description.size() > 0) {
518                 OUTMSG(("  ( %s )\n", r.description.c_str()));
519             }
520             STrinity t(CSymGen::Id2Seq(id));
521 
522 /*          OUTMSG(("%s) ", t.enabled.c_str()));
523             if (r.enabled) {
524                 OUTMSG(("enabled (recommended)\n"));
525             }
526             else {
527                 OUTMSG(("DISABLED (not recommended)\n"));
528             }*/
529 
530             OUTMSG(("%s) ", t.cached.c_str()));
531             if (r.cacheEnabled) {
532                 OUTMSG(("caching is enabled (recommended)\n"));
533             }
534             else {
535                 OUTMSG(("CACHING IS DISABLED (not recommended)\n"));
536             }
537 
538             OUTMSG(("%s) root: %s\n", t.root.c_str(), r.root.c_str()));
539         }
540 
541 //"To print help info      : Enter H and Press <Enter>\n"
542         OUTMSG(("\n\n"
543 "To cancel and exit      : Press <Enter>\n"));
544         if (d.updated) {
545             OUTMSG(("To save changes and exit: Enter Y and Press <Enter>\n"));
546         }
547         OUTMSG((
548 "To update and continue  : Enter corresponding symbol and Press <Enter>\n"));
549         OUTMSG(("\nYour choice > "));
550         char answer = toupper(m_Stdin.Read1());
551         switch (answer) {
552             case '\0': return SChoice(eCancel);
553             case  '1': return SChoice(eRemote);
554             case  'Y': return SChoice(eExit);
555             case  '2': //            case  'O':
556                 return d.site ? SChoice(eSite) : SChoice(eUnknown);
557             case  '6': return SChoice(eGlobalCacheEnable);
558             case  '3': return SChoice(eUserCacheEnable);
559             case  '4': return SChoice(eUserRoot);
560             default  : return CSymGen::Seq2Choice(string(1, answer), id);
561         }
562     }
SetRoot(int32_t id,const string & old)563     bool SetRoot(int32_t id, const string &old) {
564         const string name(id < 0 ? "Public" : "dbGaP");
565         const string prompt("Path to " + name + " Repository");
566         bool flushOld = false, reuseNew = false, ask = true;
567         string root;
568         while (true) {
569             if (ask) {
570                 root = Input(prompt, old);
571                 if (root.size() == 0) {
572                     OUTMSG(("\nRoot path to '%s' repository was not changed\n",
573                         name.c_str()));
574                     return false;
575                 }
576                 OUTMSG(("\nChanging root path to '%s' repository to '%s'\n",
577                     name.c_str(), root.c_str()));
578                 ask = false;
579             }
580             ESetRootState s = m_Config->change_repo_location
581                 (flushOld, root, reuseNew, id);
582             switch (s) {
583                 case eSetRootState_OK:
584                     return true;
585                 case eSetRootState_NewPathEmpty:
586                 case eSetRootState_Error:
587                     assert(0);
588                     return false;
589                 case eSetRootState_MkdirFail:
590                     OUTMSG(("Error: cannot make directory '%s'\n",
591                         root.c_str()));
592                     ask = true;
593                     break;
594                 case eSetRootState_NotChanged:
595                     OUTMSG(("Keeping '%s' path unchanged\n", root.c_str()));
596                     return false;
597                 case eSetRootState_NewNotDir:
598                     OUTMSG(("Error: '%s' exists and is not a directory\n",
599                         root.c_str()));
600                     ask = true;
601                     break;
602                 case eSetRootState_NotUnique:
603                     OUTMSG(("Error: there is another repository in '%s'\n",
604                         root.c_str()));
605                     ask = true;
606                     break;
607                 case eSetRootState_NewDirNotEmpty: {
608                     OUTMSG(("Warning: directory '%s' is not empty\n"
609                         "Would you like to use it? (y/N)? > ", root.c_str()));
610                     char answer = toupper(m_Stdin.Read1());
611                     if (answer == 'Y') {
612                         reuseNew = true;
613                     }
614                     else {
615                         ask = true;
616                     }
617                     break;
618                 }
619                 case eSetRootState_OldNotEmpty: {
620                     OUTMSG(("Warning: your repository '%s' is not empty\n"
621                         "Would you like to clear it? (y/N)? > ", old.c_str()));
622                     char answer = toupper(m_Stdin.Read1());
623                     if (answer == 'Y') {
624                         OUTMSG(("Clearing the old repository...\n"));
625                         flushOld = true;
626                     }
627                     else {
628                         ask = true;
629                     }
630                     break;
631                 }
632             }
633         }
634     }
Configure(void)635     virtual rc_t Configure(void) {
636         assert(m_Config);
637         SData d(m_Config);
638         while (!d.done) {
639             d.crnt.Reload();
640             SChoice answer = Inquire(d);
641             OUTMSG(("\n"));
642             switch (answer.choice) {
643                 case eSite:
644                     if (d.crnt.site_enabled) {
645                         OUTMSG(("WARNING: DISABLING SITE REPOSITORY!!!"));
646                     }
647                     else {
648                         OUTMSG(("Enabling site repository..."));
649                     }
650                     m_Config->set_site_enabled(!d.crnt.site_enabled);
651                     d.updated = true;
652                     break;
653                 case eRemote:
654                     if (d.crnt.remote_enabled) {
655                         OUTMSG(("WARNING: DISABLING REMOTE REPOSITORY!!!"));
656                     }
657                     else {
658                         OUTMSG(("Enabling remote repository..."));
659                     }
660                     m_Config->set_remote_enabled(!d.crnt.remote_enabled);
661                     d.updated = true;
662                     break;
663                 case eGlobalCacheEnable:
664                     if (d.crnt.cache_disabled) {
665                         OUTMSG(("Enabling local file caching..."));
666                     }
667                     else {
668                         OUTMSG(("WARNING: DISABLING LOCAL FILE CACHING!!!"));
669                     }
670                     m_Config->set_global_cache_enabled(d.crnt.cache_disabled);
671                     d.updated = true;
672                     break;
673                 case eUserCacheEnable:
674                     if (answer.id < 0) {
675                         if (d.crnt.userR.cacheEnabled) {
676                             OUTMSG(("WARNING: "
677                                 "DISABLING USER REPOSITORY CACHING!!!"));
678                         }
679                         else {
680                             OUTMSG(("Enabling user repository caching..."));
681                         }
682                         m_Config->set_user_cache_enabled
683                             (!d.crnt.userR.cacheEnabled);
684                         d.updated = true;
685                     }
686                     else {
687                         CProtectedRepos::TCI it
688                             (d.crnt.protectedR.Get(answer.id));
689                         if (it == d.crnt.protectedR.end()) {
690                             OUTMSG(("Unrecognized input. Continuing..."));
691                         }
692                         else {
693                             const SProtectedRepo r((*it).second);
694                             int32_t id = m_Config->get_repo_id(r.name);
695                             if (id < 0) {
696                                 OUTMSG(("ERROR: CANNOT FIND '%s' REPOSITORY",
697                                     r.name.c_str()));
698                             }
699                             else {
700                                 if (r.cacheEnabled) {
701                                     OUTMSG(("WARNING: DISABLING '%s' REPOSITORY"
702                                         " CACHING!!!", r.name.c_str()));
703                                 }
704                                 else {
705                                     OUTMSG(("Enabling '%s' repository "
706                                         "caching...", r.name.c_str()));
707                                 }
708                                 m_Config->set_protected_repo_cached
709                                     (id, !r.cacheEnabled);
710                                 d.updated = true;
711                             }
712                         }
713                     }
714                     break;
715 /*              case eUserEnable:
716                     if (answer.id < 0) {
717                         if (d.crnt.userR.enabled) {
718                             OUTMSG(("WARNING: DISABLING USER REPOSITORY!!!"));
719                         }
720                         else {
721                             OUTMSG(("Enabling user repository..."));
722                         }
723                         m_Config->set_user_enabled(!d.crnt.userR.enabled);
724                         d.updated = true;
725                     }
726                     else {
727                         CProtectedRepos::TCI it
728                             (d.crnt.protectedR.Get(answer.id));
729                         if (it == d.crnt.protectedR.end()) {
730                             OUTMSG(("Unrecognized input. Continuing..."));
731                         }
732                         else {
733                             const SProtectedRepo r((*it).second);
734                             int32_t id = m_Config->get_repo_id(r.name);
735                             if (id < 0) {
736                                 OUTMSG(("ERROR: CANNOT FIND '%s' REPOSITORY",
737                                     r.name.c_str()));
738                             }
739                             else {
740                                 if (r.enabled) {
741                                     OUTMSG(("WARNING: DISABLING '%s' "
742                                         "REPOSITORY!!!", r.name.c_str()));
743                                 }
744                                 else {
745                                     OUTMSG(("Enabling '%s' repository...",
746                                         r.name.c_str()));
747                                 }
748                                 m_Config->set_protected_repo_enabled
749                                     (id, !r.enabled);
750                                 d.updated = true;
751                             }
752                         }
753                     }
754                     break;*/
755                 case eUserRoot: {
756                     string root(d.crnt.userR.root);
757                     if (answer.id >= 0) {
758                         CProtectedRepos::TCI it
759                             (d.crnt.protectedR.Get(answer.id));
760                         if (it == d.crnt.protectedR.end()) {
761                             OUTMSG(("Unrecognized input. Continuing..."));
762                             break;
763                         }
764                         else {
765                             root = (*it).second.root;
766                         }
767                     }
768                     d.updated = SetRoot(answer.id, root);
769                     break;
770                 }
771                 case eExit:
772                     OUTMSG(("Saving..."));
773                     m_Config->commit();
774                     d.done = true;
775                     break;
776                 case eCancel:
777                     OUTMSG(("Canceling...\n\n"));
778                     ProcessCancel(d);
779                     break;
780                 default:
781                     OUTMSG(("Unrecognized input. Continuing..."));
782                     break;
783             }
784             OUTMSG(("\n\n\n"));
785         }
786         return 0;
787     }
788 public:
CTextualConfigurator(void)789     CTextualConfigurator(void) {}
790 };
791 const string CTextualConfigurator::CSymGen::magic("56789ABCDEFGHIJKLMNOPQRSTUVWXZ");
792 
793 class CVisualConfigurator : public CConfigurator
794 {
Configure(void)795     virtual rc_t Configure( void )
796     {
797         if ( m_Config == NULL )
798         {
799             return TODO;
800         }
801         /* here we can switch between:
802              - the old view : run_interactive() just repositories and caching
803              - the new view : run_interactive2() with cloud settings and repositories
804          */
805         return run_interactive2( *m_Config );
806     }
807 };
808 
configure(EConfigMode mode)809 rc_t configure(EConfigMode mode) {
810     rc_t rc = 0;
811     CConfigurator *c = NULL;
812     try {
813         switch (mode) {
814             case eCfgModeDefault:
815                 c = new CConfigurator(true);
816                 break;
817             case eCfgModeTextual:
818                 c = new CTextualConfigurator;
819                 break;
820             default:
821                 c = new CVisualConfigurator;
822                 break;
823         }
824         rc = c->Configure();
825     }
826     catch (rc_t re) {
827         if (rc == 0) {
828             rc = re;
829         }
830     }
831     catch (...) {
832         if (rc == 0) {
833             rc = TODO;
834         }
835     }
836     delete c;
837     return rc;
838 }
839 
840