1 /* Copyright (C) 2007-2011 The SpringLobby Team. All rights reserved. */
2 
3 /**
4 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
5 
6 DO NOT CHANGE THIS FILE!
7 
8 this file is deprecated and will be replaced with
9 
10 lsl/networking/tasserver.cpp
11 
12 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
13 **/
14 
15 
16 
17 #include <wx/string.h>
18 #include <wx/regex.h>
19 #include <wx/intl.h>
20 #include <wx/protocol/http.h>
21 #include <wx/socket.h>
22 #include <wx/log.h>
23 #include <wx/tokenzr.h>
24 #include <wx/platinfo.h>
25 #include <wx/stopwatch.h>
26 #include <wx/timer.h>
27 
28 #include <stdexcept>
29 #include <algorithm>
30 
31 #include <map>
32 
33 #include "base64.h"
34 #include "utils/md5.h"
35 #include "tasserver.h"
36 #include "user.h"
37 #include "utils/debug.h"
38 #include "utils/tasutil.h"
39 #include "utils/conversion.h"
40 #include "utils/platform.h"
41 #include "updater/updatehelper.h"
42 #include "serverevents.h"
43 #include "socket.h"
44 #include "channel/channel.h"
45 #include "tasservertokentable.h"
46 
47 // for SL_MAIN_ICON
48 #include "utils/customdialogs.h"
49 
50 #include "settings.h"
51 
52 #define PING_TIME 30
53 #define PING_DELAY 5 //first ping is sent after PING_DELAY
54 
55 const int udp_reply_timeout=10;
56 
57 
58 //! @brief Struct used internally by the TASServer class to get client status information.
59 struct TASClientstatus
60 {
61 unsigned int in_game   :
62     1;
63 unsigned int away      :
64     1;
65 unsigned int rank      :
66     3;
67 unsigned int moderator :
68     1;
69 unsigned int bot       :
70     1;
71 };
72 
73 
74 //! @brief Union used internally by the TASServer class to get client status information.
75 union UTASClientStatus
76 {
77     unsigned char byte;
78     TASClientstatus tasdata;
79 };
80 
81 
82 //! @brief Struct used internally by the TASServer class to get battle status information.
83 //!TODO is that last member necessary? throws a warning baout bein used uninited
84 struct TASBattleStatus
85 {
86 unsigned int :
87     1;
88 unsigned int ready :
89     1;
90 unsigned int team :
91     4;
92 unsigned int ally :
93     4;
94 unsigned int player :
95     1;
96 unsigned int handicap:
97     7;
98 unsigned int :
99     4;
100 unsigned int sync :
101     2;
102 unsigned int side :
103     4;
104 unsigned int :
105     4;
106 };
107 
108 //! @brief Union used internally by the TASServer class to get battle status information.
109 union UTASBattleStatus
110 {
111     int data;
112     TASBattleStatus tasdata;
113 };
114 
115 struct TASColor
116 {
117 unsigned int red :
118     8;
119 unsigned int green :
120     8;
121 unsigned int blue :
122     8;
123 unsigned int zero:
124     8;
125 };
126 
127 
128 union UTASColor
129 {
130     int data;
131     TASColor color;
132 };
133 
134 
135 /*
136 
137 myteamcolor:  Should be 32-bit signed integer in decimal form (e.g. 255 and not FF) where each color channel should occupy 1 byte (e.g. in hexdecimal: $00BBGGRR, B = blue, G = green, R = red). Example: 255 stands for $000000FF.
138 
139 */
140 
141 UserStatus ConvTasclientstatus( TASClientstatus );
142 UserBattleStatus ConvTasbattlestatus( TASBattleStatus );
143 TASBattleStatus ConvTasbattlestatus( UserBattleStatus );
144 IBattle::StartType IntToStartType( int start );
145 NatType IntToNatType( int nat );
146 IBattle::GameType IntToGameType( int gt );
147 
148 
TASServer(int serverEventsMode)149 TASServer::TASServer(int serverEventsMode):
150 m_ser_ver(0),
151 m_connected(false),
152 m_online(false),
153 m_debug_dont_catch( false ),
154 m_id_transmission( true ),
155 m_redirecting( false ),
156 m_buffer(wxEmptyString),
157 m_last_udp_ping(0),
158 m_last_ping(time(0) - PING_TIME + PING_DELAY), //no instant ping, delay first ping for PING_DELAY seconds
159 m_last_net_packet(0),
160 m_last_id(0),
161 m_udp_private_port(0),
162 m_nat_helper_port(0),
163 m_battle_id(-1),
164 m_server_lanmode(false),
165 m_account_id_count(0),
166 m_do_finalize_join_battle(false),
167 m_finalize_join_battle_id(-1),
168 m_token_transmission( false )
169 {
170 	m_se = IServerEvents::getInstance( *this, IServerEvents::ServerEventsMode(serverEventsMode) );
171 	FillAliasMap();
172 	m_relay_host_manager_list.Clear();
173 
174 	Start(100); // call Update every 100ms
175 }
176 
~TASServer()177 TASServer::~TASServer()
178 {
179 	Stop();
180 	Disconnect();
181 	delete m_se;
182 	m_se = NULL;
183 }
184 
Notify()185 void TASServer::Notify() {
186 	Update(GetInterval());
187 };
188 
ExecuteSayCommand(const wxString & cmd)189 bool TASServer::ExecuteSayCommand( const wxString& cmd )
190 {
191     wxArrayString arrayparams = wxStringTokenize( cmd, _T(" ") );
192     if ( arrayparams.GetCount() == 0 ) return false;
193     wxString subcmd = arrayparams[0];
194     wxString params = cmd.AfterFirst( ' ' );
195     if ( subcmd == _T("/ingame") )
196     {
197 				if ( arrayparams.GetCount() != 2 ) return false;
198         SendCmd( _T("GETINGAMETIME"), arrayparams[1] );
199         return true;
200     }
201     else if ( subcmd == _T("/kick") )
202     {
203 				if ( arrayparams.GetCount() < 2 ) return false;
204         SendCmd( _T("KICKUSER"), params );
205         return true;
206     }
207     else if ( subcmd == _T("/ban") )
208     {
209 				if ( arrayparams.GetCount() < 2 ) return false;
210         SendCmd( _T("BAN"), params );
211         return true;
212     }
213     else if ( subcmd == _T("/unban") )
214     {
215 				if ( arrayparams.GetCount() != 2 ) return false;
216         SendCmd( _T("UNBAN"), arrayparams[1] );
217         return true;
218     }
219     else if ( subcmd == _T("/banlist") )
220     {
221         SendCmd( _T("BANLIST") );
222         return true;
223     }
224     else if ( subcmd == _T("/topic") )
225     {
226 				params.Replace( _T("\n"), _T("\\n") );
227         SendCmd( _T("CHANNELTOPIC"), params );
228         return true;
229     }
230     else if ( subcmd == _T("/chanmsg") )
231     {
232 				if ( arrayparams.GetCount() < 2 ) return false;
233         SendCmd( _T("CHANNELMESSAGE"), params );
234         return true;
235     }
236     else if ( subcmd == _T("/ring") )
237     {
238 				if ( arrayparams.GetCount() != 2 ) return false;
239         SendCmd( _T("RING"), arrayparams[1] );
240         return true;
241     }
242     else if ( subcmd == _T("/ip") )
243     {
244 				if ( arrayparams.GetCount() != 2 ) return false;
245         SendCmd( _T("GETIP"), arrayparams[1] );
246         return true;
247     }
248     else if ( subcmd == _T("/mute") )
249     {
250 				if ( arrayparams.GetCount() < 4 ) return false;
251 				if ( arrayparams.GetCount() > 5 ) return false;
252         SendCmd( _T("MUTE"), params );
253         return true;
254     }
255     else if ( subcmd == _T("/unmute") )
256     {
257 				if ( arrayparams.GetCount() != 3 ) return false;
258         SendCmd( _T("UNMUTE"), arrayparams[1] + _T(" ") + arrayparams[2] );
259         return true;
260     }
261     else if ( subcmd == _T("/mutelist") )
262     {
263 				if ( arrayparams.GetCount() != 2 ) return false;
264         SendCmd( _T("MUTELIST"), arrayparams[1] );
265         return true;
266     }
267     else if ( subcmd == _T("/lastlogin") )
268     {
269 				if ( arrayparams.GetCount() != 2 ) return false;
270         SendCmd( _T("GETLASTLOGINTIME"), arrayparams[1] );
271         return true;
272     }
273     else if ( subcmd == _T("/findip") )
274     {
275 				if ( arrayparams.GetCount() != 2 ) return false;
276         SendCmd( _T("FINDIP"), arrayparams[1] );
277         return true;
278     }
279     else if ( subcmd == _T("/lastip") )
280     {
281 				if ( arrayparams.GetCount() != 2 ) return false;
282         SendCmd( _T("GETLASTIP"), arrayparams[1] );
283         return true;
284     }
285     else if ( subcmd == _T("/rename") )
286     {
287 				if ( arrayparams.GetCount() != 2 ) return false;
288         SendCmd( _T("RENAMEACCOUNT"), arrayparams[1] );
289         sett().SetServerAccountNick( sett().GetDefaultServer(), arrayparams[1] ); // this code assumes that default server hasn't changed since login ( like it should atm )
290         return true;
291     }
292     else if ( subcmd == _T("/testmd5") )
293     {
294         ExecuteCommand( _T("SERVERMSG"), GetPasswordHash(params) );
295         return true;
296     }
297     else if ( subcmd == _T("/hook") )
298     {
299         SendCmd( _T("HOOK"), params );
300         return true;
301     }
302     else if ( subcmd == _T("/quit") )
303     {
304         Disconnect();
305         return true;
306     }
307     else if ( subcmd == _T("/changepassword2") )
308     {
309 		if ( arrayparams.GetCount() < 1 ) return false;
310 		wxString oldpassword = sett().GetServerAccountPass( GetServerName() );
311 		wxString newpassword = GetPasswordHash( params );
312 		if  ( oldpassword.IsEmpty() || !sett().GetServerAccountSavePass(GetServerName()) )
313 		{
314 			m_se->OnServerMessage(_("There is no saved password for this account, please use /changepassword"));
315 			return true;
316 		}
317         SendCmd( _T("CHANGEPASSWORD"), oldpassword + _T(" ") + newpassword );
318         return true;
319     }
320     else if ( subcmd == _T("/changepassword") )
321     {
322 		if ( arrayparams.GetCount() != 2 ) return false;
323 		wxString oldpassword = GetPasswordHash(arrayparams[1]);
324 		wxString newpassword = GetPasswordHash( arrayparams[2] );
325         SendCmd( _T("CHANGEPASSWORD"), oldpassword + _T(" ") + newpassword );
326         return true;
327     }
328     else if ( subcmd == _T("/ping") )
329     {
330 				Ping();
331         return true;
332     }
333     return false;
334 }
335 
336 
Connect(const wxString & servername,const wxString & addr,const int port)337 void TASServer::Connect( const wxString& servername ,const wxString& addr, const int port )
338 {
339 	m_server_name = servername;
340     m_addr=addr;
341 	m_buffer = wxEmptyString;
342 	m_sock->Connect( addr, port );
343 	m_sock->SetSendRateLimit( 800 ); // 1250 is the server limit but 800 just to make sure :)
344 	m_connected = false;
345     m_online = false;
346     m_redirecting = false;
347     m_agreement = wxEmptyString;
348 	m_crc.ResetCRC();
349 	m_last_net_packet = time( 0 );
350 	wxString handle = m_sock->GetHandle();
351 	if ( !handle.IsEmpty() ) m_crc.UpdateData( STD_STRING( wxString( handle + m_addr ) ) );
352 }
353 
Disconnect()354 void TASServer::Disconnect()
355 {
356     if (!m_connected)
357     {
358         return;
359     }
360 	m_connected = false;
361 	SendCmd( _T("EXIT") ); // EXIT command for new protocol compatibility
362 	m_sock->Disconnect();
363 }
364 
IsConnected()365 bool TASServer::IsConnected()
366 {
367 	return (m_sock->State() == SS_Open) && (m_connected);
368 }
369 
370 
Register(const wxString & addr,const int port,const wxString & nick,const wxString & password,wxString & reason)371 bool TASServer::Register( const wxString& addr, const int port, const wxString& nick, const wxString& password, wxString& reason )
372 {
373     wxLogDebugFunc( wxEmptyString );
374 	FakeNetClass temp;
375 	Socket tempsocket( temp, true, true );
376     tempsocket.Connect( addr, port );
377     if ( tempsocket.State() != SS_Open ) return false;
378 
379     wxString data = tempsocket.Receive().BeforeLast(_T('\n'));
380     if ( data.Find( _T("\r") ) != wxNOT_FOUND ) data = data.BeforeLast(_T('\r'));
381     if ( GetWordParam( data ) != _T("TASServer") ) return false;
382 
383     tempsocket.Send( _T("REGISTER ") + nick + _T(" ") + GetPasswordHash( password ) + _T("\n") );
384 
385     data = tempsocket.Receive().BeforeLast(_T('\n'));
386     tempsocket.Disconnect();
387     if ( data.Find( _T("\r") ) != wxNOT_FOUND ) data = data.BeforeLast(_T('\r'));
388     if ( data.IsEmpty() )
389     {
390         reason = _("Connection timed out");
391         return false;
392     }
393     wxString cmd = GetWordParam( data );
394     if ( cmd == _T("REGISTRATIONACCEPTED"))
395     {
396         return true;
397     }
398     else if ( cmd == _T("REGISTRATIONDENIED") )
399     {
400         reason = data;
401         return false;
402     }
403     reason = _("Unknown answer from server");
404     return false;
405 }
406 
407 
IsPasswordHash(const wxString & pass) const408 bool TASServer::IsPasswordHash( const wxString& pass ) const
409 {
410     return pass.length() == 24 && pass[22] == '=' && pass[23] == '=';
411 }
412 
413 
GetPasswordHash(const wxString & pass) const414 wxString TASServer::GetPasswordHash( const wxString& pass ) const
415 {
416     if ( IsPasswordHash(pass) ) return pass;
417 
418     md5_state_t state;
419 	md5_byte_t digest[16];
420 	char hex_output[16*2 + 1];
421 	int di;
422 
423     std::string str = STD_STRING(pass);
424     char* cstr = new char [str.size()+1];
425     strcpy (cstr, str.c_str());
426 
427 	md5_init(&state);
428 	md5_append(&state, (const md5_byte_t *) cstr, strlen( cstr ));
429 	md5_finish(&state, digest);
430     for (di = 0; di < 16; ++di)
431 	    sprintf(hex_output + di * 2, "%02x", digest[di]);
432 	delete [] cstr;
433     wxString coded = wxBase64::Encode( digest, 16 );
434     return coded;
435 }
436 
437 
GetMe()438 User& TASServer::GetMe() {
439     return GetUser( m_user );
440 }
GetMe() const441 const User& TASServer::GetMe() const {
442     return GetUser( m_user );
443 }
444 
Useragent()445 wxString Useragent()
446 {
447 	return sett().Get( _T("Useragent"), GetAppName() ) + _T(" ") +
448 		sett().Get( _T("Userversion"), GetSpringLobbyVersion(false) );
449 }
450 
Login()451 void TASServer::Login()
452 {
453     wxLogDebugFunc( wxEmptyString );
454     wxString pass = GetPasswordHash( m_pass );
455     wxString protocol = TowxString( m_crc.GetCRC() );
456     wxString localaddr;
457 	localaddr = m_sock->GetLocalAddress();
458     if ( localaddr.IsEmpty() ) localaddr = _T("*");
459 	m_id_transmission = false;
460     wxFormat login_cmd( _T("%s %s %s %s %s\t%s\ta m sp cl") );
461     SendCmd ( _T("LOGIN"), (login_cmd % m_user % pass % GetHostCPUSpeed() % localaddr % Useragent() % protocol).str() );
462 	m_id_transmission = true;
463 }
464 
Logout()465 void TASServer::Logout()
466 {
467     wxLogDebugFunc( wxEmptyString );
468     Disconnect();
469 }
470 
IsOnline() const471 bool TASServer::IsOnline() const
472 {
473     if ( !m_connected ) return false;
474     return m_online;
475 }
476 
477 
RequestChannels()478 void TASServer::RequestChannels()
479 {
480     SendCmd( _T("CHANNELS") );
481 }
482 
483 
AcceptAgreement()484 void TASServer::AcceptAgreement()
485 {
486     SendCmd( _T("CONFIRMAGREEMENT") );
487 }
488 
489 
Update(int mselapsed)490 void TASServer::Update( int mselapsed )
491 {
492 	if (m_sock == NULL) return;
493 
494 	m_sock->OnTimer( mselapsed );
495 
496     if ( !m_connected )   // We are not formally connected yet, but might be.
497     {
498         if ( IsConnected() )
499         {
500 		m_last_udp_ping = time( 0 );
501 		m_connected = true;
502         }
503         return;
504     }
505     else   // We are connected already.
506     {
507         if ( !IsConnected() ) return;
508 
509         time_t now = time( 0 );
510 
511 	if ((m_last_ping + PING_TIME) < now) { //Send a PING every 30 seconds
512 		m_last_ping = now;
513 		Ping();
514 	}
515 
516 	if ( ( m_last_net_packet > 0 ) && ( ( now - m_last_net_packet ) > PING_TIMEOUT ) ) { // no data received, assume timeout
517 		 m_se->OnServerMessage( _("Timeout assumed, disconnecting") );
518 		 Disconnect();
519 	}
520 
521         // joining battle with nat traversal:
522         // if we havent finalized joining yet, and udp_reply_timeout seconds has passed since
523         // we did UdpPing(our name) , join battle anyway, but with warning message that nat failed.
524         // (if we'd receive reply from server, we'd finalize already)
525         //
526         if (m_do_finalize_join_battle&&(m_last_udp_ping+udp_reply_timeout<now))
527         {
528             customMessageBoxNoModal(SL_MAIN_ICON,_("Failed to punch through NAT, playing this battle might not work for you or for other players."),_("Error"), wxICON_ERROR);
529             //wxMessageBox()
530             FinalizeJoinBattle();
531             //wxMessageBox(_("Failed to punch through NAT"), _("Error"), wxICON_INFORMATION, NULL/* m_ui.mw()*/ );
532         };
533 
534         if ( ( m_last_udp_ping + m_keepalive ) < now )
535         {
536             // Is it time for a nat traversal PING?
537             m_last_udp_ping = now;
538             // Nat travelsal "ping"
539             if ( m_battle_id != -1 )
540             {
541                 Battle *battle=GetCurrentBattle();
542                 if (battle)
543                 {
544                     if ( ( battle->GetNatType() == NAT_Hole_punching || ( battle->GetNatType() == NAT_Fixed_source_ports ) ) && !battle->GetInGame() )
545                     {
546                         if ( battle->IsFounderMe() )
547                         {
548                             UdpPingTheServer(m_user);
549                             UdpPingAllClients();
550                         }
551                         else
552                         {
553                             UdpPingTheServer(m_user);
554                         }
555                     }
556                 }
557             }
558         }
559     }
560 
561 }
562 
563 
ExecuteCommand(const wxString & in)564 void TASServer::ExecuteCommand( const wxString& in )
565 {
566     wxLogMessage( _T("%s"), in.c_str()  );
567     wxString cmd;
568     wxString params = in;
569     long replyid = 0;
570 
571     if ( in.empty() ) return;
572     try
573     {
574         ASSERT_LOGIC( params.AfterFirst( '\n' ).IsEmpty(), _T("losing data") );
575     }
576     catch (...)
577     {
578         return;
579     }
580     if ( params[0] == '#' )
581     {
582 		wxString id = params.BeforeFirst( ' ' ).AfterFirst( '#' );
583         params = params.AfterFirst( ' ' );
584         id.ToLong( &replyid );
585     }
586     cmd = params.BeforeFirst( ' ' );
587 		params = params.AfterFirst( ' ' );
588 
589 		// decode message if tokenized
590 		wxString copy = cmd;
591 		cmd = DecodeTokenMessage( cmd );
592 		if ( copy != cmd ) m_token_transmission = true;
593 		cmd.MakeUpper();
594 
595     if ( m_debug_dont_catch )
596     {
597         ExecuteCommand( cmd, params, replyid );
598     }
599     else
600     {
601         try
602         {
603             ExecuteCommand( cmd, params, replyid );
604         }
605         catch ( ... ) // catch everything so the app doesn't crash, may makes odd beahviours but it's better than crashing randomly for normal users
606         {
607         }
608     }
609 }
610 
611 
ExecuteCommand(const wxString & cmd,const wxString & inparams,int replyid)612 void TASServer::ExecuteCommand( const wxString& cmd, const wxString& inparams, int replyid )
613 {
614     wxString params = inparams;
615     int pos, cpu, id, nat, port, maxplayers, rank, specs, units, top, left, right, bottom, ally, type;
616     bool haspass,lanmode = false;
617     wxString hash;
618     wxString nick, contry, host, map, title, mod, channel, error, msg, owner, ai, supported_spring_version, topic, engineName, engineVersion;
619     //NatType ntype;
620     UserStatus cstatus;
621     UTASClientStatus tasstatus;
622     UTASBattleStatus tasbstatus;
623     UserBattleStatus bstatus;
624     UTASColor color;
625 
626     if ( cmd == _T("TASSERVER"))
627     {
628         mod = GetWordParam( params );
629         mod.ToDouble( &m_ser_ver );
630         supported_spring_version = GetWordParam( params );
631         m_nat_helper_port = (unsigned long)GetIntParam( params );
632         lanmode = GetBoolParam( params );
633         m_server_lanmode = lanmode;
634         m_se->OnConnected( m_server_name, mod, (m_ser_ver > 0), supported_spring_version, lanmode );
635     }
636     else if ( cmd == _T("ACCEPTED") )
637     {
638 		if ( m_online ) return; // in case is the server sends WTF
639         m_online = true;
640         m_user = params;
641         m_se->OnLogin( );
642     }
643     else if ( cmd == _T("MOTD") )
644     {
645         m_se->OnMotd( params );
646     }
647     else if ( cmd == _T("ADDUSER") )
648     {
649         nick = GetWordParam( params );
650         contry = GetWordParam( params );
651         cpu = GetIntParam( params );
652         if ( params.IsEmpty() )
653         {
654         	// if server didn't send any account id to us, fill with an always increasing number
655         	id = m_account_id_count;
656         	m_account_id_count++;
657         }
658         else
659         {
660 					id = GetIntParam( params );
661         }
662         m_se->OnNewUser( nick, contry, cpu, TowxString(id) );
663         if ( nick == m_relay_host_bot )
664         {
665            RelayCmd( _T("OPENBATTLE"), m_delayed_open_command ); // relay bot is deployed, send host command
666            m_delayed_open_command = wxEmptyString;
667         }
668     }
669     else if ( cmd == _T("CLIENTSTATUS") )
670     {
671         nick = GetWordParam( params );
672         tasstatus.byte = GetIntParam( params );
673         cstatus = ConvTasclientstatus( tasstatus.tasdata );
674         m_se->OnUserStatus( nick, cstatus );
675     }
676     else if ( cmd == _T("BATTLEOPENED") )
677     {
678         id = GetIntParam( params );
679         type = GetIntParam( params );
680         nat = GetIntParam( params );
681         nick = GetWordParam( params );
682         host = GetWordParam( params );
683         port = GetIntParam( params );
684         maxplayers = GetIntParam( params );
685         haspass = GetBoolParam( params );
686         rank = GetIntParam( params );
687         hash = MakeHashUnsigned( GetWordParam( params ) );
688 		engineName = GetSentenceParam( params );
689 		engineVersion = GetSentenceParam( params );
690         map = GetSentenceParam( params );
691         title = GetSentenceParam( params );
692         mod = GetSentenceParam( params );
693 		m_se->OnBattleOpenedEx( id, (BattleType)type, IntToNatType( nat ), nick, host, port, maxplayers,
694 				haspass, rank, hash, engineName, engineVersion, map, title, mod );
695         if ( nick == m_relay_host_bot )
696         {
697 		   GetBattle( id ).SetProxy( m_relay_host_bot );
698            JoinBattle( id, sett().GetLastHostPassword() ); // autojoin relayed host battles
699         }
700     }
701     else if ( cmd == _T("JOINEDBATTLE") )
702     {
703         id = GetIntParam( params );
704         nick = GetWordParam( params );
705 		wxString userScriptPassword = GetWordParam( params );
706 		m_se->OnUserJoinedBattle( id, nick, userScriptPassword );
707     }
708     else if ( cmd == _T("UPDATEBATTLEINFO") )
709     {
710         id = GetIntParam( params );
711         specs = GetIntParam( params );
712         haspass = GetBoolParam( params );
713         hash = MakeHashUnsigned( GetWordParam( params ) );
714         map = GetSentenceParam( params );
715         m_se->OnBattleInfoUpdated( id, specs, haspass, hash, map );
716     }
717     else if ( cmd == _T("LOGININFOEND") )
718     {
719 		if ( UserExists( _T("RelayHostManagerList") ) ) SayPrivate( _T("RelayHostManagerList"), _T("!lm") );
720         m_se->OnLoginInfoComplete();
721     }
722     else if ( cmd == _T("REMOVEUSER") )
723     {
724         nick = GetWordParam( params );
725         if ( nick == m_user ) return; // to prevent peet doing nasty stuff to you, watch your back!
726         m_se->OnUserQuit( nick );
727     }
728     else if ( cmd == _T("BATTLECLOSED") )
729     {
730         id = GetIntParam( params );
731         if ( m_battle_id == id ) m_relay_host_bot = wxEmptyString;
732         m_se->OnBattleClosed( id );
733     }
734     else if ( cmd == _T("LEFTBATTLE") )
735     {
736         id = GetIntParam( params );
737         nick = GetWordParam( params );
738         m_se->OnUserLeftBattle( id, nick );
739     }
740     else if ( cmd == _T("PONG") )
741     {
742         HandlePong( replyid );
743     }
744     else if ( cmd == _T("JOIN") )
745     {
746         channel = GetWordParam( params );
747         m_se->OnJoinChannelResult( true, channel, wxEmptyString );
748     }
749     else if ( cmd == _T("JOIN") )
750     {
751         channel = GetWordParam( params );
752         error = GetSentenceParam( params );
753         m_se->OnJoinChannelResult( false, channel, error );
754     }
755     else if ( cmd == _T("SAID") )
756     {
757         channel = GetWordParam( params );
758         nick = GetWordParam( params );
759         m_se->OnChannelSaid( channel, nick, params );
760     }
761     else if ( cmd == _T("JOINED") )
762     {
763         channel = GetWordParam( params );
764         nick = GetWordParam( params );
765         m_se->OnUserJoinChannel( channel, nick );
766     }
767     else if ( cmd == _T("LEFT") )
768     {
769         channel = GetWordParam( params );
770         nick = GetWordParam( params );
771         msg = GetSentenceParam( params );
772         m_se->OnChannelPart( channel, nick, msg );
773     }
774     else if ( cmd == _T("CHANNELTOPIC") )
775     {
776         channel = GetWordParam( params );
777         nick = GetWordParam( params );
778         pos = GetIntParam( params );
779         params.Replace( _T("\\n"), _T("\n") );
780         m_se->OnChannelTopic( channel, nick, params, pos/1000 );
781     }
782     else if ( cmd == _T("SAIDEX") )
783     {
784         channel = GetWordParam( params );
785         nick = GetWordParam( params );
786         m_se->OnChannelAction( channel, nick, params );
787     }
788     else if ( cmd == _T("CLIENTS") )
789     {
790         channel = GetWordParam( params );
791         while ( (nick = GetWordParam( params )) != wxEmptyString )
792         {
793             m_se->OnChannelJoin( channel, nick );
794         }
795     }
796     else if ( cmd == _T("SAYPRIVATE") )
797     {
798         nick = GetWordParam( params );
799         if ( ( ( nick == m_relay_host_bot ) || ( nick == m_relay_host_manager ) ) && params.StartsWith( _T("!") ) ) return; // drop the message
800         if ( ( nick == _T("RelayHostManagerList") ) && ( params == _T("!lm") ) ) return;// drop the message
801         if ( nick == _T("SL_bot") )
802         {
803         	if ( params.StartsWith( _T("stats.report") ) ) return;
804         }
805         m_se->OnPrivateMessage( nick, params, true );
806     }
807 	else if ( cmd == _T("SAYPRIVATEEX") )
808 	{
809 		nick = GetWordParam( params );
810 		m_se->OnPrivateMessageEx( nick, params, true );
811 	}
812     else if ( cmd == _T("SAIDPRIVATE") )
813     {
814         nick = GetWordParam( params );
815 		if ( nick == m_relay_host_bot )
816 		{
817 			if ( params.StartsWith(_T("JOINEDBATTLE")) )
818 			{
819 				GetWordParam( params ); // skip first word, it's the message itself
820 				/*id =*/ GetIntParam( params );
821 				wxString usernick = GetWordParam( params );
822 				wxString userScriptPassword = GetWordParam( params );
823 				try
824 				{
825 					User& usr = GetUser(usernick);
826 					usr.BattleStatus().scriptPassword = userScriptPassword;
827 					Battle* battle = GetCurrentBattle();
828 					if (battle)
829 					{
830 						if ( battle->CheckBan( usr ) ) return;
831 					}
832 					SetRelayIngamePassword( usr );
833 				} catch (...) {}
834 				return;
835 			}
836 		}
837         if ( nick == m_relay_host_manager )
838         {
839           if ( params.StartsWith( _T("\001") ) ) // error code
840           {
841             m_se->OnServerMessageBox( params.AfterFirst( _T(' ') ) );
842           }
843           else
844           {
845             m_relay_host_bot = params;
846           }
847           m_relay_host_manager = wxEmptyString;
848           return;
849         }
850         if ( nick == _T("RelayHostManagerList") )
851 				{
852 					if  ( params.StartsWith(_T("list ")) )
853 					{
854 						 wxString list = params.AfterFirst( _T(' ') );
855 						 m_relay_host_manager_list = wxStringTokenize( list, _T("\t") );
856 						 return;
857 					}
858 				}
859         m_se->OnPrivateMessage( nick, params, false );
860     }
861 	else if ( cmd == _T("SAIDPRIVATEEX") )
862 	{
863 		nick = GetWordParam( params );
864 		m_se->OnPrivateMessageEx( nick, params, false );
865 	}
866     else if ( cmd == _T("JOINBATTLE") )
867     {
868         id = GetIntParam( params );
869         hash = MakeHashUnsigned( GetWordParam( params ) );
870         m_battle_id = id;
871 		m_se->OnJoinedBattle( id, hash );
872         m_se->OnBattleInfoUpdated( m_battle_id );
873 		try
874 		{
875 		 if (GetBattle(id).IsProxy()) RelayCmd(_T("SUPPORTSCRIPTPASSWORD")); // send flag to relayhost marking we support script passwords
876 		} catch(...) {}
877     }
878     else if ( cmd == _T("CLIENTBATTLESTATUS") )
879     {
880         nick = GetWordParam( params );
881         tasbstatus.data = GetIntParam( params );
882         bstatus = ConvTasbattlestatus( tasbstatus.tasdata );
883         color.data = GetIntParam( params );
884         bstatus.colour = wxColour( color.color.red, color.color.green, color.color.blue );
885         m_se->OnClientBattleStatus( m_battle_id, nick, bstatus );
886     }
887     else if ( cmd == _T("ADDSTARTRECT") )
888     {
889         //ADDSTARTRECT allyno left top right bottom
890         ally = GetIntParam( params );
891         left = GetIntParam( params );
892         top = GetIntParam( params );
893         right = GetIntParam( params );
894         bottom = GetIntParam( params );;
895         m_se->OnBattleStartRectAdd( m_battle_id, ally, left, top, right, bottom );
896     }
897     else if ( cmd == _T("REMOVESTARTRECT") )
898     {
899         //REMOVESTARTRECT allyno
900         ally = GetIntParam( params );
901         m_se->OnBattleStartRectRemove( m_battle_id, ally );
902     }
903     else if ( cmd == _T("ENABLEALLUNITS") )
904     {
905         //"ENABLEALLUNITS" params: "".
906         m_se->OnBattleEnableAllUnits( m_battle_id );
907     }
908     else if ( cmd == _T("ENABLEUNITS") )
909     {
910         //ENABLEUNITS unitname1 unitname2
911         while ( (nick = GetWordParam( params )) !=wxEmptyString )
912         {
913             m_se->OnBattleEnableUnit( m_battle_id, nick );
914         }
915     }
916     else if ( cmd == _T("DISABLEUNITS") )
917     {
918         //"DISABLEUNITS" params: "arm_advanced_radar_tower arm_advanced_sonar_station arm_advanced_torpedo_launcher arm_dragons_teeth arm_energy_storage arm_eraser arm_fark arm_fart_mine arm_fibber arm_geothermal_powerplant arm_guardian"
919         while ( (nick = GetWordParam( params )) != wxEmptyString )
920         {
921             m_se->OnBattleDisableUnit( m_battle_id, nick );
922         }
923     }
924     else if ( cmd == _T("CHANNEL") )
925     {
926         channel = GetWordParam( params );
927         units = GetIntParam( params );
928         topic = GetSentenceParam( params );
929         m_se->OnChannelList( channel, units, topic );
930     }
931     else if ( cmd == _T("ENDOFCHANNELS") )
932     {
933         //Cmd: ENDOFCHANNELS params:
934     }
935     else if ( cmd == _T("REQUESTBATTLESTATUS") )
936     {
937         m_se->OnRequestBattleStatus( m_battle_id );
938     }
939     else if ( cmd == _T("SAIDBATTLE") )
940     {
941         nick = GetWordParam( params );
942         m_se->OnSaidBattle( m_battle_id, nick, params );
943     }
944     else if ( cmd == _T("SAIDBATTLEEX") )
945     {
946         nick = GetWordParam( params );
947         m_se->OnBattleAction( m_battle_id, nick, params );
948     }
949     else if ( cmd == _T("AGREEMENT") )
950     {
951         msg = GetSentenceParam( params );
952         m_agreement += msg + _T("\n");
953     }
954     else if ( cmd == _T("AGREEMENTEND") )
955     {
956         m_se->OnAcceptAgreement( m_agreement );
957         m_agreement = wxEmptyString;
958     }
959     else if ( cmd == _T("OPENBATTLE") )
960     {
961         m_battle_id = GetIntParam( params );
962         m_se->OnHostedBattle( m_battle_id );
963     }
964     else if ( cmd == _T("ADDBOT") )
965     {
966         // ADDBOT BATTLE_ID name owner battlestatus teamcolor {AIDLL}
967         id = GetIntParam( params );
968         nick = GetWordParam( params );
969         owner = GetWordParam( params );
970         tasbstatus.data = GetIntParam( params );
971         bstatus = ConvTasbattlestatus( tasbstatus.tasdata );
972         color.data = GetIntParam( params );
973         bstatus.colour = wxColour( color.color.red, color.color.green, color.color.blue );
974         ai = GetSentenceParam( params );
975         if ( ai.IsEmpty() ) {
976             wxLogWarning( wxString::Format( _T("Recieved illegal ADDBOT (empty dll field) from %s for battle %d"), nick.c_str(), id ) );
977             ai = _T("INVALID|INVALID");
978         }
979         if( LSL::usync().VersionSupports( LSL::USYNC_GetSkirmishAI ) )
980         {
981 			if (ai.Find(_T('|')) != -1)
982 			{
983 				bstatus.aiversion = ai.AfterLast( _T('|') );
984 				ai = ai.BeforeLast( _T('|') );
985 			}
986 			bstatus.aishortname = ai;
987         }
988         else
989         {
990         	 bstatus.aishortname = ai;
991         }
992         bstatus.owner =owner;
993         m_se->OnBattleAddBot( id, nick, bstatus );
994     }
995     else if ( cmd == _T("UPDATEBOT") )
996     {
997         id = GetIntParam( params );
998         nick = GetWordParam( params );
999         tasbstatus.data = GetIntParam( params );
1000         bstatus = ConvTasbattlestatus( tasbstatus.tasdata );
1001         color.data = GetIntParam( params );
1002         bstatus.colour = wxColour( color.color.red, color.color.green, color.color.blue );
1003         m_se->OnBattleUpdateBot( id, nick, bstatus );
1004         //UPDATEBOT BATTLE_ID name battlestatus teamcolor
1005     }
1006     else if ( cmd == _T("REMOVEBOT") )
1007     {
1008         id = GetIntParam( params );
1009         nick = GetWordParam( params );
1010         m_se->OnBattleRemoveBot( id, nick );
1011         //REMOVEBOT BATTLE_ID name
1012     }
1013     else if ( cmd == _T("RING") )
1014     {
1015         nick = GetWordParam( params );
1016         m_se->OnRing( nick );
1017         //RING username
1018     }
1019     else if ( cmd == _T("SERVERMSG") )
1020     {
1021 				m_se->OnServerMessage( params );
1022         //SERVERMSG {message}
1023     }
1024     else if ( cmd == _T("JOINBATTLEFAILED") )
1025     {
1026         msg = GetSentenceParam( params );
1027         m_se->OnServerMessage( _T("Failed to join battle. ") + msg );
1028         //JOINBATTLEFAILED {reason}
1029     }
1030     else if ( cmd == _T("OPENBATTLEFAILED") )
1031     {
1032         msg = GetSentenceParam( params );
1033         m_se->OnServerMessage( _T("Failed to host new battle on server. ") + msg );
1034         //OPENBATTLEFAILED {reason}
1035     }
1036     else if ( cmd == _T("JOINFAILED") )
1037     {
1038         channel = GetWordParam( params );
1039         msg = GetSentenceParam( params );
1040         m_se->OnServerMessage( _T("Failed to join channel #") + channel + _T(". ") + msg );
1041         //JOINFAILED channame {reason}
1042     }
1043     else if ( cmd == _T("CHANNELMESSAGE") )
1044     {
1045         channel = GetWordParam( params );
1046         m_se->OnChannelMessage( channel, params );
1047         //CHANNELMESSAGE channame {message}
1048     }
1049     else if ( cmd == _T("ACQUIREUSERID") )
1050     {
1051         SendCmd( _T("USERID"), TowxString( m_crc.GetCRC() ) );
1052     }
1053     else if ( cmd == _T("FORCELEAVECHANNEL") )
1054     {
1055         channel = GetWordParam( params );
1056         nick = GetWordParam( params );
1057         msg = GetSentenceParam( params );
1058         m_se->OnChannelPart( channel, GetMe().GetNick(), _T("Kicked by <") + nick + _T("> ") + msg );
1059         //FORCELEAVECHANNEL channame username [{reason}]
1060     }
1061     else if ( cmd == _T("DENIED") )
1062     {
1063         if ( m_online ) return;
1064         m_last_denied = msg = GetSentenceParam( params );
1065         m_se->OnServerMessage( msg );
1066         Disconnect();
1067         //Command: "DENIED" params: "Already logged in".
1068     }
1069     else if ( cmd == _T("HOSTPORT") )
1070     {
1071         unsigned int tmp_port = (unsigned int)GetIntParam( params );
1072         m_se->OnHostExternalUdpPort( tmp_port );
1073         //HOSTPORT port
1074     }
1075     else if ( cmd == _T("UDPSOURCEPORT") )
1076     {
1077         unsigned int tmp_port = (unsigned int)GetIntParam( params );
1078         m_se->OnMyExternalUdpSourcePort( tmp_port );
1079         if (m_do_finalize_join_battle)FinalizeJoinBattle();
1080         //UDPSOURCEPORT port
1081     }
1082     else if (cmd == _T("CLIENTIPPORT"))
1083     {
1084         // clientipport username ip port
1085         nick=GetWordParam( params );
1086         wxString ip=GetWordParam(params);
1087         unsigned int u_port=(unsigned int)GetIntParam( params );
1088         m_se->OnClientIPPort(nick, ip, u_port);
1089     }
1090     else if ( cmd == _T("SETSCRIPTTAGS") )
1091     {
1092         wxString command;
1093         while ( (command = GetSentenceParam( params )) != wxEmptyString )
1094         {
1095             wxString key = command.BeforeFirst( '=' ).Lower();
1096             wxString value = command.AfterFirst( '=' );
1097             m_se->OnSetBattleInfo( m_battle_id, key, value );
1098         }
1099         m_se->OnBattleInfoUpdated( m_battle_id );
1100         // !! Command: "SETSCRIPTTAGS" params: "game/startpostype=0	game/maxunits=1000	game/limitdgun=0	game/startmetal=1000	game/gamemode=0	game/ghostedbuildings=-1	game/startenergy=1000	game/diminishingmms=0"
1101     }
1102 	else if ( cmd == _T("REMOVESCRIPTTAGS"))
1103 	{
1104 		wxString key;
1105 		while ( (key = GetWordParam(params)) != wxEmptyString )
1106 		{
1107 			m_se->OnUnsetBattleInfo( m_battle_id, key);
1108 		}
1109 		m_se->OnBattleInfoUpdated(m_battle_id);
1110 	}
1111     else if ( cmd == _T("SCRIPTSTART") )
1112     {
1113         m_se->OnScriptStart( m_battle_id );
1114         // !! Command: "SCRIPTSTART" params: ""
1115     }
1116     else if ( cmd == _T("SCRIPTEND") )
1117     {
1118         m_se->OnScriptEnd( m_battle_id );
1119         // !! Command: "SCRIPTEND" params: ""
1120     }
1121     else if ( cmd == _T("SCRIPT") )
1122     {
1123         m_se->OnScriptLine(  m_battle_id, params );
1124         // !! Command: "SCRIPT" params: "[game]"
1125     }
1126     else if ( cmd == _T("FORCEQUITBATTLE"))
1127     {
1128         m_relay_host_bot = wxEmptyString;
1129         m_se->OnKickedFromBattle();
1130     }
1131     else if ( cmd == _T("BROADCAST"))
1132     {
1133 		m_se->OnServerBroadcast( params );
1134     }
1135     else if ( cmd == _T("SERVERMSGBOX"))
1136     {
1137         m_se->OnServerMessageBox( params );
1138     }
1139     else if ( cmd == _T("REDIRECT") )
1140     {
1141         if ( m_online ) return;
1142         wxString address = GetWordParam( params );
1143         unsigned int u_port = GetIntParam( params );
1144         if ( address.IsEmpty() ) return;
1145         if ( u_port  == 0 ) u_port  = DEFSETT_DEFAULT_SERVER_PORT;
1146         m_redirecting = true;
1147         m_se->OnRedirect( address, u_port , m_user, m_pass );
1148     }
1149     else if ( cmd == _T("MUTELISTBEGIN") )
1150     {
1151         m_current_chan_name_mutelist = GetWordParam( params );
1152         m_se->OnMutelistBegin( m_current_chan_name_mutelist );
1153 
1154     }
1155     else if ( cmd == _T("MUTELIST") )
1156     {
1157         wxString mutee = GetWordParam( params );
1158 		wxString description = GetSentenceParam( params );
1159         m_se->OnMutelistItem( m_current_chan_name_mutelist, mutee, description );
1160     }
1161     else if ( cmd == _T("MUTELISTEND") )
1162     {
1163         m_se->OnMutelistEnd( m_current_chan_name_mutelist );
1164         m_current_chan_name_mutelist = wxEmptyString;
1165     }
1166     else if ( cmd == _T("FORCEJOINBATTLE") )
1167     {
1168         const int battleID = GetIntParam( params );
1169         const wxString scriptpw = GetWordParam( params );
1170         m_se->OnForceJoinBattle( battleID, scriptpw );
1171     }
1172     else
1173     {
1174         wxLogMessage( _T("??? Cmd: %s params: %s"), cmd.c_str(), params.c_str() );
1175         m_se->OnUnknownCommand( cmd, params );
1176     }
1177 }
1178 
1179 
RelayCmd(const wxString & command,const wxString & param)1180 void TASServer::RelayCmd(  const wxString& command, const wxString& param )
1181 {
1182     if ( m_relay_host_bot.IsEmpty() )
1183     {
1184       wxLogWarning( _T("Trying to send relayed commands but no relay bot is set!") );
1185       return;
1186     }
1187 
1188     wxString msg = _T("!"); // prefix comma,nds with !
1189     if ( param.IsEmpty() ) msg << command.Lower();
1190     else msg << command.Lower() << _T(" ") << param;
1191     SayPrivate( m_relay_host_bot, msg );
1192 }
1193 
1194 
SendCmd(const wxString & command,const wxString & param)1195 void TASServer::SendCmd( const wxString& command, const wxString& param )
1196 {
1197 		wxString cmd, msg;
1198 		if ( m_id_transmission )
1199 		{
1200 			m_last_id++;
1201 			msg = msg + _T("#") + TowxString( m_last_id ) + _T(" ");
1202 		}
1203 		if ( m_token_transmission )
1204 		{
1205 			cmd = EncodeTokenMessage( command );
1206 		}
1207 		else cmd = command;
1208 		if ( param.IsEmpty() ) msg = msg + cmd + _T("\n");
1209 		else msg = msg + cmd + _T(" ") + param + _T("\n");
1210 		bool send_success = m_sock->Send( msg );
1211 		if ( command != _T("PING") )
1212 		{
1213 			if ( send_success )
1214 				wxLogMessage( _T("sent: %s"), msg.c_str() );
1215 			else
1216 				wxLogMessage( _T("sending: %s failed"), msg.c_str() );
1217 		}
1218 }
1219 
SetRelayIngamePassword(const User & user)1220 void TASServer::SetRelayIngamePassword( const User& user )
1221 {
1222 	Battle* battle = GetCurrentBattle();
1223 	if (battle)
1224 	{
1225 		if ( !battle->GetInGame() ) return;
1226 	}
1227 	RelayCmd( _T("SETINGAMEPASSWORD"), user.GetNick() + _T(" ") + user.BattleStatus().scriptPassword );
1228 }
1229 
Ping()1230 void TASServer::Ping()
1231 {
1232 	SendCmd( _T("PING") );
1233 	TASPingListItem pli;
1234 	pli.id = m_last_id;
1235 	pli.t = wxGetLocalTimeMillis();
1236 	m_pinglist.push_back ( pli );
1237 }
1238 
HandlePong(int replyid)1239 void TASServer::HandlePong( int replyid )
1240 {
1241 	if (m_pinglist.empty()) //safety, shouldn't happen
1242 		return;
1243 
1244 	// server connection is tcp, we assume packets are received in order
1245 	TASPingListItem pli = m_pinglist.back();
1246 	m_pinglist.pop_back();
1247 	if (pli.id == replyid ) {
1248 		m_se->OnPong( (wxGetLocalTimeMillis() - pli.t) );
1249 	}
1250 }
1251 
1252 
JoinChannel(const wxString & channel,const wxString & key)1253 void TASServer::JoinChannel( const wxString& channel, const wxString& key )
1254 {
1255     //JOIN channame [key]
1256     wxLogDebugFunc( channel );
1257 
1258     m_channel_pw[channel] = key;
1259 	m_id_transmission = false; // workaround a retarded server bug
1260     SendCmd ( _T("JOIN"), channel + _T(" ") + key );
1261 	m_id_transmission = true;
1262 }
1263 
1264 
PartChannel(const wxString & channel)1265 void TASServer::PartChannel( const wxString& channel )
1266 {
1267     //LEAVE channame
1268     wxLogDebugFunc( channel );
1269 
1270     SendCmd( _T("LEAVE"), channel );
1271 
1272 }
1273 
1274 
DoActionChannel(const wxString & channel,const wxString & msg)1275 void TASServer::DoActionChannel( const wxString& channel, const wxString& msg )
1276 {
1277     //SAYEX channame {message}
1278     wxLogDebugFunc( wxEmptyString );
1279 
1280     SendCmd( _T("SAYEX"), channel + _T(" ") + msg );
1281 }
1282 
1283 
SayChannel(const wxString & channel,const wxString & msg)1284 void TASServer::SayChannel( const wxString& channel, const wxString& msg )
1285 {
1286     //SAY channame {message}
1287     wxLogDebugFunc( wxEmptyString );
1288 
1289     SendCmd( _T("SAY"), channel + _T(" ") + msg );
1290 }
1291 
1292 
SayPrivate(const wxString & nick,const wxString & msg)1293 void TASServer::SayPrivate( const wxString& nick, const wxString& msg )
1294 {
1295     //SAYPRIVATE username {message}
1296     wxLogDebugFunc( wxEmptyString );
1297 
1298     SendCmd( _T("SAYPRIVATE"), nick + _T(" ") + msg );
1299 }
1300 
1301 
DoActionPrivate(const wxString & nick,const wxString & msg)1302 void TASServer::DoActionPrivate( const wxString& nick, const wxString& msg )
1303 {
1304     wxLogDebugFunc( wxEmptyString );
1305 
1306     SendCmd( _T("SAYPRIVATEEX"), nick + _T(" ") + msg );
1307 }
1308 
1309 
SayBattle(int,const wxString & msg)1310 void TASServer::SayBattle( int /*unused*/, const wxString& msg )
1311 {
1312     wxLogDebugFunc( wxEmptyString );
1313 
1314     SendCmd( _T("SAYBATTLE"), msg );
1315 }
1316 
1317 
DoActionBattle(int,const wxString & msg)1318 void TASServer::DoActionBattle( int /*unused*/, const wxString& msg )
1319 {
1320     wxLogDebugFunc( wxEmptyString );
1321 
1322     SendCmd( _T("SAYBATTLEEX"), msg );
1323 }
1324 
1325 
Ring(const wxString & nick)1326 void TASServer::Ring( const wxString& nick )
1327 {
1328     wxLogDebugFunc( wxEmptyString );
1329 		try
1330 		{
1331 				ASSERT_EXCEPTION( m_battle_id != -1, _T("invalid m_battle_id value") );
1332 				ASSERT_EXCEPTION( BattleExists(m_battle_id), _T("battle doesn't exists") );
1333 
1334 				Battle& battle = GetBattle( m_battle_id );
1335 				ASSERT_EXCEPTION( battle.IsFounderMe(), _T("I'm not founder") );
1336 
1337 				if ( battle.IsProxy() )
1338 				{
1339 					RelayCmd( _T("RING"), nick );
1340 				}
1341 				else
1342 				{
1343 					SendCmd( _T("RING"), nick );
1344 				}
1345 
1346 		}
1347 		catch (...)
1348 		{
1349 			SendCmd( _T("RING"), nick );
1350 		}
1351 }
1352 
1353 
1354 
1355 
ModeratorSetChannelTopic(const wxString & channel,const wxString & topic)1356 void TASServer::ModeratorSetChannelTopic( const wxString& channel, const wxString& topic )
1357 {
1358 		wxString msgcopy = topic;
1359 	  msgcopy.Replace( _T("\n"), _T("\\n") );
1360     SendCmd( _T("CHANNELTOPIC"), channel + _T(" ") + msgcopy );
1361 }
1362 
1363 
ModeratorSetChannelKey(const wxString & channel,const wxString & key)1364 void TASServer::ModeratorSetChannelKey( const wxString& channel, const wxString& key)
1365 {
1366     SendCmd( _T("SETCHANNELKEY"), channel + _T(" ") + key );
1367 }
1368 
1369 
ModeratorMute(const wxString & channel,const wxString & nick,int duration,bool byip)1370 void TASServer::ModeratorMute( const wxString& channel, const wxString& nick, int duration, bool byip )
1371 {
1372     SendCmd( _T("MUTE"), channel + _T(" ") + nick + _T(" ") + wxString::Format( _T("%d"), duration) + (byip?_T(" ip"):wxEmptyString )  );
1373 }
1374 
1375 
ModeratorUnmute(const wxString & channel,const wxString & nick)1376 void TASServer::ModeratorUnmute( const wxString& channel, const wxString& nick )
1377 {
1378     SendCmd( _T("UNMUTE"),  channel + _T(" ") + nick );
1379 }
1380 
1381 
ModeratorKick(const wxString & channel,const wxString & reason)1382 void TASServer::ModeratorKick( const wxString& channel, const wxString& reason )
1383 {
1384     SendCmd( _T("KICKUSER"), channel + _T(" ") + reason );
1385 }
1386 
1387 
ModeratorBan(const wxString &,bool)1388 void TASServer::ModeratorBan( const wxString& /*unused*/, bool /*unused*/ )
1389 {
1390     // FIXME TASServer::ModeratorBan not yet implemented
1391 }
1392 
1393 
ModeratorUnban(const wxString &)1394 void TASServer::ModeratorUnban( const wxString& /*unused*/ )
1395 {
1396     // FIXME TASServer::ModeratorUnban not yet implemented
1397 }
1398 
1399 
ModeratorGetIP(const wxString & nick)1400 void TASServer::ModeratorGetIP( const wxString& nick )
1401 {
1402     SendCmd( _T("GETIP"), nick );
1403 }
1404 
1405 
ModeratorGetLastLogin(const wxString & nick)1406 void TASServer::ModeratorGetLastLogin( const wxString& nick )
1407 {
1408     SendCmd( _T("GETLASTLOGINTIME"), nick );
1409 }
1410 
1411 
ModeratorGetLastIP(const wxString & nick)1412 void TASServer::ModeratorGetLastIP( const wxString& nick )
1413 {
1414     SendCmd( _T("GETLASTIP"), nick );
1415 }
1416 
1417 
ModeratorFindByIP(const wxString & ipadress)1418 void TASServer::ModeratorFindByIP( const wxString& ipadress )
1419 {
1420     SendCmd( _T("FINDIP"), ipadress );
1421 }
1422 
1423 
AdminGetAccountAccess(const wxString &)1424 void TASServer::AdminGetAccountAccess( const wxString& /*unused*/ )
1425 {
1426     // FIXME TASServer::AdminGetAccountAccess not yet implemented
1427 }
1428 
1429 
AdminChangeAccountAccess(const wxString &,const wxString &)1430 void TASServer::AdminChangeAccountAccess( const wxString& /*unused*/, const wxString& /*unused*/ )
1431 {
1432     // FIXME TASServer::AdminChangeAccountAccess not yet implemented
1433 }
1434 
1435 
AdminSetBotMode(const wxString & nick,bool isbot)1436 void TASServer::AdminSetBotMode( const wxString& nick, bool isbot )
1437 {
1438     SendCmd( _T("SETBOTMODE"), nick + _T(" ") + (isbot?_T("1"):_T("0")) );
1439 }
1440 
1441 
1442 
1443 
1444 
HostBattle(BattleOptions bo,const wxString & password)1445 void TASServer::HostBattle( BattleOptions bo, const wxString& password )
1446 {
1447     wxLogDebugFunc( wxEmptyString );
1448 
1449     // to see ip addresses of users as they join (in the log), pretend you're hosting with NAT.
1450     int nat_type=bo.nattype;
1451     /*
1452     if(nat_type==0 && sett().GetShowIPAddresses()){
1453     nat_type=1;
1454     }*/
1455     wxLogMessage(_T("hosting with nat type %d"),nat_type);
1456 
1457     wxString cmd = wxString::Format( _T("0 %d "), nat_type );
1458     cmd += (password.IsEmpty())?_T("*"):password;
1459     cmd += wxString::Format( _T(" %d %d "), bo.port, bo.maxplayers );
1460     cmd += MakeHashSigned( bo.modhash );
1461     cmd += wxString::Format( _T(" %d "), bo.rankneeded );
1462     cmd += MakeHashSigned( bo.maphash ) + _T(" ");
1463 	if (!bo.userelayhost) { //FIXME: relay host hasn't multiversion support yet, see https://github.com/springlobby/springlobby/issues/98
1464 		cmd += bo.engineName + _T("\t");
1465 		cmd += bo.engineVersion + _T("\t");
1466 	}
1467     cmd += bo.mapname + _T("\t");
1468     cmd += bo.description + _T("\t");
1469     cmd += bo.modname;
1470 
1471     m_delayed_open_command = wxEmptyString;
1472 	if ( !bo.userelayhost )
1473     {
1474        SendCmd( _T("OPENBATTLE"), cmd );
1475     }
1476     else
1477     {
1478        if ( bo.relayhost.IsEmpty() )
1479        {
1480 			wxArrayString relaylist = GetRelayHostList();
1481            unsigned int numbots = relaylist.GetCount();
1482            if ( numbots > 0 )
1483            {
1484               srand ( time(NULL) );
1485               unsigned int choice = rand() % numbots;
1486 							m_relay_host_manager = relaylist[choice];
1487 							m_delayed_open_command = cmd;
1488 							SayPrivate( m_relay_host_manager, _T("!spawn") );
1489            }
1490        }
1491        else
1492        {
1493            m_relay_host_manager = bo.relayhost;
1494            m_delayed_open_command = cmd;
1495            SayPrivate(bo.relayhost,_T("!spawn"));
1496        }
1497     }
1498 
1499     if (bo.nattype>0)UdpPingTheServer(m_user);
1500 
1501     // OPENBATTLE type natType password port maphash {map} {title} {modname}
1502 }
1503 
1504 
JoinBattle(const int & battleid,const wxString & password)1505 void TASServer::JoinBattle( const int& battleid, const wxString& password )
1506 {
1507     //JOINBATTLE BATTLE_ID [parameter]
1508     wxLogDebugFunc( wxEmptyString );
1509 
1510     m_finalize_join_battle_pw=password;
1511     m_finalize_join_battle_id=battleid;
1512 
1513     if (BattleExists(battleid))
1514     {
1515         Battle *battle=&GetBattle(battleid);
1516 
1517         if (battle)
1518         {
1519             if ( ( battle->GetNatType() == NAT_Hole_punching ) || ( battle->GetNatType() == NAT_Fixed_source_ports ) )
1520             {
1521                 m_udp_private_port=sett().GetClientPort();
1522 
1523                 m_last_udp_ping = time(0);
1524                 // its important to set time now, to prevent Update()
1525                 // from calling FinalizeJoinBattle() on timeout.
1526                 // m_do_finalize_join_battle must be set to true after setting time, not before.
1527                 m_do_finalize_join_battle=true;
1528                 for (int n=0;n<5;++n) // do 5 udp pings with tiny interval
1529                 {
1530                     UdpPingTheServer( m_user );
1531                     // sleep(0);// sleep until end of timeslice.
1532                 }
1533                 m_last_udp_ping = time(0);// set time again
1534             }
1535             else
1536             {
1537                 // if not using nat, finalize now.
1538                 m_do_finalize_join_battle=true;
1539                 FinalizeJoinBattle();
1540             }
1541         }
1542         else
1543         {
1544             wxLogMessage( _T("battle doesnt exist (null)") );
1545         }
1546     }
1547     else
1548     {
1549         wxLogMessage( _T("battle doesnt exist") );
1550     }
1551     //SendCmd( _T("JOINBATTLE"), wxString::Format( _T("%d"), battleid ) + _T(" ") + password );
1552 }
1553 
1554 
FinalizeJoinBattle()1555 void TASServer::FinalizeJoinBattle()
1556 {
1557     if (m_do_finalize_join_battle)
1558     {
1559 		// save scriptPassword so user can rejoin if SL crashes or
1560 		// loosed connection
1561 		wxString scriptPassword;
1562 		if (sett().GetLastBattleId() == m_finalize_join_battle_id) {
1563 			scriptPassword = sett().GetLastScriptPassword();
1564 		} else {
1565 			srand ( time(NULL) );
1566 			scriptPassword = wxString::Format(_T("%04x%04x"), rand()&0xFFFF, rand()&0xFFFF);
1567 			// save assword and write settings file
1568 			sett().SetLastBattleId(m_finalize_join_battle_id);
1569 			sett().SetLastScriptPassword(scriptPassword);
1570 			sett().SaveSettings();
1571 		}
1572 		SendCmd( _T("JOINBATTLE"), wxString::Format( _T("%d %s %s"), m_finalize_join_battle_id, m_finalize_join_battle_pw.c_str(), scriptPassword.c_str()  ) );
1573         m_do_finalize_join_battle=false;
1574     }
1575 }
1576 
1577 
LeaveBattle(const int &)1578 void TASServer::LeaveBattle( const int& /*unused*/ )
1579 {
1580     //LEAVEBATTLE
1581     wxLogDebugFunc( wxEmptyString );
1582     m_relay_host_bot = wxEmptyString;
1583     SendCmd( _T("LEAVEBATTLE") );
1584 }
1585 
1586 
SendHostInfo(HostInfo update)1587 void TASServer::SendHostInfo( HostInfo update )
1588 {
1589     wxLogDebugFunc( wxEmptyString );
1590 
1591     try
1592     {
1593         ASSERT_LOGIC( m_battle_id != -1, _T("invalid m_battle_id value") );
1594         ASSERT_LOGIC( BattleExists(m_battle_id), _T("battle doesn't exists") );
1595     }
1596     catch (...)
1597     {
1598         return;
1599     }
1600 
1601     Battle& battle = GetBattle( m_battle_id );
1602     try
1603     {
1604         ASSERT_LOGIC( battle.IsFounderMe(), _T("I'm not founder") );
1605     }
1606     catch (...)
1607     {
1608         return;
1609     }
1610 
1611     //BattleOptions bo = battle.opts();
1612 
1613     if ( ( update & ( IBattle::HI_Map | IBattle::HI_Locked | IBattle::HI_Spectators ) ) > 0 )
1614     {
1615         // UPDATEBATTLEINFO SpectatorCount locked maphash {mapname}
1616         wxString cmd = wxString::Format( _T("%d %d "), battle.GetSpectators(), battle.IsLocked() );
1617         cmd += MakeHashSigned(TowxString(battle.LoadMap().hash)) + _T(" ");
1618         cmd += TowxString(battle.LoadMap().name);
1619 
1620         if ( !battle.IsProxy() ) SendCmd( _T("UPDATEBATTLEINFO"), cmd );
1621         else RelayCmd( _T("UPDATEBATTLEINFO"), cmd );
1622     }
1623     if ( ( update & IBattle::HI_Send_All_opts ) > 0 )
1624     {
1625         wxString cmd;
1626         for (const auto& it : battle.CustomBattleOptions().getOptions( LSL::OptionsWrapper::MapOption ))
1627         {
1628             const wxString newcmd = TowxString("game/mapoptions/" + it.first + "=" + it.second.second + "\t");
1629 			if ( cmd.size() + newcmd.size() > 900 ) // should be 1024 add margin for relayhost name and command itself
1630 			{
1631 				if ( !battle.IsProxy() ) SendCmd( _T("SETSCRIPTTAGS"), cmd );
1632 				else RelayCmd( _T("SETSCRIPTTAGS"), cmd );
1633 				cmd = wxEmptyString;
1634 			}
1635 			cmd << newcmd;
1636         }
1637         for (const auto& it : battle.CustomBattleOptions().getOptions( LSL::OptionsWrapper::ModOption ))
1638         {
1639             const wxString newcmd = TowxString("game/modoptions/" + it.first + "=" + it.second.second + "\t");
1640 			if ( cmd.size() + newcmd.size() > 900 )// should be 1024 add margin for relayhost name and command itself
1641 			{
1642 				if ( !battle.IsProxy() ) SendCmd( _T("SETSCRIPTTAGS"), cmd );
1643 				else RelayCmd( _T("SETSCRIPTTAGS"), cmd );
1644 				cmd = wxEmptyString;
1645 			}
1646 			cmd << newcmd;
1647         }
1648         for (const auto& it : battle.CustomBattleOptions().getOptions( LSL::OptionsWrapper::EngineOption ))
1649         {
1650             const wxString newcmd = TowxString("game/" + it.first + "=" + it.second.second + "\t");
1651 			if ( cmd.size() + newcmd.size() > 900 )// should be 1024 add margin for relayhost name and command itself
1652 			{
1653 				if ( !battle.IsProxy() ) SendCmd( _T("SETSCRIPTTAGS"), cmd );
1654 				else RelayCmd( _T("SETSCRIPTTAGS"), cmd );
1655 				cmd = wxEmptyString;
1656 			}
1657 			cmd << newcmd;
1658         }
1659 		if ( !battle.IsProxy() ) SendCmd( _T("SETSCRIPTTAGS"), cmd );
1660 		else RelayCmd( _T("SETSCRIPTTAGS"), cmd );
1661     }
1662 
1663     if ( (update & IBattle::HI_StartRects) > 0 )   // Startrects should be updated.
1664     {
1665         unsigned int numrects = battle.GetLastRectIdx();
1666         for ( unsigned int i = 0; i <= numrects; i++ )   // Loop through all, and remove updated or deleted.
1667         {
1668             wxString cmd;
1669             BattleStartRect sr = battle.GetStartRect( i );
1670             if ( !sr.exist ) continue;
1671             if ( sr.todelete )
1672             {
1673                 if ( !battle.IsProxy() ) SendCmd( _T("REMOVESTARTRECT"), wxString::Format( _T("%d"), i ) );
1674                 else RelayCmd( _T("REMOVESTARTRECT"), wxString::Format( _T("%d"), i ) );
1675                 battle.StartRectRemoved( i );
1676             }
1677             else if ( sr.toadd )
1678             {
1679                 if ( !battle.IsProxy() ) SendCmd( _T("ADDSTARTRECT"), wxString::Format( _T("%d %d %d %d %d"), sr.ally, sr.left, sr.top, sr.right, sr.bottom ) );
1680                 else RelayCmd( _T("ADDSTARTRECT"), wxString::Format( _T("%d %d %d %d %d"), sr.ally, sr.left, sr.top, sr.right, sr.bottom ) );
1681                 battle.StartRectAdded( i );
1682             }
1683             else if ( sr.toresize )
1684             {
1685                 if ( !battle.IsProxy() )
1686                 {
1687                   SendCmd( _T("REMOVESTARTRECT"), wxString::Format( _T("%d"), i ) );
1688                   SendCmd( _T("ADDSTARTRECT"), wxString::Format( _T("%d %d %d %d %d"), sr.ally, sr.left, sr.top, sr.right, sr.bottom ) );
1689                 }
1690                 else
1691                 {
1692                   RelayCmd( _T("REMOVESTARTRECT"), wxString::Format( _T("%d"), i ) );
1693                   RelayCmd( _T("ADDSTARTRECT"), wxString::Format( _T("%d %d %d %d %d"), sr.ally, sr.left, sr.top, sr.right, sr.bottom ) );
1694                 }
1695                 battle.StartRectResized( i );
1696             }
1697         }
1698 
1699     }
1700     if ( (update & IBattle::HI_Restrictions) > 0 )
1701     {
1702         std::map<wxString, int> units = battle.RestrictedUnits();
1703         if ( !battle.IsProxy() ) SendCmd( _T("ENABLEALLUNITS") );
1704         else RelayCmd( _T("ENABLEALLUNITS") );
1705         if ( !units.empty() )
1706         {
1707             wxString msg;
1708             wxString scriptmsg;
1709 			for ( std::map<wxString, int>::const_iterator itor = units.begin(); itor != units.end(); ++itor )
1710             {
1711             	 msg << itor->first + _T(" ");
1712             	 scriptmsg << _T("game/restrict/") + itor->first + _T("=") + TowxString(itor->second) + _T('\t'); // this is a serious protocol abuse, but on the other hand, the protocol fucking suck and it's unmaintained so it will do for now
1713             }
1714 						if ( !battle.IsProxy() )
1715 						{
1716 							 SendCmd( _T("DISABLEUNITS"), msg );
1717 							 SendCmd( _T("SETSCRIPTTAGS"), scriptmsg );
1718 						}
1719 						else
1720 						{
1721 							 RelayCmd( _T("DISABLEUNITS"), msg );
1722 						   RelayCmd( _T("SETSCRIPTTAGS"), scriptmsg );
1723 						}
1724         }
1725     }
1726 }
1727 
1728 
SendHostInfo(const wxString & Tag)1729 void TASServer::SendHostInfo( const wxString& Tag )
1730 {
1731     wxLogDebugFunc( wxEmptyString );
1732 
1733     try
1734     {
1735         ASSERT_LOGIC( m_battle_id != -1, _T("invalid m_battle_id value") );
1736         ASSERT_LOGIC( BattleExists(m_battle_id), _T("battle doesn't exists") );
1737     }
1738     catch (...)
1739     {
1740         return;
1741     }
1742 
1743     Battle& battle = GetBattle( m_battle_id );
1744 
1745     try
1746     {
1747         ASSERT_LOGIC( battle.IsFounderMe(), _T("I'm not founder") );
1748     }
1749     catch (...)
1750     {
1751         return;
1752     }
1753 
1754     wxString cmd;
1755 
1756     long type;
1757     Tag.BeforeFirst( '_' ).ToLong( &type );
1758     const wxString key = Tag.AfterFirst( '_' );
1759     if ( type == LSL::OptionsWrapper::MapOption )
1760     {
1761         cmd << _T("game/mapoptions/") << key << _T("=")
1762             << TowxString(battle.CustomBattleOptions().getSingleValue(STD_STRING(key), LSL::OptionsWrapper::MapOption ));
1763     }
1764     else if ( type == LSL::OptionsWrapper::ModOption )
1765     {
1766         cmd << _T("game/modoptions/") << key << _T("=")
1767             << TowxString(battle.CustomBattleOptions().getSingleValue(STD_STRING(key), LSL::OptionsWrapper::ModOption ));
1768     }
1769     else if ( type == LSL::OptionsWrapper::EngineOption )
1770     {
1771         cmd << _T("game/") << key << _T("=")
1772             << TowxString(battle.CustomBattleOptions().getSingleValue(STD_STRING(key), LSL::OptionsWrapper::EngineOption ));
1773     }
1774     if ( !battle.IsProxy() ) SendCmd( _T("SETSCRIPTTAGS"), cmd );
1775     else RelayCmd( _T("SETSCRIPTTAGS"), cmd );
1776 }
1777 
1778 
SendUserPosition(const User & user)1779 void TASServer::SendUserPosition( const User& user )
1780 {
1781 	wxLogDebugFunc( wxEmptyString );
1782 
1783 	try
1784 	{
1785         ASSERT_LOGIC( m_battle_id != -1, _T("invalid m_battle_id value") );
1786         ASSERT_LOGIC( BattleExists(m_battle_id), _T("battle doesn't exists") );
1787 
1788         Battle& battle = GetBattle( m_battle_id );
1789         ASSERT_LOGIC( battle.IsFounderMe(), _T("I'm not founder") );
1790 
1791         UserBattleStatus status = user.BattleStatus();
1792         wxString msgx = _T("game/Team") + TowxString( status.team ) + _T("/StartPosX=") + TowxString( status.pos.x );
1793         wxString msgy = _T("game/Team") + TowxString( status.team ) + _T("/StartPosY=") + TowxString( status.pos.y );
1794         wxString netmessage = msgx + _T("\t") + msgy;
1795         if ( battle.IsProxy() )
1796         {
1797             RelayCmd( _T("SETSCRIPTTAGS"), netmessage );
1798         }
1799         else
1800         {
1801             SendCmd( _T("SETSCRIPTTAGS"), netmessage );
1802         }
1803 	}
1804 	catch (...)
1805 	{
1806 			return;
1807 	}
1808 }
1809 
SendRaw(const wxString & raw)1810 void TASServer::SendRaw( const wxString& raw )
1811 {
1812     SendCmd( raw );
1813 }
1814 
1815 
RequestInGameTime(const wxString & nick)1816 void TASServer::RequestInGameTime( const wxString& nick )
1817 {
1818     SendCmd( _T("GETINGAMETIME"), nick );
1819 }
1820 
1821 
GetCurrentBattle()1822 Battle* TASServer::GetCurrentBattle()
1823 {
1824     try
1825     {
1826         ASSERT_EXCEPTION( m_battle_id != -1, _T("invalid m_battle_id value") );
1827         ASSERT_LOGIC( BattleExists(m_battle_id), _T("battle doesn't exists") );
1828     }
1829     catch (...)
1830     {
1831         return NULL;
1832     }
1833 
1834     return &GetBattle( m_battle_id );
1835 }
1836 
1837 
SendMyBattleStatus(UserBattleStatus & bs)1838 void TASServer::SendMyBattleStatus( UserBattleStatus& bs )
1839 {
1840     wxLogDebugFunc( wxEmptyString );
1841 
1842     UTASBattleStatus tasbs;
1843     tasbs.tasdata = ConvTasbattlestatus( bs );
1844     UTASColor tascl;
1845     tascl.color.red = bs.colour.Red();
1846     tascl.color.green = bs.colour.Green();
1847     tascl.color.blue = bs.colour.Blue();
1848     tascl.color.zero = 0;
1849     //MYBATTLESTATUS battlestatus myteamcolor
1850     SendCmd( _T("MYBATTLESTATUS"), wxString::Format( _T("%d %d"), tasbs.data, tascl.data ) );
1851 }
1852 
1853 
SendMyUserStatus()1854 void TASServer::SendMyUserStatus()
1855 {
1856     wxLogDebugFunc( wxEmptyString );
1857 
1858     UserStatus& us = GetMe().Status();
1859 
1860     UTASClientStatus taus;
1861     taus.tasdata.in_game = us.in_game;
1862     taus.tasdata.away = us.away;
1863     taus.tasdata.rank = us.rank;
1864     taus.tasdata.moderator = us.moderator;
1865     taus.tasdata.bot = us.bot;
1866 
1867     SendCmd( _T("MYSTATUS"), wxString::Format( _T("%d"), taus.byte ) );
1868 }
1869 
1870 
StartHostedBattle()1871 void TASServer::StartHostedBattle()
1872 {
1873     wxLogDebugFunc( wxEmptyString );
1874     try
1875     {
1876         ASSERT_LOGIC( m_battle_id != -1, _T("Invalid m_battle_id") );
1877         ASSERT_LOGIC( BattleExists(m_battle_id), _T("battle doesn't exists") );
1878     }
1879     catch (...)
1880     {
1881         return;
1882     }
1883     Battle *battle=GetCurrentBattle();
1884     if (battle)
1885     {
1886         if ( ( battle->GetNatType() == NAT_Hole_punching ) || ( battle->GetNatType() == NAT_Fixed_source_ports ) )
1887         {
1888             UdpPingTheServer(m_user);
1889             for (int i=0;i<5;++i)UdpPingAllClients();
1890         }
1891     }
1892 
1893     m_se->OnStartHostedBattle( m_battle_id );
1894 }
1895 
1896 
ForceSide(int battleid,User & user,int side)1897 void TASServer::ForceSide( int battleid, User& user, int side )
1898 {
1899     wxLogDebugFunc( wxEmptyString );
1900     try
1901     {
1902         ASSERT_LOGIC( m_battle_id != -1, _T("Invalid m_battle_id") );
1903         ASSERT_LOGIC( BattleExists(m_battle_id), _T("battle doesn't exists") );
1904         ASSERT_LOGIC( battleid == m_battle_id, _T("Not current battle") );
1905     }
1906     catch (...)
1907     {
1908         return;
1909     }
1910 
1911 		UserBattleStatus status = user.BattleStatus();
1912 
1913     if ( &user == &GetMe() )
1914     {
1915         status.side = side;
1916         SendMyBattleStatus( status );
1917         return;
1918     }
1919 
1920     if ( status.IsBot() )
1921     {
1922     	status.side = side;
1923     	UpdateBot( battleid, user, status );
1924     }
1925 }
1926 
1927 
ForceTeam(int battleid,User & user,int team)1928 void TASServer::ForceTeam( int battleid, User& user, int team )
1929 {
1930     wxLogDebugFunc( wxEmptyString );
1931     try
1932     {
1933         ASSERT_LOGIC( m_battle_id != -1, _T("Invalid m_battle_id") );
1934         ASSERT_LOGIC( BattleExists(m_battle_id), _T("battle doesn't exists") );
1935         ASSERT_LOGIC( battleid == m_battle_id, _T("Not current battle") );
1936     }
1937     catch (...)
1938     {
1939         return;
1940     }
1941     UserBattleStatus status = user.BattleStatus();
1942 		if ( status.IsBot() )
1943 		{
1944 				status.team = team;
1945 				UpdateBot( battleid, user, status );
1946 				return;
1947 		}
1948 		if ( &user == &GetMe() )
1949 		{
1950 				status.team = team;
1951 				SendMyBattleStatus( status );
1952 				return;
1953 		}
1954     if ( !GetBattle(battleid).IsFounderMe() )
1955     {
1956 				DoActionBattle( battleid, _T("suggests that ") + user.GetNick() + _T(" changes to team #") + wxString::Format( _T("%d"), team + 1 ) + _T(".") );
1957         return;
1958     }
1959 
1960     //FORCETEAMNO username teamno
1961     if( !GetBattle(battleid).IsProxy() ) SendCmd( _T("FORCETEAMNO"), user.GetNick() + wxString::Format(_T(" %d"), team ) );
1962     else RelayCmd( _T("FORCETEAMNO"), user.GetNick() + wxString::Format(_T(" %d"), team ) );
1963 }
1964 
1965 
ForceAlly(int battleid,User & user,int ally)1966 void TASServer::ForceAlly( int battleid, User& user, int ally )
1967 {
1968     wxLogDebugFunc( wxEmptyString );
1969     try
1970     {
1971         ASSERT_LOGIC( m_battle_id != -1, _T("Invalid m_battle_id") );
1972         ASSERT_LOGIC( BattleExists(m_battle_id), _T("battle doesn't exists") );
1973         ASSERT_LOGIC( battleid == m_battle_id, _T("Not current battle") );
1974     }
1975     catch (...)
1976     {
1977         return;
1978     }
1979 		UserBattleStatus status = user.BattleStatus();
1980 		if ( status.IsBot() )
1981 		{
1982 			 status.ally = ally;
1983 			 UpdateBot( battleid, user, status );
1984 			 return;
1985 		}
1986 
1987 		if ( &user == &GetMe() )
1988 		{
1989 				status.ally = ally;
1990 				SendMyBattleStatus( status );
1991 				return;
1992 		}
1993 
1994     if ( !GetBattle(battleid).IsFounderMe() )
1995     {
1996 			DoActionBattle( battleid, _T("suggests that ") + user.GetNick() + _T(" changes to ally #") + wxString::Format( _T("%d"), ally + 1 ) + _T(".") );
1997 			return;
1998     }
1999 
2000     //FORCEALLYNO username teamno
2001     if( !GetBattle(battleid).IsProxy() ) SendCmd( _T("FORCEALLYNO"), user.GetNick() + wxString::Format( _T(" %d"), ally ) );
2002     else RelayCmd( _T("FORCEALLYNO"), user.GetNick() + wxString::Format( _T(" %d"), ally ) );
2003 }
2004 
2005 
ForceColour(int battleid,User & user,const wxColour & col)2006 void TASServer::ForceColour( int battleid, User& user, const wxColour& col )
2007 {
2008     wxLogDebugFunc( wxEmptyString );
2009     try
2010     {
2011         ASSERT_LOGIC( m_battle_id != -1, _T("Invalid m_battle_id") );
2012         ASSERT_LOGIC( BattleExists(m_battle_id), _T("battle doesn't exists") );
2013         ASSERT_LOGIC( battleid == m_battle_id, _T("Not current battle") );
2014     }
2015     catch (...)
2016     {
2017         return;
2018     }
2019 		UserBattleStatus status = user.BattleStatus();
2020 		if ( status.IsBot() )
2021 		{
2022 			 status.colour = col;
2023 			 UpdateBot( battleid, user, status );
2024 			 return;
2025 		}
2026 		if ( &user == &GetMe() )
2027 		{
2028 				status.colour = col;
2029 				SendMyBattleStatus( status );
2030 				return;
2031 		}
2032     if ( !GetBattle(battleid).IsFounderMe() )
2033     {
2034 			DoActionBattle( battleid, _T("sugests that ") + user.GetNick() + _T(" changes colour.") );
2035 			return;
2036     }
2037 
2038     UTASColor tascl;
2039     tascl.color.red = col.Red();
2040     tascl.color.green = col.Green();
2041     tascl.color.blue = col.Blue();
2042     tascl.color.zero = 0;
2043     //FORCETEAMCOLOR username color
2044     if( !GetBattle(battleid).IsProxy() ) SendCmd( _T("FORCETEAMCOLOR"), user.GetNick() + _T(" ") + wxString::Format( _T("%d"), tascl.data ) );
2045     else RelayCmd( _T("FORCETEAMCOLOR"), user.GetNick() + _T(" ") + wxString::Format( _T("%d"), tascl.data ) );
2046 }
2047 
2048 
ForceSpectator(int battleid,User & user,bool spectator)2049 void TASServer::ForceSpectator( int battleid, User& user, bool spectator )
2050 {
2051     wxLogDebugFunc( wxEmptyString );
2052     try
2053     {
2054         ASSERT_LOGIC( m_battle_id != -1, _T("Invalid m_battle_id") );
2055         ASSERT_LOGIC( BattleExists(m_battle_id), _T("battle doesn't exists") );
2056         ASSERT_LOGIC( battleid == m_battle_id, _T("Not current battle") );
2057     }
2058     catch (...)
2059     {
2060         return;
2061     }
2062 		UserBattleStatus status = user.BattleStatus();
2063 		if ( status.IsBot() )
2064 		{
2065 			 status.spectator = spectator;
2066 			 UpdateBot( battleid, user, status );
2067 			 return;
2068 		}
2069 		if ( &user == &GetMe() )
2070 		{
2071 				status.spectator = spectator;
2072 				SendMyBattleStatus( status );
2073 				return;
2074 		}
2075     if ( !GetBattle(battleid).IsFounderMe() )
2076     {
2077 			if ( spectator ) DoActionBattle( battleid, _T("suggests that ") + user.GetNick() + _T(" becomes a spectator.") );
2078 			else DoActionBattle( battleid, _T("suggests that ") + user.GetNick() + _T(" plays.") );
2079 			return;
2080     }
2081 
2082     //FORCESPECTATORMODE username
2083     if( !GetBattle(battleid).IsProxy() ) SendCmd( _T("FORCESPECTATORMODE"), user.GetNick() );
2084     else RelayCmd( _T("FORCESPECTATORMODE"), user.GetNick() );
2085 }
2086 
2087 
BattleKickPlayer(int battleid,User & user)2088 void TASServer::BattleKickPlayer( int battleid, User& user )
2089 {
2090     wxLogDebugFunc( wxEmptyString );
2091     try
2092     {
2093         ASSERT_LOGIC( m_battle_id != -1, _T("Invalid m_battle_id") );
2094         ASSERT_LOGIC( BattleExists(m_battle_id), _T("battle doesn't exists") );
2095         ASSERT_LOGIC( battleid == m_battle_id, _T("Not current battle") );
2096     }
2097     catch (...)
2098     {
2099         return;
2100     }
2101 		UserBattleStatus status = user.BattleStatus();
2102     if ( status.IsBot() )
2103     {
2104     	RemoveBot( battleid, user );
2105     	return;
2106     }
2107 		if ( &user == &GetMe() )
2108 		{
2109 				LeaveBattle( battleid );
2110 				return;
2111 		}
2112     if ( !GetBattle(battleid).IsFounderMe() )
2113     {
2114 			DoActionBattle( battleid, _T("thinks ") + user.GetNick() + _T(" should leave.") );
2115 			return;
2116     }
2117 
2118     //KICKFROMBATTLE username
2119 	if( !GetBattle(battleid).IsProxy() )
2120 	{
2121 		user.BattleStatus().scriptPassword = wxString::Format(_T("%04x%04x"), rand()&0xFFFF, rand()&0xFFFF); // reset his password to something random, so he can't rejoin
2122 		SetRelayIngamePassword( user );
2123 		SendCmd( _T("KICKFROMBATTLE"), user.GetNick() );
2124 	}
2125     else RelayCmd( _T("KICKFROMBATTLE"), user.GetNick() );
2126 }
2127 
SetHandicap(int battleid,User & user,int handicap)2128 void TASServer::SetHandicap( int battleid, User& user, int handicap)
2129 {
2130     wxLogDebugFunc( wxEmptyString );
2131     try
2132     {
2133         ASSERT_LOGIC( m_battle_id != -1, _T("Invalid m_battle_id") );
2134         ASSERT_LOGIC( BattleExists(m_battle_id), _T("battle doesn't exists") );
2135         ASSERT_LOGIC( battleid == m_battle_id, _T("Not current battle") );
2136     }
2137     catch (...)
2138     {
2139         return;
2140     }
2141 		UserBattleStatus status = user.BattleStatus();
2142 		if ( status.IsBot() )
2143 		{
2144 				status.handicap = handicap;
2145 				UpdateBot( battleid, user, status );
2146 				return;
2147 		}
2148 
2149     if ( !GetBattle(battleid).IsFounderMe() )
2150     {
2151         DoActionBattle( battleid, _T("thinks ") + user.GetNick() + _T(" should get a ") + wxString::Format( _T("%d"), handicap) + _T("% resource bonus") );
2152         return;
2153     }
2154 
2155     //HANDICAP username value
2156     if( !GetBattle(battleid).IsProxy() ) SendCmd( _T("HANDICAP"), user.GetNick() + wxString::Format( _T(" %d"), handicap ) );
2157     else RelayCmd( _T("HANDICAP"), user.GetNick() + wxString::Format( _T(" %d"), handicap ) );
2158 }
2159 
2160 
AddBot(int battleid,const wxString & nick,UserBattleStatus & status)2161 void TASServer::AddBot( int battleid, const wxString& nick, UserBattleStatus& status )
2162 {
2163     wxLogDebugFunc( wxEmptyString );
2164     try
2165     {
2166         ASSERT_LOGIC( m_battle_id != -1, _T("Invalid m_battle_id") );
2167         ASSERT_LOGIC( BattleExists(m_battle_id), _T("battle doesn't exists") );
2168         ASSERT_LOGIC( battleid == m_battle_id, _T("Not current battle") );
2169     }
2170     catch (...)
2171     {
2172         return;
2173     }
2174 
2175     UTASBattleStatus tasbs;
2176     tasbs.tasdata = ConvTasbattlestatus( status );
2177     UTASColor tascl;
2178     tascl.color.red = status.colour.Red();
2179     tascl.color.green = status.colour.Green();
2180     tascl.color.blue = status.colour.Blue();
2181     tascl.color.zero = 0;
2182     //ADDBOT name battlestatus teamcolor {AIDLL}
2183     wxString msg;
2184     wxString ailib;
2185     ailib += status.aishortname;
2186     if ( LSL::usync().VersionSupports( LSL::USYNC_GetSkirmishAI ) ) ailib += _T("|") + status.aiversion;
2187     SendCmd( _T("ADDBOT"), nick + wxString::Format( _T(" %d %d "), tasbs.data, tascl.data ) + ailib );
2188 }
2189 
2190 
RemoveBot(int battleid,User & bot)2191 void TASServer::RemoveBot( int battleid, User& bot )
2192 {
2193     wxLogDebugFunc( wxEmptyString );
2194     try
2195     {
2196         ASSERT_LOGIC( m_battle_id != -1, _T("Invalid m_battle_id") );
2197         ASSERT_LOGIC( BattleExists(m_battle_id), _T("battle doesn't exists") );
2198         ASSERT_LOGIC( battleid == m_battle_id, _T("Not current battle") );
2199     }
2200     catch (...)
2201     {
2202         return;
2203     }
2204 
2205     Battle& battle = GetBattle( battleid );
2206     ASSERT_LOGIC( &bot != 0, _T("Bot does not exist.") );
2207 
2208     if ( !( battle.IsFounderMe() || ( bot.BattleStatus().owner == GetMe().GetNick() ) ) )
2209     {
2210         DoActionBattle( battleid, _T("thinks the bot ") + bot.GetNick() + _T(" should be removed.") );
2211         return;
2212     }
2213 
2214     //REMOVEBOT name
2215     if( !GetBattle(battleid).IsProxy() ) SendCmd( _T("REMOVEBOT"), bot.GetNick() );
2216     else RelayCmd( _T("REMOVEBOT"), bot.GetNick() );
2217 }
2218 
2219 
UpdateBot(int battleid,User & bot,UserBattleStatus & status)2220 void TASServer::UpdateBot( int battleid, User& bot, UserBattleStatus& status )
2221 {
2222     wxLogDebugFunc( wxEmptyString );
2223     try
2224     {
2225         ASSERT_LOGIC( m_battle_id != -1, _T("Invalid m_battle_id") );
2226         ASSERT_LOGIC( BattleExists(m_battle_id), _T("battle doesn't exists") );
2227         ASSERT_LOGIC( battleid == m_battle_id, _T("Not current battle") );
2228     }
2229     catch (...)
2230     {
2231         return;
2232     }
2233 
2234     UTASBattleStatus tasbs;
2235     tasbs.tasdata = ConvTasbattlestatus( status );
2236     UTASColor tascl;
2237     tascl.color.red = status.colour.Red();
2238     tascl.color.green = status.colour.Green();
2239     tascl.color.blue = status.colour.Blue();
2240     tascl.color.zero = 0;
2241     //UPDATEBOT name battlestatus teamcolor
2242     if( !GetBattle(battleid).IsProxy() ) SendCmd( _T("UPDATEBOT"), bot.GetNick() + wxString::Format( _T(" %d %d"), tasbs.data, tascl.data ) );
2243     else RelayCmd( _T("UPDATEBOT"), bot.GetNick() + wxString::Format( _T(" %d %d"), tasbs.data, tascl.data ) );
2244 }
2245 
SendScriptToProxy(const wxString & script)2246 void TASServer::SendScriptToProxy( const wxString& script )
2247 {
2248   wxArrayString strings = wxStringTokenize( script, _T("\n") );
2249   int relaylenghtprefix = 10 + 1 + m_relay_host_bot.Len() + 2; // SAYPRIVATE + space + botname + space + exclamation mark lenght
2250   int lenght = script.size();
2251   lenght += relaylenghtprefix + 11 + 1; // CLEANSCRIPT command size
2252   lenght += strings.GetCount() * ( relaylenghtprefix + 16 + 1 ); // num lines * APPENDSCRIPTLINE + space command size ( \n is already counted in script.size)
2253   lenght += relaylenghtprefix + 9 + 1; // STARTGAME command size
2254   int time = lenght / m_sock->GetSendRateLimit(); // calculate time in seconds to upload script
2255   DoActionBattle( m_battle_id, wxString::Format(_T("is preparing to start the game, game will start in approximately %d seconds"),time));
2256   RelayCmd( _T("CLEANSCRIPT") );
2257   wxStringTokenizer tkzr( script, _T("\n") );
2258   while ( tkzr.HasMoreTokens() )
2259   {
2260       wxString line = tkzr.GetNextToken();
2261       RelayCmd( _T("APPENDSCRIPTLINE"), line );
2262   }
2263   RelayCmd( _T("STARTGAME") );
2264 }
2265 
SendScriptToClients(const wxString & script)2266 void TASServer::SendScriptToClients( const wxString& script )
2267 {
2268   SendCmd( _T("SCRIPTSTART") );
2269   wxStringTokenizer tkzr( script, _T("\n") );
2270   while ( tkzr.HasMoreTokens() )
2271   {
2272       wxString line = tkzr.GetNextToken();
2273       SendCmd( _T("SCRIPT"), line );
2274   }
2275   SendCmd( _T("SCRIPTEND") );
2276 }
2277 
OnConnected(Socket *)2278 void TASServer::OnConnected( Socket* /*unused*/ )
2279 {
2280     wxLogDebugFunc( wxEmptyString );
2281     //TASServer* serv = (TASServer*)sock->GetUserdata();
2282     m_last_udp_ping = time( 0 );
2283     m_connected = true;
2284     m_online = false;
2285 	m_token_transmission = false;
2286 	m_relay_host_manager_list.Clear();
2287 	m_last_denied = wxEmptyString;
2288 	m_last_id = 0;
2289 	m_pinglist.clear();
2290 }
2291 
2292 
OnDisconnected(Socket *)2293 void TASServer::OnDisconnected( Socket* /*unused*/ )
2294 {
2295     wxLogDebugFunc( TowxString(m_connected) );
2296     bool connectionwaspresent = m_online || !m_last_denied.IsEmpty() || m_redirecting;
2297     m_last_denied = wxEmptyString;
2298     m_connected = false;
2299     m_online = false;
2300     m_redirecting = false;
2301 	m_token_transmission = false;
2302 	m_buffer = wxEmptyString;
2303 	m_relay_host_manager_list.Clear();
2304 	m_last_id = 0;
2305 	m_pinglist.clear();
2306 	m_users.Nullify();
2307 	if (m_se != NULL) {
2308 		m_se->OnDisconnected( connectionwaspresent );
2309 		Server::OnDisconnected();
2310 	}
2311 }
2312 
2313 
OnDataReceived(Socket * sock)2314 void TASServer::OnDataReceived( Socket* sock )
2315 {
2316     if ( sock == 0 ) return;
2317     m_last_net_packet = time( 0 );
2318     wxString data = sock->Receive();
2319     m_buffer << data;
2320     m_buffer.Replace( _T("\r\n"), _T("\n") );
2321     int returnpos = m_buffer.Find( _T("\n") );
2322     while ( returnpos != -1 )
2323     {
2324         wxString cmd = m_buffer.Left( returnpos );
2325         m_buffer = m_buffer.Mid( returnpos + 1 );
2326         ExecuteCommand( cmd );
2327         returnpos = m_buffer.Find( _T("\n") );
2328     }
2329 }
2330 
2331 
2332 //! @brief Send udp ping.
2333 //! @note used for nat travelsal.
2334 
UdpPing(unsigned int src_port,const wxString & target,unsigned int target_port,const wxString & message)2335 unsigned int TASServer::UdpPing(unsigned int src_port, const wxString &target, unsigned int target_port, const wxString &message)// full parameters version, used to ping all clients when hosting.
2336 {
2337     int result=0;
2338     wxLogMessage(_T("UdpPing src_port=%d , target='%s' , target_port=%d , message='%s'"),src_port,target.c_str(),target_port, message.c_str());
2339     wxIPV4address local_addr;
2340     local_addr.AnyAddress(); // <--- THATS ESSENTIAL!
2341     local_addr.Service(src_port);
2342 
2343     wxDatagramSocket udp_socket(local_addr,/* wxSOCKET_WAITALL*/wxSOCKET_NONE);
2344 
2345     wxIPV4address wxaddr;
2346     wxaddr.Hostname(target);
2347     wxaddr.Service(target_port);
2348 
2349     if (udp_socket.IsOk()&&!udp_socket.Error())
2350     {
2351         std::string m=STD_STRING(message);
2352         udp_socket.SendTo( wxaddr, m.c_str(), m.length() );
2353         wxIPV4address true_local_addr;
2354         if (udp_socket.GetLocal(true_local_addr))
2355         {
2356             result=true_local_addr.Service();
2357         }
2358     }
2359     else
2360     {
2361         wxLogMessage(_T("socket's IsOk() is false, no UDP ping done."));
2362     }
2363 
2364     if (udp_socket.Error()) {
2365         wxLogWarning(_T("wxDatagramSocket Error=%d"),udp_socket.LastError());
2366     }
2367     return result;
2368 }
2369 
UdpPingTheServer(const wxString & message)2370 void TASServer::UdpPingTheServer(const wxString &message)
2371 {
2372     unsigned int port=UdpPing(m_udp_private_port,m_addr,m_nat_helper_port,message);
2373     if (port>0)
2374     {
2375         m_udp_private_port=port;
2376         m_se->OnMyInternalUdpSourcePort( m_udp_private_port );
2377     }
2378 }
2379 
2380 
2381 // copypasta from spring.cpp , to get users ordered same way as in tasclient.
2382 struct UserOrder
2383 {
2384     int index;// user number for GetUser
2385     int order;// user order (we'll sort by it)
operator <UserOrder2386     bool operator<(UserOrder b) const  // comparison function for sorting
2387     {
2388         return order<b.order;
2389     }
2390 };
2391 
2392 
UdpPingAllClients()2393 void TASServer::UdpPingAllClients()// used when hosting with nat holepunching. has some rudimentary support for fixed source ports.
2394 {
2395     Battle *battle=GetCurrentBattle();
2396     if (!battle)return;
2397     if (!battle->IsFounderMe())return;
2398     wxLogMessage(_T("UdpPingAllClients()"));
2399 
2400     // I'm gonna mimic tasclient's behavior.
2401     // It of course doesnt matter in which order pings are sent,
2402     // but when doing "fixed source ports", the port must be
2403     // FIRST_UDP_SOURCEPORT + index of user excluding myself
2404     // so users must be reindexed in same way as in tasclient
2405     // to get same source ports for pings.
2406 
2407 
2408     // copypasta from spring.cpp
2409     std::vector<UserOrder> ordered_users;
2410 
2411 
2412     for ( UserList::user_map_t::size_type i = 0; i < battle->GetNumUsers(); i++ )
2413     {
2414         User &user=battle->GetUser(i);
2415         if (&user == &(battle->GetMe()))continue;// dont include myself (change in copypasta)
2416 
2417         UserOrder tmp;
2418         tmp.index=i;
2419         ordered_users.push_back(tmp);
2420     }
2421     std::sort(ordered_users.begin(),ordered_users.end());
2422 
2423 
2424     for (int i=0;i<int(ordered_users.size());++i)
2425     {
2426         User &user=battle->GetUser(ordered_users[i].index);
2427 
2428         wxString ip=user.BattleStatus().ip;
2429         unsigned int port=user.BattleStatus().udpport;
2430 
2431         unsigned int src_port=m_udp_private_port;
2432         if ( battle->GetNatType() == NAT_Fixed_source_ports )
2433         {
2434             port = FIRST_UDP_SOURCEPORT + i;
2435         }
2436 
2437         wxLogMessage(_T(" pinging nick=%s , ip=%s , port=%u"),user.GetNick().c_str(),ip.c_str(),port);
2438 
2439         if (port!=0 && !ip.empty())
2440         {
2441             UdpPing(src_port,ip,port,_T("hai!"));
2442         }
2443     }
2444 }
2445 
2446 
2447 //! @brief used to check if the NAT is done properly when hosting
TestOpenPort(unsigned int port) const2448 int TASServer::TestOpenPort( unsigned int port ) const
2449 {
2450     wxIPV4address local_addr;
2451     local_addr.AnyAddress(); // <--- THATS ESSENTIAL!
2452     local_addr.Service(port);
2453 
2454     wxSocketServer udp_socket(local_addr, wxSOCKET_NONE);
2455 
2456     wxHTTP connect_to_server;
2457     connect_to_server.SetTimeout( 10 );
2458 
2459     if ( !connect_to_server.Connect( _T("zjt3.com") ) ) return porttest_unreachable;
2460     connect_to_server.GetInputStream(wxString::Format( _T("/porttest.php?port=%u"), port));
2461 
2462     if (udp_socket.IsOk())
2463     {
2464         if ( !udp_socket.WaitForAccept( 10 ) ) return porttest_timeout;
2465     }
2466     else
2467     {
2468         wxLogMessage(_T("socket's IsOk() is false, no UDP packets can be checked"));
2469         return porttest_socketNotOk;
2470     }
2471     if (udp_socket.Error())
2472     {
2473         wxLogMessage(_T("Error=%d"),udp_socket.LastError());
2474         return porttest_socketError;
2475     }
2476     return porttest_pass;
2477 }
2478 
GetRelayHostList()2479 wxArrayString TASServer::GetRelayHostList()
2480 {
2481 	if ( UserExists( _T("RelayHostManagerList") ) ) SayPrivate( _T("RelayHostManagerList"), _T("!lm") );
2482 	wxArrayString ret;
2483 	for ( unsigned int i = 0; i < m_relay_host_manager_list.GetCount(); i++ )
2484 	{
2485 		try
2486 		{
2487 			User& manager = GetUser( m_relay_host_manager_list[i] );
2488 			if ( manager.Status().in_game ) continue; // skip the manager is not connected or reports it's ingame ( no slots available ), or it's away ( functionality disabled )
2489 			if ( manager.Status().away ) continue;
2490 			ret.Add( m_relay_host_manager_list[i] );
2491 		}
2492 		catch(...){}
2493 	}
2494 	return ret;
2495 }
2496 
2497 ////////////////////////
2498 // Utility functions
2499 //////////////////////
2500 
ConvTasclientstatus(TASClientstatus tas)2501 UserStatus ConvTasclientstatus( TASClientstatus tas )
2502 {
2503     UserStatus stat;
2504     stat.in_game = tas.in_game;
2505     stat.away = tas.away;
2506     stat.rank = (UserStatus::RankContainer)tas.rank;
2507     stat.moderator = tas.moderator;
2508     stat.bot = tas.bot;
2509     return stat;
2510 }
2511 
ConvTasbattlestatus(TASBattleStatus tas)2512 UserBattleStatus ConvTasbattlestatus( TASBattleStatus tas )
2513 {
2514     UserBattleStatus stat;
2515     stat.ally = tas.ally;
2516     stat.handicap = tas.handicap;
2517     stat.ready = (tas.ready==1)?true:false;
2518     stat.side = tas.side;
2519     stat.spectator = (tas.player == 0)?true:false;
2520     stat.sync = tas.sync;
2521     stat.team = tas.team;
2522     return stat;
2523 }
2524 
2525 
ConvTasbattlestatus(UserBattleStatus bs)2526 TASBattleStatus ConvTasbattlestatus( UserBattleStatus bs)
2527 {
2528     TASBattleStatus stat;
2529     stat.ally = bs.ally;
2530     stat.handicap = bs.handicap;
2531     stat.ready = bs.ready?1:0;
2532     stat.side = bs.side;
2533     stat.player = bs.spectator?0:1;
2534     stat.sync = bs.sync;
2535     stat.team = bs.team;
2536     return stat;
2537 }
2538 
2539 
IntToStartType(int start)2540 IBattle::StartType IntToStartType( int start )
2541 {
2542     switch ( start )
2543     {
2544     case 0:
2545         return IBattle::ST_Fixed;
2546     case 1:
2547         return IBattle::ST_Random;
2548     case 2:
2549         return IBattle::ST_Choose;
2550     default:
2551         ASSERT_EXCEPTION( false, _T("invalid value") );
2552     };
2553     return IBattle::ST_Fixed;
2554 }
2555 
2556 
IntToNatType(int nat)2557 NatType IntToNatType( int nat )
2558 {
2559     switch ( nat )
2560     {
2561     case 0:
2562         return NAT_None;
2563     case 1:
2564         return NAT_Hole_punching;
2565     case 2:
2566         return NAT_Fixed_source_ports;
2567     default:
2568         ASSERT_EXCEPTION( false, _T("invalid value") );
2569     };
2570     return NAT_None;
2571 }
2572 
2573 
IntToGameType(int gt)2574 IBattle::GameType IntToGameType( int gt )
2575 {
2576     switch ( gt )
2577     {
2578     case 0:
2579         return IBattle::GT_ComContinue;
2580     case 1:
2581         return IBattle::GT_ComEnds;
2582     case 2:
2583         return IBattle::GT_Lineage;
2584     default:
2585         ASSERT_EXCEPTION( false, _T("invalid value") );
2586     };
2587     return IBattle::GT_ComContinue;
2588 }
2589