1 /*  $Id: util_misc.cpp 530021 2017-03-09 19:06:46Z ucko $
2  * ===========================================================================
3  *
4  *                            PUBLIC DOMAIN NOTICE
5  *               National Center for Biotechnology Information
6  *
7  *  This software/database is a "United States Government Work" under the
8  *  terms of the United States Copyright Act.  It was written as part of
9  *  the author's official duties as a United States Government employee and
10  *  thus cannot be copyrighted.  This software/database is freely available
11  *  to the public for use. The National Library of Medicine and the U.S.
12  *  Government have not placed any restriction on its use or reproduction.
13  *
14  *  Although all reasonable efforts have been taken to ensure the accuracy
15  *  and reliability of the software and data, the NLM and the U.S.
16  *  Government do not and cannot warrant the performance or results that
17  *  may be obtained by using this software or data. The NLM and the U.S.
18  *  Government disclaim all warranties, express or implied, including
19  *  warranties of performance, merchantability or fitness for any particular
20  *  purpose.
21  *
22  *  Please cite the author in any work or product based on this material.
23  *
24  * ===========================================================================
25  *
26  * Author:  Sergey Satskiy,
27  *          Anton Lavrentiev (providing line by line advices of how it must be
28  *          implemented)
29  *
30  */
31 
32 #include <ncbi_pch.hpp>
33 #include <util/util_misc.hpp>
34 #include <corelib/ncbi_param.hpp>
35 #include <corelib/ncbifile.hpp>
36 
37 #if defined(NCBI_OS_UNIX)
38 #  include <unistd.h>
39 #if defined(HAVE_READPASSPHRASE)
40 #  include <readpassphrase.h>
41 #endif
42 #elif defined(NCBI_OS_MSWIN)
43 #  include <conio.h>
44 #else
45 #  error  "Unsuported platform"
46 #endif
47 
48 
49 BEGIN_NCBI_SCOPE
50 
51 
GetErrCodeString(void) const52 const char* CGetPasswordFromConsoleException::GetErrCodeString(void) const
53 {
54     switch (GetErrCode()) {
55     case eGetPassError:         return "eGetPassError";
56     case eKeyboardInterrupt:    return "eKeyboardInterrupt";
57     default:                    return CException::GetErrCodeString();
58     }
59 }
60 
61 
g_GetPasswordFromConsole(const string & prompt)62 string g_GetPasswordFromConsole(const string& prompt)
63 {
64     string      password;
65     CMutex      lock;
66     CMutexGuard guard(lock);
67 
68 #if defined(NCBI_OS_UNIX)
69     // UNIX implementation
70 
71 #if defined(HAVE_READPASSPHRASE)
72 
73     char password_buffer[1024];
74     char* raw_password = readpassphrase(prompt.c_str(), password_buffer,
75                                         sizeof(password_buffer),
76                                         RPP_ECHO_OFF | RPP_REQUIRE_TTY);
77 
78 #elif defined(HAVE_GETPASSPHRASE)
79 
80     char* raw_password = getpassphrase(prompt.c_str());
81 
82 #elif defined(HAVE_GETPASS)
83 
84     char* raw_password = getpass(prompt.c_str());
85 
86 #else
87 #  error "Unsupported Unix platform; the getpass, getpassphrase, and readpassphrase functions are all absent"
88 #endif
89 
90     if (!raw_password)
91         NCBI_THROW
92             (CGetPasswordFromConsoleException, eGetPassError,
93              "g_GetPasswordFromConsole(): error getting password");
94     password = string(raw_password);
95 
96 #elif defined(NCBI_OS_MSWIN)
97     // Windows implementation
98 
99     for (size_t index = 0;  index < prompt.size();  ++index) {
100         _putch(prompt[index]);
101     }
102 
103     for (;;) {
104         char ch;
105         ch = _getch();
106         if (ch == '\r'  ||  ch == '\n')
107             break;
108         if (ch == '\003')
109             NCBI_THROW(CGetPasswordFromConsoleException, eKeyboardInterrupt,
110                        "g_GetPasswordFromConsole(): keyboard interrupt");
111         if (ch == '\b') {
112             if ( !password.empty() ) {
113                 password.resize(password.size() - 1);
114             }
115         }
116         else
117             password.append(1, ch);
118     }
119 
120     _putch('\r');
121     _putch('\n');
122 #endif
123 
124     return password;
125 }
126 
127 
128 NCBI_PARAM_DECL  (string, NCBI, DataPath);
129 NCBI_PARAM_DEF_EX(string, NCBI, DataPath, "", 0, NCBI_DATA_PATH);
130 typedef NCBI_PARAM_TYPE(NCBI, DataPath) TNCBIDataPath;
131 
132 NCBI_PARAM_DECL(string, NCBI, Data);
133 NCBI_PARAM_DEF (string, NCBI, Data, "");
134 typedef NCBI_PARAM_TYPE(NCBI, Data) TNCBIDataDir;
135 
136 typedef vector<string> TIgnoreDataFiles;
137 static CSafeStatic<TIgnoreDataFiles> s_IgnoredDataFiles;
138 
g_FindDataFile(const CTempString & name,CDirEntry::EType type)139 string g_FindDataFile(const CTempString& name, CDirEntry::EType type)
140 {
141 #ifdef NCBI_OS_MSWIN
142     static const char* kDelim = ";";
143 #else
144     static const char* kDelim = ":";
145 #endif
146 
147     if ( !s_IgnoredDataFiles->empty()
148         &&  CDirEntry::MatchesMask(name, *s_IgnoredDataFiles) ) {
149         return kEmptyStr;
150     }
151 
152     list<string> dirs;
153 
154     if (CDirEntry::IsAbsolutePath(name)) {
155         dirs.push_back(kEmptyStr);
156     } else {
157         TNCBIDataPath path;
158         TNCBIDataDir dir;
159 
160         if ( !path.Get().empty() ) {
161             NStr::Split(path.Get(), kDelim, dirs,
162                     NStr::fSplit_MergeDelimiters | NStr::fSplit_Truncate);
163         }
164         if ( !dir.Get().empty() ) {
165             dirs.push_back(dir.Get());
166         }
167     }
168 
169     CDirEntry candidate;
170     EFollowLinks fl = (type == CDirEntry::eLink) ? eIgnoreLinks : eFollowLinks;
171     ITERATE (list<string>, dir, dirs) {
172         candidate.Reset(CDirEntry::MakePath(*dir, name));
173         if (candidate.Exists() &&  candidate.GetType(fl) == type) {
174             return candidate.GetPath();
175         }
176     }
177 
178     return kEmptyStr; // not found
179 }
180 
181 
g_IgnoreDataFile(const string & pattern,bool do_ignore)182 void g_IgnoreDataFile(const string& pattern, bool do_ignore)
183 {
184     vector<string>& idf = *s_IgnoredDataFiles;
185     if (do_ignore) {
186         idf.push_back(pattern);
187     } else {
188         idf.erase(remove(idf.begin(), idf.end(), pattern), idf.end());
189     }
190 }
191 
192 
g_IsDataFileOld(const CTempString & path,const CTempString & id_line)193 bool g_IsDataFileOld(const CTempString& path, const CTempString& id_line)
194 {
195     // $Id: FILENAME REVISION DATE TIME ...
196     SIZE_TYPE pos = id_line.find("$Id: ");
197     if (pos == NPOS) {
198         return false;
199     }
200     pos = id_line.find(' ', pos + 5); // skip filename
201     if (pos == NPOS) {
202         return false;
203     }
204     pos = id_line.find(' ', pos + 1); // skip revision
205     if (pos == NPOS) {
206         return false;
207     }
208     SIZE_TYPE end = id_line.find(' ', ++pos);
209     if (end == NPOS) {
210         return false;
211     }
212     end = id_line.find(' ', end + 1); // got date, now want time too
213     if (end == NPOS) {
214         return false;
215     }
216     CTempString builtin_timestamp_str = id_line.substr(pos, end - pos);
217     CTime       builtin_timestamp(builtin_timestamp_str, "Y-M-D h:m:sZ");
218     CTime       file_timestamp;
219     CFile(path).GetTime(&file_timestamp);
220     return file_timestamp < builtin_timestamp;
221 }
222 
223 END_NCBI_SCOPE
224 
225