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 // pgServer.cpp - PostgreSQL Server
9 //
10 //////////////////////////////////////////////////////////////////////////
11 
12 #include "pgAdmin3.h"
13 
14 // wxWindows headers
15 #include <wx/wx.h>
16 #include <wx/busyinfo.h>
17 #include <wx/dir.h>
18 #include <wx/fileconf.h>
19 #include <wx/wfstream.h>
20 
21 // App headers
22 #include "ctl/ctlMenuToolbar.h"
23 #include "frm/menu.h"
24 #include "utils/misc.h"
25 #include "frm/frmMain.h"
26 #include "frm/frmHint.h"
27 #include "dlg/dlgConnect.h"
28 #include "schema/pgDatabase.h"
29 #include "schema/pgTablespace.h"
30 #include "schema/pgGroup.h"
31 #include "schema/pgUser.h"
32 #include "schema/pgRole.h"
33 #include "schema/gpResQueue.h"
34 #include "agent/pgaJob.h"
35 #include "utils/utffile.h"
36 #include "utils/pgfeatures.h"
37 #include "utils/registry.h"
38 #include "frm/frmReport.h"
39 #include "dlg/dlgServer.h"
40 #include "schema/edbResourceGroup.h"
41 
42 #if defined(HAVE_OPENSSL_CRYPTO) || defined(HAVE_GCRYPT)
43 #include "utils/sshTunnel.h"
44 #endif
45 
46 #define DEFAULT_PG_DATABASE wxT("postgres")
47 
pgServer(const wxString & newName,const wxString & newHostAddr,const wxString & newDescription,const wxString & newService,const wxString & newDatabase,const wxString & newUsername,int newPort,bool _storePwd,const wxString & newRolename,bool _restore,int _ssl,const wxString & _colour,const wxString & _group,bool _sshTunnel,const wxString & newTunnelHost,const wxString & newTunnelUserName,bool _authModePwd,const wxString & newTunnelPassword,const wxString & newPublicKey,const wxString & newIdentity,const int & sshPort)48 pgServer::pgServer(const wxString &newName, const wxString &newHostAddr, const wxString &newDescription, const wxString &newService,
49                    const wxString &newDatabase, const wxString &newUsername, int newPort, bool _storePwd, const wxString &newRolename, bool _restore,
50                    int _ssl, const wxString &_colour, const wxString &_group, bool _sshTunnel, const wxString &newTunnelHost, const wxString &newTunnelUserName,
51                    bool _authModePwd, const wxString &newTunnelPassword, const wxString &newPublicKey, const wxString &newIdentity, const int &sshPort)
52 	: pgObject(serverFactory, newName)
53 {
54 	description = newDescription;
55 	hostaddr = newHostAddr;
56 	service = newService;
57 	database = newDatabase;
58 	username = newUsername;
59 	port = newPort;
60 	ssl = _ssl;
61 	colour = _colour;
62 	group = _group;
63 
64 	serverIndex = 0;
65 
66 	connected = false;
67 	lastSystemOID = 0;
68 
69 	conn = NULL;
70 	passwordValid = true;
71 	storePwd = _storePwd;
72 	rolename = newRolename;
73 	restore = _restore;
74 	superUser = false;
75 	createPrivilege = false;
76 	sshTunnel = _sshTunnel;
77 
78 #if defined(HAVE_OPENSSL_CRYPTO) || defined(HAVE_GCRYPT)
79 	// SSH Tunnel
80 	tunnelObj = NULL;
81 	tunnelHost = newTunnelHost;
82 	tunnelUserName = newTunnelUserName;
83 	authModePwd = _authModePwd;
84 	tunnelPassword = newTunnelPassword;
85 	publicKeyFile = newPublicKey;
86 	identityFile = newIdentity;
87 	tunnelPort = sshPort;
88 #endif
89 
90 #ifdef WIN32
91 	scmHandle = 0;
92 	serviceHandle = 0;
93 #endif
94 }
95 
~pgServer()96 pgServer::~pgServer()
97 {
98 	if (conn)
99 		delete conn;
100 
101 #if defined(HAVE_OPENSSL_CRYPTO) || defined(HAVE_GCRYPT)
102 	if(tunnelObj)
103 	{
104 		if(tunnelObj->IsAlive())
105 		{
106 			tunnelObj->Cleanup();
107 		}
108 		tunnelObj = NULL;
109 	}
110 #endif
111 
112 #ifdef WIN32
113 	if (serviceHandle)
114 		CloseServiceHandle(serviceHandle);
115 	if (scmHandle)
116 		CloseServiceHandle(scmHandle);
117 #endif
118 }
119 
120 
GetTranslatedMessage(int kindOfMessage) const121 wxString pgServer::GetTranslatedMessage(int kindOfMessage) const
122 {
123 	wxString message = wxEmptyString;
124 
125 	switch (kindOfMessage)
126 	{
127 		case RETRIEVINGDETAILS:
128 			message = _("Retrieving details on server");
129 			message += wxT(" ") + GetName();
130 			break;
131 		case REFRESHINGDETAILS:
132 			message = _("Refreshing server");
133 			message += wxT(" ") + GetName();
134 			break;
135 		case BACKUPGLOBALS:
136 			message = _("Backup globals of server");
137 			message += wxT(" ") + GetName();
138 			break;
139 		case BACKUPSERVERTITLE:
140 			message = _("Backup server");
141 			message += wxT(" ") + GetName();
142 			break;
143 		case DROPTITLE:
144 			message = _("Drop server?");
145 			break;
146 		case PROPERTIESREPORT:
147 			message = _("Server properties report");
148 			message += wxT(" - ") + GetName();
149 			break;
150 		case PROPERTIES:
151 			message = _("Server properties");
152 			break;
153 		case STATISTICSREPORT:
154 			message = _("Server statistics report");
155 			message += wxT(" - ") + GetName();
156 			break;
157 		case OBJSTATISTICS:
158 			message = _("Server statistics");
159 			break;
160 	}
161 
162 	return message;
163 }
164 
165 
GetIconId()166 int pgServer::GetIconId()
167 {
168 	if (GetConnected())
169 		return serverFactory.GetIconId();
170 	else
171 		return serverFactory.GetClosedIconId();
172 }
173 
174 
GetNewMenu()175 wxMenu *pgServer::GetNewMenu()
176 {
177 	wxMenu *menu = 0;
178 	if (connected && (GetSuperUser() || GetCreateRole()))
179 	{
180 		menu = new wxMenu();
181 		if (settings->GetDisplayOption(_("Tablespaces")))
182 			tablespaceFactory.AppendMenu(menu);
183 		if (GetConnection()->BackendMinimumVersion(8, 1))
184 		{
185 			if (settings->GetDisplayOption(_("Groups/group Roles")))
186 				groupRoleFactory.AppendMenu(menu);
187 			if (settings->GetDisplayOption(_("Users/login Roles")))
188 				loginRoleFactory.AppendMenu(menu);
189 			if (GetConnection()->GetIsGreenplum())
190 			{
191 				if (settings->GetDisplayOption(_("Resource Queues")))
192 					resQueueFactory.AppendMenu(menu);
193 			}
194 		}
195 		else
196 		{
197 			if (settings->GetDisplayOption(_("Groups/group Roles")))
198 				groupFactory.AppendMenu(menu);
199 			if (settings->GetDisplayOption(_("Users/login Roles")))
200 				userFactory.AppendMenu(menu);
201 		}
202 		// Added Resource Group only for PPAS 9.4 and above
203 		if (conn->GetIsEdb() && conn->EdbMinimumVersion(9, 4))
204 		{
205 			if (settings->GetDisplayOption(_("Resource Groups")))
206 				resourceGroupFactory.AppendMenu(menu);
207 		}
208 	}
209 	return menu;
210 }
211 
GetServer() const212 pgServer *pgServer::GetServer() const
213 {
214 	if (connected)
215 		return (pgServer *)this;
216 	return 0;
217 }
218 
219 
CreateConn(wxString dbName,OID oid,wxString applicationname)220 pgConn *pgServer::CreateConn(wxString dbName, OID oid, wxString applicationname)
221 {
222 	if (!connected)
223 		return 0;
224 
225 	if (dbName.IsEmpty())
226 	{
227 		dbName = GetDatabaseName();
228 		oid = dbOid;
229 	}
230 
231 	pgConn *conn = NULL;
232 #if defined(HAVE_OPENSSL_CRYPTO) || defined(HAVE_GCRYPT)
233 	if(sshTunnel)
234 	{
235 		conn = new pgConn(local_listenhost, service, hostaddr, dbName, username, password, local_listenport, rolename, ssl, oid, applicationname, sslcert, sslkey, sslrootcert, sslcrl, sslcompression);
236 	}
237 	else
238 #endif
239 	{
240 		conn = new pgConn(GetName(), service, hostaddr, dbName, username, password, port, rolename, ssl, oid, applicationname, sslcert, sslkey, sslrootcert, sslcrl, sslcompression);
241 	}
242 
243 	if (conn && conn->GetStatus() != PGCONN_OK)
244 	{
245 		wxLogError(wxT("%s"), conn->GetLastError().c_str());
246 		delete conn;
247 		return 0;
248 	}
249 	return conn;
250 }
251 
252 
GetFullName()253 wxString pgServer::GetFullName()
254 {
255 	if (GetDescription().Length() > 0)
256 		return GetDescription() + wxT(" (") + GetIdentifier() + wxT(")");
257 	else
258 		return wxT("(") + GetIdentifier() + wxT(")");
259 }
260 
GetFullIdentifier()261 wxString pgServer::GetFullIdentifier()
262 {
263 	return GetFullName();
264 }
265 
Disconnect(frmMain * form)266 bool pgServer::Disconnect(frmMain *form)
267 {
268 #if defined(HAVE_OPENSSL_CRYPTO) || defined(HAVE_GCRYPT)
269 	if(tunnelObj)
270 	{
271 		if(tunnelObj->IsAlive())
272 		{
273 			tunnelObj->Cleanup();
274 		}
275 		tunnelObj = NULL;
276 	}
277 #endif
278 
279 	if (conn)
280 	{
281 		delete conn;
282 		conn = 0;
283 		connected = false;
284 		expandedKids = false;
285 		ver = wxT("");
286 		versionNum = wxT("");
287 		lastSystemOID = 0;
288 	}
289 
290 	if (form)
291 		UpdateIcon(form->GetBrowser());
292 
293 	return true;
294 }
295 
296 
GetCanHint()297 bool pgServer::GetCanHint()
298 {
299 	return connected && conn->BackendMinimumVersion(8, 1) && !autovacuumRunning;
300 }
301 
302 
ShowHint(frmMain * form,bool force)303 void pgServer::ShowHint(frmMain *form, bool force)
304 {
305 	wxArrayString hints;
306 
307 	if (!autovacuumRunning)
308 		hints.Add(HINT_AUTOVACUUM);
309 
310 	if (force || !hintShown)
311 		frmHint::ShowHint(form, hints, GetFullIdentifier(), force);
312 	hintShown = true;
313 }
314 
315 
316 #define SERVICEBUFSIZE  10000
317 #define QUERYBUFSIZE    256
318 
319 #ifdef WIN32
GetDependentServices(SC_HANDLE handle)320 wxArrayString pgServer::GetDependentServices(SC_HANDLE handle)
321 {
322 	wxArrayString services;
323 	LPENUM_SERVICE_STATUS sbuf = (LPENUM_SERVICE_STATUS) new char[SERVICEBUFSIZE];
324 
325 	DWORD servicesReturned = 0, bytesNeeded;
326 	::EnumDependentServices(handle, SERVICE_STATE_ALL, sbuf, SERVICEBUFSIZE, &bytesNeeded, &servicesReturned);
327 
328 
329 	DWORD i;
330 	for (i = 0 ; i < servicesReturned ; i++)
331 	{
332 		SC_HANDLE h =::OpenService(scmHandle, sbuf[i].lpServiceName, SERVICE_QUERY_CONFIG);
333 		if (h)
334 		{
335 			char buffer[QUERYBUFSIZE];
336 			LPQUERY_SERVICE_CONFIG qsc = (LPQUERY_SERVICE_CONFIG)buffer;
337 			if(::QueryServiceConfig(h, qsc, QUERYBUFSIZE, &bytesNeeded))
338 			{
339 				if (qsc->dwStartType != SERVICE_DISABLED)
340 					services.Add(sbuf[i].lpServiceName);
341 			}
342 
343 			::CloseServiceHandle(h);
344 		}
345 	}
346 	delete[] sbuf;
347 
348 	return services;
349 }
350 #endif
351 
352 
StartService()353 bool pgServer::StartService()
354 {
355 	bool done = false;
356 #ifdef WIN32
357 	if (serviceHandle)
358 	{
359 		done = (::StartService(serviceHandle, 0, 0) != 0);
360 		if (!done)
361 		{
362 			DWORD rc = ::GetLastError();
363 			if (rc == ERROR_SERVICE_ALREADY_RUNNING)
364 			{
365 				GetServerRunning();
366 				return true;
367 			}
368 			// report error
369 			wxLogError(__("Failed to start server %s: Errcode=%d\nCheck event log for details."),
370 			           serviceId.c_str(), rc);
371 		}
372 		else
373 		{
374 			GetServerRunning();     // ignore result, just to wait for startup
375 
376 			wxArrayString services = GetDependentServices(serviceHandle);
377 
378 			if (services.GetCount() > 0)
379 			{
380 				size_t i;
381 				wxString serviceString;
382 				for (i = 0 ; i < services.GetCount() ; i++)
383 					serviceString += wxT("   ") + services.Item(i) + wxT("\n");
384 
385 				wxMessageDialog msg(0, _("There are dependent services configured:\n\n")
386 				                    + serviceString + _("\nStart dependent services too?"), _("Dependent services"),
387 				                    wxICON_EXCLAMATION | wxYES_NO | wxYES_DEFAULT);
388 
389 				if (msg.ShowModal() == wxID_YES)
390 				{
391 					for (i = 0 ; i < services.GetCount() ; i++)
392 					{
393 						SC_HANDLE h =::OpenService(scmHandle, services.Item(i), GENERIC_EXECUTE | GENERIC_READ);
394 						if (h)
395 						{
396 							if (!::StartService(h, 0, 0))
397 								done = false;
398 							CloseServiceHandle(h);
399 						}
400 						else
401 							done = false;
402 					}
403 					if (!done)
404 					{
405 						wxMessageDialog msg(0, _("One or more dependent services didn't start; see the eventlog for details."), _("Service start problem"),
406 						                    wxICON_EXCLAMATION | wxOK);
407 						msg.ShowModal();
408 						done = true;
409 					}
410 				}
411 			}
412 		}
413 	}
414 #else
415 	wxString res = ExecProcess(serviceId + wxT(" start"));
416 	done = (res.Find(wxT("tarting")) > 0);
417 #endif
418 	return done;
419 }
420 
421 
StopService()422 bool pgServer::StopService()
423 {
424 	bool done = false;
425 #ifdef WIN32
426 	if (serviceHandle)
427 	{
428 		SERVICE_STATUS st;
429 
430 		done = (::ControlService(serviceHandle, SERVICE_CONTROL_STOP, &st) != 0);
431 		if (!done)
432 		{
433 			if (::GetLastError() == ERROR_DEPENDENT_SERVICES_RUNNING)
434 			{
435 				LPENUM_SERVICE_STATUS sbuf = (LPENUM_SERVICE_STATUS) new char[SERVICEBUFSIZE];
436 				DWORD bytesNeeded, servicesReturned = 0;
437 				::EnumDependentServices(serviceHandle, SERVICE_ACTIVE, sbuf, SERVICEBUFSIZE, &bytesNeeded, &servicesReturned);
438 
439 				done = true;
440 
441 				if (servicesReturned)
442 				{
443 					DWORD i;
444 					wxString services;
445 					for (i = 0 ; i < servicesReturned ; i++)
446 						services += wxT("   ") + wxString(sbuf[i].lpDisplayName) + wxT("\n");
447 
448 					wxMessageDialog msg(0, _("There are dependent services running:\n\n")
449 					                    + services + _("\nStop dependent services?"), _("Dependent services"),
450 					                    wxICON_EXCLAMATION | wxYES_NO | wxYES_DEFAULT);
451 					if (msg.ShowModal() != wxID_YES)
452 						return false;
453 
454 					for (i = 0 ; done && i < servicesReturned ; i++)
455 					{
456 						SC_HANDLE h =::OpenService(scmHandle, sbuf[i].lpServiceName, GENERIC_EXECUTE | GENERIC_READ);
457 						if (h)
458 						{
459 							done = (::ControlService(h, SERVICE_CONTROL_STOP, &st) != 0);
460 							CloseServiceHandle(h);
461 						}
462 						else
463 							done = false;
464 					}
465 					if (done)
466 					{
467 						done = (::ControlService(serviceHandle, SERVICE_CONTROL_STOP, &st) != 0);
468 
469 						int retries = 10;
470 						while (!done && retries > 0)
471 						{
472 							done = (::ControlService(serviceHandle, SERVICE_CONTROL_STOP, &st) != 0);
473 							retries--;
474 
475 							wxSleep(5);
476 						}
477 
478 					}
479 				}
480 			}
481 			// report error
482 
483 			if (!done)
484 				wxLogError(__("Failed to stop server %s: Errcode=%d\nCheck event log for details."),
485 				           serviceId.c_str(), ::GetLastError());
486 		}
487 	}
488 #else
489 	wxString res = ExecProcess(serviceId + wxT(" stop"));
490 	done = (res.Find(wxT("stopped")) > 0);
491 #endif
492 	return done;
493 }
494 
495 
GetServerRunning()496 bool pgServer::GetServerRunning()
497 {
498 	bool done = false;
499 #ifdef WIN32
500 	if (serviceHandle)
501 	{
502 		SERVICE_STATUS st;
503 		int loops;
504 
505 		for (loops = 0 ; loops < 20 ; loops++)
506 		{
507 			if (::QueryServiceStatus(serviceHandle, &st) == 0)
508 			{
509 				DWORD rc = ::GetLastError();
510 				CloseServiceHandle(serviceHandle);
511 				CloseServiceHandle(scmHandle);
512 				serviceHandle = 0;
513 				scmHandle = 0;
514 
515 				return false;
516 			}
517 			done = (st.dwCurrentState == SERVICE_RUNNING);
518 			if (st.dwCurrentState == SERVICE_START_PENDING)
519 				Sleep(100);
520 			else
521 				break;
522 		}
523 	}
524 #else
525 
526 	wxString res = ExecProcess(serviceId + wxT(" status"));
527 	done = (res.Find(wxT("PID: ")) > 0);
528 
529 #endif
530 	return done;
531 }
532 
533 
iSetServiceID(const wxString & s)534 void pgServer::iSetServiceID(const wxString &s)
535 {
536 	serviceId = s;
537 #ifdef WIN32
538 	if (serviceId.Find('\\') < 0)
539 		scmHandle = OpenSCManager(0, SERVICES_ACTIVE_DATABASE, GENERIC_EXECUTE);
540 	else
541 		scmHandle = OpenSCManager(wxT("\\\\") + serviceId.BeforeFirst('\\'), SERVICES_ACTIVE_DATABASE, GENERIC_EXECUTE | GENERIC_READ);
542 
543 	if (scmHandle)
544 		serviceHandle = OpenService(scmHandle, serviceId.AfterLast('\\'), GENERIC_EXECUTE | GENERIC_READ);
545 #endif
546 }
547 
548 
GetServerControllable()549 bool pgServer::GetServerControllable()
550 {
551 #ifdef WIN32
552 	return serviceHandle != 0;
553 #else
554 	return !serviceId.IsEmpty();
555 #endif
556 }
557 
558 
passwordFilename()559 wxString pgServer::passwordFilename()
560 {
561 	wxString fname = sysSettings::GetConfigFile(sysSettings::PGPASS);
562 
563 	wxLogInfo(wxT("Using password file %s"), fname.c_str());
564 	return fname;
565 }
566 
567 
568 
GetPasswordIsStored()569 bool pgServer::GetPasswordIsStored()
570 {
571 	wxString fname = passwordFilename();
572 
573 
574 	if (!wxFile::Exists(fname))
575 		return false;
576 
577 	wxUtfFile file(fname, wxFile::read, wxFONTENCODING_SYSTEM);
578 
579 	if (file.IsOpened())
580 	{
581 		wxString before;
582 		file.Read(before);
583 
584 		wxStringTokenizer lines(before, wxT("\n\r"));
585 
586 		wxString seekStr = GetName() + wxT(":")
587 		                   + NumToStr((long)GetPort()) + wxT(":*:")
588 		                   + username + wxT(":") ;
589 
590 		wxString seekStr2 = wxString(GetName().mb_str(wxConvUTF8), wxConvLibc) + wxT(":")
591 		                    + NumToStr((long)GetPort()) + wxT(":*:")
592 		                    + wxString(username.mb_str(wxConvUTF8), wxConvLibc) + wxT(":") ;
593 
594 		while (lines.HasMoreTokens())
595 		{
596 			wxString str = lines.GetNextToken();
597 			if (str.Left(seekStr.Length()) == seekStr)
598 				return true;
599 
600 			if (str.Left(seekStr2.Length()) == seekStr2)
601 				return true;
602 		}
603 	}
604 
605 	return false;
606 }
607 
608 
StorePassword()609 void pgServer::StorePassword()
610 {
611 	wxString fname = passwordFilename();
612 
613 	if (!wxFile::Exists(fname))
614 	{
615 		return;
616 	}
617 	wxUtfFile file;
618 	// Don't try to read and write in one OP - it doesn't work well
619 	wxString before;
620 	file.Open(fname, wxFile::read, wxFONTENCODING_SYSTEM);
621 	file.Read(before);
622 	file.Close();
623 
624 	file.Open(fname, wxFile::write, wxFONTENCODING_SYSTEM);
625 
626 	if (file.IsOpened())
627 	{
628 		wxString after;
629 
630 		wxString passwd;
631 		wxString seekStr;
632 
633 		if (GetConnection()->GetNeedUtfConnectString())
634 		{
635 			passwd = wxString(password.mb_str(wxConvUTF8), wxConvLibc);
636 			seekStr = wxString(GetName().mb_str(wxConvUTF8), wxConvLibc) + wxT(":")
637 			          + NumToStr((long)GetPort()) + wxT(":*:")
638 			          + wxString(username.mb_str(wxConvUTF8), wxConvLibc) + wxT(":") ;
639 		}
640 		else
641 		{
642 			passwd = password;
643 			seekStr = GetName() + wxT(":")
644 			          + NumToStr((long)GetPort()) + wxT(":*:")
645 			          + username + wxT(":") ;
646 		}
647 
648 		// Escape ":" and "\" from the password field
649 		if (!passwd.IsEmpty())
650 		{
651 			passwd.Replace(wxT("\\"), wxT("\\\\"));
652 			passwd.Replace(wxT(":") , wxT("\\:"));
653 		}
654 
655 		file.Read(before);
656 		wxStringTokenizer lines(before, wxT("\n\r"));
657 
658 		file.Seek(0);
659 		bool found = false;
660 		while (lines.HasMoreTokens())
661 		{
662 			wxString str = lines.GetNextToken();
663 			if (str.Left(seekStr.Length()) == seekStr && !passwd.IsEmpty())
664 			{
665 				// entry found
666 				found = true;
667 				if (storePwd)
668 					file.Write(seekStr + passwd + END_OF_LINE);
669 			}
670 			else
671 				file.Write(str + END_OF_LINE);
672 		}
673 		if (!found && storePwd && !passwd.IsEmpty())
674 			file.Write(seekStr + passwd + END_OF_LINE);
675 
676 		file.Close();
677 	}
678 }
679 
680 
Connect(frmMain * form,bool askPassword,const wxString & pwd,bool forceStorePassword,bool askTunnelPassword)681 int pgServer::Connect(frmMain *form, bool askPassword, const wxString &pwd, bool forceStorePassword, bool askTunnelPassword)
682 {
683 	wxLogInfo(wxT("Attempting to create a connection object..."));
684 
685 	bool storePassword = false;
686 
687 	if (!conn || conn->GetStatus() != PGCONN_OK)
688 	{
689 		if (conn)
690 		{
691 			delete conn;
692 			conn = 0;
693 		}
694 		if (askPassword)
695 		{
696 			if ((sshTunnel || !passwordValid || !GetPasswordIsStored() || !GetStorePwd()) && GetSSLCert() == wxEmptyString)
697 			{
698 				wxString txt;
699 				txt.Printf(_("Please enter password for user %s\non server %s (%s)"), username.c_str(), description.c_str(), GetName().c_str());
700 				dlgConnect *dlg = NULL;
701 				// if sshTunnel is true then we have to hide 'Stored Password' option
702 				if(sshTunnel)
703 					dlg = new dlgConnect(NULL, txt, false);
704 				else
705 					dlg = new dlgConnect(form, txt, GetStorePwd());
706 
707 				dlg->SetWindowStyleFlag( dlg->GetWindowStyleFlag() | wxSTAY_ON_TOP);
708 
709 				switch (dlg->Go())
710 				{
711 					case wxID_OK:
712 						// Give the UI a chance to redraw
713 						wxSafeYield();
714 						wxMilliSleep(100);
715 						wxSafeYield();
716 						break;
717 					case wxID_CANCEL:
718 					case -1:
719 						// Give the UI a chance to redraw
720 						wxSafeYield();
721 						wxMilliSleep(100);
722 						wxSafeYield();
723 						return PGCONN_ABORTED;
724 					default:
725 						// Give the UI a chance to redraw
726 						wxSafeYield();
727 						wxMilliSleep(100);
728 						wxSafeYield();
729 						wxLogError(__("Couldn't create a connection dialogue!"));
730 						return PGCONN_BAD;
731 				}
732 
733 				iSetStorePwd(dlg->GetStorePwd());
734 				password = dlg->GetPassword();
735 				storePassword = true;
736 				if(dlg)
737 				{
738 					delete dlg;
739 					dlg = NULL;
740 				}
741 			}
742 		}
743 		else
744 			iSetPassword(pwd);
745 
746 		form->StartMsg(_("Connecting to database"));
747 
748 		wxString host;
749 		int iPort;
750 #if defined(HAVE_OPENSSL_CRYPTO) || defined(HAVE_GCRYPT)
751 		if(sshTunnel)
752 		{
753 			//Ask Tunnel Password
754 			if(askTunnelPassword)
755 			{
756 				wxString txt;
757 				if(GetAuthModePwd())
758 				{
759 					txt.Printf(_("Please enter the SSH tunnel password for user %s\non server %s"), tunnelUserName.c_str(), tunnelHost.c_str());
760 				}
761 				else
762 				{
763 					txt.Printf(_("Please enter the pass phrase for the identity file\n%s"), identityFile.c_str());
764 				}
765 				dlgConnect dlg(NULL, txt, false);
766 
767 				switch (dlg.Go())
768 				{
769 					case wxID_OK:
770 						// Give the UI a chance to redraw
771 						wxSafeYield();
772 						wxMilliSleep(100);
773 						wxSafeYield();
774 						tunnelPassword = dlg.GetPassword();
775 						break;
776 					case wxID_CANCEL:
777 					case -1:
778 					default:
779 						// Give the UI a chance to redraw
780 						wxSafeYield();
781 						wxMilliSleep(100);
782 						wxSafeYield();
783 						form->EndMsg(false);
784 						return PGCONN_ABORTED;
785 				}
786 			}
787 			// Create SSH Tunnel if required
788 			if(!tunnelObj)
789 			{
790 				if(!createSSHTunnel())
791 				{
792 					form->EndMsg(false);
793 					return PGCONN_SSHTUNNEL_ERROR;
794 				}
795 			}
796 
797 			host = local_listenhost;
798 			iPort = local_listenport;
799 		}
800 		else
801 #endif
802 		{
803 			host = GetName();
804 			iPort = port;
805 		}
806 
807 		if (database.IsEmpty())
808 		{
809 			conn = new pgConn(host, service, hostaddr, DEFAULT_PG_DATABASE, username, password, iPort, rolename, ssl, 0, appearanceFactory->GetLongAppName() + _(" - Browser"), sslcert, sslkey, sslrootcert, sslcrl, sslcompression);
810 			if (conn->GetStatus() == PGCONN_OK)
811 				database = DEFAULT_PG_DATABASE;
812 			else if (conn->GetStatus() == PGCONN_BAD && conn->GetLastError().Find(
813 			             wxT("database \"") DEFAULT_PG_DATABASE wxT("\" does not exist")) >= 0)
814 			{
815 				delete conn;
816 				conn = new pgConn(host, service, hostaddr, wxT("template1"), username, password, iPort, rolename, ssl, 0, appearanceFactory->GetLongAppName() + _(" - Browser"), sslcert, sslkey, sslrootcert, sslcrl, sslcompression);
817 				if (conn && conn->GetStatus() == PGCONN_OK)
818 					database = wxT("template1");
819 			}
820 		}
821 		else
822 		{
823 			conn = new pgConn(host, service, hostaddr, database, username, password, iPort, rolename, ssl, 0, appearanceFactory->GetLongAppName() + _(" - Browser"), sslcert, sslkey, sslrootcert, sslcrl, sslcompression);
824 			if (!conn)
825 			{
826 				form->EndMsg(false);
827 				wxLogError(__("Couldn't create a connection object!"));
828 				return PGCONN_BAD;
829 			}
830 		}
831 	}
832 	int status = conn->GetStatus();
833 	if (status == PGCONN_OK)
834 	{
835 		dbOid = conn->GetDbOid();
836 
837 		// Check the server version
838 		if (conn->GetIsGreenplum())
839 		{
840 			// Greenplum HAWQ (SQL on Hadoop) is not supported by this pgAdmin version
841 			if (conn->GetIsHawq())
842 			{
843 				wxLogWarning(_("The server you are connecting to is not a version that is supported by this release of %s.\n\n%s may not function as expected."),
844 				             appearanceFactory->GetLongAppName().c_str(),
845 				             appearanceFactory->GetLongAppName().c_str());
846 			}
847 			else
848 			{
849 				// Check for Greenplum specific version
850 				// Greenplum always shows PG version "8.2.15" for now
851 				// this might change once the merge with recent PG versions makes progress
852 				// therefore also check for the max version
853 				if (!(conn->BackendMinimumVersion(GP_MIN_VERSION_N >> 8, GP_MIN_VERSION_N & 0x00FF)) ||
854 				        (conn->BackendMinimumVersion(GP_MAX_VERSION_N >> 8, (GP_MAX_VERSION_N & 0x00FF) + 1)))
855 				{
856 					if (GP_MIN_VERSION_N == GP_MAX_VERSION_N)
857 					{
858 						wxLogWarning(_("The server you are connecting to is not a version that is supported by this release of %s.\n\n%s may not function as expected.\n\nSupported server version is %s."),
859 						             appearanceFactory->GetLongAppName().c_str(),
860 						             appearanceFactory->GetLongAppName().c_str(),
861 						             wxString(GP_MIN_VERSION_T).c_str());
862 					}
863 					else
864 					{
865 						wxLogWarning(_("The server you are connecting to is not a version that is supported by this release of %s.\n\n%s may not function as expected.\n\nSupported server versions are %s to %s."),
866 						             appearanceFactory->GetLongAppName().c_str(),
867 						             appearanceFactory->GetLongAppName().c_str(),
868 						             wxString(GP_MIN_VERSION_T).c_str(),
869 						             wxString(GP_MAX_VERSION_T).c_str());
870 					}
871 				}
872 			}
873 		}
874 		else
875 		{
876 			if (!(conn->BackendMinimumVersion(SERVER_MIN_VERSION_N >> 8, SERVER_MIN_VERSION_N & 0x00FF)) ||
877 			        (conn->BackendMinimumVersion(SERVER_MAX_VERSION_N >> 8, (SERVER_MAX_VERSION_N & 0x00FF) + 1)))
878 			{
879 				wxLogWarning(_("The server you are connecting to is not a version that is supported by this release of %s.\n\n%s may not function as expected.\n\nSupported server versions are %s to %s."),
880 				             appearanceFactory->GetLongAppName().c_str(),
881 				             appearanceFactory->GetLongAppName().c_str(),
882 				             wxString(SERVER_MIN_VERSION_T).c_str(),
883 				             wxString(SERVER_MAX_VERSION_T).c_str());
884 			}
885 		}
886 
887 		connected = true;
888 		bool hasUptime = false;
889 
890 		wxString sql = wxT("SELECT usecreatedb, usesuper");
891 		if (conn->BackendMinimumVersion(8, 1))
892 		{
893 			hasUptime = true;
894 			sql += wxT(", CASE WHEN usesuper THEN pg_postmaster_start_time() ELSE NULL END as upsince");
895 		}
896 		else if (conn->HasFeature(FEATURE_POSTMASTER_STARTTIME))
897 		{
898 			hasUptime = true;
899 			sql += wxT(", CASE WHEN usesuper THEN pg_postmaster_starttime() ELSE NULL END as upsince");
900 		}
901 		if (conn->BackendMinimumVersion(8, 4))
902 		{
903 			sql += wxT(", CASE WHEN usesuper THEN pg_conf_load_time() ELSE NULL END as confloadedsince");
904 		}
905 		if (conn->BackendMinimumVersion(8, 5))
906 		{
907 			sql += wxT(", CASE WHEN usesuper THEN pg_is_in_recovery() ELSE NULL END as inrecovery");
908 			if (conn->BackendMinimumVersion(10, 0))
909 			{
910 				sql += wxT(", CASE WHEN usesuper THEN pg_last_wal_receive_lsn() ELSE NULL END as receiveloc");
911 				sql += wxT(", CASE WHEN usesuper THEN pg_last_wal_replay_lsn() ELSE NULL END as replayloc");
912 			}
913 			else
914 			{
915 			        sql += wxT(", CASE WHEN usesuper THEN pg_last_xlog_receive_location() ELSE NULL END as receiveloc");
916 			        sql += wxT(", CASE WHEN usesuper THEN pg_last_xlog_replay_location() ELSE NULL END as replayloc");
917 		        }
918 		}
919 		if (conn->BackendMinimumVersion(9, 1))
920 		{
921 			sql += wxT(", CASE WHEN usesuper THEN pg_last_xact_replay_timestamp() ELSE NULL END as replay_timestamp");
922 			if (conn->BackendMinimumVersion(10, 0))
923 				sql += wxT(", CASE WHEN usesuper AND pg_is_in_recovery() THEN pg_is_wal_replay_paused() ELSE NULL END as isreplaypaused");
924 			else
925 			        sql += wxT(", CASE WHEN usesuper AND pg_is_in_recovery() THEN pg_is_xlog_replay_paused() ELSE NULL END as isreplaypaused");
926 		}
927 
928 		pgSet *set = ExecuteSet(sql + wxT("\n  FROM pg_user WHERE usename=current_user"));
929 		if (set)
930 		{
931 			iSetCreatePrivilege(set->GetBool(wxT("usecreatedb")));
932 			iSetSuperUser(set->GetBool(wxT("usesuper")));
933 			if (hasUptime)
934 				iSetUpSince(set->GetDateTime(wxT("upsince")));
935 			if (conn->BackendMinimumVersion(8, 4))
936 				iSetConfLoadedSince(set->GetDateTime(wxT("confloadedsince")));
937 			if (conn->BackendMinimumVersion(8, 5))
938 			{
939 				iSetInRecovery(set->GetBool(wxT("inrecovery")));
940 				iSetReplayLoc(set->GetVal(wxT("replayloc")));
941 				iSetReceiveLoc(set->GetVal(wxT("receiveloc")));
942 			}
943 			if (conn->BackendMinimumVersion(9, 1))
944 			{
945 				iSetReplayTimestamp(set->GetVal(wxT("replay_timestamp")));
946 				SetReplayPaused(set->GetBool(wxT("isreplaypaused")));
947 			}
948 			delete set;
949 		}
950 
951 		if (conn->BackendMinimumVersion(8, 1))
952 		{
953 			set = ExecuteSet(wxT("SELECT rolcreaterole, rolcreatedb FROM pg_roles WHERE rolname = current_user;"));
954 
955 			if (set)
956 			{
957 				iSetCreatePrivilege(set->GetBool(wxT("rolcreatedb")));
958 				iSetCreateRole(set->GetBool(wxT("rolcreaterole")));
959 				delete set;
960 			}
961 		}
962 		else
963 			iSetCreateRole(false);
964 
965 		wxString version, allVersions;
966 		version.Printf(wxT("%d.%d"), conn->GetMajorVersion(), conn->GetMinorVersion());
967 		allVersions = settings->Read(wxT("Updates/pgsql-Versions"), wxEmptyString);
968 		if (allVersions.Find(version) < 0)
969 		{
970 			if (!allVersions.IsEmpty())
971 				allVersions += wxT(", ");
972 			allVersions += version;
973 			settings->Write(wxT("Updates/pgsql-Versions"), allVersions);
974 		}
975 		if (conn->IsSSLconnected())
976 			settings->WriteBool(wxT("Updates/UseSSL"), true);
977 
978 		UpdateIcon(form->GetBrowser());
979 		if (storePassword || forceStorePassword)
980 			StorePassword();
981 	}
982 	else
983 	{
984 		connected = false;
985 	}
986 
987 	form->EndMsg(connected && status == PGCONN_OK);
988 
989 	passwordValid = connected;
990 	return status;
991 }
992 
993 
GetIdentifier() const994 wxString pgServer::GetIdentifier() const
995 {
996 	wxString idstr;
997 	if (GetService().IsEmpty())
998 	{
999 		if (GetName().IsEmpty())
1000 			idstr.Printf(wxT("local:.s.PGSQL.%d"), port);
1001 		else if (GetName().StartsWith(wxT("/")))
1002 			idstr.Printf(wxT("local:%s/.s.PGSQL.%d"), GetName().c_str(), port);
1003 		else
1004 			idstr.Printf(wxT("%s:%d"), GetName().c_str(), port);
1005 	}
1006 	else
1007 		idstr.Printf(_("service %s"), GetService().c_str());
1008 	return idstr;
1009 }
1010 
1011 
GetVersionString()1012 wxString pgServer::GetVersionString()
1013 {
1014 	if (connected)
1015 	{
1016 		if (ver.IsEmpty())
1017 			ver = wxString(conn->GetVersionString());
1018 		return ver;
1019 	}
1020 	else
1021 		return wxEmptyString;
1022 }
1023 
1024 
GetVersionNumber()1025 wxString pgServer::GetVersionNumber()
1026 {
1027 	if (connected)
1028 	{
1029 		if (versionNum.IsEmpty())
1030 		{
1031 			int major = 0, minor = 0;
1032 			sscanf(GetVersionString().ToAscii(), "%*s %d.%d", &major, &minor);
1033 			versionNum.Printf(wxT("%d.%d"), major, minor);
1034 		}
1035 
1036 	}
1037 	return versionNum;
1038 }
1039 
1040 
GetLastSystemOID()1041 OID pgServer::GetLastSystemOID()
1042 {
1043 	if (connected)
1044 	{
1045 		if (lastSystemOID == 0)
1046 			lastSystemOID = conn->GetLastSystemOID();
1047 		return lastSystemOID;
1048 	}
1049 	else
1050 		return 0;
1051 }
1052 
1053 
SetPassword(const wxString & newVal)1054 bool pgServer::SetPassword(const wxString &newVal)
1055 {
1056 	wxString sql;
1057 	sql.Printf(wxT("ALTER USER %s WITH ENCRYPTED PASSWORD %s;"), qtIdent(username).c_str(), qtDbString(conn->EncryptPassword(username, newVal)).c_str());
1058 	bool executed = conn->ExecuteVoid(sql);
1059 	if (executed)
1060 	{
1061 		password = newVal;
1062 		StorePassword();
1063 		return true;
1064 	}
1065 	else
1066 		return false;
1067 }
1068 
1069 
GetLastError() const1070 wxString pgServer::GetLastError() const
1071 {
1072 	wxString msg;
1073 	if (conn)
1074 	{
1075 		if (error != wxT(""))
1076 		{
1077 			if (conn->GetLastError() != wxT(""))
1078 			{
1079 				msg.Printf(wxT("%s\n%s"), error.c_str(), conn->GetLastError().c_str());
1080 			}
1081 			else
1082 			{
1083 				msg = error;
1084 			}
1085 		}
1086 		else
1087 		{
1088 			msg = conn->GetLastError();
1089 		}
1090 	}
1091 	return msg;
1092 }
1093 
1094 
1095 
ShowTreeDetail(ctlTree * browser,frmMain * form,ctlListView * properties,ctlSQLBox * sqlPane)1096 void pgServer::ShowTreeDetail(ctlTree *browser, frmMain *form, ctlListView *properties, ctlSQLBox *sqlPane)
1097 {
1098 	// Add child nodes if necessary
1099 	if (GetConnected())
1100 	{
1101 		// Reset password menu option
1102 //        form->fileMenu->Enable(MNU_PASSWORD, true);
1103 
1104 		if (!expandedKids)
1105 		{
1106 			expandedKids = true;
1107 			// Log
1108 
1109 			wxLogInfo(wxT("Adding child object to server %s"), GetIdentifier().c_str());
1110 
1111 			if (settings->GetDisplayOption(_("Databases")))
1112 				browser->AppendCollection(this, databaseFactory);
1113 
1114 			if (conn->BackendMinimumVersion(8, 0) && settings->GetDisplayOption(_("Tablespaces")))
1115 				browser->AppendCollection(this, tablespaceFactory);
1116 
1117 			// Jobs
1118 			// We only add the Jobs node if the appropriate objects are the initial DB.
1119 			if (settings->GetDisplayOption(_("pgAgent Jobs")))
1120 			{
1121 				wxString exists = conn->ExecuteScalar(
1122 				                      wxT("SELECT cl.oid FROM pg_class cl JOIN pg_namespace ns ON ns.oid=relnamespace\n")
1123 				                      wxT(" WHERE relname='pga_job' AND nspname='pgagent'"));
1124 
1125 				if (!exists.IsNull())
1126 				{
1127 					exists = conn->ExecuteScalar(wxT("SELECT has_schema_privilege('pgagent', 'USAGE')"));
1128 
1129 					if (exists == wxT("t"))
1130 						browser->AppendCollection(this, jobFactory);
1131 				}
1132 			}
1133 
1134 			if (conn->BackendMinimumVersion(8, 1))
1135 			{
1136 				if (settings->GetDisplayOption(_("Groups/group Roles")))
1137 					browser->AppendCollection(this, groupRoleFactory);
1138 				if (settings->GetDisplayOption(_("Users/login Roles")))
1139 					browser->AppendCollection(this, loginRoleFactory);
1140 				if (GetConnection()->GetIsGreenplum())
1141 				{
1142 					if (settings->GetDisplayOption(_("Resource Queues")))
1143 						browser->AppendCollection(this, resQueueFactory);
1144 				}
1145 			}
1146 			else
1147 			{
1148 				if (settings->GetDisplayOption(_("Groups/group Roles")))
1149 					browser->AppendCollection(this, groupFactory);
1150 				if (settings->GetDisplayOption(_("Users/login Roles")))
1151 					browser->AppendCollection(this, userFactory);
1152 			}
1153 
1154 			// Added Resource Group only for PPAS 9.4 and above
1155 			if (conn->GetIsEdb() && conn->EdbMinimumVersion(9, 4))
1156 			{
1157 				if (settings->GetDisplayOption(_("Resource Groups")))
1158 					browser->AppendCollection(this, resourceGroupFactory);
1159 			}
1160 
1161 			autovacuumRunning = true;
1162 
1163 			wxString qry;
1164 			if (conn->BackendMinimumVersion(8, 3))
1165 				qry = wxT("SELECT setting FROM pg_settings WHERE name IN ('autovacuum', 'track_counts')");
1166 			else
1167 				qry = wxT("SELECT setting FROM pg_settings WHERE name IN ('autovacuum', 'stats_start_collector', 'stats_row_level')");
1168 
1169 			pgSetIterator set(conn, qry);
1170 
1171 			while (autovacuumRunning && set.RowsLeft())
1172 				autovacuumRunning = set.GetBool(wxT("setting"));
1173 		}
1174 	}
1175 
1176 
1177 	if (properties)
1178 	{
1179 		// Add the properties view columns
1180 		CreateListColumns(properties);
1181 
1182 		// Display the Server properties
1183 
1184 		properties->AppendItem(_("Description"), GetDescription());
1185 		properties->AppendItem(_("Service"), GetService());
1186 		if (GetName().IsEmpty() || GetName().StartsWith(wxT("/")))
1187 		{
1188 			if (GetName().IsEmpty() && !GetService().IsEmpty())
1189 				properties->AppendItem(_("Hostname"), wxEmptyString);
1190 			else
1191 				properties->AppendItem(_("Hostname"), wxT("local:") + GetName());
1192 
1193 			if (GetPort() == 0 && !GetService().IsEmpty())
1194 				properties->AppendItem(_("Port"), wxEmptyString);
1195 			else
1196 				properties->AppendItem(_("Port"), (long)GetPort());
1197 		}
1198 		else
1199 		{
1200 			properties->AppendItem(_("Hostname"), GetName());
1201 			properties->AppendItem(_("Host Address"), GetHostAddr());
1202 			if (GetPort() == 0 && !GetService().IsEmpty())
1203 				properties->AppendItem(_("Port"), wxEmptyString);
1204 			else
1205 				properties->AppendItem(_("Port"), (long)GetPort());
1206 #ifdef PG_SSL
1207 			if (GetConnected())
1208 			{
1209 				properties->AppendItem(_("Encryption"),
1210 				                       conn->IsSSLconnected() ? _("SSL encrypted") : _("not encrypted"));
1211 			}
1212 			else
1213 			{
1214 				if (ssl > 0)
1215 				{
1216 					wxString sslMode;
1217 					switch (ssl)
1218 					{
1219 						case 1:
1220 							sslMode = _("require");
1221 							break;
1222 						case 2:
1223 							sslMode = _("prefer");
1224 							break;
1225 						case 3:
1226 							sslMode = _("allow");
1227 							break;
1228 						case 4:
1229 							sslMode = _("disable");
1230 							break;
1231 						case 5:
1232 							sslMode = _("verify-ca");
1233 							break;
1234 						case 6:
1235 							sslMode = _("verify-full");
1236 							break;
1237 					}
1238 					properties->AppendItem(_("SSL Mode"), sslMode);
1239 				}
1240 			}
1241 			properties->AppendItem(_("SSL Certificate File"), GetSSLCert());
1242 			properties->AppendItem(_("SSL Key File"), GetSSLKey());
1243 			properties->AppendItem(_("SSL Root Certificate File"), GetSSLRootCert());
1244 			properties->AppendItem(_("SSL Certificate Revocation List"), GetSSLCrl());
1245 			properties->AppendItem(_("SSL Compression?"), (GetSSLCompression() ? _("yes") : _("no")));
1246 #endif
1247 		}
1248 		if (!serviceId.IsEmpty())
1249 			properties->AppendItem(_("Service ID"), serviceId);
1250 
1251 		properties->AppendItem(_("Maintenance database"), GetDatabaseName());
1252 		properties->AppendItem(_("Username"), GetUsername());
1253 		if (!GetRolename().IsEmpty())
1254 			properties->AppendItem(_("Default role"), GetRolename());
1255 
1256 		properties->AppendYesNoItem(_("Store password?"), GetStorePwd());
1257 		properties->AppendYesNoItem(_("Restore environment?"), GetRestore());
1258 		if (GetConnected())
1259 		{
1260 			properties->AppendItem(_("Version string"), GetVersionString());
1261 			properties->AppendItem(_("Version number"), GetVersionNumber());
1262 			properties->AppendItem(_("Last system OID"), GetLastSystemOID());
1263 		}
1264 		properties->AppendYesNoItem(_("Connected?"), GetConnected());
1265 		if (GetConnected())
1266 		{
1267 			if (GetUpSince().IsValid())
1268 				properties->AppendItem(_("Up since"), GetUpSince());
1269 			if (GetConfLoadedSince().IsValid())
1270 				properties->AppendItem(_("Configuration loaded since"), GetConfLoadedSince());
1271 			if (conn->BackendMinimumVersion(8, 1))
1272 				properties->AppendItem(wxT("Autovacuum"), (autovacuumRunning ? _("running") : _("not running")));
1273 			if (conn->BackendMinimumVersion(8, 5))
1274 			{
1275 				properties->AppendItem(_("In recovery"), (GetInRecovery() ? _("yes") : _("no")));
1276 				properties->AppendItem(_("Last XLOG receive location"), GetReceiveLoc());
1277 				properties->AppendItem(_("Last XLOG replay location"), GetReplayLoc());
1278 			}
1279 			if (conn->BackendMinimumVersion(9, 1))
1280 			{
1281 				properties->AppendItem(_("Last XACT replay timestamp"), GetReplayTimestamp());
1282 				if (GetInRecovery())
1283 					properties->AppendItem(_("Replay paused"), (GetReplayPaused() ? _("paused") : _("running")));
1284 				else
1285 					properties->AppendItem(_("Replay paused"), wxEmptyString);
1286 			}
1287 		}
1288 		if (GetServerControllable())
1289 			properties->AppendYesNoItem(_("Running?"), GetServerRunning());
1290 
1291 		if (!GetDbRestriction().IsEmpty())
1292 			properties->AppendItem(_("DB restriction"), GetDbRestriction());
1293 
1294 #if defined(HAVE_OPENSSL_CRYPTO) || defined(HAVE_GCRYPT)
1295 		if(sshTunnel)
1296 		{
1297 			properties->AppendItem(_("SSH tunneling?"), (sshTunnel ? _("Yes") : _("No")));
1298 			properties->AppendItem(_("Tunnel host"), GetTunnelHost());
1299 			properties->AppendItem(_("Tunnel username"), GetTunnelUserName());
1300 			properties->AppendItem(_("Authentication mode"), (GetAuthModePwd() ? _("Password") : _("Identity file")));
1301 			if(!GetAuthModePwd())
1302 			{
1303 				properties->AppendItem(_("Identity file path"), GetIdentityFile());
1304 			}
1305 		}
1306 #endif
1307 	}
1308 
1309 	if(!GetConnected())
1310 		return;
1311 
1312 	if (form && GetCanHint() && !hintShown)
1313 	{
1314 		ShowHint(form, false);
1315 	}
1316 }
1317 
1318 #if defined(HAVE_OPENSSL_CRYPTO) || defined(HAVE_GCRYPT)
1319 
createSSHTunnel()1320 bool pgServer::createSSHTunnel()
1321 {
1322 	bool retVal = false;
1323 
1324 	tunnelObj = new CSSHTunnelThread(tunnelHost, GetName(), port, tunnelUserName, tunnelPassword, publicKeyFile,
1325 	                                 identityFile, authModePwd ? AUTH_PASSWORD : AUTH_PUBLICKEY, tunnelPort);
1326 
1327 	if(tunnelObj)
1328 	{
1329 		if(tunnelObj->Initialize())
1330 		{
1331 			if ( tunnelObj->Create() != wxTHREAD_NO_ERROR )
1332 			{
1333 				delete tunnelObj;
1334 				tunnelObj = NULL;
1335 				wxLogError(_("SSH Error: Unable to create SSH Tunnling Thread"));
1336 			}
1337 			else
1338 			{
1339 				if (tunnelObj->Run() != wxTHREAD_NO_ERROR )
1340 				{
1341 					delete tunnelObj;
1342 					tunnelObj = NULL;
1343 					wxLogError(_("SSH Error: Unable to start SSH Tunnling Thread"));
1344 				}
1345 
1346 				SetLocalListenHost(tunnelObj->GetLocalListenIP());
1347 				SetLocalListenPort(tunnelObj->GetLocalListenPort());
1348 				retVal = true;
1349 			}
1350 		}
1351 		else
1352 		{
1353 			delete tunnelObj;
1354 			tunnelObj = NULL;
1355 		}
1356 	}
1357 
1358 	return retVal;
1359 }
1360 #endif
1361 
ShowStatistics(frmMain * form,ctlListView * statistics)1362 void pgServer::ShowStatistics(frmMain *form, ctlListView *statistics)
1363 {
1364 	if (conn)
1365 	{
1366 		wxString pidcol = GetConnection()->BackendMinimumVersion(9, 2) ? wxT("pid") : wxT("procpid");
1367 		wxString querycol = GetConnection()->BackendMinimumVersion(9, 2) ? wxT("query") : wxT("current_query");
1368 		wxString sql;
1369 		wxString replication_query;
1370 		if (conn->BackendMinimumVersion(10, 0))
1371 			replication_query = wxT("state || ' (' || sent_lsn || ' sent, ' || write_lsn || ' written, ' || flush_lsn || ' flushed, ' || replay_lsn || ' applied)'");
1372 		else
1373 			replication_query = wxT("state || ' (' || sent_location || ' sent, ' || write_location || ' written, ' || flush_location || ' flushed, ' || replay_location || ' applied)'");
1374 		wxLogInfo(wxT("Displaying statistics for server %s"), GetIdentifier().c_str());
1375 
1376 		// Add the statistics view columns
1377 		statistics->ClearAll();
1378 		statistics->AddColumn(wxT("PID"), 35);
1379 		statistics->AddColumn(_("User"), 70);
1380 		statistics->AddColumn(_("Database"), 70);
1381 		if (GetConnection()->BackendMinimumVersion(8, 1))
1382 		{
1383 			statistics->AddColumn(_("Backend start"), 70);
1384 			statistics->AddColumn(_("Client"), 70);
1385 		}
1386 		statistics->AddColumn(_("Current Query"), 300);
1387 
1388 		sql = wxT("SELECT ") + pidcol + wxT(" AS pid, usename, datname, backend_start, client_addr, ");
1389 		if (GetConnection()->BackendMinimumVersion(9, 1))
1390 			sql += wxT("client_hostname, ");
1391 		sql += wxT("client_port, ") + querycol + wxT(" AS query FROM pg_stat_activity\n");
1392 		if (GetConnection()->BackendMinimumVersion(9, 1))
1393 		{
1394 			sql += wxT("UNION\n")
1395 			       wxT("SELECT ") + pidcol + wxT(", usename, '' AS datname, backend_start, client_addr, client_hostname, client_port, ")
1396 			       + replication_query + wxT(" AS query FROM pg_stat_replication");
1397 		}
1398 
1399 		pgSet *stats = ExecuteSet(sql);
1400 		if (stats)
1401 		{
1402 			int pos = 0;
1403 			while (!stats->Eof())
1404 			{
1405 				statistics->InsertItem(pos, stats->GetVal(wxT("pid")), 0);
1406 				int colpos = 1;
1407 				statistics->SetItem(pos, colpos++, stats->GetVal(wxT("usename")));
1408 				statistics->SetItem(pos, colpos++, stats->GetVal(wxT("datname")));
1409 				if (GetConnection()->BackendMinimumVersion(8, 1))
1410 				{
1411 					statistics->SetItem(pos, colpos++, stats->GetVal(wxT("backend_start")));
1412 					wxString client;
1413 					if (GetConnection()->BackendMinimumVersion(9, 1) && !stats->GetVal(wxT("client_hostname")).IsEmpty())
1414 						client = stats->GetVal(wxT("client_hostname")) + wxT(":") + stats->GetVal(wxT("client_port"));
1415 					else
1416 						client = stats->GetVal(wxT("client_addr")) + wxT(":") + stats->GetVal(wxT("client_port"));
1417 					if (client == wxT(":-1"))
1418 						client = _("local pipe");
1419 					statistics->SetItem(pos, colpos++, client);
1420 				}
1421 				statistics->SetItem(pos, colpos++, stats->GetVal(wxT("query")));
1422 
1423 				stats->MoveNext();
1424 				pos++;
1425 			}
1426 
1427 			delete stats;
1428 		}
1429 	}
1430 }
1431 
ShowDependencies(frmMain * form,ctlListView * Dependencies,const wxString & wh)1432 void pgServer::ShowDependencies(frmMain *form, ctlListView *Dependencies, const wxString &wh)
1433 {
1434 }
1435 
1436 
ShowDependents(frmMain * form,ctlListView * referencedBy,const wxString & wh)1437 void pgServer::ShowDependents(frmMain *form, ctlListView *referencedBy, const wxString &wh)
1438 {
1439 }
1440 
1441 
ReloadConfiguration()1442 bool pgServer::ReloadConfiguration()
1443 {
1444 	wxString sql = wxT("select pg_reload_conf()");
1445 	return conn->ExecuteVoid(sql);
1446 }
1447 
1448 
PauseReplay()1449 bool pgServer::PauseReplay()
1450 {
1451 	SetReplayPaused(true);
1452 	wxString sql;
1453 	if (conn->BackendMinimumVersion(10, 0))
1454 		sql = wxT("SELECT pg_wal_replay_pause()");
1455 	else
1456 		sql = wxT("SELECT pg_xlog_replay_pause()");
1457 	return conn->ExecuteVoid(sql);
1458 }
1459 
1460 
ResumeReplay()1461 bool pgServer::ResumeReplay()
1462 {
1463 	SetReplayPaused(false);
1464 	wxString sql;
1465 	if (conn->BackendMinimumVersion(10, 0))
1466 		sql = wxT("SELECT pg_wal_replay_resume()");
1467 	else
1468 		sql = wxT("SELECT pg_xlog_replay_resume()");
1469 	return conn->ExecuteVoid(sql);
1470 }
1471 
1472 
AddNamedRestorePoint()1473 bool pgServer::AddNamedRestorePoint()
1474 {
1475 	wxString namedrestorepoint = wxGetTextFromUser(_("Enter the name of the restore point to add"), _("Restore point name"));
1476 	if (!namedrestorepoint.IsEmpty())
1477 	{
1478 		wxString sql = wxT("select pg_create_restore_point(") + qtDbString(namedrestorepoint) + wxT(")");
1479 		return conn->ExecuteVoid(sql);
1480 	}
1481 	return false;
1482 }
1483 
pgServerCollection(pgaFactory * factory)1484 pgServerCollection::pgServerCollection(pgaFactory *factory)
1485 	: pgCollection(factory)
1486 {
1487 }
1488 
1489 
GetTranslatedMessage(int kindOfMessage) const1490 wxString pgServerCollection::GetTranslatedMessage(int kindOfMessage) const
1491 {
1492 	wxString message = wxEmptyString;
1493 
1494 	switch (kindOfMessage)
1495 	{
1496 		case RETRIEVINGDETAILS:
1497 			message = _("Retrieving details on servers");
1498 			break;
1499 		case REFRESHINGDETAILS:
1500 			message = _("Refreshing servers");
1501 			break;
1502 		case OBJECTSLISTREPORT:
1503 			message = _("Servers list report");
1504 			break;
1505 	}
1506 
1507 	return message;
1508 }
1509 
1510 
pgServerObjCollection(pgaFactory * factory,pgServer * sv)1511 pgServerObjCollection::pgServerObjCollection(pgaFactory *factory, pgServer *sv)
1512 	: pgCollection(factory)
1513 {
1514 	server = sv;
1515 }
1516 
1517 
CanCreate()1518 bool pgServerObjCollection::CanCreate()
1519 {
1520 	// We can't create resource queues on Greenplum yet.
1521 	if (IsCollectionForType(GP_RESOURCE_QUEUE))
1522 		return false;
1523 
1524 	// We can't create tablespaces on Greenplum
1525 	if (server->GetConnection()->GetIsGreenplum() && IsCollectionForType(PGM_TABLESPACE))
1526 		return false;
1527 
1528 	if (server->GetMetaType() == PGM_DATABASE)
1529 		return (GetServer()->GetCreatePrivilege() || GetServer()->GetSuperUser());
1530 	else
1531 	{
1532 		if (server->GetConnection()->BackendMinimumVersion(8, 1) && GetMetaType() == PGM_ROLE)
1533 			return (server->GetCreateRole() || server->GetSuperUser());
1534 		else if (server->GetConnection()->BackendMinimumVersion(8, 1) && GetMetaType() == PGM_DATABASE)
1535 			return (server->GetCreatePrivilege() || server->GetSuperUser());
1536 		else if (GetMetaType() == PGM_JOB)
1537 			return true;
1538 		else
1539 			return server->GetSuperUser();
1540 	}
1541 }
1542 
1543 
CreateObjects(pgCollection * obj,ctlTree * browser,const wxString & restr)1544 pgObject *pgServerFactory::CreateObjects(pgCollection *obj, ctlTree *browser, const wxString &restr)
1545 {
1546 	wxTreeItemId groupitem, serveritem;
1547 	wxTreeItemIdValue groupcookie;
1548 	bool found;
1549 
1550 	long numServers = settings->Read(wxT("Servers/Count"), 0L);
1551 
1552 	long loop, port, ssl = 0;
1553 	wxString key, servername, hostaddr, description, service, database, username, lastDatabase, lastSchema;
1554 	wxString storePwd, rolename, restore, serviceID, discoveryID, dbRestriction, colour;
1555 	wxString group, sslcert, sslkey, sslrootcert, sslcrl, sslcompression;
1556 
1557 #if defined(HAVE_OPENSSL_CRYPTO) || defined(HAVE_GCRYPT)
1558 	wxString sshTunnel, authModePwd, tunnelHost, tunnelUserName, tunnelPassword, publicKeyFile, identityFile;
1559 	long tunnelPort;
1560 #endif
1561 	pgServer *server = 0;
1562 
1563 	wxArrayString discoveredServers;
1564 
1565 	// Get the hostname for later...
1566 	char buf[255];
1567 	gethostname(buf, 255);
1568 	wxString hostname = wxString(buf, wxConvUTF8);
1569 
1570 	//wxLogError(wxT("Loading previously registered servers"));
1571 	wxLogInfo(wxT("Loading previously registered servers"));
1572 
1573 	for (loop = 1; loop <= numServers; ++loop)
1574 	{
1575 		key.Printf(wxT("Servers/%d/"), (int)loop);
1576 
1577 		settings->Read(key + wxT("Server"), &servername, wxEmptyString);
1578 		settings->Read(key + wxT("HostAddr"), &hostaddr, wxEmptyString);
1579 		settings->Read(key + wxT("Service"), &service, wxEmptyString);
1580 		settings->Read(key + wxT("ServiceID"), &serviceID, wxEmptyString);
1581 		settings->Read(key + wxT("DiscoveryID"), &discoveryID, serviceID);
1582 		settings->Read(key + wxT("Description"), &description, wxEmptyString);
1583 		settings->Read(key + wxT("StorePwd"), &storePwd, wxEmptyString);
1584 		settings->Read(key + wxT("Rolename"), &rolename, wxEmptyString);
1585 		settings->Read(key + wxT("Restore"), &restore, wxT("true"));
1586 		settings->Read(key + wxT("Port"), &port, 0);
1587 		settings->Read(key + wxT("Database"), &database, wxEmptyString);
1588 		settings->Read(key + wxT("Username"), &username, wxEmptyString);
1589 		settings->Read(key + wxT("LastDatabase"), &lastDatabase, wxEmptyString);
1590 		settings->Read(key + wxT("LastSchema"), &lastSchema, wxEmptyString);
1591 		settings->Read(key + wxT("DbRestriction"), &dbRestriction, wxEmptyString);
1592 		settings->Read(key + wxT("Colour"), &colour, wxEmptyString);
1593 		settings->Read(key + wxT("Group"), &group, wxT("Servers"));
1594 		settings->Read(key + wxT("SSLCert"), &sslcert, wxEmptyString);
1595 		settings->Read(key + wxT("SSLKey"), &sslkey, wxEmptyString);
1596 		settings->Read(key + wxT("SSLRootCert"), &sslrootcert, wxEmptyString);
1597 		settings->Read(key + wxT("SSLCrl"), &sslcrl, wxEmptyString);
1598 		settings->Read(key + wxT("SSLCompression"), &sslcompression, wxT("true"));
1599 #if defined(HAVE_OPENSSL_CRYPTO) || defined(HAVE_GCRYPT)
1600 		settings->Read(key + wxT("SSHTunnel"), &sshTunnel, wxT("false"));
1601 		settings->Read(key + wxT("TunnelHost"), &tunnelHost, wxEmptyString);
1602 		settings->Read(key + wxT("TunnelUserName"), &tunnelUserName, wxEmptyString);
1603 		settings->Read(key + wxT("TunnelModePwd"), &authModePwd, wxT("true"));
1604 		settings->Read(key + wxT("PublicKeyFile"), &publicKeyFile, wxEmptyString);
1605 		settings->Read(key + wxT("IdentityFile"), &identityFile, wxEmptyString);
1606 		settings->Read(key + wxT("TunnelPort"), &tunnelPort, DEFAULT_SSH_PORT);
1607 #endif
1608 		// Sanitize the colour
1609 		colour = colour.Trim();
1610 
1611 		if (!colour.IsEmpty())
1612 		{
1613 			wxColour cColour;
1614 
1615 			if (cColour.Set(colour))
1616 				colour = cColour.GetAsString(wxC2S_HTML_SYNTAX);
1617 			else
1618 				colour = wxEmptyString;
1619 		}
1620 
1621 		if (colour.IsEmpty())
1622 		{
1623 			wxColour cColour;
1624 			cColour.Set(wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW).GetAsString(wxC2S_HTML_SYNTAX));
1625 			colour = cColour.GetAsString(wxC2S_HTML_SYNTAX);
1626 		}
1627 
1628 		// SSL mode
1629 #ifdef PG_SSL
1630 		settings->Read(key + wxT("SSL"), &ssl, 0);
1631 #endif
1632 
1633 		// Sanitize the group
1634 		if (group.IsEmpty())
1635 		{
1636 			group = _("Servers");
1637 		}
1638 
1639 		// Add the Server node
1640 #if defined(HAVE_OPENSSL_CRYPTO) || defined(HAVE_GCRYPT)
1641 		server = new pgServer(servername, hostaddr, description, service, database, username, port, StrToBool(storePwd), rolename, StrToBool(restore), ssl,
1642 		                      colour, group, StrToBool(sshTunnel), tunnelHost, tunnelUserName, StrToBool(authModePwd), tunnelPassword, publicKeyFile, identityFile, tunnelPort);
1643 #else
1644 		server = new pgServer(servername, hostaddr, description, service, database, username, port, StrToBool(storePwd), rolename, StrToBool(restore), ssl,
1645 		                      colour, group);
1646 #endif
1647 		server->iSetLastDatabase(lastDatabase);
1648 		server->iSetLastSchema(lastSchema);
1649 		server->iSetService(service);
1650 		server->iSetServiceID(serviceID);
1651 		server->iSetDiscoveryID(discoveryID);
1652 		server->iSetDiscovered(false);
1653 		server->iSetDbRestriction(dbRestriction);
1654 		server->iSetServerIndex(loop);
1655 		server->SetSSLCert(sslcert);
1656 		server->SetSSLKey(sslkey);
1657 		server->SetSSLRootCert(sslrootcert);
1658 		server->SetSSLCrl(sslcrl);
1659 		server->iSetSSLCompression(StrToBool(sslcompression));
1660 
1661 		found = false;
1662 		if (browser->ItemHasChildren(obj->GetId()))
1663 		{
1664 			groupitem = browser->GetFirstChild(obj->GetId(), groupcookie);
1665 			while (!found && groupitem)
1666 			{
1667 				if (browser->GetItemText(groupitem).StartsWith(group))
1668 					found = true;
1669 				else
1670 					groupitem = browser->GetNextChild(obj->GetId(), groupcookie);
1671 			}
1672 		}
1673 
1674 		if (!found)
1675 		{
1676 			groupitem = browser->AppendItem(obj->GetId(), group, obj->GetIconId());
1677 		}
1678 
1679 		serveritem = browser->AppendItem(groupitem, server->GetFullName(), server->GetIconId(), -1, server);
1680 		browser->SortChildren(groupitem);
1681 		if (!server->GetColour().IsEmpty())
1682 			browser->SetItemBackgroundColour(serveritem, wxColour(server->GetColour()));
1683 
1684 		// Note if we're reloading a discovered server
1685 		if (!discoveryID.IsEmpty())
1686 			discoveredServers.Add(discoveryID);
1687 	}
1688 
1689 	group = _("Servers");
1690 
1691 #ifdef __WXMSW__
1692 
1693 	// Add local servers. Will currently only work on Win32 with >= BETA3
1694 	// of the Win32 PostgreSQL installer.
1695 	wxLogInfo(wxT("Loading servers registered on the local machine"));
1696 
1697 	pgRegKey::PGREGWOWMODE wowMode = pgRegKey::PGREG_WOW_DEFAULT;
1698 	if (::wxIsPlatform64Bit())
1699 		wowMode = pgRegKey::PGREG_WOW32;
1700 
1701 	pgRegKey *pgKey = pgRegKey::OpenRegKey(HKEY_LOCAL_MACHINE, wxT("Software\\PostgreSQL\\Services"), pgRegKey::PGREG_READ, wowMode);
1702 
1703 	if (pgKey == NULL)
1704 	{
1705 		wowMode = pgRegKey::PGREG_WOW64;
1706 		pgKey = pgRegKey::OpenRegKey(HKEY_LOCAL_MACHINE, wxT("Software\\PostgreSQL\\Services"), pgRegKey::PGREG_READ, wowMode);
1707 	}
1708 
1709 	while (pgKey != NULL)
1710 	{
1711 		pgRegKey *svcKey = NULL;
1712 		wxString svcName;
1713 		long cookie = 0;
1714 		DWORD tmpport = 0;
1715 		bool flag = false;
1716 
1717 		flag = pgKey->GetFirstKey(svcKey, cookie);
1718 
1719 		while (flag != false)
1720 		{
1721 			svcName = svcKey->GetKeyName();
1722 			// On Windows, the discovery ID is always the service name.
1723 			// Only load the server if we didn't load it with all the others.
1724 			if (discoveredServers.Index(svcName, false) < 0)
1725 			{
1726 				servername = wxT("localhost");
1727 				database = wxEmptyString;
1728 				svcKey->QueryValue(wxT("Display Name"), description);
1729 				svcKey->QueryValue(wxT("Database Superuser"), username);
1730 				svcKey->QueryValue(wxT("Port"), &tmpport);
1731 
1732 				// Add the Server node
1733 				server = new pgServer(servername, wxEmptyString, description, wxEmptyString, database, username, (long)tmpport, false, wxEmptyString, false);
1734 				server->iSetDiscoveryID(svcName);
1735 				server->iSetDiscovered(true);
1736 				server->iSetServiceID(svcName);
1737 				server->iSetGroup(group);
1738 
1739 				found = false;
1740 
1741 				if (browser->ItemHasChildren(browser->GetRootItem()))
1742 				{
1743 					groupitem = browser->GetFirstChild(browser->GetRootItem(), groupcookie);
1744 					while (!found && groupitem)
1745 					{
1746 						if (browser->GetItemText(groupitem).StartsWith(group))
1747 							found = true;
1748 						else
1749 							groupitem = browser->GetNextChild(browser->GetRootItem(), groupcookie);
1750 					}
1751 				}
1752 
1753 				if (!found)
1754 				{
1755 					groupitem = browser->AppendItem(browser->GetRootItem(), group, obj->GetIconId());
1756 					browser->SortChildren(browser->GetRootItem());
1757 				}
1758 
1759 				browser->AppendItem(groupitem, server->GetFullName(), server->GetIconId(), -1, server);
1760 				browser->SortChildren(groupitem);
1761 			}
1762 			// Release the current registry key
1763 			delete svcKey;
1764 
1765 			// Get the next one...
1766 			flag = pgKey->GetNextKey(svcKey, cookie);
1767 		}
1768 
1769 		/* Release current registry key */
1770 		delete pgKey;
1771 		pgKey = NULL;
1772 		/*
1773 		 * If wowMode is equal to WOW32, that means this machine is a 64 bit machine and we need to read now 64 bit registry
1774 		 */
1775 		if (wowMode == pgRegKey::PGREG_WOW32)
1776 		{
1777 			wowMode = pgRegKey::PGREG_WOW64;
1778 			pgKey = pgRegKey::OpenRegKey(HKEY_LOCAL_MACHINE, wxT("Software\\PostgreSQL\\Services"), pgRegKey::PGREG_READ, wowMode);
1779 		}
1780 	}
1781 #endif // __WXMSW__
1782 
1783 	// Add local servers on non-Win32 platforms (on Win32, they will be picked up above)
1784 #ifndef WIN32
1785 
1786 	// On Unix/Mac, the discovery ID can be anything. We use the PostgreSQL
1787 	// package config filename if it's present, as that is the only thing vaguely
1788 	// discoverable and unique to a given installation. We can do the same for
1789 	// other distros in the future if they drop a suitable file someplace.
1790 	// Look for any files that match the basic postgres*.ini pattern.
1791 
1792 	wxLogInfo(wxT("Loading servers registered on the local machine"));
1793 
1794 	if (wxFile::Exists(REGISTRY_FILE))
1795 	{
1796 		wxString version, locale;
1797 		long cookie;
1798 
1799 		wxFileInputStream fst(REGISTRY_FILE);
1800 		wxFileConfig *cnf = new wxFileConfig(fst);
1801 
1802 		// PostgreSQL servers
1803 		cnf->SetPath(wxT("/PostgreSQL"));
1804 		bool flag = cnf->GetFirstGroup(version, cookie);
1805 		while (flag)
1806 		{
1807 			// If there is no Version entry, this is probably an uninstalled server
1808 			if (cnf->Read(version + wxT("/Version"), wxEmptyString) != wxEmptyString)
1809 			{
1810 				// Only load this server if we haven't read it from the pgAdmin config
1811 				if (discoveredServers.Index(cnf->GetPath() + wxT("/") + version, false) < 0)
1812 				{
1813 
1814 					// Basic details
1815 					servername = wxT("localhost");
1816 					cnf->Read(version + wxT("/Description"), &description, wxT("PostgreSQL ") + version);
1817 					cnf->Read(version + wxT("/Superuser"), &username, wxEmptyString);
1818 					cnf->Read(version + wxT("/Port"), &port, 0);
1819 
1820 					// Add the item, if it looks sane
1821 					if (port != 0 && username != wxEmptyString)
1822 					{
1823 						server = new pgServer(servername, wxEmptyString, description, wxEmptyString, wxT("postgres"), username, port, false, rolename, 0);
1824 						server->iSetDiscoveryID(cnf->GetPath() + wxT("/") + version);
1825 						server->iSetDiscovered(true);
1826 						server->iSetGroup(group);
1827 						found = false;
1828 						if (browser->ItemHasChildren(browser->GetRootItem()))
1829 						{
1830 							groupitem = browser->GetFirstChild(browser->GetRootItem(), groupcookie);
1831 							while (!found && groupitem)
1832 							{
1833 								if (browser->GetItemText(groupitem).StartsWith(group))
1834 									found = true;
1835 								else
1836 									groupitem = browser->GetNextChild(browser->GetRootItem(), groupcookie);
1837 							}
1838 						}
1839 
1840 						if (!found)
1841 						{
1842 							groupitem = browser->AppendItem(browser->GetRootItem(), group, obj->GetIconId());
1843 							browser->SortChildren(browser->GetRootItem());
1844 						}
1845 
1846 						browser->AppendItem(groupitem, server->GetFullName(), server->GetIconId(), -1, server);
1847 						browser->SortChildren(groupitem);
1848 					}
1849 				}
1850 			}
1851 
1852 			flag = cnf->GetNextGroup(version, cookie);
1853 		}
1854 
1855 		// EnterpriseDB servers
1856 		cnf->SetPath(wxT("/EnterpriseDB"));
1857 		flag = cnf->GetFirstGroup(version, cookie);
1858 		while (flag)
1859 		{
1860 			// If there is no Version entry, this is probably an uninstalled server
1861 			if (cnf->Read(version + wxT("/Version"), wxEmptyString) != wxEmptyString)
1862 			{
1863 				// Only load this server if we haven't read it from the pgAdmin config
1864 				if (discoveredServers.Index(cnf->GetPath() + wxT("/") + version, false) < 0)
1865 				{
1866 
1867 					// Basic details
1868 					servername = wxT("localhost");
1869 					cnf->Read(version + wxT("/Description"), &description, wxT("EnterpriseDB ") + version);
1870 					cnf->Read(version + wxT("/Superuser"), &username, wxEmptyString);
1871 					cnf->Read(version + wxT("/Port"), &port, 0);
1872 
1873 					// Add the item, if it looks sane
1874 					if (port != 0 && username != wxEmptyString)
1875 					{
1876 						server = new pgServer(servername, wxEmptyString, description, wxEmptyString, wxT("edb"), username, port, false, rolename, 0);
1877 						server->iSetDiscoveryID(cnf->GetPath() + wxT("/") + version);
1878 						server->iSetDiscovered(true);
1879 						groupitem = browser->GetFirstChild(obj->GetId(), groupcookie);
1880 						if (!groupitem.IsOk())
1881 							groupitem = browser->AppendItem(obj->GetId(), group, obj->GetIconId());
1882 						browser->AppendItem(groupitem, server->GetFullName(), server->GetIconId(), -1, server);
1883 					}
1884 				}
1885 			}
1886 
1887 			flag = cnf->GetNextGroup(version, cookie);
1888 		}
1889 
1890 		delete cnf;
1891 		browser->SortChildren(obj->GetId());
1892 	}
1893 
1894 #endif // !WIN32
1895 
1896 	return server;
1897 }
1898 
1899 #include "images/servers.pngc"
1900 #include "images/server.pngc"
1901 #include "images/server-sm.pngc"
1902 #include "images/serverbad.pngc"
1903 #include "images/serverbad-sm.pngc"
1904 
pgServerFactory()1905 pgServerFactory::pgServerFactory()
1906 	: pgaFactory(__("Server"), __("New Server Registration"), __("Create a new Server registration."), server_png_img, server_sm_png_img)
1907 {
1908 	metaType = PGM_SERVER;
1909 	closedId = addIcon(serverbad_png_img);
1910 	smallClosedId = addIcon(serverbad_sm_png_img);
1911 }
1912 
CreateCollection(pgObject * obj)1913 pgCollection *pgServerFactory::CreateCollection(pgObject *obj)
1914 {
1915 	return new pgCollection(GetCollectionFactory());
1916 }
1917 
CreateCollection(pgObject * obj)1918 pgCollection *pgServerObjFactory::CreateCollection(pgObject *obj)
1919 {
1920 	return new pgServerObjCollection(GetCollectionFactory(), (pgServer *)obj);
1921 }
1922 
1923 pgServerFactory serverFactory;
1924 static pgaCollectionFactory cf(&serverFactory, __("Servers"), servers_png_img);
1925 
1926 #include "images/connect.pngc"
addServerFactory(menuFactoryList * list,wxMenu * mnu,ctlMenuToolbar * toolbar)1927 addServerFactory::addServerFactory(menuFactoryList *list, wxMenu *mnu, ctlMenuToolbar *toolbar) : actionFactory(list)
1928 {
1929 	mnu->Append(id, _("&Add Server..."), _("Add a connection to a server."));
1930 	toolbar->AddTool(id, _("Add Server"), *connect_png_bmp, _("Add a connection to a server."), wxITEM_NORMAL);
1931 }
1932 
1933 
StartDialog(frmMain * form,pgObject * obj)1934 wxWindow *addServerFactory::StartDialog(frmMain *form, pgObject *obj)
1935 {
1936 	int rc = PGCONN_BAD;
1937 
1938 	dlgServer dlg(&serverFactory, form, 0);
1939 	dlg.CenterOnParent();
1940 
1941 	while (rc != PGCONN_OK)
1942 	{
1943 		if (dlg.GoNew() != wxID_OK)
1944 			return 0;
1945 
1946 		pgServer *server = (pgServer *)dlg.CreateObject(0);
1947 
1948 		if (dlg.GetTryConnect())
1949 		{
1950 			wxBusyInfo waiting(wxString::Format(_("Connecting to server %s (%s:%d)"),
1951 			                                    server->GetDescription().c_str(), server->GetName().c_str(), server->GetPort()), form);
1952 
1953 			// Give the UI a chance to redraw
1954 			wxSafeYield();
1955 			wxMilliSleep(100);
1956 			wxSafeYield();
1957 
1958 			rc = server->Connect(form, false, dlg.GetPassword(), true);
1959 		}
1960 		else
1961 		{
1962 			rc = PGCONN_OK;
1963 			server->InvalidatePassword();
1964 		}
1965 		switch (rc)
1966 		{
1967 			case PGCONN_OK:
1968 			{
1969 				int icon;
1970 				ctlTree *browser = form->GetBrowser();
1971 				wxTreeItemId groupitem, parentitem;
1972 				wxTreeItemIdValue groupcookie;
1973 				int total;
1974 				wxString label;
1975 
1976 				if (server->GetConnected())
1977 					icon = serverFactory.GetIconId();
1978 				else
1979 					icon = serverFactory.GetClosedIconId();
1980 				wxLogInfo(wxT("pgServer object initialised as required."));
1981 
1982 				// Add the new server in its group
1983 				wxString group = server->GetGroup();
1984 				if (group.Length() == 0)
1985 					group = _("Servers");
1986 
1987 				// Get the parent group
1988 				groupitem = browser->GetFirstChild(browser->GetRootItem(), groupcookie);
1989 				while (!parentitem && groupitem)
1990 				{
1991 					if (browser->GetItemText(groupitem).StartsWith(group))
1992 						parentitem = groupitem;
1993 					groupitem = browser->GetNextChild(browser->GetRootItem(), groupcookie);
1994 				}
1995 
1996 				if (!parentitem)
1997 					parentitem = browser->AppendItem(browser->GetRootItem(), group, icon, -1);
1998 
1999 				browser->AppendItem(parentitem, server->GetFullName(), icon, -1, server);
2000 				browser->SortChildren(parentitem);
2001 				browser->Expand(parentitem);
2002 
2003 				total = browser->GetChildrenCount(parentitem, false);
2004 				label = group + wxT(" (") + NumToStr((long)total) + wxT(")");
2005 				browser->SetItemText(parentitem, label);
2006 
2007 				form->StoreServers();
2008 				return 0;
2009 			}
2010 			case PGCONN_DNSERR:
2011 			{
2012 				delete server;
2013 				break;
2014 			}
2015 			case PGCONN_BAD:
2016 			case PGCONN_BROKEN:
2017 			{
2018 				form->ReportConnError(server);
2019 				delete server;
2020 
2021 				break;
2022 			}
2023 			case PGCONN_SSHTUNNEL_ERROR:
2024 			{
2025 				delete server;
2026 				break;
2027 			}
2028 			default:
2029 			{
2030 				wxLogInfo(__("pgServer object didn't initialise because the user aborted."));
2031 				delete server;
2032 				return 0;
2033 			}
2034 		}
2035 	}
2036 	return 0;
2037 }
2038 
2039 
startServiceFactory(menuFactoryList * list,wxMenu * mnu,ctlMenuToolbar * toolbar)2040 startServiceFactory::startServiceFactory(menuFactoryList *list, wxMenu *mnu, ctlMenuToolbar *toolbar) : contextActionFactory(list)
2041 {
2042 	mnu->Append(id, _("Start Service"), _("Start PostgreSQL Service"));
2043 }
2044 
2045 
StartDialog(frmMain * form,pgObject * obj)2046 wxWindow *startServiceFactory::StartDialog(frmMain *form, pgObject *obj)
2047 {
2048 	pgServer *server = (pgServer *)obj;
2049 	form->StartMsg(_("Starting Service"));
2050 	bool rc = server->StartService();
2051 	if (rc)
2052 		form->execSelChange(server->GetId(), true);
2053 	form->EndMsg(rc);
2054 	return 0;
2055 }
2056 
2057 
CheckEnable(pgObject * obj)2058 bool startServiceFactory::CheckEnable(pgObject *obj)
2059 {
2060 	if (obj && obj->IsCreatedBy(serverFactory))
2061 	{
2062 		pgServer *server = (pgServer *)obj;
2063 		return server->GetServerControllable() && !server->GetServerRunning();
2064 	}
2065 	return false;
2066 }
2067 
2068 
stopServiceFactory(menuFactoryList * list,wxMenu * mnu,ctlMenuToolbar * toolbar)2069 stopServiceFactory::stopServiceFactory(menuFactoryList *list, wxMenu *mnu, ctlMenuToolbar *toolbar) : contextActionFactory(list)
2070 {
2071 	mnu->Append(id, _("Stop Service"), _("Stop PostgreSQL Service"));
2072 }
2073 
2074 
StartDialog(frmMain * form,pgObject * obj)2075 wxWindow *stopServiceFactory::StartDialog(frmMain *form, pgObject *obj)
2076 {
2077 	pgServer *server = (pgServer *)obj;
2078 	wxMessageDialog msg(form, _("Are you sure you wish to shutdown this server?"),
2079 	                    _("Stop Service"), wxYES_NO | wxICON_QUESTION);
2080 	if (msg.ShowModal() == wxID_YES)
2081 	{
2082 		form->StartMsg(_("Stopping service"));
2083 
2084 		bool done = server->StopService();
2085 
2086 		if (done)
2087 		{
2088 			if (server->Disconnect(form))
2089 			{
2090 				form->GetBrowser()->DeleteChildren(server->GetId());
2091 				form->execSelChange(server->GetId(), true);
2092 			}
2093 		}
2094 		form->EndMsg(done);
2095 	}
2096 
2097 	return 0;
2098 }
2099 
2100 
CheckEnable(pgObject * obj)2101 bool stopServiceFactory::CheckEnable(pgObject *obj)
2102 {
2103 	if (obj && obj->IsCreatedBy(serverFactory))
2104 	{
2105 		pgServer *server = (pgServer *)obj;
2106 		return server->GetServerControllable() && server->GetServerRunning();
2107 	}
2108 	return false;
2109 }
2110 
2111 
connectServerFactory(menuFactoryList * list,wxMenu * mnu,ctlMenuToolbar * toolbar)2112 connectServerFactory::connectServerFactory(menuFactoryList *list, wxMenu *mnu, ctlMenuToolbar *toolbar) : contextActionFactory(list)
2113 {
2114 	mnu->Append(id, _("&Connect"), _("Connect to the selected server."));
2115 }
2116 
2117 
StartDialog(frmMain * form,pgObject * obj)2118 wxWindow *connectServerFactory::StartDialog(frmMain *form, pgObject *obj)
2119 {
2120 	pgServer *server = (pgServer *)obj;
2121 	form->ReconnectServer(server);
2122 	return 0;
2123 }
2124 
2125 
CheckEnable(pgObject * obj)2126 bool connectServerFactory::CheckEnable(pgObject *obj)
2127 {
2128 	if (obj && obj->IsCreatedBy(serverFactory))
2129 		return !((pgServer *)obj)->GetConnected();
2130 
2131 	return false;
2132 }
2133 
2134 
disconnectServerFactory(menuFactoryList * list,wxMenu * mnu,ctlMenuToolbar * toolbar)2135 disconnectServerFactory::disconnectServerFactory(menuFactoryList *list, wxMenu *mnu, ctlMenuToolbar *toolbar) : contextActionFactory(list)
2136 {
2137 	mnu->Append(id, _("Disconnec&t server"), _("Disconnect from the selected server."));
2138 }
2139 
2140 
StartDialog(frmMain * form,pgObject * obj)2141 wxWindow *disconnectServerFactory::StartDialog(frmMain *form, pgObject *obj)
2142 {
2143 	if (obj->CheckOpenDialogs(form->GetBrowser(), form->GetBrowser()->GetSelection()))
2144 	{
2145 		wxString msg = _("There are properties dialogues open for one or more objects belonging to a database which will be disconnected. Please close the properties dialogues and try again.");
2146 		wxMessageBox(msg, _("Cannot disconnect database"), wxICON_WARNING | wxOK);
2147 	}
2148 	else
2149 	{
2150 		pgServer *server = (pgServer *)obj;
2151 		server->Disconnect(form);
2152 		server->UpdateIcon(form->GetBrowser());
2153 		form->GetBrowser()->DeleteChildren(obj->GetId());
2154 		form->execSelChange(obj->GetId(), true);
2155 	}
2156 
2157 	return 0;
2158 }
2159 
2160 
CheckEnable(pgObject * obj)2161 bool disconnectServerFactory::CheckEnable(pgObject *obj)
2162 {
2163 	if (obj && obj->IsCreatedBy(serverFactory))
2164 		return ((pgServer *)obj)->GetConnected();
2165 
2166 	return false;
2167 }
2168 
reloadconfServiceFactory(menuFactoryList * list,wxMenu * mnu,ctlMenuToolbar * toolbar)2169 reloadconfServiceFactory::reloadconfServiceFactory(menuFactoryList *list, wxMenu *mnu, ctlMenuToolbar *toolbar) : contextActionFactory(list)
2170 {
2171 	mnu->Append(id, _("Reload configuration"), _("Reload configuration"));
2172 }
2173 
2174 
StartDialog(frmMain * form,pgObject * obj)2175 wxWindow *reloadconfServiceFactory::StartDialog(frmMain *form, pgObject *obj)
2176 {
2177 	pgServer *server = (pgServer *)obj;
2178 	form->StartMsg(_("Reloading configuration"));
2179 	bool rc = server->ReloadConfiguration();
2180 	form->EndMsg(rc);
2181 	return 0;
2182 }
2183 
2184 
CheckEnable(pgObject * obj)2185 bool reloadconfServiceFactory::CheckEnable(pgObject *obj)
2186 {
2187 	if (obj && obj->IsCreatedBy(serverFactory))
2188 	{
2189 		pgServer *server = (pgServer *)obj;
2190 		return server->GetConnected() && server->connection()->BackendMinimumVersion(8, 1);
2191 	}
2192 	return false;
2193 }
2194 
2195 
pausereplayServiceFactory(menuFactoryList * list,wxMenu * mnu,ctlMenuToolbar * toolbar)2196 pausereplayServiceFactory::pausereplayServiceFactory(menuFactoryList *list, wxMenu *mnu, ctlMenuToolbar *toolbar) : contextActionFactory(list)
2197 {
2198 	mnu->Append(id, _("Pause replay of WAL"), _("Pause replay of WAL"));
2199 }
2200 
2201 
StartDialog(frmMain * form,pgObject * obj)2202 wxWindow *pausereplayServiceFactory::StartDialog(frmMain *form, pgObject *obj)
2203 {
2204 	pgServer *server = (pgServer *)obj;
2205 	form->StartMsg(_("Pausing replay of WAL"));
2206 	bool rc = server->PauseReplay();
2207 	form->EndMsg(rc);
2208 	return 0;
2209 }
2210 
2211 
CheckEnable(pgObject * obj)2212 bool pausereplayServiceFactory::CheckEnable(pgObject *obj)
2213 {
2214 	if (obj && obj->IsCreatedBy(serverFactory))
2215 	{
2216 		pgServer *server = (pgServer *)obj;
2217 		return server->GetConnected() &&
2218 		       server->connection()->BackendMinimumVersion(9, 1) &&
2219 		       server->GetInRecovery() &&
2220 		       !server->GetReplayPaused();
2221 	}
2222 	return false;
2223 }
2224 
2225 
resumereplayServiceFactory(menuFactoryList * list,wxMenu * mnu,ctlMenuToolbar * toolbar)2226 resumereplayServiceFactory::resumereplayServiceFactory(menuFactoryList *list, wxMenu *mnu, ctlMenuToolbar *toolbar) : contextActionFactory(list)
2227 {
2228 	mnu->Append(id, _("Resume replay of WAL"), _("Resume replay of WAL"));
2229 }
2230 
2231 
StartDialog(frmMain * form,pgObject * obj)2232 wxWindow *resumereplayServiceFactory::StartDialog(frmMain *form, pgObject *obj)
2233 {
2234 	pgServer *server = (pgServer *)obj;
2235 	form->StartMsg(_("Resuming replay of WAL"));
2236 	bool rc = server->ResumeReplay();
2237 	form->EndMsg(rc);
2238 	return 0;
2239 }
2240 
2241 
CheckEnable(pgObject * obj)2242 bool resumereplayServiceFactory::CheckEnable(pgObject *obj)
2243 {
2244 	if (obj && obj->IsCreatedBy(serverFactory))
2245 	{
2246 		pgServer *server = (pgServer *)obj;
2247 		return server->GetConnected() &&
2248 		       server->connection()->BackendMinimumVersion(9, 1) &&
2249 		       server->GetInRecovery() &&
2250 		       server->GetReplayPaused();
2251 	}
2252 	return false;
2253 }
2254 
2255 
addnamedrestorepointServiceFactory(menuFactoryList * list,wxMenu * mnu,ctlMenuToolbar * toolbar)2256 addnamedrestorepointServiceFactory::addnamedrestorepointServiceFactory(menuFactoryList *list, wxMenu *mnu, ctlMenuToolbar *toolbar) : contextActionFactory(list)
2257 {
2258 	mnu->Append(id, _("Add named restore point"), _("Add named restore point"));
2259 }
2260 
2261 
StartDialog(frmMain * form,pgObject * obj)2262 wxWindow *addnamedrestorepointServiceFactory::StartDialog(frmMain *form, pgObject *obj)
2263 {
2264 	pgServer *server = (pgServer *)obj;
2265 	form->StartMsg(_("Add named restore point"));
2266 	bool rc = server->AddNamedRestorePoint();
2267 	form->EndMsg(rc);
2268 	return 0;
2269 }
2270 
2271 
CheckEnable(pgObject * obj)2272 bool addnamedrestorepointServiceFactory::CheckEnable(pgObject *obj)
2273 {
2274 	if (obj && obj->IsCreatedBy(serverFactory))
2275 	{
2276 		pgServer *server = (pgServer *)obj;
2277 		return server->GetConnected() && server->connection()->BackendMinimumVersion(9, 1) && !server->GetInRecovery();
2278 	}
2279 	return false;
2280 }
2281