1 /* Copyright (C) 2007-2011 The SpringLobby Team. All rights reserved. */
2 //
3 // Class: Ui
4 //
5 
6 #ifdef _MSC_VER
7 #ifndef NOMINMAX
8 #define NOMINMAX
9 #endif // NOMINMAX
10 #include <winsock2.h>
11 #endif // _MSC_VER
12 
13 
14 #include <wx/textdlg.h>
15 #include <stdexcept>
16 #include <wx/intl.h>
17 #include <wx/utils.h>
18 #include <wx/debugrpt.h>
19 #include <wx/filename.h>
20 #include <wx/app.h>
21 
22 #include "ui.h"
23 #include "tasserver.h"
24 #include "settings.h"
25 #include "server.h"
26 #include "spring.h"
27 #include "channel/channel.h"
28 #include "connectwindow.h"
29 #include "mainwindow.h"
30 #include "user.h"
31 #include "utils/debug.h"
32 #include "utils/conversion.h"
33 #include "utils/uievents.h"
34 #include "updater/updatehelper.h"
35 #include "uiutils.h"
36 #include "chatpanel.h"
37 #include "battlelist/battlelisttab.h"
38 #include "hosting/battleroomtab.h"
39 #include "hosting/mainjoinbattletab.h"
40 #include "hosting/mainsingleplayertab.h"
41 #include "mainchattab.h"
42 #include "crashreport.h"
43 #include "maindownloadtab.h"
44 #include "downloader/prdownloader.h"
45 
46 #include "agreementdialog.h"
47 
48 #include "updater/updatehelper.h"
49 #include <wx/stdpaths.h>
50 
51 #include "reconnectdialog.h"
52 #include "utils/customdialogs.h"
53 #include "utils/platform.h"
54 #include "updater/versionchecker.h"
55 #include "sound/alsound.h"
56 #include <lslutils/globalsmanager.h>
57 #include <lslunitsync/c_api.h>
58 #include "utils/misc.h"
59 #include "textentrydialog.h"
60 
61 SLCONFIG("/General/AutoUpdate", true, "Determines if sprinlobby should check for updates on startup");
62 SLCONFIG("/GUI/StartTab", (long)MainWindow::PAGE_SINGLE, "which tab to show on startup");
63 SLCONFIG("/Chat/BroadcastEverywhere",true, "setting to spam the server messages in all channels");
64 SLCONFIG("/Server/Autoconnect", false, "Connect to server on startup");
65 
66 static const unsigned int s_reconnect_delay_ms = 6000;
67 
ui()68 Ui& ui()
69 {
70 	assert(wxThread::IsMain());
71 	static LSL::Util::LineInfo<Ui> m( AT );
72 	static LSL::Util::GlobalObjectHolder<Ui, LSL::Util::LineInfo<Ui> > m_ui( m );
73 	return m_ui;
74 }
75 
Ui()76 Ui::Ui() :
77 	wxEvtHandler(),
78 	m_serv(0),
79 	m_main_win(0),
80 	m_con_win(0),
81 	m_reconnect_dialog(0),
82 	m_first_update_trigger(true),
83 	m_recconecting_wait(false),
84 	m_disable_autoconnect(false),
85 	m_battle_info_updatedSink( this, &BattleEvents::GetBattleEventSender( ( BattleEvents::BattleInfoUpdate ) ) )
86 {
87 	m_main_win = new MainWindow( );
88 	CustomMessageBoxBase::setLobbypointer(m_main_win);
89 	m_serv = new TASServer();
90 	serverSelector().SetCurrentServer( m_serv );
91 	ConnectGlobalEvent(this, GlobalEvent::OnSpringTerminated, wxObjectEventFunction(&Ui::OnSpringTerminated));
92 	ConnectGlobalEvent(this, GlobalEvent::OnQuit, wxObjectEventFunction(&Ui::OnQuit));
93 }
94 
~Ui()95 Ui::~Ui()
96 {
97 	m_disable_autoconnect = true;
98 	Disconnect();
99 	delete m_serv;
100 }
101 
GetActiveChatPanel()102 ChatPanel* Ui::GetActiveChatPanel()
103 {
104 	return mw().GetActiveChatPanel();
105 }
106 
107 
mw()108 MainWindow& Ui::mw()
109 {
110 	assert(wxThread::IsMain());
111 	ASSERT_LOGIC( m_main_win != 0, _T("m_main_win = 0") );
112 	return *m_main_win;
113 }
114 
mw() const115 const MainWindow& Ui::mw() const
116 {
117 	ASSERT_LOGIC( m_main_win != 0, _T("m_main_win = 0") );
118 	return *m_main_win;
119 }
120 
121 
IsMainWindowCreated() const122 bool Ui::IsMainWindowCreated() const
123 {
124 	if ( m_main_win == 0 ) return false;
125 	else return true;
126 }
127 
128 
129 //! @brief Shows the main window on screen
ShowMainWindow()130 void Ui::ShowMainWindow()
131 {
132 	ASSERT_LOGIC( m_main_win != 0, _T("m_main_win = 0") );
133 	mw().Show(true);
134 }
135 
136 
137 //! @brief Show the connect window on screen
138 //!
139 //! @note It will create the ConnectWindow if not allready created
ShowConnectWindow()140 void Ui::ShowConnectWindow()
141 {
142 	if ( IsConnecting() || IsConnected() || m_recconecting_wait )
143 		return;
144 	if ( m_con_win == 0 ) {
145 		ASSERT_LOGIC( m_main_win != 0, _T("m_main_win = 0") );
146 		m_con_win = new ConnectWindow( m_main_win, *this );
147 	}
148 	m_con_win->CenterOnParent();
149 	m_con_win->Show(true);
150 	m_con_win->Raise();
151 }
152 
153 
154 //! @brief Connects to default server or opens the ConnectWindow
155 //!
156 //! @todo Fix Auto Connect
157 //! @see DoConnect
Connect()158 void Ui::Connect()
159 {
160 	wxString server_name = sett().GetDefaultServer();
161 	wxString nick = sett().GetServerAccountNick( server_name );
162 	bool autoconnect = cfg().ReadBool(_T( "/Server/Autoconnect" ));
163 	if ( !autoconnect || server_name.IsEmpty() || nick.IsEmpty() ) {
164 		ShowConnectWindow();
165 		return;
166 	}
167 	if (m_disable_autoconnect)
168 		return;
169 	m_con_win = 0;
170 	wxString pass = sett().GetServerAccountPass( server_name );
171 	DoConnect( server_name, nick, pass);
172 }
173 
174 
Reconnect()175 void Ui::Reconnect()
176 {
177 	wxString servname = sett().GetDefaultServer();
178 
179 	wxString pass  = sett().GetServerAccountPass(servname);
180 	if ( !sett().GetServerAccountSavePass(servname) ) {
181 		if ( !AskPassword( _("Server password"), _("Password"), pass ) ) return;
182 	}
183 
184 	Disconnect();
185 	DoConnect( servname, sett().GetServerAccountNick(servname), pass );
186 }
187 
188 
Disconnect()189 void Ui::Disconnect()
190 {
191 	if ( m_serv != 0 ) {
192 		if ( IsConnected() ) {
193 			serverSelector().GetServer().Disconnect();
194 		}
195 	}
196 }
197 
198 
199 //! @brief Opens the accutial connection to a server.
DoConnect(const wxString & servername,const wxString & username,const wxString & password)200 void Ui::DoConnect( const wxString& servername, const wxString& username, const wxString& password )
201 {
202 	if ( m_reconnect_delay_timer.IsRunning() ) {
203 		m_recconecting_wait = true;
204 		AutocloseMessageBox m( &mw(), _("Waiting for reconnect"), wxMessageBoxCaptionStr, s_reconnect_delay_ms );
205 		int res = m.ShowModal();
206 		m_recconecting_wait = false;
207 		if ( res == wxID_CANCEL ) {
208 			m_reconnect_delay_timer.Stop();
209 			return;
210 		}
211 	}
212 
213 	wxString host;
214 	int port;
215 
216 	if ( servername != m_last_used_backup_server ) { // do not save the server as default if it's a backup one
217 		sett().SetDefaultServer( servername );
218 	} else {
219 		m_last_used_backup_server = wxEmptyString;
220 	}
221 
222 	if ( !sett().ServerExists( servername ) ) {
223 		ASSERT_LOGIC( false, _T("Server does not exist in settings") );
224 		return;
225 	}
226 
227 	Disconnect();
228 
229 	serverSelector().GetServer().SetUsername( username );
230 	serverSelector().GetServer().SetPassword( password );
231 
232 	if ( sett().GetServerAccountSavePass( servername ) ) {
233 		if ( serverSelector().GetServer().IsPasswordHash(password) ) sett().SetServerAccountPass( servername, password );
234 		else sett().SetServerAccountPass( servername, serverSelector().GetServer().GetPasswordHash( password ) );
235 	} else {
236 		sett().SetServerAccountPass( servername, wxEmptyString );
237 	}
238 
239 	host = sett().GetServerHost( servername );
240 	port = sett().GetServerPort( servername );
241 
242 	AddServerWindow( servername );
243 	serverSelector().GetServer().uidata.panel->StatusMessage( _T("Connecting to server ") + servername + _T("...") );
244 
245 	// Connect
246 	serverSelector().GetServer().Connect( servername, host, port );
247 
248 }
249 
AddServerWindow(const wxString & servername)250 void Ui::AddServerWindow( const wxString& servername )
251 {
252 	if ( !serverSelector().GetServer().uidata.panel ) {
253 		serverSelector().GetServer().uidata.panel = m_main_win->GetChatTab().AddChatPanel( *m_serv, servername );
254 
255 	}
256 }
257 
258 
ReopenServerTab()259 void Ui::ReopenServerTab()
260 {
261 	if ( serverSelector().GetServer().IsOnline() ) {
262 		AddServerWindow( serverSelector().GetServer().GetServerName() );
263 		// re-add all users to the user list
264 		const UserList& list = serverSelector().GetServer().GetUserList();
265 		for ( unsigned int i = 0; i < list.GetNumUsers(); i++ ) {
266 			serverSelector().GetServer().uidata.panel->OnChannelJoin( list.GetUser(i) );
267 		}
268 	}
269 }
270 
DoRegister(const wxString & servername,const wxString & username,const wxString & password,wxString & reason)271 bool Ui::DoRegister( const wxString& servername, const wxString& username, const wxString& password,wxString& reason)
272 {
273 	wxString host;
274 	int port;
275 
276 	if ( !sett().ServerExists( servername ) ) {
277 		ASSERT_LOGIC( false, _T("Server does not exist in settings") );
278 		return false;
279 	}
280 
281 	host = sett().GetServerHost( servername );
282 	port = sett().GetServerPort( servername );
283 	bool success = serverSelector().GetServer().Register( host, port, username, password,reason );
284 	if ( success ) {
285 		customMessageBox(SL_MAIN_ICON, _("Registration successful,\nyou should now be able to login."), _("Registration successful"), wxOK );
286 	} else {
287 		wxLogWarning( _T("registration failed, reason: %s"), reason.c_str()  );
288 		if ( reason == _("Connection timed out") || reason.IsEmpty() ) ConnectionFailurePrompt();
289 		else	customMessageBox(SL_MAIN_ICON,_("Registration failed, the reason was:\n")+ reason , _("Registration failed."), wxOK );
290 	}
291 	return success;
292 
293 }
294 
IsConnecting() const295 bool Ui::IsConnecting() const
296 {
297 	if ( m_reconnect_dialog != 0 ) return m_reconnect_dialog->IsShown();
298 	return false;
299 }
300 
IsConnected() const301 bool Ui::IsConnected() const
302 {
303 	if ( m_serv != 0 ) return m_serv->IsConnected();
304 	return false;
305 }
306 
JoinChannel(const wxString & name,const wxString & password)307 void Ui::JoinChannel( const wxString& name, const wxString& password )
308 {
309 	if ( m_serv != 0 ) serverSelector().GetServer().JoinChannel( name, password );
310 }
311 
312 
IsSpringRunning() const313 bool Ui::IsSpringRunning() const
314 {
315 	return spring().IsRunning();
316 }
317 
318 
319 //! @brief Quits the entire application
Quit()320 void Ui::Quit()
321 {
322 	m_disable_autoconnect = true;
323 	Disconnect();
324 	if ( m_con_win != 0 )
325 		m_con_win->Close();
326 }
327 
Download(const wxString & category,const wxString & name,const wxString &)328 void Ui::Download( const wxString& category, const wxString& name, const wxString& /*hash */)
329 {
330 	const std::string scat = STD_STRING(category);
331 	const std::string sname = STD_STRING(name);
332 	int count = prDownloader().GetDownload(scat, sname);
333 	assert( count > 0 );
334 }
335 
336 //void Ui::DownloadFileWebsite( const wxString& name )
337 //{
338 //	wxString newname = name;
339 //	newname.Replace( _T(" "), _T("+") );
340 //	wxString url = _T("http://spring.jobjol.nl/search_result.php?search_cat=1&select_select=select_file_subject&Submit=Search&search=") + newname;
341 //	OpenWebBrowser ( url );
342 //}
343 
344 //! @brief Display a dialog asking a question with OK and Canel buttons
345 //!
346 //! @return true if OK button was pressed
347 //! @note this does not return until the user pressed any of the buttons or closed the dialog.
Ask(const wxString & heading,const wxString & question) const348 bool Ui::Ask( const wxString& heading, const wxString& question ) const
349 {
350 	int answer = customMessageBox( SL_MAIN_ICON, question, heading, wxYES_NO );
351 	return ( answer == wxYES );
352 }
353 
354 //! cannot be const because parent window cannot be const
AskPassword(const wxString & heading,const wxString & message,wxString & password)355 bool Ui::AskPassword( const wxString& heading, const wxString& message, wxString& password )
356 {
357 	wxPasswordEntryDialog pw_dlg( &mw(), message, heading, password );
358 	int res = pw_dlg.ShowModal();
359 	password = pw_dlg.GetValue();
360 	return ( res == wxID_OK );
361 }
362 
AskText(const wxString & heading,const wxString & question,wxString & answer,bool multiline)363 bool Ui::AskText( const wxString& heading, const wxString& question, wxString& answer, bool multiline )
364 {
365 	TextEntryDialog name_dlg( &mw(), question, heading, answer, multiline );
366 	int res = name_dlg.ShowModal();
367 	answer = name_dlg.GetValue();
368 	return ( res == wxID_OK );
369 }
370 
371 
ShowMessage(const wxString & heading,const wxString & message) const372 void Ui::ShowMessage( const wxString& heading, const wxString& message ) const
373 {
374 	if ( m_main_win == 0 ) return;
375 	serverMessageBox( SL_MAIN_ICON, message, heading, wxOK);
376 }
377 
378 
ExecuteSayCommand(const wxString & cmd)379 bool Ui::ExecuteSayCommand( const wxString& cmd )
380 {
381 	if ( !IsConnected() ) return false;
382 
383 	if ( (cmd.BeforeFirst(' ').Lower() == _T("/join")) || (cmd.BeforeFirst(' ').Lower() == _T("/j")) ) {
384 		wxString channel = cmd.AfterFirst(' ');
385 		wxString pass = channel.AfterFirst(' ');
386 		if ( !pass.IsEmpty() ) channel = channel.BeforeFirst(' ');
387 		if ( channel.StartsWith(_T("#")) ) channel.Remove( 0, 1 );
388 		serverSelector().GetServer().JoinChannel( channel, pass );
389 		return true;
390 	} else if ( cmd.BeforeFirst(' ').Lower() == _T("/away") ) {
391 		serverSelector().GetServer().GetMe().Status().away = true;
392 		serverSelector().GetServer().GetMe().SendMyUserStatus();
393 		mw().GetJoinTab().GetBattleRoomTab().UpdateMyInfo();
394 		return true;
395 	} else if ( cmd.BeforeFirst(' ').Lower() == _T("/back") ) {
396 		if ( IsConnected() ) {
397 			serverSelector().GetServer().GetMe().Status().away = false;
398 			serverSelector().GetServer().GetMe().SendMyUserStatus();
399 			mw().GetJoinTab().GetBattleRoomTab().UpdateMyInfo();
400 			return true;
401 		}
402 	} else if ( cmd.BeforeFirst(' ').Lower() == _T("/ingame") ) {
403 		wxString nick = cmd.AfterFirst(' ');
404 		serverSelector().GetServer().RequestInGameTime( nick );
405 		return true;
406 	} else if ( cmd.BeforeFirst(' ').Lower() == _T("/help") ) {
407 		wxString topic = cmd.AfterFirst(' ');
408 		ConsoleHelp( topic.Lower() );
409 		return true;
410 	} else if ( cmd.BeforeFirst(' ').Lower() == _T("/msg") ) {
411 		wxString user = cmd.AfterFirst(' ').BeforeFirst(' ');
412 		wxString msg = cmd.AfterFirst(' ').AfterFirst(' ');
413 		serverSelector().GetServer().SayPrivate( user, msg );
414 		return true;
415 	} else if ( cmd.BeforeFirst(' ').Lower() == _T("/channels") ) {
416 		mw().ShowChannelChooser();
417 		return true;
418 	}
419 	return false;
420 }
421 
422 
ConsoleHelp(const wxString & topic)423 void Ui::ConsoleHelp( const wxString& topic )
424 {
425 	ChatPanel* panel = GetActiveChatPanel();
426 	if ( panel == 0 ) {
427 		ShowMessage( _("Help error"), _("Type /help in a chat box. (A bug currently prevents this from working in battleroom") );
428 		return;
429 	}
430 	if ( topic == wxEmptyString ) {
431 		panel->ClientMessage( IdentityString( _("%s commands help.") ) );
432 		panel->ClientMessage( wxEmptyString );
433 		panel->ClientMessage( _("Global commands:") );
434 		panel->ClientMessage( _("  \"/away\" - Sets your status to away.") );
435 		panel->ClientMessage( _("  \"/back\" - Resets your away status.") );
436 		panel->ClientMessage( _("  \"/changepassword2 newpassword\" - Changes the current active account's password, needs the old password saved in login box") );
437 		panel->ClientMessage( _("  \"/changepassword oldpassword newpassword\" - Changes the current active account's password, password cannot contain spaces") );
438 		panel->ClientMessage( _("  \"/channels\" - Lists currently active channels.") );
439 		panel->ClientMessage( _("  \"/help [topic]\" - Put topic if you want to know more specific information about a command.") );
440 		panel->ClientMessage( _("  \"/join channel [password]\" - Joins a channel.") );
441 		panel->ClientMessage( _("  \"/j\" - Alias to /join.") );
442 		panel->ClientMessage( _("  \"/ingame\" - Shows how much time you have in game.") );
443 		panel->ClientMessage( _("  \"/msg username [text]\" - Sends a private message containing text to username.") );
444 		panel->ClientMessage( _("  \"/part\" - Leaves current channel.") );
445 		panel->ClientMessage( _("  \"/p\" - Alias to /part.") );
446 		panel->ClientMessage( _("  \"/rename newalias\" - Changes your nickname to newalias.") );
447 		panel->ClientMessage( IdentityString( _("  \"/sayver\" - Says what version of %s you have in chat.") ) );
448 		panel->ClientMessage( _("  \"/testmd5 text\" - Returns md5-b64 hash of given text.") );
449 		panel->ClientMessage( IdentityString( _("  \"/ver\" - Displays what version of %s you have.") ) );
450 		panel->ClientMessage( _("  \"/clear\" - Clears all text from current chat panel") );
451 		panel->ClientMessage( wxEmptyString );
452 		panel->ClientMessage( _("Chat commands:") );
453 		panel->ClientMessage( _("  \"/me action\" - Say IRC style action message.") );
454 		panel->ClientMessage( wxEmptyString );
455 		panel->ClientMessage( _("If you are missing any commands, go to #springlobby and try to type it there :)") );
456 //    panel->ClientMessage( _("  \"/\" - .") );
457 	} else if ( topic == _T("topics") ) {
458 		panel->ClientMessage( _("No topics written yet.") );
459 	} else {
460 		panel->ClientMessage( _("The topic \"") + topic + _("\" was not found. Type \"/help topics\" only for available topics.") );
461 	}
462 }
463 
464 
GetChannelChatPanel(const wxString & channel)465 ChatPanel* Ui::GetChannelChatPanel( const wxString& channel )
466 {
467 	return mw().GetChannelChatPanel( channel );
468 }
469 
470 
471 ////////////////////////////////////////////////////////////////////////////////////////////
472 // EVENTS
473 ////////////////////////////////////////////////////////////////////////////////////////////
474 
475 //! @brief Called when connected to a server
476 //!
477 //! @todo Display in servertab
OnConnected(Server & server,const wxString & server_name,const wxString &,bool)478 void Ui::OnConnected( Server& server, const wxString& server_name, const wxString& /*unused*/, bool /*supported*/ )
479 {
480 	wxLogDebugFunc( wxEmptyString );
481 
482 	if ( server.uidata.panel ) server.uidata.panel->StatusMessage( _T("Connected to ") + server_name + _T(".") );
483 	mw().GetBattleListTab().OnConnected();
484 
485 	delete m_con_win;
486 	m_con_win = 0;
487 
488 	delete m_reconnect_dialog;
489 	m_reconnect_dialog = 0;
490 }
491 
492 
VersionGetMajor(const std::string & version)493 std::string VersionGetMajor(const std::string& version)
494 {
495 	const int pos = version.find(".");
496 	if (pos>0) {
497 		return version.substr(0, pos);
498 	}
499 	return version;
500 }
501 
VersionIsRelease(const std::string & version)502 bool VersionIsRelease(const std::string& version) { //try to detect if a version is major
503 	const std::string allowedChars = "01234567890.";
504 	for(int i=0; i<version.length(); i++) {
505 		if (allowedChars.find(version[i]) == std::string::npos) { //found invalid char -> not stable version
506 			return false;
507 		}
508 	}
509 	return true;
510 }
511 
VersionSyncCompatible(const std::string & ver1,const std::string & ver2)512 bool VersionSyncCompatible(const std::string& ver1, const std::string& ver2)
513 {
514 	if (ver1 == ver2) {
515 		return true;
516 	}
517 	if ( (VersionIsRelease(ver1) &&  VersionIsRelease(ver2)) &&
518 	 (VersionGetMajor(ver1) == VersionGetMajor(ver2))) {
519 		return true;
520 	}
521 	return false;
522 }
523 
IsSpringCompatible(const wxString & engine,const wxString & version)524 bool Ui::IsSpringCompatible(const wxString& engine, const wxString& version)
525 {
526 	assert(engine == _T("spring"));
527 	if ( sett().GetDisableSpringVersionCheck() ) return true;
528 	const std::string neededversion = STD_STRING(version);
529 	const auto versionlist = sett().GetSpringVersionList();
530 	for ( const auto pair : versionlist ) {
531 		const wxString ver = pair.first;
532 		const LSL::SpringBundle bundle = pair.second;
533 		if ( VersionSyncCompatible(neededversion, STD_STRING(ver))) {
534 			if ( sett().GetCurrentUsedSpringIndex() != ver ) {
535 				wxLogMessage(_T("server enforce usage of version: %s, switching to profile: %s"), ver.c_str(), ver.c_str());
536 				sett().SetUsedSpringIndex( ver );
537 				LSL::usync().ReloadUnitSyncLib();
538 			}
539 			return true;
540 		}
541 	}
542 	if ( wxYES == customMessageBox( SL_MAIN_ICON,
543 					_("The selected preset requires the engine ") + engine + _(" ") + version+ _(". Should it be downloaded? \nPlease reselect the preset after download finished"),
544 					_("Engine missing"),
545 					wxYES_NO ) )
546 
547 		Download(TowxString(PrDownloader::GetEngineCat()), version, wxEmptyString);
548 	return false; // no compatible version found
549 }
550 
551 
OnLoggedIn()552 void Ui::OnLoggedIn( )
553 {
554 	if ( m_main_win == 0 ) return;
555 	mw().GetChatTab().RejoinChannels();
556 	// FIXME RejoinChannels changes active tab, we change back to
557 	// default tab on auto connect
558 	if ( cfg().ReadBool(_T( "/Server/Autoconnect" )) )
559 		mw().ShowTab( cfg().ReadLong(_T( "/GUI/StartTab" )));
560 	mw().GetBattleListTab().SortBattleList();
561 }
562 
563 
OnDisconnected(Server & server,bool wasonline)564 void Ui::OnDisconnected( Server& server, bool wasonline )
565 {
566 	m_reconnect_delay_timer.Start( s_reconnect_delay_ms, true );
567 	if ( m_main_win == 0 ) return;
568 	wxLogDebugFunc( wxEmptyString );
569 	if (!&server) {
570 		wxLogError(_T("WTF got null reference!!!"));
571 		return;
572 	}
573 
574 	mw().GetJoinTab().LeaveCurrentBattle();
575 	mw().GetBattleListTab().RemoveAllBattles();
576 
577 	mw().GetChatTab().LeaveChannels();
578 
579 	wxString disconnect_msg = wxFormat(_("disconnected from server: %s") ) % server.GetServerName();
580 	UiEvents::GetStatusEventSender( UiEvents::addStatusMessage ).SendEvent(
581 		UiEvents::StatusData( disconnect_msg, 1 ) );
582 	if ( !wxTheApp->IsActive() ) {
583 		UiEvents::GetNotificationEventSender().SendEvent(
584 			UiEvents::NotficationData( UiEvents::ServerConnection, disconnect_msg ) );
585 	}
586 	if ( server.uidata.panel ) {
587 		server.uidata.panel->StatusMessage( disconnect_msg );
588 
589 		server.uidata.panel->SetServer( 0 );
590 	}
591 	if ( (!m_disable_autoconnect) && (!wasonline)) {// couldn't even estabilish a socket, prompt the user to switch to another server
592 		ConnectionFailurePrompt();
593 	}
594 }
595 
ConnectionFailurePrompt()596 void Ui::ConnectionFailurePrompt()
597 {
598 	if ( m_reconnect_dialog != 0 ) {
599 		return;
600 	}
601 	if ( m_recconecting_wait ) {
602 		return;
603 	}
604 	// if connect window instance exists, delete it to avoid 2 windows which do the same task
605 	delete m_con_win;
606 	m_con_win = 0;
607 	m_reconnect_dialog = new ReconnectDialog();
608 	int returnval = m_reconnect_dialog->ShowModal();
609 	delete m_reconnect_dialog;
610 	m_reconnect_dialog = 0;
611 	switch ( returnval ) {
612 	case wxID_YES: { // try again with the same server/settings
613 		Reconnect();
614 		break;
615 	}
616 	case wxID_NO: { // switch to next server in the list
617 		m_last_used_backup_server = GetNextServer();
618 		wxString current_server = sett().GetDefaultServer();
619 		sett().SetDefaultServer( m_last_used_backup_server );// temp set backup server as default
620 		Connect();
621 		sett().SetDefaultServer( current_server ); // restore original serv
622 		break;
623 	}
624 	default:
625 	case wxID_CANCEL: { // do nothing
626 		return;
627 	}
628 	}
629 }
630 
631 
632 
GetNextServer()633 wxString Ui::GetNextServer()
634 {
635 	wxString previous_server = m_last_used_backup_server;
636 	if ( previous_server.IsEmpty() ) previous_server = sett().GetDefaultServer();
637 	wxArrayString serverlist = sett().GetServers();
638 	int position = serverlist.Index( previous_server );
639 	if ( position == wxNOT_FOUND ) position = -1;
640 	position = ( position + 1) % serverlist.GetCount(); // switch to next in the list
641 	return serverlist[position];
642 }
643 
IsAutoJoinChannel(Channel & chan)644 static inline bool IsAutoJoinChannel( Channel& chan )
645 {
646 	typedef std::vector<ChannelJoinInfo>
647 	Vec;
648 	typedef Vec::const_iterator
649 	VecIt;
650 	const Vec chans = sett().GetChannelsJoin();
651 	for ( VecIt it = chans.begin(); it != chans.end(); ++it ) {
652 		if ( it->name == chan.GetName() )
653 			return true;
654 	}
655 	return false;
656 }
657 //! @brief Called when client has joined a channel
658 //!
659 //! @todo Check if a pannel allready exists for this channel
OnJoinedChannelSuccessful(Channel & chan)660 void Ui::OnJoinedChannelSuccessful( Channel& chan )
661 {
662 	bool doFocus = !cfg().ReadBool(_T( "/Server/Autoconnect" )) || !IsAutoJoinChannel( chan );
663 	bool panel_exists = mw().GetChannelChatPanel( chan.GetName() ) != NULL;
664 	OnJoinedChannelSuccessful( chan, !panel_exists && doFocus );
665 }
666 
OnJoinedChannelSuccessful(Channel & chan,bool focusTab)667 void Ui::OnJoinedChannelSuccessful( Channel& chan, bool focusTab )
668 {
669 	if ( m_main_win == 0 ) return;
670 	wxLogDebugFunc( wxEmptyString );
671 
672 	chan.uidata.panel = 0;
673 
674 	mw().OpenChannelChat( chan, focusTab );
675 }
676 
677 //! @brief Called when something is said in a channel
OnChannelSaid(Channel & channel,User & user,const wxString & message)678 void Ui::OnChannelSaid( Channel& channel, User& user, const wxString& message )
679 {
680 	wxLogDebugFunc( wxEmptyString );
681 	if ( channel.uidata.panel == 0 ) {
682 		wxLogError( _T("OnChannelSaid: ud->panel NULL") );
683 		return;
684 	}
685 	channel.uidata.panel->Said( user.GetNick(), message );
686 }
687 
688 
OnChannelDidAction(Channel & channel,User & user,const wxString & action)689 void Ui::OnChannelDidAction( Channel& channel , User& user, const wxString& action )
690 {
691 	wxLogDebugFunc( wxEmptyString );
692 	if ( channel.uidata.panel == 0 ) {
693 		wxLogError( _T("OnChannelDidAction: ud->panel NULL") );
694 		return;
695 	}
696 	channel.uidata.panel->DidAction( user.GetNick(), action );
697 }
698 
699 
OnChannelMessage(const wxString & channel,const wxString & msg)700 void Ui::OnChannelMessage( const wxString& channel, const wxString& msg )
701 {
702 	ChatPanel* panel = GetChannelChatPanel( channel );
703 	if ( panel != 0 ) {
704 		panel->StatusMessage( msg );
705 	}
706 }
707 
708 
OnUserJoinedChannel(Channel & chan,User & user)709 void Ui::OnUserJoinedChannel( Channel& chan, User& user )
710 {
711 	//wxLogDebugFunc( wxEmptyString );
712 	if ( chan.uidata.panel == 0 ) {
713 		wxLogError( _T("OnUserJoinedChannel: ud->panel NULL") );
714 		return;
715 	}
716 	chan.uidata.panel->Joined( user );
717 }
718 
719 
OnChannelJoin(Channel & chan,User & user)720 void Ui::OnChannelJoin( Channel& chan, User& user )
721 {
722 	//wxLogDebugFunc( wxEmptyString );
723 	if ( chan.uidata.panel == 0 ) {
724 		wxLogError( _T("OnChannelJoin: ud->panel NULL") );
725 		return;
726 	}
727 	chan.uidata.panel->OnChannelJoin( user );
728 }
729 
730 
OnUserLeftChannel(Channel & chan,User & user,const wxString & reason)731 void Ui::OnUserLeftChannel( Channel& chan, User& user, const wxString& reason )
732 {
733 	//wxLogDebugFunc( wxEmptyString );
734 	if ( chan.uidata.panel == 0 ) {
735 		wxLogError( _T("OnUserLeftChannel: ud->panel NULL") );
736 		return;
737 	}
738 	chan.uidata.panel->Parted( user, reason );
739 }
740 
741 
OnChannelTopic(Channel & channel,const wxString & user,const wxString & topic)742 void Ui::OnChannelTopic( Channel& channel, const wxString& user, const wxString& topic )
743 {
744 	wxLogDebugFunc( wxEmptyString );
745 	if ( channel.uidata.panel == 0 ) {
746 		wxLogError( _T("OnChannelTopic: ud->panel NULL") );
747 		return;
748 	}
749 	channel.uidata.panel->SetTopic( user, topic );
750 }
751 
752 
OnChannelList(const wxString & channel,const int & numusers)753 void Ui::OnChannelList( const wxString& channel, const int& numusers )
754 {
755 	ChatPanel* panel = GetActiveChatPanel();
756 	if ( panel == 0 ) {
757 		ShowMessage( _("error"), _("no active chat panels open.") );
758 		return;
759 	}
760 	panel->StatusMessage( wxFormat( _("%s (%d users)") ) % channel % numusers );
761 }
762 
763 
OnUserOnline(User & user)764 void Ui::OnUserOnline( User& user )
765 {
766 	if ( m_main_win == 0 ) return;
767 	mw().GetChatTab().OnUserConnected( user );
768 }
769 
770 
OnUserOffline(User & user)771 void Ui::OnUserOffline( User& user )
772 {
773 	if ( m_main_win == 0 ) return;
774 	mw().GetChatTab().OnUserDisconnected( user );
775 	if ( user.uidata.panel ) {
776 		user.uidata.panel->SetUser( 0 );
777 		user.uidata.panel = 0;
778 	}
779 }
780 
781 
OnUserStatusChanged(User & user)782 void Ui::OnUserStatusChanged( User& user )
783 {
784 	if ( m_main_win == 0 ) return;
785 	for ( int i = 0; i < serverSelector().GetServer().GetNumChannels(); i++ ) {
786 		Channel& chan = serverSelector().GetServer().GetChannel( i );
787 		if ( ( chan.UserExists(user.GetNick()) ) && ( chan.uidata.panel != 0 ) ) {
788 			chan.uidata.panel->UserStatusUpdated( user );
789 		}
790 	}
791 	if ( user.uidata.panel ) {
792 		user.uidata.panel->UserStatusUpdated( user );
793 	}
794 	if ( user.GetStatus().in_game ) mw().GetBattleListTab().UserUpdate( user );
795 	try {
796 		ChatPanel& server = mw().GetChatTab().ServerChat();
797 		server.UserStatusUpdated( user );
798 	} catch(...) {}
799 }
800 
801 
OnUnknownCommand(Server & server,const wxString & command,const wxString & params)802 void Ui::OnUnknownCommand( Server& server, const wxString& command, const wxString& params )
803 {
804 	if ( server.uidata.panel != 0 ) server.uidata.panel->UnknownCommand( command, params );
805 }
806 
807 
OnMotd(Server & server,const wxString & message)808 void Ui::OnMotd( Server& server, const wxString& message )
809 {
810 	if ( server.uidata.panel != 0 ) server.uidata.panel->Motd( message );
811 }
812 
OnServerBroadcast(Server &,const wxString & message)813 void Ui::OnServerBroadcast( Server& /*server*/, const wxString& message )
814 {
815 	if ( m_main_win == 0 ) return;
816 	mw().GetChatTab().BroadcastMessage( message );
817 	try { // send it to battleroom too
818 		mw().GetJoinTab().GetBattleRoomTab().GetChatPanel().StatusMessage(message);
819 	} catch(...) {}
820 }
821 
822 
OnServerMessage(Server & server,const wxString & message)823 void Ui::OnServerMessage( Server& server, const wxString& message )
824 {
825 	if ( !cfg().ReadBool(_T("/Chat/BroadcastEverywhere")) ) {
826 		if ( server.uidata.panel != 0 ) server.uidata.panel->StatusMessage( message );
827 	} else {
828 		if ( server.uidata.panel != 0 ) server.uidata.panel->StatusMessage( message );
829 		if ( m_main_win == 0 ) return;
830 		ChatPanel* activepanel = mw().GetChatTab().GetActiveChatPanel();
831 		if ( activepanel != 0 ) {
832 			if (activepanel != server.uidata.panel) activepanel->StatusMessage(message); // don't send it twice to the server tab
833 		}
834 		try { // send it to battleroom too
835 			mw().GetJoinTab().GetBattleRoomTab().GetChatPanel().StatusMessage(message);
836 		} catch(...) {}
837 	}
838 }
839 
840 
OnUserSaid(User & user,const wxString & message,bool fromme)841 void Ui::OnUserSaid( User& user, const wxString& message, bool fromme )
842 {
843 	if ( m_main_win == 0 ) return;
844 	if ( user.uidata.panel == 0 ) {
845 		mw().OpenPrivateChat( user );
846 	}
847 	if ( fromme ) user.uidata.panel->Said( serverSelector().GetServer().GetMe().GetNick(), message );
848 	else user.uidata.panel->Said( user.GetNick(), message );
849 }
850 
OnUserSaidEx(User & user,const wxString & action,bool fromme)851 void Ui::OnUserSaidEx( User& user, const wxString& action, bool fromme )
852 {
853 	if ( m_main_win == 0 ) return;
854 	if ( user.uidata.panel == 0 ) {
855 		mw().OpenPrivateChat( user );
856 	}
857 	if ( fromme ) user.uidata.panel->DidAction ( serverSelector().GetServer().GetMe().GetNick(), action );
858 	else user.uidata.panel->DidAction( user.GetNick(), action );
859 }
860 
OnBattleOpened(IBattle & battle)861 void Ui::OnBattleOpened( IBattle& battle )
862 {
863 	if ( m_main_win == 0 ) return;
864 	mw().GetBattleListTab().AddBattle( battle );
865 	try {
866 		User& user = battle.GetFounder();
867 		for ( int i = 0; i < serverSelector().GetServer().GetNumChannels(); i++ ) {
868 			Channel& chan = serverSelector().GetServer().GetChannel( i );
869 			if ( ( chan.UserExists(user.GetNick()) ) && ( chan.uidata.panel != 0 ) ) {
870 				chan.uidata.panel->UserStatusUpdated( user );
871 			}
872 		}
873 	} catch(...) {}
874 }
875 
876 
OnBattleClosed(IBattle & battle)877 void Ui::OnBattleClosed( IBattle& battle )
878 {
879 	if ( m_main_win == 0 ) return;
880 	mw().GetBattleListTab().RemoveBattle( battle );
881 	try {
882 		if ( mw().GetJoinTab().GetBattleRoomTab().GetBattle() == &battle ) {
883 			if (!battle.IsFounderMe() )
884 				customMessageBoxNoModal(SL_MAIN_ICON,_("The current battle was closed by the host."),_("Battle closed"));
885 			mw().GetJoinTab().LeaveCurrentBattle();
886 		}
887 	} catch (...) {}
888 	for ( unsigned int b = 0; b < battle.GetNumUsers(); b++ ) {
889 		User& user = battle.GetUser( b );
890 		user.SetBattle(0);
891 		for ( int i = 0; i < serverSelector().GetServer().GetNumChannels(); i++ ) {
892 			Channel& chan = serverSelector().GetServer().GetChannel( i );
893 			if ( ( chan.UserExists(user.GetNick()) ) && ( chan.uidata.panel != 0 ) ) {
894 				chan.uidata.panel->UserStatusUpdated( user );
895 			}
896 		}
897 	}
898 }
899 
900 
OnUserJoinedBattle(IBattle & battle,User & user)901 void Ui::OnUserJoinedBattle( IBattle& battle, User& user )
902 {
903 	if ( m_main_win == 0 ) return;
904 	mw().GetBattleListTab().UpdateBattle( battle );
905 
906 	try {
907 		if ( mw().GetJoinTab().GetBattleRoomTab().GetBattle() == &battle ) {
908 			mw().GetJoinTab().GetBattleRoomTab().OnUserJoined( user );
909 			OnBattleInfoUpdated( std::make_pair(&battle,wxString()) );
910 		}
911 	} catch (...) {}
912 
913 	for ( int i = 0; i < serverSelector().GetServer().GetNumChannels(); i++ ) {
914 		Channel& chan = serverSelector().GetServer().GetChannel( i );
915 		if ( ( chan.UserExists(user.GetNick()) ) && ( chan.uidata.panel != 0 ) ) {
916 			chan.uidata.panel->UserStatusUpdated( user );
917 		}
918 	}
919 }
920 
921 
OnUserLeftBattle(IBattle & battle,User & user,bool isbot)922 void Ui::OnUserLeftBattle( IBattle& battle, User& user, bool isbot )
923 {
924 	assert(wxThread::IsMain());
925 	if ( m_main_win == 0 ) return;
926 	user.SetSideiconIndex( -1 ); //just making sure he's not running around with some icon still set
927 	user.BattleStatus().side = 0; // and reset side, so after rejoin we don't potentially stick with a num higher than avail
928 	mw().GetBattleListTab().UpdateBattle( battle );
929 	try {
930 		if ( mw().GetJoinTab().GetBattleRoomTab().GetBattle() == &battle ) {
931 			mw().GetJoinTab().GetBattleRoomTab().OnUserLeft( user );
932 			OnBattleInfoUpdated( std::make_pair(&battle,wxString()) );
933 			if ( &user == &serverSelector().GetServer().GetMe() ) {
934 				mw().GetJoinTab().LeaveCurrentBattle();
935 				mw().ShowTab(MainWindow::PAGE_LIST);
936 			}
937 		}
938 	} catch (...) {}
939 	if ( isbot ) return;
940 	for ( int i = 0; i < serverSelector().GetServer().GetNumChannels(); i++ ) {
941 		Channel& chan = serverSelector().GetServer().GetChannel( i );
942 		if ( ( chan.UserExists(user.GetNick()) ) && ( chan.uidata.panel != 0 ) ) {
943 			chan.uidata.panel->UserStatusUpdated( user );
944 		}
945 	}
946 }
947 
OnBattleInfoUpdated(BattleEvents::BattleEventData data)948 void Ui::OnBattleInfoUpdated( BattleEvents::BattleEventData data )
949 {
950 	IBattle& battle = *data.first;
951 	const wxString& Tag = data.second;
952 	if ( m_main_win == 0 ) return;
953 	mw().GetBattleListTab().UpdateBattle( battle );
954 	if ( mw().GetJoinTab().GetCurrentBattle() == &battle ) {
955 		if ( Tag.IsEmpty() )
956 			mw().GetJoinTab().UpdateCurrentBattle();
957 		else
958 			mw().GetJoinTab().UpdateCurrentBattle( Tag );
959 	}
960 }
961 
OnJoinedBattle(Battle & battle)962 void Ui::OnJoinedBattle( Battle& battle )
963 {
964 	if ( m_main_win == 0 ) return;
965 	mw().GetJoinTab().JoinBattle( battle );
966 	mw().FocusBattleRoomTab();
967 	if ( !LSL::usync().IsLoaded() ) {
968 		customMessageBox(SL_MAIN_ICON, _("Your spring settings are probably not configured correctly,\nyou should take another look at your settings before trying\nto play online."), _("Spring settings error"), wxOK );
969 	}
970 	if ( battle.GetNatType() != NAT_None ) {
971 		wxLogWarning( _T("joining game with NAT transversal") );
972 	}
973 }
974 
975 
OnHostedBattle(Battle & battle)976 void Ui::OnHostedBattle( Battle& battle )
977 {
978 	if ( m_main_win == 0 )
979 		return;
980 	mw().GetJoinTab().HostBattle( battle );
981 	mw().FocusBattleRoomTab();
982 }
983 
984 
OnUserBattleStatus(IBattle & battle,User & user)985 void Ui::OnUserBattleStatus( IBattle& battle, User& user )
986 {
987 	if ( m_main_win == 0 ) return;
988 	mw().GetJoinTab().BattleUserUpdated( user );
989 	OnBattleInfoUpdated( std::make_pair(&battle,wxString()) );
990 }
991 
992 
OnRequestBattleStatus(IBattle & battle)993 void Ui::OnRequestBattleStatus( IBattle& battle )
994 {
995 	if ( m_main_win == 0 ) return;
996 	try {
997 		if ( mw().GetJoinTab().GetBattleRoomTab().GetBattle() == &battle ) {
998 			mw().GetJoinTab().GetBattleRoomTab().GetBattle()->OnRequestBattleStatus();
999 		}
1000 	} catch (...) {}
1001 }
1002 
1003 
OnBattleStarted(Battle & battle)1004 void Ui::OnBattleStarted( Battle& battle )
1005 {
1006 	if ( m_main_win == 0 ) return;
1007 	wxLogDebugFunc( wxEmptyString );
1008 	mw().GetBattleListTab().UpdateBattle( battle );
1009 }
1010 
1011 
OnSaidBattle(IBattle &,const wxString & nick,const wxString & msg)1012 void Ui::OnSaidBattle( IBattle& /*battle*/, const wxString& nick, const wxString& msg )
1013 {
1014 	if ( m_main_win == 0 ) return;
1015 	try {
1016 		mw().GetJoinTab().GetBattleRoomTab().GetChatPanel().Said( nick, msg );
1017 	} catch (...) {}
1018 }
1019 
OnSpringTerminated(wxCommandEvent & data)1020 void Ui::OnSpringTerminated( wxCommandEvent& data  )
1021 {
1022 	const int exit_code  = data.GetInt();
1023 
1024 	if ( !m_serv ) return;
1025 
1026 	try {
1027 		serverSelector().GetServer().GetMe().Status().in_game = false;
1028 		serverSelector().GetServer().GetMe().SendMyUserStatus();
1029 		Battle *battle = serverSelector().GetServer().GetCurrentBattle();
1030 		if ( !battle )
1031 			return;
1032 		if( battle->IsFounderMe() && battle->GetAutoLockOnStart() ) {
1033 			battle->SetIsLocked( false );
1034 			battle->SendHostInfo( IBattle::HI_Locked );
1035 		}
1036 	} catch ( assert_exception ) {}
1037 
1038 	if (exit_code != 0) {
1039 #if wxUSE_DEBUGREPORT && defined(ENABLE_DEBUG_REPORT)
1040 		SpringDebugReport report;
1041 		if ( wxDebugReportPreviewStd().Show( report ) )
1042 			report.Process();
1043 #else
1044 		if ( customMessageBox( SL_MAIN_ICON, _T("The game has crashed.\nOpen infolog.txt?"), _T("Crash"), wxYES_NO ) == wxYES )
1045 			OpenFileInEditor( sett().GetCurrentUsedDataDir() + wxFileName::GetPathSeparator() + _T("infolog.txt") );
1046 #endif
1047 	}
1048 }
1049 
1050 
OnAcceptAgreement(const wxString & agreement)1051 void Ui::OnAcceptAgreement( const wxString& agreement )
1052 {
1053 	AgreementDialog dlg( m_main_win, agreement );
1054 	if ( dlg.ShowModal() == 1 ) {
1055 		serverSelector().GetServer().AcceptAgreement();
1056 		serverSelector().GetServer().Login();
1057 	}
1058 }
1059 
1060 
OnRing(const wxString & from)1061 void Ui::OnRing( const wxString& from )
1062 {
1063 	if ( m_main_win == 0 ) return;
1064 	m_main_win->RequestUserAttention();
1065 
1066 	if ( !wxTheApp->IsActive() ) {
1067 		const wxString msg = wxFormat(_("%s:\nring!") ) % from;
1068 		UiEvents::GetNotificationEventSender().SendEvent(
1069 			UiEvents::NotficationData( UiEvents::ServerConnection, msg ) );
1070 	}
1071 
1072 #ifndef DISABLE_SOUND
1073 	if ( sett().GetChatPMSoundNotificationEnabled() )
1074 		sound().ring();
1075 #else
1076 	wxBell();
1077 #endif
1078 }
1079 
IsThisMe(User & other) const1080 bool Ui::IsThisMe(User& other) const
1081 {
1082 	return IsThisMe( other.GetNick() );
1083 }
1084 
IsThisMe(User * other) const1085 bool Ui::IsThisMe(User* other) const
1086 {
1087 	return ( ( other != 0 ) && IsThisMe( other->GetNick() ) );
1088 }
1089 
IsThisMe(const wxString & other) const1090 bool Ui::IsThisMe(const wxString& other) const
1091 {
1092 	//if i'm not connected i have no identity
1093 	if (!IsConnected() || m_serv==0)
1094 		return false;
1095 	else
1096 		return ( other == serverSelector().GetServer().GetMe().GetNick() );
1097 }
1098 
TestHostPort(unsigned int port) const1099 int Ui::TestHostPort( unsigned int port ) const
1100 {
1101 	return serverSelector().GetServer().TestOpenPort( port );
1102 }
1103 
ReloadPresetList()1104 void Ui::ReloadPresetList()
1105 {
1106 	try {
1107 		mw().GetSPTab().ReloadPresetList();
1108 	} catch (...) {}
1109 	try {
1110 		mw().GetJoinTab().ReloadPresetList();
1111 	} catch (...) {}
1112 }
1113 
OnPresetRequiringMap(const wxString & mapname)1114 bool Ui::OnPresetRequiringMap( const wxString& mapname )
1115 {
1116 	if ( wxYES == customMessageBox( SL_MAIN_ICON,
1117 					_("The selected preset requires the map ") + mapname + _(". Should it be downloaded? \
1118                                     \n Selecting \"no\" will remove the missing map from the preset.\n\
1119                                     Please reselect the preset after download finished"),
1120 					_("Map missing"),
1121 					wxYES_NO ) ) {
1122 		Download( _T("map") , mapname, wxEmptyString );
1123 		return true;
1124 	}
1125 	return false;
1126 }
1127 
OpenFileInEditor(const wxString & filepath)1128 void Ui::OpenFileInEditor( const wxString& filepath )
1129 {
1130 	wxString editor_path = sett().GetEditorPath( );
1131 	if ( editor_path == wxEmptyString ) {
1132 		customMessageBoxNoModal( SL_MAIN_ICON, _T("You have not chosen an external text editor to open files with.\nPlease Select one now."), _T("No editor set") );
1133 		mw().ShowConfigure( MainWindow::OPT_PAGE_GENERAL );
1134 		return;
1135 	}
1136 	bool success = ( wxExecute( editor_path + _T(" \"") + filepath + _T("\""), wxEXEC_ASYNC ) != 0 );
1137 	if ( !success ) {
1138 		customMessageBoxNoModal( SL_MAIN_ICON, _T("There was a problem launching the editor.\nPlease make sure the path is correct and the binary executable for your user.\nNote it's currently not possible to use shell-only editors like ed, vi, etc."), _T("Problem launching editor") );
1139 		mw().ShowConfigure( MainWindow::OPT_PAGE_GENERAL );
1140 	}
1141 }
1142 
OnInit()1143 void Ui::OnInit()
1144 {
1145 	if (sett().IsFirstRun()) {
1146 		FirstRunWelcome();
1147 	} else {
1148 		if (cfg().ReadBool(_T( "/Server/Autoconnect" ))) {
1149 			Connect(); // OnConnect changes tab
1150 		} else {
1151 			mw().ShowTab(cfg().ReadLong(_T( "/GUI/StartTab" )));
1152 		}
1153 		//don't ask for updates on first run, that's a bit much for a newbie
1154 		if (cfg().ReadBool(_T("/General/AutoUpdate"))) {
1155 			CheckForUpdates();
1156 		}
1157 	}
1158 }
1159 
1160 
FirstRunWelcome()1161 void Ui::FirstRunWelcome()
1162 {
1163 #ifdef __WXMSW__
1164 	sett().SetOldSpringLaunchMethod( true );
1165 #endif
1166 
1167 	wxLogMessage( _T("first time startup"));
1168 	wxMessageBox( wxFormat( _("Hi %s,\nIt looks like this is your first time using %s. I have guessed a configuration that I think will work for you but you should review it, especially the Spring configuration.") )
1169 				  % wxGetUserName()
1170 				  % GetAppName(),
1171 				  _("Welcome"),
1172 				  wxOK | wxICON_INFORMATION, &mw() );
1173 
1174 	// copy uikeys.txt
1175 	wxPathList pl;
1176 	pl.AddEnvList( _T("%ProgramFiles%") );
1177 	pl.AddEnvList( _T("XDG_DATA_DIRS") );
1178 	pl = PathlistFactory::AdditionalSearchPaths( pl );
1179 	wxString uikeyslocation = pl.FindValidPath( _T("uikeys.txt") );
1180 	if ( !uikeyslocation.IsEmpty() ) {
1181 		wxCopyFile( uikeyslocation, sett().GetCurrentUsedDataDir() + wxFileName::GetPathSeparator() + _T("uikeys.txt"), false );
1182 	}
1183 
1184 	//this ensures that for new configs there's a default perspective to fall back on
1185 	mw().SavePerspectives( _T("SpringLobby-default") );
1186 	mw().ShowConfigure();
1187 }
1188 
CheckForUpdates()1189 void Ui::CheckForUpdates()
1190 {
1191 	wxString latestVersion = GetLatestVersion();
1192 
1193 	if (latestVersion == _T("-1")) {
1194 		customMessageBoxNoModal(SL_MAIN_ICON, _("There was an error checking for the latest version.\nPlease try again later.\nIf the problem persists, please use Help->Report Bug to report this bug."), _("Error"));
1195 		return;
1196 	}
1197 	//get current rev w/o AUX_VERSION added
1198 	wxString myVersion = GetSpringLobbyVersion( false ) ;
1199 
1200 	wxString msg = _("Your Version: ") + myVersion + _T("\n") + _("Latest Version: ") + latestVersion;
1201 	if ( !latestVersion.IsSameAs(myVersion, false) ) {
1202 #ifdef __WXMSW__
1203 		int answer = customMessageBox(SL_MAIN_ICON,
1204 					      wxFormat( _("Your %s version is not up to date.\n\n%s\n\nWould you like for me to autodownload the new version? Changes will take effect next you launch the lobby again.") )
1205 					      % GetAppName()
1206 					      % msg,
1207 					      _("Not up to date"), wxYES_NO);
1208 		if (answer == wxYES) {
1209 			wxString command = _T("\"") + wxPathOnly( wxStandardPaths::Get().GetExecutablePath() ) + wxFileName::GetPathSeparator() + _T("springlobby_updater.exe\"");
1210 			wxString params = _T("-f \"") + wxStandardPaths::Get().GetExecutablePath() + _T("\"") + _T(" -r ") +  latestVersion  ;
1211 			if( WinExecute( command, params ) > 0 ) {
1212 				//returned pid > 0 -> proc started successfully
1213 				// now close this instance immeadiately
1214 				wxCloseEvent dummy;
1215 				ui().mw().OnClose( dummy );
1216 			} else {
1217 				//this will also happen if updater exe is not present so we don't really ne special check for existance of it
1218 				customMessageBox(SL_MAIN_ICON, _("Automatic update failed\n\nyou will be redirected to a web page with instructions and the download link will be opened in your browser.") + msg, _("Updater error.") );
1219 				OpenWebBrowser( _T("http://projects.springlobby.info/wiki/springlobby/Install#Windows-Binary") );
1220 				OpenWebBrowser( GetDownloadUrl( latestVersion ) );
1221 
1222 			}
1223 		}
1224 #else
1225 		customMessageBoxNoModal(SL_MAIN_ICON, _("Your SpringLobby version is not up to date.\n\n") + msg, _("Not up to Date") );
1226 #endif
1227 	}
1228 	/* TODO currently not usable cause automatic update calls this function too and we don't want a msg box everytime the check succeeds
1229 	else
1230 	    customMessageBoxNoModal(SL_MAIN_ICON, _("Your SpringLobby version is up to date.\n\n") + msg, _("Up to Date") );
1231 	*/
1232 }
1233 
1234 
OnQuit(wxCommandEvent &)1235 void Ui::OnQuit(wxCommandEvent& /*data*/)
1236 {
1237 	m_disable_autoconnect = true;
1238 	Disconnect();
1239 	delete m_serv;
1240 	m_serv = NULL;
1241 }
1242