1 //////////////////////////////////////////////////////////////////////////
2 //
3 // pgAdmin III - PostgreSQL Tools
4 //
5 // Copyright (C) 2002 - 2016, The pgAdmin Development Team
6 // This software is released under the PostgreSQL Licence
7 //
8 // dlgSelectDatabase.cpp - Database Selection for connection string
9 //
10 //////////////////////////////////////////////////////////////////////////
11 
12 // App headers
13 #include "pgAdmin3.h"
14 
15 #include <wx/regex.h>
16 
17 #include "utils/misc.h"
18 #include "dlg/dlgSelectDatabase.h"
19 #include "schema/pgServer.h"
20 #include "schema/pgDatabase.h"
21 #include "frm/frmMain.h"
22 
23 extern frmMain *winMain;
24 wxWindowID TCSERVER_ID = ::wxNewId();
25 
BEGIN_EVENT_TABLE(dlgSelectDatabase,wxDialog)26 BEGIN_EVENT_TABLE(dlgSelectDatabase, wxDialog)
27 	EVT_TREE_ITEM_ACTIVATED (TCSERVER_ID, dlgSelectDatabase::OnSelActivate)
28 	EVT_TREE_SEL_CHANGED    (TCSERVER_ID, dlgSelectDatabase::OnSelect)
29 END_EVENT_TABLE()
30 
31 
32 dlgSelectDatabase::dlgSelectDatabase(wxWindow *parent, int id, const wxPoint &pos, const wxSize &size, long style):
33 	wxDialog(parent, id, wxT("Select Database"), pos, size, wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER)
34 {
35 
36 #ifdef __WXMSW__
37 	SetWindowStyleFlag(GetWindowStyleFlag() & ~wxMAXIMIZE_BOX);
38 #endif
39 
40 	wxBoxSizer *mainSizer = new wxBoxSizer(wxVERTICAL);
41 
42 	tcServers = new wxTreeCtrl(this, TCSERVER_ID);
43 	mainSizer->Add(tcServers, 1, wxEXPAND, 0);
44 
45 	wxBoxSizer *bottomSizer = new wxBoxSizer(wxHORIZONTAL);
46 
47 	bottomSizer->AddStretchSpacer();
48 
49 	wxButton *btnOk = new wxButton(this, wxID_OK, wxT("&OK"));
50 	bottomSizer->Add(btnOk);
51 
52 	wxButton *btnCANCEL = new wxButton(this, wxID_CANCEL, wxT("&Cancel"));
53 	bottomSizer->Add(btnCANCEL, 0, wxLEFT, 10);
54 
55 	mainSizer->Add(bottomSizer, 0, wxALL | wxALIGN_RIGHT, 5);
56 	SetSizer(mainSizer);
57 
58 	SetSize(wxSize(200, 240));
59 
60 	Layout();
61 	Centre();
62 
63 	Initialize();
64 }
65 
Initialize()66 void dlgSelectDatabase::Initialize()
67 {
68 	// Add the root node
69 	pgServerCollection *serversObj = new pgServerCollection(serverFactory.GetCollectionFactory());
70 	wxTreeItemId rootItemID = tcServers->AddRoot(wxGetTranslation(serverFactory.GetCollectionFactory()->GetTypeName()),
71 	                          serversObj->GetIconId(), -1, serversObj);
72 	tcServers->SetImageList(imageList);
73 
74 	ctlTree *browser = winMain->GetBrowser();
75 
76 	wxTreeItemId servers = tcServers->GetRootItem();
77 
78 	wxTreeItemIdValue foldercookie;
79 	wxTreeItemId folderitem = browser->GetFirstChild(browser->GetRootItem(), foldercookie);
80 	while (folderitem)
81 	{
82 		if (browser->ItemHasChildren(folderitem))
83 		{
84 			wxCookieType cookie;
85 			wxTreeItemId serverItem = browser->GetFirstChild(folderitem, cookie);
86 
87 			wxTreeItemId tcGroupsItem = tcServers->AppendItem(rootItemID, browser->GetItemText(folderitem), serversObj->GetIconId());
88 			while (serverItem)
89 			{
90 				pgServer *server = (pgServer *)browser->GetObject(serverItem);
91 
92 				if (server && server->IsCreatedBy(serverFactory))
93 				{
94 					dlgSelDBNode *cnInfo = new dlgSelDBNode(server);
95 					wxTreeItemId itm = tcServers->AppendItem(tcGroupsItem, server->GetFullName(), server->GetIconId(), -1, cnInfo);
96 
97 					pgConn *conn = server->connection();
98 
99 					if (conn && conn->IsAlive())
100 					{
101 						pgSet *res = conn->ExecuteSet(wxT("SELECT datname, datallowconn FROM pg_catalog.pg_database"));
102 						if (res)
103 						{
104 							while (!res->Eof())
105 							{
106 								if (res->GetBool(wxT("datallowconn")))
107 								{
108 									dlgSelDBNode *cnInfo = new dlgSelDBNode(server, res->GetVal(wxT("datname")));
109 									tcServers->AppendItem(itm, cnInfo->getDatabase(), databaseFactory.GetIconId(), -1, cnInfo);
110 								}
111 
112 								res->MoveNext();
113 							}
114 							delete res;
115 						}
116 					}
117 				}
118 
119 				serverItem = browser->GetNextChild(folderitem, cookie);
120 			}
121 			folderitem = browser->GetNextChild(browser->GetRootItem(), foldercookie);
122 		}
123 	}
124 
125 	tcServers->Expand(servers);
126 	selectedConn = NULL;
127 }
128 
OnSelect(wxTreeEvent & ev)129 void dlgSelectDatabase::OnSelect(wxTreeEvent &ev)
130 {
131 	wxTreeItemId sel = tcServers->GetSelection();
132 
133 	if (sel.IsOk() && sel != tcServers->GetRootItem() && tcServers->GetItemParent(sel) != tcServers->GetRootItem())
134 	{
135 		selectedConn = (dlgSelDBNode *)tcServers->GetItemData(sel);
136 	}
137 	else
138 	{
139 		selectedConn = NULL;
140 	}
141 }
142 
OnSelActivate(wxTreeEvent & ev)143 void dlgSelectDatabase::OnSelActivate(wxTreeEvent &ev)
144 {
145 	wxTreeItemId selID = tcServers->GetSelection();
146 
147 	if (selID.IsOk() && selID != tcServers->GetRootItem())
148 	{
149 		selectedConn = (dlgSelDBNode *)tcServers->GetItemData(selID);
150 
151 		if (selectedConn->dbname.IsEmpty() && tcServers->GetChildrenCount(selID, false) == 0)
152 		{
153 			winMain->ReconnectServer(selectedConn->server, true);
154 
155 			pgConn *conn = selectedConn->server->connection();
156 			if (conn && conn->GetStatus() == PGCONN_OK)
157 			{
158 				pgSet *res = conn->ExecuteSet(wxT("SELECT datname, datallowconn FROM pg_catalog.pg_database"));
159 				if (res)
160 				{
161 					while (!res->Eof())
162 					{
163 						if (res->GetBool(wxT("datallowconn")))
164 						{
165 							dlgSelDBNode *cnInfo = new dlgSelDBNode(selectedConn->server, res->GetVal(wxT("datname")));
166 							tcServers->AppendItem(selID, cnInfo->getDatabase(), databaseFactory.GetIconId(), -1, cnInfo);
167 						}
168 
169 						res->MoveNext();
170 					}
171 				}
172 				delete res;
173 			}
174 			tcServers->Expand(selID);
175 		}
176 	}
177 	else
178 	{
179 		selectedConn = NULL;
180 	}
181 }
182 
183 
getConnInfo()184 wxString dlgSelectDatabase::getConnInfo()
185 {
186 	if (selectedConn)
187 	{
188 		return selectedConn->getConnectionString();
189 	}
190 
191 	return wxEmptyString;
192 }
193 
getValidConnectionString(wxString connStr,wxString & resultStr)194 bool dlgSelectDatabase::getValidConnectionString(wxString connStr, wxString &resultStr)
195 {
196 	wxString      user;
197 	wxString      dbname;
198 	wxString      host;
199 	unsigned long port = 0;
200 	wxString      password;
201 	unsigned long connection_timeout = 0;
202 
203 	wxRegEx propertyExp;
204 
205 	// Remove white-spaces ahead the '="
206 	bool res = propertyExp.Compile(wxT("(([ ]*[\t]*)+)="));
207 	propertyExp.ReplaceAll(&connStr, wxT("="));
208 
209 	// Remove white-spaces after the '="
210 	res = propertyExp.Compile(wxT("=(([ ]*[\t]*)+)"));
211 	propertyExp.ReplaceAll(&connStr, wxT("="));
212 	wxArrayString tokens = wxStringTokenize(connStr, wxT("\t \n\r"));
213 
214 	unsigned int index = 0;
215 	while (index < tokens.Count())
216 	{
217 		wxString prop, value;
218 
219 		// Find pairs
220 		//   i.e. user=xxx
221 		//        password=xxx
222 		wxArrayString pairs = wxStringTokenize(tokens[index++], wxT("="));
223 
224 		// pair must exist in pair=value format
225 		if (pairs.GetCount() != 2)
226 			return false;
227 
228 		prop = pairs[0];
229 		value = pairs[1];
230 
231 		if (prop.CmpNoCase(wxT("user")) == 0)
232 			user = value;
233 		else if (prop.CmpNoCase(wxT("host")) == 0 || prop.CmpNoCase(wxT("hostAddr")) == 0)
234 			host = value;
235 		else if (prop.CmpNoCase(wxT("port")) == 0)
236 		{
237 			if (!value.ToULong(&port))
238 				// port must be an unsigned integer
239 				return false;
240 		}
241 		else if (prop.CmpNoCase(wxT("password")) == 0)
242 			password = value;
243 		else if (prop.CmpNoCase(wxT("connection_timeout")) == 0)
244 		{
245 			if (!value.ToULong(&connection_timeout))
246 				// connection timeout must be an unsigned interger
247 				return false;
248 		}
249 		else if (prop.CmpNoCase(wxT("dbname")) == 0)
250 			dbname = value;
251 		else
252 			// Not valid property found
253 			return false;
254 	}
255 
256 	if (dbname.IsEmpty())
257 		return false;
258 
259 	if (!user.IsEmpty())
260 		resultStr = wxT("user=") + user + wxT(" ");
261 
262 	if (!host.IsEmpty())
263 	{
264 		resultStr += wxT("host=") + host + wxT(" ");
265 	}
266 
267 
268 	if (!resultStr.IsEmpty())
269 		resultStr += wxT(" ");
270 	resultStr += wxT("dbname=") + dbname + wxT(" ");
271 
272 	if (port != 0)
273 	{
274 		wxString portStr;
275 		portStr.Printf(wxT("port=%ld"), port);
276 		resultStr += portStr + wxT(" ");
277 	}
278 
279 
280 	if (connection_timeout != 0)
281 	{
282 		wxString strConnTimeOut;
283 		strConnTimeOut.Printf(wxT("connection_timeout=%ld"), connection_timeout);
284 		resultStr += strConnTimeOut + wxT(" ");
285 	}
286 
287 	if (!password.IsEmpty())
288 	{
289 		resultStr += wxT("password=") + password + wxT(" ");
290 	}
291 
292 	resultStr = resultStr.Trim();
293 
294 	return true;
295 }
296 
dlgSelDBNode(pgServer * _server,const wxString & _dbname)297 dlgSelDBNode::dlgSelDBNode (pgServer *_server, const wxString &_dbname)
298 {
299 	server = _server;
300 	dbname = _dbname;
301 }
302 
getConnectionString()303 wxString dlgSelDBNode::getConnectionString()
304 {
305 	if (dbname.IsEmpty())
306 		return wxEmptyString;
307 
308 	pgConn *conn = server->connection();
309 	wxString connStr;
310 
311 	if (conn && conn->GetStatus() == PGCONN_OK)
312 	{
313 		connStr += wxT("user=") + conn->GetUser() + wxT(" ");
314 		connStr += wxT("host=") + conn->GetHostName() + wxT(" ");
315 
316 		wxString port;
317 		port.Printf(wxT("port=%d "), conn->GetPort());
318 		connStr += port;
319 
320 		connStr += wxT("dbname=") + dbname;
321 	}
322 
323 	return connStr;
324 }
325 
326