pgadmin3/utils/pgconfig.cpp
lsv 2734a746a9 Migration to wxWidgets 3.1.5
Выполнен переход на новые библтотеки. Устранены проблемы совместимости.
Множество мелких правок.
2021-05-21 11:09:20 +05:00

625 lines
11 KiB
C++

//////////////////////////////////////////////////////////////////////////
//
// pgAdmin III - PostgreSQL Tools
//
// Copyright (C) 2002 - 2016, The pgAdmin Development Team
// This software is released under the PostgreSQL Licence
//
// pgconfig.cpp - backend configuration classes
//
//////////////////////////////////////////////////////////////////////////
#include "pgAdmin3.h"
#include <wx/textbuf.h>
#include "utils/pgconfig.h"
#include "db/pgConn.h"
#include "db/pgSet.h"
#include "utils/utffile.h"
#define DEFAULT_COMMENT_INDEX wxT("\t\t# ")
int FindToken(const wxString &str, const wxChar **list)
{
int index;
for (index = 0 ; list[index] ; index++)
{
if (list[index] == str)
return index;
}
return -1;
}
const wxChar *pgConfigTypeStrings[] =
{
wxT("bool"),
wxT("integer"),
wxT("real"),
wxT("string"),
0
};
void pgSettingItem::SetType(const wxString &str)
{
int index = FindToken(str, pgConfigTypeStrings);
if (index < 0)
type = PGC_STRING;
else
type = (pgConfigType)index;
}
const wxChar *pgConfigContextStrings[] =
{
wxT("internal"),
wxT("postmaster"),
wxT("sighup"),
wxT("backend"),
wxT("superuser"),
wxT("userlimit"),
wxT("user"),
0
};
void pgSettingItem::SetContext(const wxString &str)
{
int index = FindToken(str, pgConfigContextStrings);
if (index < 0)
context = PGC_INTERNAL;
else
context = (pgConfigContext)index;
}
const wxChar *pgConfigSourceStrings[] =
{
wxT("default"),
wxT("environment variable"),
wxT("configuration file"),
wxT("command line"),
wxT("unprivileged"),
wxT("database"),
wxT("user"),
wxT("client"),
wxT("override"),
wxT("interactive"),
wxT("test"),
wxT("session"),
0
};
void pgSettingItem::SetSource(const wxString &str)
{
int index = FindToken(str, pgConfigSourceStrings);
if (index < 0)
source = PGC_UNKNOWNSOURCE;
else
source = (pgConfigSource)index;
}
wxString pgSettingItem::GetActiveValue()
{
if (newLine)
{
if (!newLine->isComment)
return newLine->value;
}
else if (orgLine)
{
if (!orgLine->isComment)
return orgLine->value;
}
return value;
}
pgConfigLine::pgConfigLine(pgConfigLine *line)
{
item = line->item;
value = line->value;
comment = line->comment;
isComment = line->isComment;
}
bool pgConfigLine::Differs(pgConfigLine *line)
{
return value != line->value || comment != line->comment || isComment != line->isComment;
}
wxString pgConfigLine::GetNewText()
{
wxString quote;
wxString newLine;
if (item->type == pgSettingItem::PGC_STRING)
{
if (value.Find('\'') >= 0)
quote = wxT("\"");
else
quote = wxT("'");
}
if (isComment)
newLine = wxT("# ");
newLine += item->name + wxT(" = ")
+ quote + value + quote;
if (!comment.IsEmpty())
{
if (item->orgLine && item->orgLine->commentIndent.Find('#') >= 0)
newLine += item->orgLine->commentIndent;
else
newLine += DEFAULT_COMMENT_INDEX;
newLine += comment;
}
return newLine;
}
pgConfigOrgLine::pgConfigOrgLine(pgConfigLine *line) : pgConfigLine(line)
{
text = line->GetNewText();
if (isComment)
commentIndent = DEFAULT_COMMENT_INDEX;
}
wxString pgConfigOrgLine::GetNewText()
{
if (!item || !item->newLine)
return text;
return item->newLine->GetNewText();
}
////////////////////////////////////////////////
pgSettingFileReader::pgSettingFileReader(bool localized)
{
wxUtfFile file;
wxString path = i18nPath + wxT("/") + settings->GetCanonicalLanguageName() + wxT("/pg_settings.csv");
if (localized && wxFile::Exists(path))
file.Open(path);
else
file.Open(i18nPath + wxT("/pg_settings.csv"));
if (file.IsOpened())
{
file.Read(buffer);
file.Close();
}
if (!buffer.IsEmpty())
{
buffer = wxTextBuffer::Translate(buffer, wxTextFileType_Unix);
columnNames = buffer.BeforeFirst('\n');
bp = const_cast<wxChar *>((const wxChar *)buffer + columnNames.Length() + 1);
}
}
pgSettingFileReader::~pgSettingFileReader()
{
}
pgSettingItem *pgSettingFileReader::GetNextItem()
{
if (!bp || !*bp || *bp == '\n')
return 0;
pgSettingItem *item = new pgSettingItem;
wxStringTokenizer tk(columnNames, wxT(";"));
wxString column = tk.GetNextToken();
wxChar *c = bp;
while (*c)
{
wxString value;
if (*c++ != '"')
{
// invalid syntax
return 0;
}
while (*c && *c != '\n')
{
if (*c == '"')
{
if (c[1] == '"')
c++;
else
break;
}
value.Append(*c++);
}
if (*c++ != '"')
{
// format error
return 0;
}
if (column == wxT("name") || column == wxT("\"name\""))
item->name = value.Lower();
else if (column == wxT("category") || column == wxT("\"category\""))
item->category = value;
else if (column == wxT("short_desc") || column == wxT("\"short_desc\""))
item->short_desc = value;
else if (column == wxT("extra_desc") || column == wxT("\"extra_desc\""))
item->extra_desc = value;
else if (column == wxT("min_val") || column == wxT("\"min_val\""))
item->min_val = value;
else if (column == wxT("max_val") || column == wxT("\"max_val\""))
item->max_val = value;
else if (column == wxT("context") || column == wxT("\"context\""))
item->SetContext(value);
else if (column == wxT("vartype") || column == wxT("\"vartype\""))
item->SetType(value);
column = tk.GetNextToken();
if (*c == '\n')
{
bp = c + 1;
break;
}
else if (!*c)
{
bp = 0;
break;
}
else if (*c == ';')
c++;
else
{
// invalid syntax
return 0;
}
}
return item;
}
pgSettingDbReader::pgSettingDbReader(pgConn *conn)
{
set = conn->ExecuteSet(wxT("SELECT name, setting, source, category, short_desc, extra_desc, context, vartype, min_val, max_val FROM pg_settings ORDER BY name"));
}
pgSettingDbReader::~pgSettingDbReader()
{
if (set)
delete set;
}
pgSettingItem *pgSettingDbReader::GetNextItem()
{
if (set->Eof())
return 0;
pgSettingItem *item = new pgSettingItem;
item->name = set->GetVal(wxT("name")).Lower();
item->category = set->GetVal(wxT("category"));
item->short_desc = set->GetVal(wxT("short_desc"));
item->extra_desc = set->GetVal(wxT("extra_desc"));
item->min_val = set->GetVal(wxT("min_val"));
item->max_val = set->GetVal(wxT("max_val"));
item->SetContext(set->GetVal(wxT("context")));
item->SetType(set->GetVal(wxT("vartype")));
item->SetSource(set->GetVal(wxT("source")));
item->value = set->GetVal(wxT("setting"));
set->MoveNext();
return item;
}
///////////////////////////////////////////////////////
// must match enum pgHbaConnectType!!!
const wxChar *pgHbaConnectTypeStrings[] =
{
wxT("local"),
wxT("host"),
wxT("hostssl"),
wxT("hostnossl"),
0
};
// must match enum pgHbaMethod!!!
const wxChar* pgHbaMethodStrings[] =
{
wxT("trust"),
wxT("reject"),
wxT("md5"),
wxT("crypt"),
wxT("password"),
wxT("krb4"),
wxT("krb5"),
wxT("ident"),
wxT("pam"),
wxT("ldap"),
wxT("gss"),
wxT("sspi"),
wxT("cert"),
wxT("peer"),
wxT("radius"),
wxT("scram-sha-256"),
0
};
bool IsSpaceChar(wxChar c, const wxChar *spaceChars = wxT("\t "))
{
return wxStrchr(spaceChars, c) != NULL;
}
void SkipSpace(const wxChar *&ptr, const wxChar *spaceChars = wxT("\t "))
{
while (*ptr && IsSpaceChar(*ptr))
ptr++;
}
void SkipNonspace(const wxChar *&ptr, const wxChar *spaceChars = wxT("\t "))
{
while (*ptr && !IsSpaceChar(*ptr))
ptr++;
}
pgHbaConfigLine::pgHbaConfigLine(const wxString &line)
{
item = -1;
isValid = false;
isComment = true;
connectType = PGC_INVALIDCONF;
method = PGC_INVALIDMETHOD;
Init(line);
}
void pgHbaConfigLine::Init(const wxString &line)
{
isValid = false;
connectType = PGC_INVALIDCONF;
changed = false;
if (line.IsEmpty())
return;
text = line;
const wxChar *p0 = line.c_str();
if (*p0 == '#')
{
isComment = true;
p0++;
SkipSpace(p0);
}
else
isComment = false;
const wxChar *p1 = p0;
SkipNonspace(p1);
wxString str = line.Mid(p0 - line.c_str(), p1 - p0);
int i = FindToken(str, pgHbaConnectTypeStrings);
if (i >= 0)
connectType = (pgHbaConnectType)i;
else
{
connectType = PGC_INVALIDCONF;
return;
}
SkipSpace(p1);
const wxChar *p2 = p1;
bool quoted = false;
while (*p2)
{
if (!quoted && IsSpaceChar(*p2))
break;
if (*p2 == '"')
quoted = !quoted;
p2++;
}
database = line.Mid(p1 - line.c_str(), p2 - p1);
SkipSpace(p2);
const wxChar *p3 = p2;
quoted = false;
while (*p3)
{
if (!quoted && IsSpaceChar(*p3))
break;
if (*p3 == '"')
quoted = !quoted;
p3++;
}
user = line.Mid(p2 - line.c_str(), p3 - p2);
SkipSpace(p3);
const wxChar *p4 = p3;
if (connectType == PGC_LOCAL)
{
// no ip address
}
else
{
bool hasCidr = false;
while (*p4 && !IsSpaceChar(*p4))
{
if (*p4 == '/')
hasCidr = true;
p4++;
}
if (!hasCidr)
{
//SkipSpace(p4);
//SkipNonspace(p4);
}
ipaddress = line.Mid(p3 - line.c_str(), p4 - p3);
SkipSpace(p4);
}
const wxChar *p5 = p4;
SkipNonspace(p5);
str = line.Mid(p4 - line.c_str(), p5 - p4);
i = FindToken(str, pgHbaMethodStrings);
if (i >= 0)
method = (pgHbaMethod)i;
else
{
return;
}
SkipSpace(p5);
option = p5;
isValid = true;
}
const wxChar *pgHbaConfigLine::GetConnectType()
{
if (connectType >= 0 && connectType < PGC_INVALIDCONF)
return pgHbaConnectTypeStrings[connectType];
return 0;
}
const wxChar *pgHbaConfigLine::GetMethod()
{
if (method >= 0 && method < PGC_INVALIDMETHOD)
return pgHbaMethodStrings[method];
return 0;
}
wxString pgHbaConfigLine::GetText()
{
if (!changed)
return text;
wxString str;
wxString tabspace = wxT("\t ");
if (isComment)
str = wxT("# ");
str += GetConnectType()
+ tabspace + database
+ tabspace + user;
if (connectType != PGC_LOCAL)
str += tabspace + ipaddress;
str += tabspace + GetMethod();
if (method >= PGC_IDENT && !option.IsEmpty())
str += tabspace + option;
return str;
}
////////////////////////////////////////////////
pgPassConfigLine::pgPassConfigLine(const wxString &line)
{
item = -1;
Init(line);
}
void pgPassConfigLine::Init(const wxString &line)
{
text = line;
if (line.IsEmpty())
return;
isComment = line.StartsWith(wxT("#"));
wxString tmpLine = line;
// De-escape backslash "\"
tmpLine.Replace(wxT("\\\\"), wxT("\\"));
int iVarCount = 0;
wxStringTokenizer tok(isComment ? tmpLine.Mid(1) : tmpLine, wxT(":"));
while(tok.HasMoreTokens())
{
wxString val = tok.GetNextToken();
if (!val.IsEmpty())
{
/* if last charecter of the token is backslash "\" then it means
that it is used to escape ":" so we need to add the next token.
*/
while(val.Last() == wxT('\\'))
{
val.RemoveLast();
val = val + wxT(":") + tok.GetNextToken();
}
iVarCount++;
switch(iVarCount)
{
case 1: // hostname
hostname = val;
break;
case 2: // port
port = val;
break;
case 3: // database
database = val;
break;
case 4: //username
username = val;
break;
case 5: // password
password = val;
break;
}
}
}
}
wxString pgPassConfigLine::GetText()
{
return (isComment ? wxT("#") : wxT("")) +
hostname + wxT(":") +
port + wxT(":") +
database + wxT(":") +
username + wxT(":") +
password;
}