mirror of
https://github.com/levinsv/pgadmin3.git
synced 2026-05-15 06:05:49 -06:00
Выполнен переход на новые библтотеки. Устранены проблемы совместимости. Множество мелких правок.
625 lines
11 KiB
C++
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;
|
|
}
|