1 #include "network_cmd_ingame.h"
2 #include "network.h"
3 #include "network_file_transfer.h"
4 #include "network_packet.h"
5 #include "network_socket_list.h"
6 #include "network_cmp_pakset.h"
7 #include "network_cmd_scenario.h"
8 
9 #include "../dataobj/loadsave.h"
10 #include "../dataobj/gameinfo.h"
11 #include "../dataobj/scenario.h"
12 #include "../simmenu.h"
13 #include "../simversion.h"
14 #include "../gui/simwin.h"
15 #include "../simmesg.h"
16 #include "../simsys.h"
17 #include "../dataobj/environment.h"
18 #include "../player/simplay.h"
19 #include "../gui/player_frame_t.h"
20 #include "../utils/simrandom.h"
21 #include "../utils/cbuffer_t.h"
22 #include "../utils/csv.h"
23 #include "../display/viewport.h"
24 #include "../script/script.h" // callback for calls to tools
25 
26 
read_from_packet(packet_t * p)27 network_command_t* network_command_t::read_from_packet(packet_t *p)
28 {
29 	// check data
30 	if (p==NULL  ||  p->has_failed()  ||  !p->check_version()) {
31 		delete p;
32 		dbg->warning("network_command_t::read_from_packet", "error in packet");
33 		return NULL;
34 	}
35 	network_command_t* nwc = NULL;
36 	switch (p->get_id()) {
37 		case NWC_GAMEINFO:    nwc = new nwc_gameinfo_t(); break;
38 		case NWC_NICK:	      nwc = new nwc_nick_t(); break;
39 		case NWC_CHAT:	      nwc = new nwc_chat_t(); break;
40 		case NWC_JOIN:	      nwc = new nwc_join_t(); break;
41 		case NWC_SYNC:        nwc = new nwc_sync_t(); break;
42 		case NWC_GAME:        nwc = new nwc_game_t(); break;
43 		case NWC_READY:       nwc = new nwc_ready_t(); break;
44 		case NWC_TOOL:        nwc = new nwc_tool_t(); break;
45 		case NWC_CHECK:       nwc = new nwc_check_t(); break;
46 		case NWC_PAKSETINFO:  nwc = new nwc_pakset_info_t(); break;
47 		case NWC_SERVICE:     nwc = new nwc_service_t(); break;
48 		case NWC_AUTH_PLAYER: nwc = new nwc_auth_player_t(); break;
49 		case NWC_CHG_PLAYER:  nwc = new nwc_chg_player_t(); break;
50 		case NWC_SCENARIO:    nwc = new nwc_scenario_t(); break;
51 		case NWC_SCENARIO_RULES:
52 		                      nwc = new nwc_scenario_rules_t(); break;
53 		case NWC_STEP:        nwc = new nwc_step_t(); break;
54 		default:
55 			dbg->warning("network_command_t::read_from_socket", "received unknown packet id %d", p->get_id());
56 	}
57 	if (nwc) {
58 		if (!nwc->receive(p) ||  p->has_failed()) {
59 			dbg->warning("network_command_t::read_from_packet", "error while reading cmd from packet");
60 			delete nwc;
61 			nwc = NULL;
62 		}
63 	}
64 	return nwc;
65 }
66 
67 
rdwr()68 void nwc_gameinfo_t::rdwr()
69 {
70 	network_command_t::rdwr();
71 	packet->rdwr_long(len);
72 
73 }
74 
75 
76 // will send the gameinfo to the client
execute(karte_t * welt)77 bool nwc_gameinfo_t::execute(karte_t *welt)
78 {
79 	if (env_t::server) {
80 		dbg->message("nwc_gameinfo_t::execute", "");
81 		// TODO: check whether we can send a file
82 		nwc_gameinfo_t nwgi;
83 		// init the rest of the packet
84 		SOCKET s = packet->get_sender();
85 		loadsave_t fd;
86 		if(  fd.wr_open( "serverinfo.sve", loadsave_t::xml_bzip2, "info", SERVER_SAVEGAME_VER_NR )  ) {
87 			gameinfo_t gi(welt);
88 			gi.rdwr( &fd );
89 			fd.close();
90 			// get gameinfo size
91 			FILE *fh = dr_fopen( "serverinfo.sve", "rb" );
92 			fseek( fh, 0, SEEK_END );
93 			nwgi.len = ftell( fh );
94 			rewind( fh );
95 //			nwj.client_id = network_get_client_id(s);
96 			nwgi.rdwr();
97 			if ( nwgi.send( s ) ) {
98 				// send gameinfo
99 				while(  !feof(fh)  ) {
100 					char buffer[1024];
101 					int bytes_read = (int)fread( buffer, 1, sizeof(buffer), fh );
102 					uint16 dummy;
103 					if(  !network_send_data(s,buffer,bytes_read,dummy,250)) {
104 						dbg->warning( "nwc_gameinfo_t::execute", "Client closed connection during transfer" );
105 						break;
106 					}
107 				}
108 			}
109 			else {
110 				dbg->warning( "nwc_gameinfo_t::execute", "send of NWC_GAMEINFO failed" );
111 			}
112 			fclose( fh );
113 			dr_remove("serverinfo.sve");
114 		}
115 		socket_list_t::remove_client( s );
116 	}
117 	else {
118 		len = 0;
119 	}
120 	return true;
121 }
122 
123 
rdwr()124 void nwc_nick_t::rdwr()
125 {
126 	network_command_t::rdwr();
127 	packet->rdwr_str(nickname);
128 }
129 
130 
131 /**
132  * if server: checks whether nickname is taken and generates default nick
133  */
execute(karte_t * welt)134 bool nwc_nick_t::execute(karte_t *welt)
135 {
136 	if(env_t::server) {
137 		uint32 client_id = socket_list_t::get_client_id(packet->get_sender());
138 
139 		if(nickname==NULL) {
140 			goto generate_default_nick;
141 		}
142 
143 		// check for same nick
144 		for(uint32 i = 0; i<socket_list_t::get_count(); i++) {
145 			socket_info_t& info = socket_list_t::get_client(i);
146 			if ( (info.state == socket_info_t::playing  ||  i==0)
147 				&&  i != client_id
148 				&&  (nickname == info.nickname.c_str()  ||  nickname == "Admin")  )
149 			{
150 				goto generate_default_nick;
151 			}
152 		}
153 		if (id == NWC_NICK) {
154 			// do not call this tool if called by nwc_join_t::execute
155 			nwc_nick_t::server_tools(welt, client_id, CHANGE_NICK, nickname);
156 		}
157 		return true;
158 
159 generate_default_nick:
160 		// nick exists already
161 		// generate default nick
162 		cbuffer_t buf;
163 		buf.printf("Client#%d", client_id);
164 		nickname = (const char*)buf;
165 		return true;
166 	}
167 	else {
168 		env_t::nickname = nickname!=NULL ? nickname.c_str() : "(null)";
169 	}
170 	return true;
171 }
172 
173 
server_tools(karte_t * welt,uint32 client_id,uint8 what,const char * nick)174 void nwc_nick_t::server_tools(karte_t *welt, uint32 client_id, uint8 what, const char* nick)
175 {
176 	if (!socket_list_t::is_valid_client_id(client_id)) {
177 		return;
178 	}
179 	socket_info_t &info = socket_list_t::get_client(client_id);
180 
181 	cbuffer_t buf;
182 	buf.printf("%d,", message_t::general | message_t::local_flag);
183 
184 	switch(what) {
185 		case WELCOME: {
186 			// welcome message
187 			buf.printf(translator::translate("Welcome, %s!", welt->get_settings().get_name_language_id()),
188 				   info.nickname.c_str());
189 
190 			// Log chat message - please don't change order of fields
191 			CSV_t csv;
192 			csv.add_field( "connect" );
193 			csv.add_field( client_id );
194 			csv.add_field( info.address.get_str() );
195 			csv.add_field( info.nickname.c_str() );
196 			dbg->warning( "__ChatLog__", "%s", csv.get_str() );
197 			break;
198 		}
199 
200 		case CHANGE_NICK: {
201 			if (nick==NULL  ||  info.nickname == nick) {
202 				return;
203 			}
204 			// change nickname
205 			buf.printf(translator::translate("%s now known as %s.", welt->get_settings().get_name_language_id()),
206 				   info.nickname.c_str(), nick);
207 
208 			// record nickname change
209 			for(uint8 i=0; i<PLAYER_UNOWNED; i++) {
210 				FOR(slist_tpl<connection_info_t>, &iter, nwc_chg_player_t::company_active_clients[i]) {
211 					if (iter ==  info) {
212 						iter.nickname = nick;
213 					}
214 				}
215 			}
216 
217 			// Log chat message - please don't change order of fields
218 			CSV_t csv;
219 			csv.add_field( "namechange" );
220 			csv.add_field( client_id );
221 			csv.add_field( info.address.get_str() );
222 			csv.add_field( info.nickname.c_str() );
223 			csv.add_field( nick );
224 			dbg->warning( "__ChatLog__", "%s", csv.get_str() );
225 
226 			info.nickname = nick;
227 
228 			if (client_id > 0) {
229 				// send new nickname back to client
230 				nwc_nick_t nwc(nick);
231 				nwc.send(info.socket);
232 			}
233 			else {
234 				// human at server
235 				env_t::nickname = nick;
236 			}
237 			break;
238 		}
239 		case FAREWELL: {
240 			buf.printf(translator::translate("%s has left.", welt->get_settings().get_name_language_id()),
241 				   info.nickname.c_str());
242 
243 			// Log chat message - please don't change order of fields
244 			CSV_t csv;
245 			csv.add_field( "disconnect" );
246 			csv.add_field( client_id );
247 			csv.add_field( info.address.get_str() );
248 			csv.add_field( info.nickname.c_str() );
249 			dbg->warning( "__ChatLog__", "%s", csv.get_str() );
250 
251 			break;
252 		}
253 		default: return;
254 	}
255 	tool_t *tmp_tool = create_tool( TOOL_ADD_MESSAGE | SIMPLE_TOOL );
256 	tmp_tool->set_default_param( buf );
257 	// queue tool for network
258 	nwc_tool_t *nwc = new nwc_tool_t(NULL, tmp_tool, koord3d::invalid, 0, welt->get_map_counter(), true);
259 	network_send_server(nwc);
260 	// since init always returns false, it is safe to delete immediately
261 	delete tmp_tool;
262 }
263 
264 
rdwr()265 void nwc_chat_t::rdwr()
266 {
267 	network_command_t::rdwr();
268 	packet->rdwr_str( message );
269 	packet->rdwr_byte( player_nr );
270 	packet->rdwr_str( clientname );
271 	packet->rdwr_str( destination );
272 
273 	dbg->warning("nwc_chat_t::rdwr", "rdwr message=%s plnr=%d clientname=%s destination=%s", message.c_str(), player_nr, clientname.c_str(), destination.c_str());
274 }
275 
276 
add_message(karte_t * welt) const277 void nwc_chat_t::add_message (karte_t* welt) const
278 {
279 	dbg->warning("nwc_chat_t::add_message", "");
280 	cbuffer_t buf;  // Output which will be printed to chat window
281 
282 	FLAGGED_PIXVAL color = player_nr < PLAYER_UNOWNED  ?  color_idx_to_rgb(welt->get_player( player_nr )->get_player_color1())  :  color_idx_to_rgb(COL_WHITE);
283 	uint16 flag = message_t::chat;
284 
285 	if (  destination == NULL  ) {
286 		if (  player_nr < PLAYER_UNOWNED  ) {
287 			buf.printf( "%s <%s>: %s", clientname.c_str(), welt->get_player( player_nr )->get_name(), message.c_str() );
288 		}
289 		else {
290 			buf.printf( "%s: %s", clientname.c_str(), message.c_str() );
291 		}
292 	}
293 	else {
294 		// Whisper, do not store message in savegame
295 		flag |= message_t::local_flag;
296 		if (  player_nr < PLAYER_UNOWNED  ) {
297 			buf.printf( "%s <%s> --> %s: %s", clientname.c_str(), welt->get_player( player_nr )->get_name(), destination.c_str(), message.c_str() );
298 		}
299 		else {
300 			buf.printf( "%s --> %s: %s", clientname.c_str(), destination.c_str(), message.c_str() );
301 		}
302 	}
303 	welt->get_message()->add_message( buf.get_str(), koord::invalid, flag, color, IMG_EMPTY );
304 }
305 
306 
execute(karte_t * welt)307 bool nwc_chat_t::execute (karte_t* welt)
308 {
309 	if (  message == NULL  ) {
310 		dbg->warning("nwc_chat_t::execute", "null message");
311 		return true;
312 	}
313 
314 	// Relay message to all listening clients
315 	if (  env_t::server  ) {
316 		uint32 client_id = socket_list_t::get_client_id( packet->get_sender() );
317 
318 		dbg->warning("nwc_chat_t::execute", "server, client id: %d", client_id);
319 
320 		// Clients can only send messages as companies they have unlocked
321 		if (  player_nr < PLAYER_UNOWNED  &&  !socket_list_t::get_client( client_id ).is_player_unlocked( player_nr )  ) {
322 			dbg->warning("nwc_chat_t::execute", "attempt to send message as locked company by client %d, redirecting to PLAYER_UNOWNED", client_id);
323 			player_nr = PLAYER_UNOWNED;
324 		}
325 
326 		// Otherwise forward message as appropriate
327 		socket_info_t &info = socket_list_t::get_client( client_id );
328 
329 		nwc_chat_t* nwchat = new nwc_chat_t( message, player_nr, info.nickname.c_str(), destination );
330 
331 		if (  destination == NULL  ) {
332 			// Do not send messages to ourself (server)
333 			network_send_all( nwchat, true );
334 
335 			// Act on message (for display of messages on server, and to keep record of messages for new clients joining)
336 			add_message(welt);
337 
338 			// Log chat message - please don't change order of fields
339 			CSV_t csv;
340 			csv.add_field( "chat" );
341 			csv.add_field( client_id );
342 			csv.add_field( info.address.get_str() );
343 			csv.add_field( info.nickname.c_str() );
344 			csv.add_field( player_nr );
345 			csv.add_field( player_nr < PLAYER_UNOWNED ? welt->get_player( player_nr )->get_name() : "" );
346 			csv.add_field( message.c_str() );
347 			dbg->warning( "__ChatLog__", "%s", csv.get_str() );
348 		}
349 		else {
350 			// Send to a specific client
351 			// Look up a client with a matching name, if none matches
352 			// send a message back saying that client doesn't exist
353 
354 			// Check if destination nick exists
355 			for (  uint32 i = 0;  i < socket_list_t::get_count();  i++  ) {
356 				socket_info_t& dest_info = socket_list_t::get_client(i);
357 				if (  (dest_info.state == socket_info_t::playing  ||  i == 0  )
358 					&&  i != client_id
359 					&&  destination == dest_info.nickname.c_str()  )
360 				{
361 					nwchat->send( dest_info.socket );
362 				}
363 			}
364 
365 			// TODO also send a copy back to sending client for logging
366 
367 			delete nwchat;
368 
369 			// Log chat message - please don't change order of fields
370 			CSV_t csv;
371 			csv.add_field( "private" );
372 			csv.add_field( client_id );
373 			csv.add_field( info.address.get_str() );
374 			csv.add_field( info.nickname.c_str() );
375 			csv.add_field( player_nr );
376 			csv.add_field( player_nr < PLAYER_UNOWNED ? welt->get_player( player_nr )->get_name() : "" );
377 			csv.add_field( destination.c_str() );
378 			csv.add_field( message.c_str() );
379 			dbg->warning( "__ChatLog__", "%s", csv.get_str() );
380 		}
381 	}
382 	else {
383 		add_message(welt);
384 	}
385 	return true;
386 }
387 
388 
389 
390 SOCKET nwc_join_t::pending_join_client = INVALID_SOCKET;
391 
rdwr()392 void nwc_join_t::rdwr()
393 {
394 	nwc_nick_t::rdwr();
395 	packet->rdwr_long(client_id);
396 	packet->rdwr_byte(answer);
397 }
398 
399 
execute(karte_t * welt)400 bool nwc_join_t::execute(karte_t *welt)
401 {
402 	if(env_t::server) {
403 		dbg->message("nwc_join_t::execute", "");
404 		// TODO: check whether we can send a file
405 		nwc_join_t nwj;
406 		nwj.client_id = socket_list_t::get_client_id(packet->get_sender());
407 		//save nickname
408 		if (socket_list_t::is_valid_client_id(nwj.client_id)) {
409 			// check nickname
410 			nwc_nick_t::execute(welt);
411 			nwj.nickname = nickname;
412 			socket_list_t::get_client(nwj.client_id).nickname = nickname;
413 		}
414 
415 		// no other joining process active?
416 		nwj.answer = socket_list_t::get_client(nwj.client_id).is_active()  &&  pending_join_client == INVALID_SOCKET ? 1 : 0;
417 		DBG_MESSAGE( "nwc_join_t::execute", "client_id=%i active=%i pending_join_client=%i active=%d", socket_list_t::get_client_id(packet->get_sender()), socket_list_t::get_client(nwj.client_id).is_active(), pending_join_client, nwj.answer );
418 		nwj.rdwr();
419 		if(  nwj.send( packet->get_sender() )  ) {
420 			if(  nwj.answer==1  ) {
421 				// now send sync command
422 				const uint32 new_map_counter = welt->generate_new_map_counter();
423 				// since network_send_all() does not include non-playing clients -> send sync command separately to the joining client
424 				nwc_sync_t nw_sync(welt->get_sync_steps() + 1, welt->get_map_counter(), nwj.client_id, new_map_counter);
425 				nw_sync.rdwr();
426 				if(  nw_sync.send( packet->get_sender() )  ) {
427 					// now send sync command to the server and the remaining clients
428 					nwc_sync_t *nws = new nwc_sync_t(welt->get_sync_steps() + 1, welt->get_map_counter(), nwj.client_id, new_map_counter);
429 					network_send_all(nws, false);
430 					pending_join_client = packet->get_sender();
431 					DBG_MESSAGE( "nwc_join_t::execute", "pending_join_client now %i", pending_join_client);
432 					// unpause world
433 					if (welt->is_paused()) {
434 						welt->set_pause(false);
435 					}
436 				}
437 				else {
438 					dbg->warning("nwc_join_t::execute", "send of NWC_SYNC to the joining client failed");
439 				}
440 			}
441 		}
442 		else {
443 			dbg->warning( "nwc_join_t::execute", "send of NWC_JOIN failed" );
444 		}
445 	}
446 	return true;
447 }
448 
449 
450 /**
451  * saves the history of map counters
452  * the current one is at index zero, the older ones behind
453  */
454 #define MAX_MAP_COUNTERS (7)
455 vector_tpl<uint32> nwc_ready_t::all_map_counters(MAX_MAP_COUNTERS);
456 
457 
append_map_counter(uint32 map_counter_)458 void nwc_ready_t::append_map_counter(uint32 map_counter_)
459 {
460 	if (all_map_counters.get_count() == MAX_MAP_COUNTERS) {
461 		all_map_counters.pop_back();
462 	}
463 	all_map_counters.insert_at(0, map_counter_);
464 }
465 
466 
clear_map_counters()467 void nwc_ready_t::clear_map_counters()
468 {
469 	all_map_counters.clear();
470 }
471 
472 
execute(karte_t * welt)473 bool nwc_ready_t::execute(karte_t *welt)
474 {
475 	if(  env_t::server  ) {
476 		// compare checklist
477 		if(  welt->is_checklist_available(sync_step)  &&  checklist!=welt->get_checklist_at(sync_step)  ) {
478 			// client has gone out of sync
479 			socket_list_t::remove_client( get_sender() );
480 			char buf[256];
481 			welt->get_checklist_at(sync_step).print(buf, "server");
482 			checklist.print(buf, "client");
483 			dbg->warning("nwc_ready_t::execute", "disconnect client due to checklist mismatch : sync_step=%u %s", sync_step, buf);
484 			return true;
485 		}
486 		// check the validity of the map counter
487 		FOR(vector_tpl<uint32>, const i, all_map_counters) {
488 			if (i == map_counter) {
489 				// unpause the sender by sending nwc_ready_t back
490 				nwc_ready_t nwc(sync_step, map_counter, checklist);
491 				if(  !nwc.send( get_sender())  ) {
492 					dbg->warning("nwc_ready_t::execute", "send of NWC_READY failed");
493 				}
494 				return true;
495 			}
496 		}
497 		// no matching map counter -> disconnect client
498 		socket_list_t::remove_client( get_sender() );
499 		dbg->warning("nwc_ready_t::execute", "disconnect client id=%u due to invalid map counter", our_client_id);
500 	}
501 	else {
502 		dbg->warning("nwc_ready_t::execute", "set sync_step=%d where map_counter=%d", sync_step, map_counter);
503 		if(  map_counter==welt->get_map_counter()  ) {
504 			welt->network_game_set_pause(false, sync_step);
505 			welt->set_checklist_at(sync_step, checklist);
506 		}
507 		else {
508 			welt->network_disconnect();
509 			dbg->warning("nwc_ready_t::execute", "disconnecting due to map counter mismatch");
510 		}
511 	}
512 	return true;
513 }
514 
515 
rdwr()516 void nwc_ready_t::rdwr()
517 {
518 	network_command_t::rdwr();
519 	packet->rdwr_long(sync_step);
520 	packet->rdwr_long(map_counter);
521 	checklist.rdwr(packet);
522 }
523 
524 
rdwr()525 void nwc_game_t::rdwr()
526 {
527 	network_command_t::rdwr();
528 	packet->rdwr_long(len);
529 }
530 
531 
execute(karte_t * welt)532 bool nwc_auth_player_t::execute(karte_t *welt)
533 {
534 	dbg->message("nwc_auth_player_t::execute","plnr = %d  unlock = %d  our_client_id = %d", player_nr, player_unlocked, our_client_id);
535 
536 	if(  env_t::server  &&  !(our_client_id==0  &&  player_nr==255)) {
537 		// sent to server, and not sent to player playing on server
538 		if (socket_list_t::is_valid_client_id(our_client_id)) {
539 
540 			// player activated for this client? or admin connection via nettool?
541 			socket_info_t &info = socket_list_t::get_client(our_client_id);
542 			if (info.is_player_unlocked(player_nr)  ||  info.state == socket_info_t::admin) {
543 				dbg->message("nwc_auth_player_t::execute","set pwd for plnr = %d", player_nr);
544 
545 				// change password
546 				if (welt->get_player(player_nr)->access_password_hash() != hash) {
547 					welt->get_player(player_nr)->access_password_hash() = hash;
548 					// unlock all clients if new password is empty
549 					// otherwise lock all
550 					socket_list_t::unlock_player_all(player_nr, hash.empty(), our_client_id);
551 				}
552 			}
553 			else if (player_nr < PLAYER_UNOWNED) {
554 				// players with public service player access always pass password checks
555 				if(  info.is_player_unlocked(1)  ) {
556 					info.unlock_player(player_nr);
557 				}
558 				// check password
559 				else if (welt->get_player(player_nr)->access_password_hash() == hash) {
560 
561 					dbg->message("nwc_auth_player_t::execute","unlock plnr = %d at our_client_id = %d", player_nr, our_client_id);
562 
563 					info.unlock_player(player_nr);
564 				}
565 			}
566 
567 			// report back to client who sent the command
568 			if (our_client_id == 0) {
569 				// unlock player on the server and clear unlock_pending flag
570 				welt->get_player(player_nr)->unlock(info.is_player_unlocked(player_nr), false);
571 			}
572 			else {
573 				// send unlock-info to player on the client (to clear unlock_pending flag)
574 				nwc_auth_player_t nwc;
575 				nwc.player_unlocked = info.player_unlocked;
576 				nwc.send( get_sender());
577 			}
578 		}
579 	}
580 	else {
581 		for(uint8 i=0; i<PLAYER_UNOWNED; i++) {
582 			if (player_t *player = welt->get_player(i)) {
583 				player->unlock( player_unlocked & (1<<i), false);
584 			}
585 		}
586 	}
587 	// update the player window
588 	ki_kontroll_t* playerwin = (ki_kontroll_t*)win_get_magic(magic_ki_kontroll_t);
589 	if (playerwin) {
590 		playerwin->update_data();
591 	}
592 	return true;
593 }
594 
595 
init_player_lock_server(karte_t * welt)596 void nwc_auth_player_t::init_player_lock_server(karte_t *welt)
597 {
598 	uint16 player_unlocked = 0;
599 	for(uint8 i=0; i<PLAYER_UNOWNED; i++) {
600 		// player not activated or password matches stored password
601 		player_t *player = welt->get_player(i);
602 		if (player == NULL  ||  player->access_password_hash() == welt->get_player_password_hash(i) ) {
603 			player_unlocked |= 1<<i;
604 		}
605 		if (player) {
606 			player->unlock( player_unlocked & (1<<i), false);
607 		}
608 	}
609 	// get the local server socket
610 	socket_info_t &info = socket_list_t::get_client(0);
611 	info.player_unlocked = player_unlocked;
612 	dbg->message("nwc_auth_player_t::init_player_lock_server", "new = %d", player_unlocked);
613 }
614 
615 
network_world_command_t(uint16 id,uint32 sync_step,uint32 map_counter)616 network_world_command_t::network_world_command_t(uint16 id, uint32 sync_step, uint32 map_counter)
617 : network_command_t(id)
618 {
619 	this->sync_step = sync_step;
620 	this->map_counter = map_counter;
621 }
622 
623 
rdwr()624 void network_world_command_t::rdwr()
625 {
626 	network_command_t::rdwr();
627 	packet->rdwr_long(sync_step);
628 	packet->rdwr_long(map_counter);
629 }
630 
631 
execute(karte_t * welt)632 bool network_world_command_t::execute(karte_t *welt)
633 {
634 	DBG_MESSAGE("network_world_command_t::execute","do_command %d at sync_step %d world now at %d", get_id(), get_sync_step(), welt->get_sync_steps());
635 	// want to execute something in the past?
636 	if (get_sync_step() < welt->get_sync_steps()) {
637 		if (!ignore_old_events()) {
638 			dbg->warning("network_world_command_t::execute", "wanted to execute(%d) in the past", get_id());
639 			welt->network_disconnect();
640 		}
641 		return true; // to delete cmd
642 	}
643 	if (map_counter != welt->get_map_counter()) {
644 		// command from another world
645 		// could happen if we are behind and still have to execute the next sync command
646 		dbg->warning("network_world_command_t::execute", "wanted to execute(%d) from another world (mpc=%d)", get_id(), map_counter);
647 		if (env_t::server) {
648 			return true; // to delete cmd
649 		}
650 		// map_counter has to be checked before calling do_command()
651 	}
652 	welt->command_queue_append(this);
653 	return false;
654 }
655 
656 
rdwr()657 void nwc_sync_t::rdwr()
658 {
659 	network_world_command_t::rdwr();
660 	packet->rdwr_long(client_id);
661 	packet->rdwr_long(new_map_counter);
662 }
663 
664 
665 // save, load, pause, if server send game
do_command(karte_t * welt)666 void nwc_sync_t::do_command(karte_t *welt)
667 {
668 	dbg->warning("nwc_sync_t::do_command", "sync_steps %d", get_sync_step());
669 	// save screen coordinates & offsets
670 	const koord ij = welt->get_viewport()->get_world_position();
671 	const sint16 xoff = welt->get_viewport()->get_x_off();
672 	const sint16 yoff = welt->get_viewport()->get_y_off();
673 	// save active player
674 	const uint8 active_player = welt->get_active_player_nr();
675 	// save lock state
676 	uint16 player_unlocked = 0;
677 	for(uint8 i=0; i<PLAYER_UNOWNED; i++) {
678 		if (player_t *player = welt->get_player(i)) {
679 			if (!player->is_locked()) {
680 				player_unlocked |= 1<<i;
681 			}
682 		}
683 	}
684 	// transfer game, all clients need to sync (save, reload, and pause)
685 	// now save and send
686 	dr_chdir( env_t::user_dir );
687 	if(  !env_t::server  ) {
688 		char fn[256];
689 		sprintf( fn, "client%i-network.sve", network_get_client_id() );
690 
691 		bool old_restore_UI = env_t::restore_UI;
692 		env_t::restore_UI = true;
693 
694 		welt->save( fn, loadsave_t::autosave_mode, SERVER_SAVEGAME_VER_NR, false );
695 		uint32 old_sync_steps = welt->get_sync_steps();
696 		welt->load( fn );
697 		env_t::restore_UI = old_restore_UI;
698 
699 		// pause clients, restore steps
700 		welt->network_game_set_pause( true, old_sync_steps);
701 
702 		// apply new map counter
703 		welt->set_map_counter(new_map_counter);
704 
705 		// tell server we are ready
706 		network_command_t *nwc = new nwc_ready_t( old_sync_steps, welt->get_map_counter(), welt->get_checklist_at(old_sync_steps) );
707 		network_send_server(nwc);
708 	}
709 	else {
710 		char fn[256];
711 		// first save password hashes
712 		sprintf( fn, "server%d-pwdhash.sve", env_t::server );
713 		loadsave_t file;
714 		if(file.wr_open(fn, loadsave_t::zipped, "hashes", SAVEGAME_VER_NR )) {
715 			welt->rdwr_player_password_hashes( &file );
716 			file.close();
717 		}
718 
719 		// remove passwords before transfer on the server and set default client mask
720 		// they will be restored in karte_t::laden
721 		uint16 unlocked_players = 0;
722 		for(  int i=0;  i<PLAYER_UNOWNED; i++  ) {
723 			player_t *player = welt->get_player(i);
724 			if(  player==NULL  ||  player->access_password_hash().empty()  ) {
725 				unlocked_players |= (1<<i);
726 			}
727 			else {
728 				player->access_password_hash().clear();
729 			}
730 		}
731 
732 		// save game
733 		sprintf( fn, "server%d-network.sve", env_t::server );
734 		bool old_restore_UI = env_t::restore_UI;
735 		env_t::restore_UI = true;
736 		welt->save( fn, loadsave_t::save_mode, SERVER_SAVEGAME_VER_NR, false );
737 
738 		// ok, now sending game
739 		// this sends nwc_game_t
740 		const char *err = network_send_file( client_id, fn );
741 		if (err) {
742 			dbg->warning("nwc_sync_t::do_command","send game failed with: %s", err);
743 		}
744 
745 		uint32 old_sync_steps = welt->get_sync_steps();
746 		welt->load( fn );
747 		env_t::restore_UI = old_restore_UI;
748 
749 		// restore steps
750 		welt->network_game_set_pause( false, old_sync_steps);
751 
752 		// apply new map counter
753 		welt->set_map_counter(new_map_counter);
754 
755 		// unpause the client that received the game
756 		// we do not want to wait for him (maybe loading failed due to pakset-errors)
757 		SOCKET sock = socket_list_t::get_socket(client_id);
758 		if(  sock != INVALID_SOCKET  ) {
759 			nwc_ready_t nwc( old_sync_steps, welt->get_map_counter(), welt->get_checklist_at(old_sync_steps) );
760 			if (nwc.send(sock)) {
761 				socket_list_t::change_state( client_id, socket_info_t::playing);
762 				if (socket_list_t::is_valid_client_id(client_id)) {
763 					socket_list_t::get_client(client_id).player_unlocked = unlocked_players;
764 					// send information about locked state
765 					nwc_auth_player_t nwc;
766 					nwc.player_unlocked = unlocked_players;
767 					nwc.send(sock);
768 
769 					// welcome message
770 					nwc_nick_t::server_tools(welt, client_id, nwc_nick_t::WELCOME, NULL);
771 				}
772 			}
773 			else {
774 				dbg->warning( "nwc_sync_t::do_command", "send of NWC_READY failed" );
775 			}
776 		}
777 		nwc_join_t::pending_join_client = INVALID_SOCKET;
778 	}
779 	// restore screen coordinates & offsets
780 	welt->get_viewport()->change_world_position(ij, xoff, yoff);
781 	welt->switch_active_player(active_player,true);
782 	// restore lock state
783 	for(uint8 i=0; i<PLAYER_UNOWNED; i++) {
784 		if (player_t *player = welt->get_player(i)) {
785 			player->unlock(player_unlocked & (1<<i));
786 		}
787 	}
788 }
789 
790 
rdwr()791 void nwc_check_t::rdwr()
792 {
793 	network_world_command_t::rdwr();
794 	server_checklist.rdwr(packet);
795 	packet->rdwr_long(server_sync_step);
796 	if (packet->is_loading()  &&  env_t::server) {
797 		// server does not receive nwc_check_t-commands
798 		packet->failed();
799 	}
800 }
801 
802 
rdwr()803 void network_broadcast_world_command_t::rdwr()
804 {
805 	network_world_command_t::rdwr();
806 	packet->rdwr_bool(exec);
807 
808 	if (packet->is_loading()  &&  env_t::server  &&  exec) {
809 		// server does not receive exec-commands
810 		packet->failed();
811 	}
812 }
813 
814 
execute(karte_t * welt)815 bool network_broadcast_world_command_t::execute(karte_t *welt)
816 {
817 	if (exec) {
818 		// append to command queue
819 		return network_world_command_t::execute(welt);
820 	}
821 	else if (env_t::server) {
822 		// check map_counter
823 		if (map_counter != welt->get_map_counter()) {
824 			// command from another world
825 			dbg->warning("network_broadcast_world_command_t::execute", "wanted to execute(%d) from another world", get_id());
826 			return true;
827 		}
828 		// clone
829 		network_broadcast_world_command_t *nwc = clone(welt);
830 		if (nwc == NULL) {
831 			return true;
832 		}
833 		// next call to execute will put it in command queue
834 		nwc->exec = true;
835 		nwc->sync_step = welt->get_sync_steps() + 1;
836 		// broadcast
837 		network_send_all(nwc, false);
838 		// return true to delete this command only if clone() returned something new
839 		return true;
840 	}
841 	else {
842 		dbg->warning("network_broadcast_world_command_t::execute", "should not reach here!");
843 	}
844 	return true;
845 }
846 
847 
~nwc_chg_player_t()848 nwc_chg_player_t::~nwc_chg_player_t()
849 {
850 	delete pending_company_creator;
851 }
852 
853 
rdwr()854 void nwc_chg_player_t::rdwr()
855 {
856 	network_broadcast_world_command_t::rdwr();
857 	packet->rdwr_byte(cmd);
858 	packet->rdwr_byte(player_nr);
859 	packet->rdwr_short(param);
860 	packet->rdwr_bool(scripted_call);
861 }
862 
863 
clone(karte_t * welt)864 network_broadcast_world_command_t* nwc_chg_player_t::clone(karte_t *welt)
865 {
866 	if (!socket_list_t::is_valid_client_id(our_client_id)) {
867 		return NULL;
868 	}
869 	socket_info_t const& info = socket_list_t::get_client(our_client_id);
870 
871 	// scripts only run on server
872 	if (socket_list_t::get_client_id(packet->get_sender()) != 0) {
873 		// not sent by server, clear flag
874 		scripted_call = false;
875 	}
876 
877 	if (!welt->change_player_tool(cmd, player_nr, param, info.is_player_unlocked(1)  ||  scripted_call, false)) {
878 		return NULL;
879 	}
880 	// now create the new command
881 	nwc_chg_player_t* nwc = new nwc_chg_player_t(get_sync_step(), get_map_counter(), cmd, player_nr, param);
882 
883 	// .. and store company_creator if necessary
884 	if (cmd == karte_t::new_player) {
885 		nwc->pending_company_creator = new connection_info_t(info);
886 
887 		dbg->warning("nwc_chg_player_t::clone", "pending_company_creator for %d is set to %s/%s", player_nr, info.address.get_str(), info.nickname.c_str());
888 	}
889 
890 	return nwc;
891 }
892 
893 
894 connection_info_t* nwc_chg_player_t::company_creator[PLAYER_UNOWNED] = {
895 		NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL};
896 
897 slist_tpl<connection_info_t> nwc_chg_player_t::company_active_clients[PLAYER_UNOWNED];
898 
899 
company_removed(uint8 player_nr)900 void nwc_chg_player_t::company_removed(uint8 player_nr)
901 {
902 	// delete history
903 	delete company_creator[player_nr];
904 	company_creator[player_nr] = NULL;
905 	company_active_clients[player_nr].clear();
906 }
907 
908 
do_command(karte_t * welt)909 void nwc_chg_player_t::do_command(karte_t *welt)
910 {
911 	welt->change_player_tool(cmd, player_nr, param, true, true);
912 
913 	// store IP of client who created this company
914 	if (env_t::server  &&   cmd == karte_t::new_player  &&  player_nr < lengthof(company_creator)) {
915 		company_creator[player_nr] =  pending_company_creator;
916 
917 		if (pending_company_creator) {
918 			dbg->warning("nwc_chg_player_t::do_command", "company_creator for %d is set to %s/%s", player_nr,
919 					 pending_company_creator->address.get_str(), pending_company_creator->nickname.c_str());
920 		}
921 		pending_company_creator = NULL; // to prevent deletion in ~nwc_chg_player_t
922 	}
923 
924 	// reset locked state
925 	if (cmd == karte_t::new_player  ||  cmd == karte_t::delete_player) {
926 		socket_list_t::unlock_player_all(player_nr, true);
927 	}
928 
929 	// update the window
930 	ki_kontroll_t* playerwin = (ki_kontroll_t*)win_get_magic(magic_ki_kontroll_t);
931 	if (playerwin) {
932 		playerwin->update_data();
933 	}
934 }
935 
936 
nwc_tool_t()937 nwc_tool_t::nwc_tool_t() : network_broadcast_world_command_t(NWC_TOOL, 0, 0),
938 	custom_data(custom_data_buf, lengthof(custom_data_buf), true)
939 {
940 	tool = NULL;
941 }
942 
943 
nwc_tool_t(player_t * player,tool_t * tool_,koord3d pos_,uint32 sync_steps,uint32 map_counter,bool init_)944 nwc_tool_t::nwc_tool_t(player_t *player, tool_t *tool_, koord3d pos_, uint32 sync_steps, uint32 map_counter, bool init_)
945 	: network_broadcast_world_command_t(NWC_TOOL, sync_steps, map_counter),
946 	custom_data(custom_data_buf, lengthof(custom_data_buf), true)
947 {
948 	pos = pos_;
949 	player_nr = player ? player->get_player_nr() : -1;
950 	tool_id = tool_->get_id();
951 	wt = tool_->get_waytype();
952 	default_param = tool_->get_default_param(player);
953 	init = init_;
954 	tool_client_id = 0;
955 	flags = tool_->flags;
956 
957 	karte_ptr_t welt;
958 	last_sync_step = welt->get_last_checklist_sync_step();
959 	last_checklist = welt->get_last_checklist();
960 
961 	callback_id = tool_->callback_id;
962 	// write custom data of tool_ to our internal buffer
963 	if (player) {
964 		tool_->rdwr_custom_data(&custom_data);
965 	}
966 	tool = NULL;
967 }
968 
969 
nwc_tool_t(const nwc_tool_t & nwt)970 nwc_tool_t::nwc_tool_t(const nwc_tool_t &nwt)
971 	: network_broadcast_world_command_t(NWC_TOOL, nwt.get_sync_step(), nwt.get_map_counter()),
972 	custom_data(custom_data_buf, lengthof(custom_data_buf), true)
973 {
974 	pos = nwt.pos;
975 	player_nr = nwt.player_nr;
976 	tool_id = nwt.tool_id;
977 	wt = nwt.wt;
978 	default_param = nwt.default_param;
979 	init = nwt.init;
980 	tool_client_id = nwt.our_client_id;
981 	flags = nwt.flags;
982 	callback_id = nwt.callback_id;
983 	// copy custom data of tool to our internal buffer
984 	custom_data.append(nwt.custom_data);
985 	tool = NULL;
986 }
987 
988 
~nwc_tool_t()989 nwc_tool_t::~nwc_tool_t()
990 {
991 	delete tool;
992 }
993 
994 
rdwr()995 void nwc_tool_t::rdwr()
996 {
997 	network_broadcast_world_command_t::rdwr();
998 	packet->rdwr_long(last_sync_step);
999 	last_checklist.rdwr(packet);
1000 	packet->rdwr_byte(player_nr);
1001 	sint16 posx = pos.x; packet->rdwr_short(posx); pos.x = posx;
1002 	sint16 posy = pos.y; packet->rdwr_short(posy); pos.y = posy;
1003 	sint8  posz = pos.z; packet->rdwr_byte(posz);  pos.z = posz;
1004 	packet->rdwr_short(tool_id);
1005 	packet->rdwr_short(wt);
1006 	packet->rdwr_str(default_param);
1007 	packet->rdwr_bool(init);
1008 	packet->rdwr_long(tool_client_id);
1009 	packet->rdwr_byte(flags);
1010 	packet->rdwr_long(callback_id);
1011 	// copy custom data of tool to/from packet
1012 	if (packet->is_saving()) {
1013 		// write to packet
1014 		packet->append(custom_data);
1015 	}
1016 	else {
1017 		// read from packet
1018 		custom_data.append_tail(*packet);
1019 	}
1020 
1021 	//if (packet->is_loading()) {
1022 		dbg->warning("nwc_tool_t::rdwr", "rdwr id=%d client=%d plnr=%d pos=%s tool_id=%d defpar=%s init=%d flags=%d", id, tool_client_id, player_nr, pos.get_str(), tool_id, (char const*)default_param, init, flags);
1023 	//}
1024 }
1025 
1026 
init_tool()1027 void nwc_tool_t::init_tool()
1028 {
1029 	delete tool;
1030 	// create new memory_rw_t that is in reading mode to read tool data
1031 	memory_rw_t new_custom_data(custom_data_buf, custom_data.get_current_index(), false);
1032 
1033 	if ( (tool = create_tool(tool_id)) ) {
1034 		tool->set_default_param(default_param);
1035 		tool->rdwr_custom_data(&new_custom_data);
1036 	}
1037 }
1038 
1039 
clone(karte_t * welt)1040 network_broadcast_world_command_t* nwc_tool_t::clone(karte_t *welt)
1041 {
1042 	init_tool();
1043 	if (tool == NULL) {
1044 		// invalid id
1045 		return NULL;
1046 	}
1047 
1048 	// do not open dialog windows across network
1049 	if (  init  ?  tool->is_init_network_save() :  tool->is_work_network_save() ){
1050 		// no reason to send request over network
1051 		return NULL;
1052 	}
1053 
1054 	// scenario scripts only run on server
1055 	if (socket_list_t::get_client_id(packet->get_sender()) != 0) {
1056 		// not sent by server, clear flag
1057 		flags &= ~tool_t::WFL_NO_CHK;
1058 	}
1059 	// scripted calls do not need authentication check
1060 	bool const needs_check = (flags & tool_t::WFL_NO_CHK) == 0;
1061 
1062 	// check authentication and scenario rules
1063 	if (needs_check) {
1064 
1065 		scenario_t *scen = welt->get_scenario();
1066 		// check for map editor tools - they need unlocked public player
1067 		// scenario should check itself
1068 		if (!scen->is_scripted()) {
1069 			switch( tool_id ) {
1070 				case TOOL_CHANGE_CITY_SIZE | GENERAL_TOOL:
1071 				case TOOL_BUILD_HOUSE | GENERAL_TOOL:
1072 				case TOOL_BUILD_LAND_CHAIN | GENERAL_TOOL:
1073 				case TOOL_CITY_CHAIN | GENERAL_TOOL:
1074 				case TOOL_BUILD_FACTORY | GENERAL_TOOL:
1075 				case TOOL_LINK_FACTORY | GENERAL_TOOL:
1076 				case TOOL_ADD_CITYCAR | GENERAL_TOOL:
1077 				case TOOL_INCREASE_INDUSTRY | SIMPLE_TOOL:
1078 				case TOOL_STEP_YEAR | SIMPLE_TOOL:
1079 				case TOOL_FILL_TREES | SIMPLE_TOOL:
1080 					player_nr = 1;
1081 				default: ;
1082 			}
1083 		}
1084 
1085 		// check whether player is authorized do this
1086 		socket_info_t const& info = socket_list_t::get_client(our_client_id);
1087 		if ( player_nr < PLAYER_UNOWNED  &&  !info.is_player_unlocked(player_nr) ) {
1088 			if (tool_id == (TOOL_ADD_MESSAGE|SIMPLE_TOOL)) {
1089 				player_nr = PLAYER_UNOWNED;
1090 			}
1091 			else {
1092 				dbg->warning("nwc_tool_t::clone", "client %d not allowed to act as player %d", our_client_id, player_nr);
1093 				return NULL; // indicate failure
1094 			}
1095 		}
1096 		// log that this client acted as this player
1097 		if ( player_nr < PLAYER_UNOWNED) {
1098 			nwc_chg_player_t::company_active_clients[player_nr].append_unique( connection_info_t(info) );
1099 		}
1100 
1101 		// do scenario checks here, send error message back
1102 		if ( scen->is_scripted() ) {
1103 			if (!scen->is_tool_allowed(welt->get_player(player_nr), tool_id, wt)) {
1104 				dbg->warning("nwc_tool_t::clone", "tool_id=%d  wt=%d tool not allowed", tool_id, wt);
1105 				// TODO return error message ?
1106 				return NULL;
1107 			}
1108 			if (!init) {
1109 				const char *err = scen->is_work_allowed_here(welt->get_player(player_nr), tool_id, wt, pos);
1110 				if (err == NULL) {
1111 					if (two_click_tool_t *two_ctool = dynamic_cast<two_click_tool_t*>(tool)) {
1112 						if (!two_ctool->is_first_click()) {
1113 							err = scen->is_work_allowed_here(welt->get_player(player_nr), tool_id, wt, two_ctool->get_start_pos());
1114 						}
1115 					}
1116 				}
1117 				if (err) {
1118 					nwc_tool_t *nwt = new nwc_tool_t(*this);
1119 					nwt->tool_id = TOOL_ERROR_MESSAGE | GENERAL_TOOL;
1120 					nwt->default_param = err;
1121 					nwt->last_sync_step = welt->get_last_checklist_sync_step();
1122 					nwt->last_checklist = welt->get_last_checklist();
1123 					dbg->warning("nwc_tool_t::clone", "send sync_steps=%d  tool_id=%d  error=%s", nwt->get_sync_step(), tool_id, err);
1124 					return nwt;
1125 				}
1126 			}
1127 		}
1128 	}
1129 
1130 	// copy data, sets tool_client_id to sender client_id
1131 	nwc_tool_t *nwt = new nwc_tool_t(*this);
1132 	nwt->last_sync_step = welt->get_last_checklist_sync_step();
1133 	nwt->last_checklist = welt->get_last_checklist();
1134 	dbg->warning("nwc_tool_t::clone", "send sync_steps=%d  tool_id=%d %s", nwt->get_sync_step(), tool_id, init ? "init" : "work");
1135 	return nwt;
1136 }
1137 
1138 
ignore_old_events() const1139 bool nwc_tool_t::ignore_old_events() const
1140 {
1141 	// messages are allowed to arrive at any time (return true if message)
1142 	return tool_id==(SIMPLE_TOOL|TOOL_ADD_MESSAGE);
1143 }
1144 
1145 
do_command(karte_t * welt)1146 void nwc_tool_t::do_command(karte_t *welt)
1147 {
1148 	if (tool == NULL) {
1149 		init_tool();
1150 	}
1151 	DBG_MESSAGE("nwc_tool_t::do_command", "steps %d tool_id %d %s", get_sync_step(), tool_id, init ? "init" : "work");
1152 
1153 	// commands are treated differently if they come from this client or not
1154 	bool local = tool_client_id == network_get_client_id();
1155 
1156 	player_t *player = player_nr < PLAYER_UNOWNED ? welt->get_player(player_nr) : NULL;
1157 
1158 	// before calling work initialize new tool
1159 	assert(tool);
1160 	bool init_successfull = true;
1161 	if (!init) {
1162 		// init command was not sent if tool->is_init_network_safe() returned true
1163 		tool->flags = 0;
1164 		// init tool
1165 		init_successfull = tool->init(player);
1166 	}
1167 
1168 	// read custom data (again, necessary for two_click_tool_t)
1169 	{
1170 		memory_rw_t new_custom_data(custom_data_buf, custom_data.get_current_index(), false);
1171 		tool->rdwr_custom_data(&new_custom_data);
1172 	}
1173 	// set flags correctly
1174 	if (local) {
1175 		tool->flags = flags | tool_t::WFL_LOCAL;
1176 	}
1177 	else {
1178 		tool->flags = flags & ~tool_t::WFL_LOCAL;
1179 	}
1180 	DBG_MESSAGE("nwc_tool_t::do_command","id=%d init=%d defpar=%s flag=%d",tool_id&0xFFF,init,(const char*)default_param,tool->flags);
1181 
1182 	const char* err = NULL;
1183 	bool res = false;
1184 	// call INIT
1185 	if(  init  ) {
1186 		// we should be here only if tool->init() returns false
1187 		// no need to change active tool of world
1188 		res = tool->init(player);
1189 	}
1190 	// call WORK
1191 	else if (init_successfull) {
1192 		// remove preview tiles of active tool
1193 		two_click_tool_t *active_tool = dynamic_cast<two_click_tool_t*>(welt->get_tool(welt->get_active_player_nr()));
1194 		if(active_tool  &&  active_tool->remove_preview_necessary()) {
1195 			active_tool->cleanup();
1196 		}
1197 		err = tool->work( player, pos );
1198 		// only local players get the callback
1199 		if (local  &&  callback_id == 0) {
1200 			player->tell_tool_result(tool, pos, err);
1201 		}
1202 		if (err) {
1203 			dbg->warning("nwc_tool_t::do_command","failed with '%s'",err);
1204 		}
1205 		tool->exit(player);
1206 	}
1207 	else {
1208 		err = "Init was not succesfull, returned false.";
1209 	}
1210 
1211 	// callback to script here
1212 	if (local  &&  callback_id != 0) {
1213 		if (init) {
1214 			suspended_scripts_t::tell_return_value(callback_id, res);
1215 		}
1216 		else {
1217 			suspended_scripts_t::tell_return_value(callback_id, err);
1218 		}
1219 	}
1220 }
1221 
1222 
1223 extern address_list_t blacklist;
1224 
execute(karte_t * welt)1225 bool nwc_service_t::execute(karte_t *welt)
1226 {
1227 	if (flag>=SRVC_MAX  ||  !env_t::server) {
1228 		// wrong flag, no server
1229 		return true;  // to delete
1230 	}
1231 	// check whether admin connection is established
1232 	const uint32 sender_id = socket_list_t::get_client_id(packet->get_sender());
1233 	const bool admin_logged_in = socket_list_t::get_client(sender_id).state == socket_info_t::admin;
1234 	if (!admin_logged_in  &&  (flag != SRVC_LOGIN_ADMIN  &&  flag != SRVC_ANNOUNCE_SERVER) ) {
1235 		return true;  // to delete
1236 	}
1237 
1238 	switch(flag) {
1239 		case SRVC_LOGIN_ADMIN: {
1240 			nwc_service_t nws;
1241 			nws.flag = SRVC_LOGIN_ADMIN;
1242 			// check password
1243 			bool ok = !env_t::server_admin_pw.empty()  &&  env_t::server_admin_pw.compare(text)==0;
1244 			if (ok) {
1245 				socket_list_t::get_client(sender_id).state = socket_info_t::admin;
1246 			}
1247 			nws.number = ok ? sender_id : 0;
1248 			nws.send(packet->get_sender());
1249 			break;
1250 		}
1251 
1252 		case SRVC_ANNOUNCE_SERVER:
1253 			// Startup announce, to force full details resend
1254 			welt->announce_server( 0 );
1255 			break;
1256 
1257 		case SRVC_GET_CLIENT_LIST: {
1258 			nwc_service_t nws;
1259 			nws.flag = SRVC_GET_CLIENT_LIST;
1260 			// send, socket list will be written in rdwr
1261 			nws.send(packet->get_sender());
1262 			break;
1263 		}
1264 
1265 		case SRVC_KICK_CLIENT:
1266 		case SRVC_BAN_CLIENT: {
1267 			bool ban = flag == SRVC_BAN_CLIENT;
1268 			uint32 client_id = number;
1269 			net_address_t address;
1270 			SOCKET kick = socket_list_t::get_socket(client_id);
1271 			if (kick!=INVALID_SOCKET) {
1272 				socket_info_t &info = socket_list_t::get_client(client_id);
1273 				address.ip = info.address.ip;
1274 				if (info.state == socket_info_t::playing) {
1275 					socket_list_t::remove_client(info.socket);
1276 				}
1277 			}
1278 			if (ban  &&  address.ip) {
1279 				fd_set fd;
1280 				FD_ZERO(&fd);
1281 				socket_list_t::fill_set(&fd);
1282 				socket_list_t::client_socket_iterator_t iter(&fd);
1283 				while(iter.next()) {
1284 					SOCKET sock = iter.get_current();
1285 					socket_info_t& info = socket_list_t::get_client(socket_list_t::get_client_id(sock));
1286 					if (address.matches(info.address)) {
1287 						socket_list_t::remove_client(sock);
1288 					}
1289 				}
1290 				blacklist.append(address);
1291 			}
1292 			break;
1293 		}
1294 		case SRVC_GET_BLACK_LIST: {
1295 			nwc_service_t nws;
1296 			nws.flag = SRVC_GET_BLACK_LIST;
1297 			// send, blacklist will be written in rdwr
1298 			nws.send(packet->get_sender());
1299 			break;
1300 		}
1301 
1302 		case SRVC_BAN_IP:
1303 		case SRVC_UNBAN_IP: {
1304 			net_address_t address(text);
1305 			if (address.ip) {
1306 				if (flag==SRVC_BAN_IP) {
1307 					blacklist.append(address);
1308 				}
1309 				else {
1310 					blacklist.remove(address);
1311 				}
1312 			}
1313 			break;
1314 		}
1315 
1316 		case SRVC_ADMIN_MSG:
1317 			if (text) {
1318 				// Send message to all clients as Public Service
1319 				// with reserved username Admin
1320 				nwc_chat_t* nwchat = new nwc_chat_t( text, 1, "Admin" );
1321 				network_send_all( nwchat, false );
1322 
1323 				// Log chat message - please don't change order of fields
1324 				CSV_t csv;
1325 				csv.add_field( "adminmsg" );
1326 				csv.add_field( text );
1327 				dbg->warning( "__ChatLog__", "%s", csv.get_str() );
1328 			}
1329 			break;
1330 
1331 		case SRVC_SHUTDOWN: {
1332 			welt->stop( true );
1333 			break;
1334 		}
1335 
1336 		case SRVC_FORCE_SYNC: {
1337 			const uint32 new_map_counter = welt->generate_new_map_counter();
1338 			nwc_sync_t *nw_sync = new nwc_sync_t(welt->get_sync_steps() + 1, welt->get_map_counter(), -1, new_map_counter);
1339 
1340 			if (welt->is_paused()) {
1341 				if (socket_list_t::get_playing_clients() == 0) {
1342 					// we can save directly without disturbing clients
1343 					nw_sync->do_command(welt);
1344 				}
1345 				delete nw_sync;
1346 			}
1347 			else {
1348 				// send sync command
1349 				network_send_all(nw_sync, false);
1350 			}
1351 			break;
1352 		}
1353 
1354 		case SRVC_GET_COMPANY_LIST:
1355 		case SRVC_GET_COMPANY_INFO: {
1356 			bool detailed = flag == SRVC_GET_COMPANY_INFO  &&  number < PLAYER_UNOWNED;
1357 			uint8 min_index = detailed ? number   : 0;
1358 			uint8 max_index = detailed ? number+1 : PLAYER_UNOWNED;
1359 
1360 			cbuffer_t buf;
1361 			for (uint8 i=min_index; i<max_index; i++) {
1362 				if (player_t *player = welt->get_player(i)) {
1363 					buf.printf("Company #%d: %s\n", i, player->get_name());
1364 					buf.printf("    Password: %sset\n", player->access_password_hash().empty() ? "NOT " :"");
1365 					// print creator information
1366 					if (i < lengthof(nwc_chg_player_t::company_creator)) {
1367 						if (connection_info_t const* creator = nwc_chg_player_t::company_creator[i]) {
1368 							buf.printf("    founded by %s at %s\n", creator->nickname.c_str(), creator->address.get_str());
1369 						}
1370 					}
1371 					// print clients who have this player unlocked
1372 					for(uint32 j = 0; j < socket_list_t::get_count(); j++) {
1373 						socket_info_t const& info = socket_list_t::get_client(j);
1374 						if (info.is_active()  &&  info.is_player_unlocked(i)) {
1375 							buf.printf("    unlocked for [%d] %s at %s\n", j, info.nickname.c_str(), info.address.get_str());
1376 						}
1377 					}
1378 					// print clients who played for this company
1379 					uint32 j=0;
1380 					FOR(slist_tpl<connection_info_t>, &iter, nwc_chg_player_t::company_active_clients[i]) {
1381 						if (!detailed  &&  j > 3  &&  nwc_chg_player_t::company_active_clients[i].get_count() > 5) {
1382 							buf.printf("    .. and %d more.\n", nwc_chg_player_t::company_active_clients[i].get_count()-j);
1383 							break;
1384 						}
1385 						buf.printf("    played by %s at %s\n", iter.nickname.c_str(), iter.address.get_str());
1386 						j++;
1387 					}
1388 				}
1389 			}
1390 
1391 			nwc_service_t nws;
1392 			nws.flag = flag;
1393 			nws.text = strdup(buf);
1394 			if (text  &&  (strlen(text) > MAX_PACKET_LEN - 256)) {
1395 				text[MAX_PACKET_LEN - 256] = 0;
1396 			}
1397 			nws.send(packet->get_sender());
1398 			break;
1399 		}
1400 
1401 		case SRVC_UNLOCK_COMPANY: {
1402 			if (number >= PLAYER_UNOWNED) {
1403 				break; // invalid number
1404 			}
1405 			uint8 player_nr = number;
1406 			// empty password
1407 			player_t *player = welt->get_player(player_nr);
1408 			if (player) {
1409 				player->access_password_hash().clear();
1410 				// unlock all clients
1411 				socket_list_t::unlock_player_all(player_nr, true, packet->get_sender());
1412 				// unlock player on the server
1413 				player->unlock(true, false);
1414 			}
1415 			break;
1416 		}
1417 
1418 		case SRVC_REMOVE_COMPANY: {
1419 			if (number >= PLAYER_UNOWNED) {
1420 				break; // invalid number
1421 			}
1422 
1423 			nwc_chg_player_t *nwc = new nwc_chg_player_t(welt->get_sync_steps(), welt->get_map_counter(), karte_t::delete_player, number);
1424 			if (nwc->execute(welt)) {
1425 				delete nwc;
1426 			}
1427 			break;
1428 		}
1429 
1430 		default: ;
1431 	}
1432 	return true; // to delete
1433 }
1434