1 /*
2 Copyright (C) 1996-1997 Id Software, Inc.
3 
4 This program is free software; you can redistribute it and/or
5 modify it under the terms of the GNU General Public License
6 as published by the Free Software Foundation; either version 2
7 of the License, or (at your option) any later version.
8 
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12 
13 See the GNU General Public License for more details.
14 
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
18 
19 
20 */
21 
22 #ifndef CLIENTONLY
23 #include "qwsvdef.h"
24 
25 #ifdef SERVERONLY
26 
27 qbool       host_initialized;
28 qbool       host_everything_loaded;	// true if OnChange() applied to every var, end of Host_Init()
29 
30 double      curtime;			// not bounded or scaled, shared by local client and server.
31 double      realtime;			// affected by pause, you should not use it unless it something like physics and such.
32 
33 static int  host_hunklevel;
34 
35 #else
36 
37 qbool       server_cfg_done = false;
38 double      realtime;			// affected by pause, you should not use it unless it something like physics and such.
39 
40 #endif
41 
42 int		current_skill;			// for entity spawnflags checking
43 
44 client_t	*sv_client;			// current client
45 
46 char		master_rcon_password[128] = "";	//bliP: password for remote server commands
47 
48 cvar_t	sv_mintic = {"sv_mintic","0.013"};	// bound the size of the
49 cvar_t	sv_maxtic = {"sv_maxtic","0.1"};	// physics time tic
50 cvar_t	sv_maxfps = {"maxfps", "77", CVAR_SERVERINFO};  // It actually should be called maxpps (max packets per second).
51 														// It was serverinfo variable for quite long time, lets legolize it as cvar.
52 														// Sad part is what we can't call it like sv_maxfps since clients relay on its name 'maxfps' already.
53 
54 void OnChange_sysselecttimeout_var (cvar_t *var, char *value, qbool *cancel);
55 cvar_t	sys_select_timeout = {"sys_select_timeout", "10000", 0, OnChange_sysselecttimeout_var}; // microseconds.
56 
57 cvar_t	sys_restart_on_error = {"sys_restart_on_error", "0"};
58 cvar_t  sv_mod_extensions = { "sv_mod_extensions", "2", CVAR_ROM };
59 
60 #ifdef SERVERONLY
61 cvar_t  sys_simulation = { "sys_simulation", "0" };
62 cvar_t	developer = {"developer", "0"};		// show extra messages
63 cvar_t	version = {"version", "", CVAR_ROM};
64 #endif
65 
66 cvar_t	timeout = {"timeout", "65"};		// seconds without any message
67 cvar_t	zombietime = {"zombietime", "2"};	// seconds to sink messages
68 // after disconnect
69 
70 #ifdef SERVERONLY
71 cvar_t	rcon_password = {"rcon_password", ""};	// password for remote server commands
72 cvar_t	password = {"password", ""};	// password for entering the game
73 #else
74 // client already have such variables.
75 extern cvar_t rcon_password;
76 extern cvar_t password;
77 #endif
78 
79 cvar_t	sv_hashpasswords = {"sv_hashpasswords", "1"}; // 0 - plain passwords; 1 - hashed passwords
80 cvar_t	sv_crypt_rcon = {"sv_crypt_rcon", "1"}; // use SHA1 for encryption of rcon_password and using timestamps
81 // Time in seconds during which in rcon command this encryption is valid (change only with master_rcon_password).
82 cvar_t	sv_timestamplen = {"sv_timestamplen", "60"};
83 cvar_t	sv_rconlim = {"sv_rconlim", "10"};	// rcon bandwith limit: requests per second
84 
85 //bliP: telnet log level
86 void OnChange_telnetloglevel_var (cvar_t *var, char *string, qbool *cancel);
87 cvar_t  telnet_log_level = {"telnet_log_level", "0", 0, OnChange_telnetloglevel_var};
88 //<-
89 
90 cvar_t	frag_log_type = {"frag_log_type", "0"};
91 //	frag log type:
92 //		0 - old style (  qwsv - v0.165)
93 //		1 - new style (v0.168 - v0.172)
94 
95 void OnChange_qconsolelogsay_var (cvar_t *var, char *string, qbool *cancel);
96 cvar_t	qconsole_log_say = {"qconsole_log_say", "0", 0, OnChange_qconsolelogsay_var};
97 // logging "say" and "say_team" messages to the qconsole_PORT.log file
98 
99 cvar_t	sys_command_line = {"sys_command_line", "", CVAR_ROM};
100 
101 cvar_t	sv_use_dns = {"sv_use_dns", "0"}; // 1 - use DNS lookup in status command, 0 - don't use
102 cvar_t	spectator_password = {"spectator_password", ""};	// password for entering as a sepctator
103 cvar_t	vip_password = {"vip_password", ""};	// password for entering as a VIP sepctator
104 cvar_t	vip_values = {"vip_values", ""};
105 
106 cvar_t	allow_download = {"allow_download", "1"};
107 cvar_t	allow_download_skins = {"allow_download_skins", "1"};
108 cvar_t	allow_download_models = {"allow_download_models", "1"};
109 cvar_t	allow_download_sounds = {"allow_download_sounds", "1"};
110 cvar_t	allow_download_maps	= {"allow_download_maps", "1"};
111 cvar_t	allow_download_pakmaps = {"allow_download_pakmaps", "1"};
112 cvar_t	allow_download_demos = {"allow_download_demos", "1"};
113 cvar_t	allow_download_other = {"allow_download_other", "0"};
114 //bliP: init ->
115 cvar_t	download_map_url = {"download_map_url", ""};
116 
117 cvar_t	sv_specprint = {"sv_specprint", "0"};
118 cvar_t	sv_reconnectlimit = {"sv_reconnectlimit", "0"};
119 
120 void OnChange_admininfo_var (cvar_t *var, char *string, qbool *cancel);
121 cvar_t  sv_admininfo = {"sv_admininfo", "", 0, OnChange_admininfo_var};
122 
123 cvar_t	sv_unfake = {"sv_unfake", "1"}; //bliP: 24/9 kickfake to unfake
124 cvar_t	sv_kicktop = {"sv_kicktop", "1"};
125 
126 cvar_t	sv_allowlastscores = {"sv_allowlastscores", "1"};
127 
128 cvar_t	sv_maxlogsize = {"sv_maxlogsize", "0"};
129 //bliP: 24/9 ->
130 void OnChange_logdir_var (cvar_t *var, char *string, qbool *cancel);
131 cvar_t  sv_logdir = {"sv_logdir", ".", 0, OnChange_logdir_var};
132 
133 cvar_t  sv_speedcheck = {"sv_speedcheck", "1"};
134 //<-
135 //<-
136 //cvar_t	sv_highchars = {"sv_highchars", "1"};
137 cvar_t	sv_phs = {"sv_phs", "1"};
138 cvar_t	pausable = {"pausable", "0"};
139 cvar_t	sv_maxrate = {"sv_maxrate", "0"};
140 cvar_t	sv_getrealip = {"sv_getrealip", "1"};
141 cvar_t	sv_serverip = {"sv_serverip", ""};
142 cvar_t	sv_forcespec_onfull = {"sv_forcespec_onfull", "2"};
143 cvar_t	sv_maxdownloadrate = {"sv_maxdownloadrate", "0"};
144 
145 cvar_t  sv_loadentfiles = {"sv_loadentfiles", "1"}; //loads .ent files by default if there
146 cvar_t  sv_loadentfiles_dir = {"sv_loadentfiles_dir", ""}; // check for .ent file in maps/sv_loadentfiles_dir first then just maps/
147 cvar_t	sv_default_name = {"sv_default_name", "unnamed"};
148 
149 void sv_mod_msg_file_OnChange(cvar_t *cvar, char *value, qbool *cancel);
150 cvar_t	sv_mod_msg_file = {"sv_mod_msg_file", "", CVAR_NONE, sv_mod_msg_file_OnChange};
151 
152 cvar_t  sv_reliable_sound = {"sv_reliable_sound", "0"};
153 
154 //
155 // game rules mirrored in svs.info
156 //
157 cvar_t	fraglimit = {"fraglimit","0",CVAR_SERVERINFO};
158 cvar_t	timelimit = {"timelimit","0",CVAR_SERVERINFO};
159 cvar_t	teamplay = {"teamplay","0",CVAR_SERVERINFO};
160 cvar_t	maxclients = {"maxclients","24",CVAR_SERVERINFO};
161 cvar_t	maxspectators = {"maxspectators","8",CVAR_SERVERINFO};
162 cvar_t	maxvip_spectators = {"maxvip_spectators","0"/*,CVAR_SERVERINFO*/};
163 cvar_t	deathmatch = {"deathmatch","3",CVAR_SERVERINFO};
164 cvar_t	watervis = {"watervis","0",CVAR_SERVERINFO};
165 cvar_t	serverdemo = {"serverdemo","",CVAR_SERVERINFO | CVAR_ROM};
166 
167 cvar_t	samelevel = {"samelevel","1"}; // dont delete this variable - it used by mods
168 cvar_t	skill = {"skill", "1"}; // dont delete this variable - it used by mods
169 cvar_t	coop = {"coop", "0"}; // dont delete this variable - it used by mods
170 
171 cvar_t	sv_paused = {"sv_paused", "0", CVAR_ROM};
172 
173 cvar_t	hostname = {"hostname", "unnamed", CVAR_SERVERINFO};
174 
175 cvar_t sv_forcenick = {"sv_forcenick", "0"}; //0 - don't force; 1 - as login;
176 cvar_t sv_registrationinfo = {"sv_registrationinfo", ""}; // text shown before "enter login"
177 
178 // We need this cvar, because some mods didn't allow us to go at some placeses of, for example, start map.
179 cvar_t registered = {"registered", "1", CVAR_ROM};
180 
181 cvar_t	sv_halflifebsp = {"halflifebsp", "0", CVAR_ROM};
182 cvar_t  sv_bspversion = {"sv_bspversion", "1", CVAR_ROM};
183 
184 // If set, don't send broadcast messages, entities or player info to ServeMe bot
185 cvar_t sv_serveme_fix = { "sv_serveme_fix", "1", CVAR_ROM };
186 
187 #ifdef FTE_PEXT_FLOATCOORDS
188 cvar_t sv_bigcoords = {"sv_bigcoords", "", CVAR_SERVERINFO};
189 #endif
190 #ifdef MVD_PEXT1_SERVERSIDEWEAPON
191 // Only enabled on KTX mod (see sv_init)
192 cvar_t sv_pext_mvdsv_serversideweapon = { "sv_pext_mvdsv_serversideweapon", "1" };
193 #endif
194 
195 cvar_t sv_extlimits = { "sv_extlimits", "2" };
196 
197 qbool sv_error = false;
198 
199 client_t *WatcherId = NULL; // QW262
200 
201 //============================================================================
202 
GameStarted(void)203 qbool GameStarted(void)
204 {
205 	mvddest_t *d;
206 
207 	for (d = demo.dest; d; d = d->nextdest)
208 		if (d->desttype != DEST_STREAM) // oh, its not stream, treat as "game is started"
209 			break;
210 
211 	return (d || strncasecmp(Info_ValueForKey(svs.info, "status"), "Standby", 8));
212 }
213 /*
214 ================
215 SV_Shutdown
216 
217 Quake calls this before calling Sys_Quit or Sys_Error
218 ================
219 */
SV_Shutdown(char * finalmsg)220 void SV_Shutdown (char *finalmsg)
221 {
222 	int i;
223 
224 	if (!sv.state)
225 		return; // already shutdown. FIXME: what about error during SV_SpawnServer() ?
226 
227 	SV_FinalMessage(finalmsg);
228 
229 	Master_Shutdown ();
230 
231 	for (i = MIN_LOG; i < MAX_LOG; ++i)
232 	{
233 		if (logs[i].sv_logfile)
234 		{
235 			fclose (logs[i].sv_logfile);
236 			logs[i].sv_logfile = NULL;
237 		}
238 	}
239 	if (sv.mvdrecording)
240 		SV_MVDStop_f();
241 
242 #ifndef SERVER_ONLY
243 	NET_CloseServer ();
244 #endif
245 
246 #if defined(SERVERONLY) && defined(WWW_INTEGRATION)
247 	Central_Shutdown();
248 #endif
249 
250 	// Shutdown game.
251 	PR_GameShutDown();
252 	PR_UnLoadProgs();
253 
254 	memset (&sv, 0, sizeof(sv));
255 	sv.state = ss_dead;
256 #ifndef SERVERONLY
257 	com_serveractive = false;
258 	{
259 		extern  ctxinfo_t _localinfo_;
260 
261 		Info_RemoveAll(&_localinfo_);
262 		for (i = 0; i < MAX_CLIENTS; ++i) {
263 			Info_RemoveAll(&svs.clients[i]._userinfo_ctx_);
264 			Info_RemoveAll(&svs.clients[i]._userinfoshort_ctx_);
265 		}
266 	}
267 #endif
268 
269 	memset (svs.clients, 0, sizeof(svs.clients));
270 	svs.lastuserid = 0;
271 	svs.serverflags = 0;
272 }
273 
274 /*
275 ================
276 SV_Error
277 
278 Sends a datagram to all the clients informing them of the server crash,
279 then exits
280 ================
281 */
SV_Error(char * error,...)282 void SV_Error (char *error, ...)
283 {
284 	static qbool inerror = false;
285 	static char string[1024];
286 	va_list argptr;
287 
288 	sv_error = true;
289 
290 	if (inerror)
291 		Sys_Error ("SV_Error: recursively entered (%s)", string);
292 
293 	inerror = true;
294 
295 	va_start (argptr, error);
296 	vsnprintf (string, sizeof (string), error, argptr);
297 	va_end (argptr);
298 
299 	SV_Shutdown (va ("SV_Error: %s\n", string));
300 
301 	Sys_Error ("SV_Error: %s", string);
302 }
303 
SV_FreeHeadDelayedPacket(client_t * cl)304 static void SV_FreeHeadDelayedPacket(client_t *cl) {
305 	if (cl->packets) {
306 		packet_t *next = cl->packets->next;
307 		cl->packets->next = svs.free_packets;
308 		svs.free_packets = cl->packets;
309 		cl->packets = next;
310 	}
311 }
312 
313 
SV_FreeDelayedPackets(client_t * cl)314 void SV_FreeDelayedPackets (client_t *cl) {
315 	while (cl->packets)
316 		SV_FreeHeadDelayedPacket(cl);
317 }
318 
319 /*
320 ==================
321 SV_FinalMessage
322 
323 Used by SV_Error and SV_Quit_f to send a final message to all connected
324 clients before the server goes down.  The messages are sent immediately,
325 not just stuck on the outgoing message list, because the server is going
326 to totally exit after returning from this function.
327 ==================
328 */
SV_FinalMessage(const char * message)329 void SV_FinalMessage (const char *message)
330 {
331 	client_t *cl;
332 	int i;
333 
334 	SZ_Clear (&net_message);
335 	MSG_WriteByte (&net_message, svc_print);
336 	MSG_WriteByte (&net_message, PRINT_HIGH);
337 	MSG_WriteString (&net_message, message);
338 	MSG_WriteByte (&net_message, svc_disconnect);
339 
340 	for (i=0, cl = svs.clients ; i<MAX_CLIENTS ; i++, cl++)
341 		if (cl->state >= cs_spawned
342 #ifdef USE_PR2
343 			&& !cl->isBot
344 #endif
345 		) {
346 			Netchan_Transmit(&cl->netchan, net_message.cursize
347 				, net_message.data);
348 		}
349 }
350 
351 
352 
353 /*
354 =====================
355 SV_DropClient
356 
357 Called when the player is totally leaving the server, either willingly
358 or unwillingly.  This is NOT called if the entire server is quiting
359 or crashing.
360 =====================
361 */
SV_DropClient(client_t * drop)362 void SV_DropClient(client_t* drop)
363 {
364 	//bliP: cuff, mute ->
365 	SV_SavePenaltyFilter (drop, ft_mute, drop->lockedtill);
366 	SV_SavePenaltyFilter (drop, ft_cuff, drop->cuff_time);
367 	//<-
368 
369 	//bliP: player logging
370 	if (drop->name[0])
371 		SV_LogPlayer(drop, "disconnect", 1);
372 	//<-
373 
374 	// add the disconnect
375 #ifdef USE_PR2
376 	if( drop->isBot )
377 	{
378 		extern void RemoveBot(client_t *cl);
379 		RemoveBot(drop);
380 		return;
381 	}
382 #endif
383 	MSG_WriteByte (&drop->netchan.message, svc_disconnect);
384 
385 	if (drop->state == cs_spawned)
386 	{
387 		// call the prog function for removing a client
388 		// this will set the body to a dead frame, among other things
389 		pr_global_struct->self = EDICT_TO_PROG(drop->edict);
390 		PR_GameClientDisconnect(drop->spectator);
391 	}
392 
393 	if (drop->spectator)
394 		Con_Printf ("Spectator %s removed\n",drop->name);
395 	else
396 		Con_Printf ("Client %s removed\n",drop->name);
397 
398 	if (drop->download)
399 	{
400 		VFS_CLOSE(drop->download);
401 		drop->download = NULL;
402 	}
403 	if (drop->upload)
404 	{
405 		fclose (drop->upload);
406 		drop->upload = NULL;
407 	}
408 	*drop->uploadfn = 0;
409 
410 	SV_Logout(drop);
411 
412 	drop->state = cs_zombie;		    // become free in a few seconds
413 	SV_SetClientConnectionTime(drop);   // for zombie timeout
414 
415 // MD -->
416 	if (drop == WatcherId)
417 		WatcherId = NULL;
418 // <-- MD
419 
420 	drop->old_frags = 0;
421 	drop->edict->v.frags = 0.0;
422 	drop->name[0] = 0;
423 
424 	Info_RemoveAll(&drop->_userinfo_ctx_);
425 	Info_RemoveAll(&drop->_userinfoshort_ctx_);
426 
427 	// send notification to all remaining clients
428 	SV_FullClientUpdate(drop, &sv.reliable_datagram);
429 }
430 
431 
432 //====================================================================
433 
434 /*
435 ===================
436 SV_CalcPing
437 
438 ===================
439 */
SV_CalcPing(client_t * cl)440 int SV_CalcPing (client_t *cl)
441 {
442 	register client_frame_t *frame;
443 	int count, i;
444 	float ping;
445 
446 
447 	//bliP: 999 ping for connecting players
448 	if (cl->state != cs_spawned)
449 		return 999;
450 	//<-
451 
452 	ping = 0;
453 	count = 0;
454 #ifdef USE_PR2
455 	if (cl->isBot) {
456 		return 10;
457 	}
458 #endif
459 	for (frame = cl->frames, i=0 ; i<UPDATE_BACKUP ; i++, frame++)
460 	{
461 		if (frame->ping_time > 0)
462 		{
463 			ping += frame->ping_time;
464 			count++;
465 		}
466 	}
467 	if (!count)
468 		return 9999;
469 	ping /= count;
470 
471 	return ping*1000;
472 }
473 
474 /*
475 ===================
476 SV_FullClientUpdate
477 
478 Writes all update values to a sizebuf
479 ===================
480 */
SV_FullClientUpdate(client_t * client,sizebuf_t * buf)481 void SV_FullClientUpdate (client_t *client, sizebuf_t *buf)
482 {
483 	char info[MAX_EXT_INFO_STRING];
484 	int i;
485 
486 	i = client - svs.clients;
487 
488 	//Sys_Printf("SV_FullClientUpdate:  Updated frags for client %d\n", i);
489 
490 	MSG_WriteByte (buf, svc_updatefrags);
491 	MSG_WriteByte (buf, i);
492 	MSG_WriteShort (buf, client->old_frags);
493 
494 	MSG_WriteByte (buf, svc_updateping);
495 	MSG_WriteByte (buf, i);
496 	MSG_WriteShort (buf, SV_CalcPing (client));
497 
498 	MSG_WriteByte (buf, svc_updatepl);
499 	MSG_WriteByte (buf, i);
500 	MSG_WriteByte (buf, client->lossage);
501 
502 	MSG_WriteByte (buf, svc_updateentertime);
503 	MSG_WriteByte (buf, i);
504 	MSG_WriteFloat (buf, SV_ClientGameTime(client));
505 
506 	Info_ReverseConvert(&client->_userinfoshort_ctx_, info, sizeof(info));
507 	Info_RemovePrefixedKeys (info, '_');	// server passwords, etc
508 
509 	MSG_WriteByte (buf, svc_updateuserinfo);
510 	MSG_WriteByte (buf, i);
511 	MSG_WriteLong (buf, client->userid);
512 	MSG_WriteString (buf, info);
513 }
514 
515 /*
516 ===================
517 SV_FullClientUpdateToClient
518 
519 Writes all update values to a client's reliable stream
520 ===================
521 */
SV_FullClientUpdateToClient(client_t * client,client_t * cl)522 void SV_FullClientUpdateToClient (client_t *client, client_t *cl)
523 {
524 	char info[MAX_EXT_INFO_STRING];
525 
526 	Info_ReverseConvert(&client->_userinfoshort_ctx_, info, sizeof(info));
527 
528 	ClientReliableCheckBlock(cl, 24 + strlen(info));
529 	if (cl->num_backbuf)
530 	{
531 		SV_FullClientUpdate (client, &cl->backbuf);
532 		ClientReliable_FinishWrite(cl);
533 	}
534 	else
535 		SV_FullClientUpdate (client, &cl->netchan.message);
536 }
537 
538 //Returns a unique userid in [1..MAXUSERID] range
539 #define MAXUSERID 99
SV_GenerateUserID(void)540 int SV_GenerateUserID (void)
541 {
542 	client_t *cl;
543 	int i;
544 
545 
546 	do {
547 		svs.lastuserid++;
548 		if (svs.lastuserid == 1 + MAXUSERID)
549 			svs.lastuserid = 1;
550 		for (i = 0, cl = svs.clients; i < MAX_CLIENTS; i++, cl++)
551 			if (cl->state != cs_free && cl->userid == svs.lastuserid)
552 				break;
553 	} while (i != MAX_CLIENTS);
554 
555 	return svs.lastuserid;
556 }
557 
558 /*
559 ==============================================================================
560 
561 CONNECTIONLESS COMMANDS
562 
563 ==============================================================================
564 */
565 
566 /*
567 SVC_QTVStreams
568 
569 Responds with info on connected QTV users
570 */
SVC_QTVUsers(void)571 static void SVC_QTVUsers (void)
572 {
573 	SV_BeginRedirect (RD_PACKET);
574 	QTV_Streams_UserList ();
575 	SV_EndRedirect ();
576 }
577 
578 /*
579 ================
580 SVC_Status
581 
582 Responds with all the info that qplug or qspy can see
583 This message can be up to around 5k with worst case string lengths.
584 ================
585 */
586 #define STATUS_OLDSTYLE                 0
587 #define STATUS_SERVERINFO               1
588 #define STATUS_PLAYERS                  2
589 #define STATUS_SPECTATORS               4
590 #define STATUS_SPECTATORS_AS_PLAYERS    8 //for ASE - change only frags: show as "S"
591 #define STATUS_SHOWTEAMS                16
592 #define STATUS_SHOWQTV                  32
593 #define STATUS_SHOWFLAGS                64
594 
SVC_Status(void)595 static void SVC_Status (void)
596 {
597 	int top, bottom, ping, i, opt = 0;
598 	char *name, *frags;
599 	client_t *cl;
600 
601 
602 	if (Cmd_Argc() > 1)
603 		opt = Q_atoi(Cmd_Argv(1));
604 
605 	SV_BeginRedirect (RD_PACKET);
606 	if (opt == STATUS_OLDSTYLE || (opt & STATUS_SERVERINFO))
607 		Con_Printf ("%s\n", svs.info);
608 	if (opt == STATUS_OLDSTYLE || (opt & (STATUS_PLAYERS | STATUS_SPECTATORS)))
609 		for (i = 0; i < MAX_CLIENTS; i++)
610 		{
611 			cl = &svs.clients[i];
612 			if ( (cl->state >= cs_preconnected/* || cl->state == cs_spawned */) &&
613 			        ( (!cl->spectator && ((opt & STATUS_PLAYERS) || opt == STATUS_OLDSTYLE)) ||
614 			          ( cl->spectator && ( opt & STATUS_SPECTATORS)) ) )
615 			{
616 				top    = Q_atoi(Info_Get (&cl->_userinfo_ctx_, "topcolor"));
617 				bottom = Q_atoi(Info_Get (&cl->_userinfo_ctx_, "bottomcolor"));
618 				top    = (top    < 0) ? 0 : ((top    > 13) ? 13 : top);
619 				bottom = (bottom < 0) ? 0 : ((bottom > 13) ? 13 : bottom);
620 				ping   = SV_CalcPing (cl);
621 				name   = cl->name;
622 				if (cl->spectator)
623 				{
624 					if (opt & STATUS_SPECTATORS_AS_PLAYERS)
625 						frags = "S";
626 					else
627 					{
628 						ping  = -ping;
629 						frags = "-9999";
630 						name  = va("\\s\\%s", name);
631 					}
632 				}
633 				else
634 					frags = va("%i", cl->old_frags);
635 
636 				Con_Printf ("%i %s %i %i \"%s\" \"%s\" %i %i", cl->userid, frags,
637 				            (int)(SV_ClientConnectedTime(cl) / 60.0f), ping, name,
638 				            Info_Get (&cl->_userinfo_ctx_, "skin"), top, bottom);
639 
640 				if (opt & STATUS_SHOWTEAMS) {
641 					Con_Printf(" \"%s\"", cl->team);
642 				}
643 
644 				if (opt & STATUS_SHOWFLAGS) {
645 					if (cl->login_flag[0]) {
646 						Con_Printf(" \"%s\"", cl->login_flag);
647 					}
648 					else if (cl->logged_in_via_web || cl->logged > 0) {
649 						Con_Printf(" \"none\"");
650 					}
651 					else {
652 						Con_Printf(" \"\"");
653 					}
654 				}
655 
656 				Con_Printf("\n");
657 			}
658 		}
659 
660 	if (opt & STATUS_SHOWQTV)
661 		QTV_Streams_List ();
662 	SV_EndRedirect ();
663 }
664 
665 /*
666 ===================
667 SVC_LastScores
668 
669 ===================
670 */
671 void SV_LastScores_f (void);
SVC_LastScores(void)672 static void SVC_LastScores (void)
673 {
674 	if(!(int)sv_allowlastscores.value)
675 		return;
676 
677 	SV_BeginRedirect (RD_PACKET);
678 	SV_LastScores_f ();
679 	SV_EndRedirect ();
680 }
681 
682 /*
683 ===================
684 SVC_DemoList
685 SVC_DemoListRegex
686 ===================
687 */
688 void SV_DemoList_f (void);
SVC_DemoList(void)689 static void SVC_DemoList (void)
690 {
691 	SV_BeginRedirect (RD_PACKET);
692 	SV_DemoList_f ();
693 	SV_EndRedirect ();
694 }
695 void SV_DemoListRegex_f (void);
SVC_DemoListRegex(void)696 static void SVC_DemoListRegex (void)
697 {
698 	SV_BeginRedirect (RD_PACKET);
699 	SV_DemoListRegex_f ();
700 	SV_EndRedirect ();
701 }
702 
703 /*
704 ===================
705 SV_CheckLog
706 
707 ===================
708 */
709 #define	LOG_HIGHWATER	(MAX_DATAGRAM - 128)
710 #define	LOG_FLUSH		10*60
SV_CheckLog(void)711 static void SV_CheckLog (void)
712 {
713 	sizebuf_t *sz;
714 
715 	if (sv.state != ss_active)
716 		return;
717 
718 	sz = &svs.log[svs.logsequence&1];
719 
720 	// bump sequence if allmost full, or ten minutes have passed and
721 	// there is something still sitting there
722 	if (sz->cursize > LOG_HIGHWATER
723 	        || (realtime - svs.logtime > LOG_FLUSH && sz->cursize) )
724 	{
725 		// swap buffers and bump sequence
726 		svs.logtime = realtime;
727 		svs.logsequence++;
728 		sz = &svs.log[svs.logsequence&1];
729 		sz->cursize = 0;
730 		Con_DPrintf ("beginning fraglog sequence %i\n", svs.logsequence);
731 	}
732 
733 }
734 
735 /*
736 ================
737 SVC_Log
738 
739 Responds with all the logged frags for ranking programs.
740 If a sequence number is passed as a parameter and it is
741 the same as the current sequence, an A2A_NACK will be returned
742 instead of the data.
743 ================
744 */
SVC_Log(void)745 static void SVC_Log (void)
746 {
747 	char data[MAX_DATAGRAM+64];
748 	int seq;
749 
750 
751 	if (Cmd_Argc() == 2)
752 		seq = Q_atoi(Cmd_Argv(1));
753 	else
754 		seq = -1;
755 
756 	if (seq == svs.logsequence-1 || !logs[FRAG_LOG].sv_logfile)
757 	{	// they already have this data, or we aren't logging frags
758 		data[0] = A2A_NACK;
759 		NET_SendPacket (NS_SERVER, 1, data, net_from);
760 		return;
761 	}
762 
763 	Con_DPrintf ("sending log %i to %s\n", svs.logsequence-1, NET_AdrToString(net_from));
764 
765 	snprintf (data, MAX_DATAGRAM + 64, "stdlog %i\n", svs.logsequence-1);
766 	strlcat (data, (char *)svs.log_buf[((svs.logsequence-1)&1)], MAX_DATAGRAM + 64);
767 
768 	NET_SendPacket (NS_SERVER, strlen(data)+1, data, net_from);
769 }
770 
771 /*
772 ================
773 SVC_Ping
774 
775 Just responds with an acknowledgement
776 ================
777 */
SVC_Ping(void)778 static void SVC_Ping (void)
779 {
780 	char data = A2A_ACK;
781 
782 	NET_SendPacket (NS_SERVER, 1, &data, net_from);
783 }
784 
785 /*
786 =================
787 SVC_GetChallenge
788 
789 Returns a challenge number that can be used
790 in a subsequent client_connect command.
791 We do this to prevent denial of service attacks that
792 flood the server with invalid connection IPs.  With a
793 challenge, they must give a valid IP address.
794 =================
795 */
SVC_GetChallenge(void)796 static void SVC_GetChallenge (void)
797 {
798 	int oldestTime, oldest, i;
799 	char buf[256], *over;
800 
801 
802 	oldest = 0;
803 	oldestTime = 0x7fffffff;
804 
805 	// see if we already have a challenge for this ip
806 	for (i = 0 ; i < MAX_CHALLENGES ; i++)
807 	{
808 		if (NET_CompareBaseAdr (net_from, svs.challenges[i].adr))
809 			break;
810 		if (svs.challenges[i].time < oldestTime)
811 		{
812 			oldestTime = svs.challenges[i].time;
813 			oldest = i;
814 		}
815 	}
816 
817 	if (i == MAX_CHALLENGES)
818 	{
819 		// overwrite the oldest
820 		svs.challenges[oldest].challenge = (rand() << 16) ^ rand();
821 		svs.challenges[oldest].adr = net_from;
822 		svs.challenges[oldest].time = realtime;
823 		i = oldest;
824 	}
825 
826 	// send it back
827 	snprintf(buf, sizeof(buf), "%c%i", S2C_CHALLENGE, svs.challenges[i].challenge);
828 	over = buf + strlen(buf) + 1;
829 
830 #ifdef PROTOCOL_VERSION_FTE
831 	//tell the client what fte extensions we support
832 	if (svs.fteprotocolextensions)
833 	{
834 		int lng;
835 
836 		lng = LittleLong(PROTOCOL_VERSION_FTE);
837 		memcpy(over, &lng, sizeof(int));
838 		over += 4;
839 
840 		lng = LittleLong(svs.fteprotocolextensions);
841 		memcpy(over, &lng, sizeof(int));
842 		over += 4;
843 	}
844 #endif // PROTOCOL_VERSION_FTE
845 
846 #ifdef PROTOCOL_VERSION_FTE2
847 	//tell the client what fte extensions2 we support
848 	if (svs.fteprotocolextensions2)
849 	{
850 		int lng;
851 
852 		lng = LittleLong(PROTOCOL_VERSION_FTE2);
853 		memcpy(over, &lng, sizeof(int));
854 		over += 4;
855 
856 		lng = LittleLong(svs.fteprotocolextensions2);
857 		memcpy(over, &lng, sizeof(int));
858 		over += 4;
859 	}
860 #endif // PROTOCOL_VERSION_FTE2
861 
862 #ifdef PROTOCOL_VERSION_MVD1
863 	// tell the client what mvdsv extensions we support
864 	if (svs.mvdprotocolextension1) {
865 		int lng;
866 
867 		lng = LittleLong(PROTOCOL_VERSION_MVD1);
868 		memcpy(over, &lng, sizeof(int));
869 		over += 4;
870 
871 		lng = LittleLong(svs.mvdprotocolextension1);
872 		memcpy(over, &lng, sizeof(int));
873 		over += 4;
874 	}
875 #endif
876 
877 	Netchan_OutOfBand(NS_SERVER, net_from, over-buf, (byte*) buf);
878 }
879 
ValidateUserInfo(char * userinfo)880 static qbool ValidateUserInfo (char *userinfo)
881 {
882 	if (strstr(userinfo, "&c") || strstr(userinfo, "&r"))
883 		return false;
884 
885 	while (*userinfo)
886 	{
887 		if (*userinfo == '\\')
888 			userinfo++;
889 
890 		if (*userinfo++ == '\\')
891 			return false;
892 		while (*userinfo && *userinfo != '\\')
893 			userinfo++;
894 	}
895 	return true;
896 }
897 
898 //==============================================
899 
FixMaxClientsCvars(void)900 void FixMaxClientsCvars(void)
901 {
902 	if ((int)maxclients.value > MAX_CLIENTS)
903 		Cvar_SetValue (&maxclients, MAX_CLIENTS);
904 
905 	if ((int)maxspectators.value > MAX_CLIENTS)
906 		Cvar_SetValue (&maxspectators, MAX_CLIENTS);
907 
908 	if ((int)maxvip_spectators.value > MAX_CLIENTS)
909 		Cvar_SetValue (&maxvip_spectators, MAX_CLIENTS);
910 
911 	if ((int)maxspectators.value + maxclients.value > MAX_CLIENTS)
912 		Cvar_SetValue (&maxspectators, MAX_CLIENTS - (int)maxclients.value);
913 
914 	if ((int)maxspectators.value + maxclients.value + maxvip_spectators.value > MAX_CLIENTS)
915 		Cvar_SetValue (&maxvip_spectators, MAX_CLIENTS - (int)maxclients.value - (int)maxspectators.value);
916 
917 }
918 
919 //==============================================
920 
921 // see if the challenge is valid
CheckChallange(int challenge)922 qbool CheckChallange( int challenge )
923 {
924 	int i;
925 
926 	if (net_from.type == NA_LOOPBACK)
927 		return true; // local client do not need challenge
928 
929 	for (i = 0; i < MAX_CHALLENGES; i++)
930 	{
931 		if (NET_CompareBaseAdr (net_from, svs.challenges[i].adr))
932 		{
933 			if (challenge == svs.challenges[i].challenge)
934 				break;		// good
935 
936 			Netchan_OutOfBandPrint (NS_SERVER, net_from, "%c\nBad challenge.\n", A2C_PRINT);
937 			return false;
938 		}
939 	}
940 
941 	if (i == MAX_CHALLENGES)
942 	{
943 		Netchan_OutOfBandPrint (NS_SERVER, net_from, "%c\nNo challenge for address.\n", A2C_PRINT);
944 		return false;
945 	}
946 
947 	return true;
948 }
949 
950 //==============================================
951 
CheckProtocol(int ver)952 qbool CheckProtocol( int ver )
953 {
954 	if (ver != PROTOCOL_VERSION)
955 	{
956 		Netchan_OutOfBandPrint (NS_SERVER, net_from, "%c\nServer is version " QW_VERSION ".\n", A2C_PRINT);
957 		Con_Printf ("* rejected connect from version %i\n", ver);
958 		return false;
959 	}
960 
961 	return true;
962 }
963 
964 //==============================================
965 
CheckUserinfo(char * userinfobuf,unsigned int bufsize,char * userinfo)966 qbool CheckUserinfo( char *userinfobuf, unsigned int bufsize, char *userinfo )
967 {
968 	strlcpy (userinfobuf, userinfo, bufsize);
969 
970 	// and now validate userinfo
971 	if ( !ValidateUserInfo( userinfobuf ) )
972 	{
973 		Netchan_OutOfBandPrint (NS_SERVER, net_from, "%c\nInvalid userinfo, perhaps &c sequences. Restart your qwcl\n", A2C_PRINT);
974 		return false;
975 	}
976 
977 	return true;
978 }
979 
980 //==============================================
981 
982 int SV_VIPbyIP(netadr_t adr);
983 int SV_VIPbyPass (char *pass);
984 
CheckPasswords(char * userinfo,int userinfo_size,qbool * spass_ptr,qbool * vip_ptr,int * spectator_ptr)985 qbool CheckPasswords( char *userinfo, int userinfo_size, qbool *spass_ptr, qbool *vip_ptr, int *spectator_ptr )
986 {
987 	int spectator;
988 	qbool spass, vip;
989 
990 	char *s = Info_ValueForKey (userinfo, "spectator");
991 	char *pwd;
992 
993 	spass = vip = spectator = false;
994 
995 	if (s[0] && strcmp(s, "0"))
996 	{
997 		spass = true;
998 
999 		// first the pass, then ip
1000 		if ( !( vip = SV_VIPbyPass( s ) ) )
1001 		{
1002 			if ( !( vip = SV_VIPbyPass( Info_ValueForKey( userinfo, "password") ) ) )
1003 			{
1004 				vip = SV_VIPbyIP( net_from );
1005 			}
1006 		}
1007 
1008 		pwd = spectator_password.string;
1009 
1010 		if (pwd[0] && strcasecmp(pwd, "none") && strcmp(pwd, s))
1011 		{
1012 			spass = false; // failed
1013 		}
1014 
1015 		if (!vip && !spass)
1016 		{
1017 			Con_Printf ("%s:spectator password failed\n", NET_AdrToString (net_from));
1018 			Netchan_OutOfBandPrint (NS_SERVER, net_from, "%c\nrequires a spectator password\n\n", A2C_PRINT);
1019 
1020 			return false;
1021 		}
1022 
1023 		Info_RemoveKey (userinfo, "spectator"); // remove passwd
1024 		Info_SetValueForStarKey (userinfo, "*spectator", "1", userinfo_size);
1025 
1026 		spectator = Q_atoi(s);
1027 
1028 		if (!spectator)
1029 			spectator = true;
1030 	}
1031 	else
1032 	{
1033 		s = Info_ValueForKey (userinfo, "password");
1034 
1035 		// first the pass, then ip
1036 		if (!(vip = SV_VIPbyPass(s)))
1037 		{
1038 			vip = SV_VIPbyIP(net_from);
1039 		}
1040 
1041 		pwd = password.string;
1042 
1043 		if (!vip && pwd[0] && strcasecmp(pwd, "none") && strcmp(pwd, s))
1044 		{
1045 			Con_Printf ("%s:password failed\n", NET_AdrToString (net_from));
1046 			Netchan_OutOfBandPrint (NS_SERVER, net_from, "%c\nserver requires a password\n\n", A2C_PRINT);
1047 
1048 			return false;
1049 		}
1050 
1051 		Info_RemoveKey (userinfo, "spectator"); // remove "spectator 0" for example
1052 
1053 		spectator = false;
1054 	}
1055 
1056 	Info_RemoveKey (userinfo, "password"); // remove passwd
1057 
1058 	// copy
1059 	*spass_ptr     = spass;
1060 	*vip_ptr       = vip;
1061 	*spectator_ptr = spectator;
1062 
1063 	return true;
1064 }
1065 
1066 //==============================================
1067 
CheckReConnect(netadr_t adr,int qport)1068 qbool CheckReConnect( netadr_t adr, int qport )
1069 {
1070 	int i;
1071 	client_t *cl;
1072 
1073 	for (i = 0, cl = svs.clients; i < MAX_CLIENTS; i++, cl++)
1074 	{
1075 		if (cl->state == cs_free)
1076 			continue;
1077 
1078 		if (NET_CompareBaseAdr (adr, cl->netchan.remote_address) &&
1079 			(cl->netchan.qport == qport || adr.port == cl->netchan.remote_address.port))
1080 		{
1081 			if (SV_ClientConnectedTime(cl) < sv_reconnectlimit.value)
1082 			{
1083 				Con_Printf ("%s:reconnect rejected: too soon\n", NET_AdrToString (adr));
1084 				return false;
1085 			}
1086 
1087 			switch ( cl->state )
1088 			{
1089 				case cs_zombie: // zombie already dropped.
1090 					break;
1091 
1092 				case cs_preconnected:
1093 				case cs_connected:
1094 				case cs_spawned:
1095 
1096 					SV_DropClient (cl);
1097 					SV_ClearReliable (cl);	// don't send the disconnect
1098 					break;
1099 
1100 				default:
1101 					return false; // unknown state, should not be the case.
1102 			}
1103 
1104 			cl->state = cs_free;
1105 			Con_Printf ("%s:reconnect\n", NET_AdrToString (adr));
1106 			break;
1107 		}
1108 	}
1109 
1110 	return true;
1111 }
1112 
1113 //==============================================
1114 
CountPlayersSpecsVips(int * clients_ptr,int * spectators_ptr,int * vips_ptr,client_t ** newcl_ptr)1115 void CountPlayersSpecsVips(int *clients_ptr, int *spectators_ptr, int *vips_ptr, client_t **newcl_ptr)
1116 {
1117 	client_t *cl = NULL, *newcl = NULL;
1118 	int clients = 0, spectators = 0, vips = 0;
1119 	int i;
1120 
1121 	for (i = 0, cl = svs.clients; i < MAX_CLIENTS; i++, cl++)
1122 	{
1123 		if (cl->state == cs_free)
1124 		{
1125 			if (!newcl)
1126 				newcl = cl; // grab first available slot
1127 
1128 			continue;
1129 		}
1130 
1131 		if (cl->spectator)
1132 		{
1133 			if (cl->vip)
1134 				vips++;
1135 			else
1136 				spectators++;
1137 		}
1138 		else
1139 		{
1140 			clients++;
1141 		}
1142 	}
1143 
1144 	if (clients_ptr)
1145 		*clients_ptr = clients;
1146 	if (spectators_ptr)
1147 		*spectators_ptr = spectators;
1148 	if (vips_ptr)
1149 		*vips_ptr = vips;
1150 	if (newcl_ptr)
1151 		*newcl_ptr = newcl;
1152 }
1153 
1154 //==============================================
1155 
SpectatorCanConnect(int vip,int spass,int spectators,int vips)1156 qbool SpectatorCanConnect(int vip, int spass, int spectators, int vips)
1157 {
1158 	FixMaxClientsCvars(); // not a bad idea
1159 
1160 	if (vip)
1161 	{
1162 		if (spass && (spectators < (int)maxspectators.value || vips < (int)maxvip_spectators.value))
1163 			return true;
1164 	}
1165 	else
1166 	{
1167 		if (spass && spectators < (int)maxspectators.value)
1168 			return true;
1169 	}
1170 
1171 	return false;
1172 }
1173 
PlayerCanConnect(int clients)1174 qbool PlayerCanConnect(int clients)
1175 {
1176 	FixMaxClientsCvars(); // not a bad idea
1177 
1178 	if (clients < (int)maxclients.value)
1179 		return true;
1180 
1181 	return false;
1182 }
1183 
1184 /*
1185 ==================
1186 SVC_DirectConnect
1187 
1188 A connection request that did not come from the master
1189 ==================
1190 */
1191 extern void MVD_PlayerReset(int player);
1192 
1193 extern char *shortinfotbl[];
1194 
SVC_DirectConnect(void)1195 static void SVC_DirectConnect (void)
1196 {
1197 	int spectator;
1198 	qbool spass, vip, rip_vip;
1199 
1200 	int clients, spectators, vips;
1201 	int qport, i, edictnum;
1202 
1203 	client_t *newcl;
1204 
1205 	char userinfo[1024];
1206 	char *s;
1207 	netadr_t adr;
1208 	edict_t *ent;
1209 
1210 #ifdef PROTOCOL_VERSION_FTE
1211 	unsigned int protextsupported = 0;
1212 #endif // PROTOCOL_VERSION_FTE
1213 
1214 #ifdef PROTOCOL_VERSION_FTE2
1215 	unsigned int protextsupported2 = 0;
1216 #endif // PROTOCOL_VERSION_FTE2
1217 
1218 #ifdef PROTOCOL_VERSION_MVD1
1219 	unsigned int mvdext_supported1 = 0;
1220 #endif
1221 
1222 	// check version/protocol
1223 	if ( !CheckProtocol( Q_atoi( Cmd_Argv( 1 ) ) ) )
1224 		return; // wrong protocol number
1225 
1226 	// get qport
1227 	qport = Q_atoi( Cmd_Argv( 2 ) );
1228 
1229 	// see if the challenge is valid
1230 	if ( !CheckChallange( Q_atoi( Cmd_Argv( 3 ) ) ) )
1231 		return; // wrong challange
1232 
1233 	// and now validate userinfo
1234 	if ( !CheckUserinfo( userinfo, sizeof( userinfo ), Cmd_Argv( 4 ) ) )
1235 		return; // wrong userinfo
1236 
1237 //
1238 // WARNING: WARNING: WARNING: using Cmd_TokenizeString() so do all Cmd_Argv() above.
1239 //
1240 
1241 	while( !msg_badread )
1242 	{
1243 		Cmd_TokenizeString( MSG_ReadStringLine() );
1244 
1245 		switch( Q_atoi( Cmd_Argv( 0 ) ) )
1246 		{
1247 #ifdef PROTOCOL_VERSION_FTE
1248 		case PROTOCOL_VERSION_FTE:
1249 			protextsupported = Q_atoi( Cmd_Argv( 1 ) );
1250 			Con_DPrintf("Client supports 0x%x fte extensions\n", protextsupported);
1251 			break;
1252 #endif // PROTOCOL_VERSION_FTE
1253 
1254 #ifdef PROTOCOL_VERSION_FTE2
1255 		case PROTOCOL_VERSION_FTE2:
1256 			protextsupported2 = Q_atoi( Cmd_Argv( 1 ) );
1257 			Con_DPrintf("Client supports 0x%x fte extensions2\n", protextsupported2);
1258 			break;
1259 #endif // PROTOCOL_VERSION_FTE2
1260 
1261 #ifdef PROTOCOL_VERSION_MVD1
1262 		case PROTOCOL_VERSION_MVD1:
1263 			mvdext_supported1 = Q_atoi( Cmd_Argv( 1 ) );
1264 			Con_DPrintf("Client supports 0x%x mvdsv extensions\n", mvdext_supported1);
1265 			break;
1266 #endif
1267 		}
1268 	}
1269 
1270 	msg_badread = false;
1271 
1272 	spass = vip = rip_vip = spectator = false;
1273 
1274 	// check for password or spectator_password
1275 	if ( !CheckPasswords( userinfo, sizeof(userinfo), &spass, &vip, &spectator) )
1276 		return; // pass was wrong
1277 
1278 	adr = net_from;
1279 
1280 	// if there is already a slot for this ip, reuse (changed from drop) it
1281 	if ( !CheckReConnect( adr, qport ) )
1282 		return; // can't do that for some reason
1283 
1284 	// count up the clients and spectators
1285 	CountPlayersSpecsVips(&clients, &spectators, &vips, &newcl);
1286 
1287 	FixMaxClientsCvars();
1288 
1289 	// if at server limits, refuse connection
1290 
1291 	if ((spectator && !SpectatorCanConnect(vip, spass, spectators, vips)) ||
1292 	    (!spectator && !PlayerCanConnect(clients)) ||
1293 	    !newcl)
1294 	{
1295 		Sys_Printf ("%s:full connect\n", NET_AdrToString (adr));
1296 
1297 		// no way to connect does't matter VIP or whatever, just no free slots
1298 		if (!newcl)
1299 		{
1300 			Netchan_OutOfBandPrint (NS_SERVER, adr, "%c\nserver is full\n\n", A2C_PRINT);
1301 			return;
1302 		}
1303 
1304 		// !!! SPECTATOR 2 FEATURE !!!
1305 		if (spectator == 2 && !vip &&  vips < (int)maxvip_spectators.value)
1306 		{
1307 			vip = rip_vip = 1; // yet can be connected if realip is on vip list
1308 		}
1309 		else if (    !spectator && spectators < (int)maxspectators.value
1310 				  && (
1311 				  	      ( (int)sv_forcespec_onfull.value == 2
1312 							&&   (Q_atoi(Info_ValueForKey(userinfo, "svf")) & SVF_SPEC_ONFULL)
1313 				  	      )
1314 				   	   		||
1315 						  ( (int)sv_forcespec_onfull.value == 1
1316 							&&   !(Q_atoi(Info_ValueForKey(userinfo, "svf")) & SVF_NO_SPEC_ONFULL)
1317 						  )
1318 				   	 )
1319 				)
1320 		{
1321 			Netchan_OutOfBandPrint (NS_SERVER, adr, "%c\nserver is full: connecting as spectator\n", A2C_PRINT);
1322 			Info_SetValueForStarKey (userinfo, "*spectator", "1", sizeof(userinfo));
1323 			spectator = true;
1324 		}
1325 		else
1326 		{
1327 			Netchan_OutOfBandPrint (NS_SERVER, adr, "%c\nserver is full\n\n", A2C_PRINT);
1328 			return;
1329 		}
1330 	}
1331 
1332 	// build a new connection
1333 	// accept the new client
1334 	// this is the only place a client_t is ever initialized
1335 	memset (newcl, 0, sizeof(*newcl));
1336 
1337 	newcl->userid = SV_GenerateUserID();
1338 
1339 #ifdef PROTOCOL_VERSION_FTE
1340 	newcl->fteprotocolextensions = protextsupported;
1341 #endif // PROTOCOL_VERSION_FTE
1342 
1343 #ifdef PROTOCOL_VERSION_FTE2
1344 	newcl->fteprotocolextensions2 = protextsupported2;
1345 #endif // PROTOCOL_VERSION_FTE2
1346 
1347 #ifdef PROTOCOL_VERSION_MVD1
1348 	newcl->mvdprotocolextensions1 = mvdext_supported1;
1349 #endif
1350 
1351 	newcl->_userinfo_ctx_.max      = MAX_CLIENT_INFOS;
1352 	newcl->_userinfoshort_ctx_.max = MAX_CLIENT_INFOS;
1353 	Info_Convert(&newcl->_userinfo_ctx_, userinfo);
1354 
1355 	// request protocol extensions.
1356 	if (*Info_Get(&newcl->_userinfo_ctx_, "Qizmo")
1357 		|| *Info_Get(&newcl->_userinfo_ctx_, "*qtv")
1358 	)
1359 	{
1360 		newcl->process_pext = false; // this whould not work over such proxies.
1361 	}
1362 	else
1363 	{
1364 		newcl->process_pext = true;
1365 	}
1366 
1367 	Netchan_OutOfBandPrint (NS_SERVER, adr, "%c", S2C_CONNECTION);
1368 
1369 	Netchan_Setup (NS_SERVER, &newcl->netchan, adr, qport, Q_atoi(Info_Get(&newcl->_userinfo_ctx_, "mtu")));
1370 
1371 	newcl->state = cs_preconnected;
1372 
1373 	newcl->datagram.allowoverflow = true;
1374 	newcl->datagram.data = newcl->datagram_buf;
1375 	newcl->datagram.maxsize = sizeof(newcl->datagram_buf);
1376 
1377 	// spectator mode can ONLY be set at join time
1378 	newcl->spectator = spectator;
1379 	newcl->vip = vip;
1380 	newcl->rip_vip = rip_vip;
1381 
1382 	// extract extensions mask
1383 	newcl->extensions = Q_atoi(Info_Get(&newcl->_userinfo_ctx_, "*z_ext"));
1384 	Info_Remove (&newcl->_userinfo_ctx_, "*z_ext");
1385 
1386 	edictnum = (newcl-svs.clients)+1;
1387 	ent = EDICT_NUM(edictnum);
1388 	ent->e->free = false;
1389 	newcl->edict = ent;
1390 	// restore client name.
1391 	PR_SetEntityString(ent, ent->v.netname, newcl->name);
1392 
1393 	s = ( vip ? va("%d", vip) : "" );
1394 
1395 	Info_SetStar (&newcl->_userinfo_ctx_, "*VIP", s);
1396 
1397 	// copy the most important userinfo into userinfoshort
1398 	// {
1399 
1400 	// parse some info from the info strings
1401 	SV_ExtractFromUserinfo (newcl, true);
1402 
1403 	for (i = 0; shortinfotbl[i] != NULL; i++)
1404 	{
1405 		s = Info_Get(&newcl->_userinfo_ctx_, shortinfotbl[i]);
1406 		Info_SetStar (&newcl->_userinfoshort_ctx_, shortinfotbl[i], s);
1407 	}
1408 
1409 	// move star keys to infoshort
1410 	Info_CopyStar( &newcl->_userinfo_ctx_, &newcl->_userinfoshort_ctx_ );
1411 
1412 	// }
1413 
1414 	// JACK: Init the floodprot stuff.
1415 	memset(newcl->whensaid, 0, sizeof(newcl->whensaid));
1416 	newcl->whensaidhead = 0;
1417 	newcl->lockedtill = 0;
1418 	newcl->disable_updates_stop = -1.0; // Vladis
1419 
1420 	newcl->realip_num = rand();
1421 
1422 	//bliP: init
1423 	newcl->spec_print = (int)sv_specprint.value;
1424 	newcl->logincount = 0;
1425 	//<-
1426 
1427 #ifdef FTE_PEXT2_VOICECHAT
1428 	SV_VoiceInitClient(newcl);
1429 #endif
1430 
1431 	// call the progs to get default spawn parms for the new client
1432 	PR_GameSetNewParms();
1433 
1434 	for (i=0 ; i<NUM_SPAWN_PARMS ; i++)
1435 		newcl->spawn_parms[i] = (&PR_GLOBAL(parm1))[i];
1436 
1437 	// mvd/qtv related stuff
1438 	// Well, here is a chance what player connect after demo recording started,
1439 	// so demo.info[edictnum - 1].model == player_model so SV_MVDWritePackets() will not wrote player model index,
1440 	// so client during playback this demo will got invisible model, because model index will be 0.
1441 	// Fixing that.
1442 	// Btw, struct demo contain different client specific structs, may be they need clearing too, not sure.
1443 	// Also, we have Cmd_Join_f()/Cmd_Observe_f() which have close behaviour to SVC_DirectConnect(),
1444 	// so I put same demo fix in mentioned functions too.
1445 	MVD_PlayerReset(NUM_FOR_EDICT(newcl->edict) - 1);
1446 
1447 	newcl->sendinfo = true;
1448 }
1449 
char2int(int c)1450 static int char2int (int c)
1451 {
1452 	if (c <= '9' && c >= '0')
1453 		return c - '0';
1454 	else if (c <= 'f' && c >= 'a')
1455 		return c - 'a' + 10;
1456 	else if (c <= 'F' && c >= 'A')
1457 		return c - 'A' + 10;
1458 	return 0;
1459 }
1460 /*
1461  * rcon_bandlim() - check for rcon requests bandwidth limit
1462  *
1463  *      From kernel of the FreeBSD 4.10 release:
1464  *      sys/netinet/ip_icmp.c(846): int badport_bandlim(int which);
1465  *
1466  *	Return false if it is ok to check rcon_password, true if we have
1467  *	hit our bandwidth limit and it is not ok.
1468  *
1469  *	If sv_rconlim.value is <= 0, the feature is disabled and false is returned.
1470  *
1471  *	Note that the printing of the error message is delayed so we can
1472  *	properly print the rcon limit error rate that the system was trying to do
1473  *	(i.e. 22000/100 rcon pps, etc...).  This can cause long delays in printing
1474  *	the 'final' error, but it doesn't make sense to solve the printing
1475  *	delay with more complex code.
1476  */
rcon_bandlim(void)1477 static qbool rcon_bandlim (void)
1478 {
1479 	static double lticks = 0;
1480 	static int lpackets = 0;
1481 
1482 	/*
1483 	 * Return ok status if feature disabled or argument out of
1484 	 * ranage.
1485 	 */
1486 
1487 	if ((int)sv_rconlim.value <= 0)
1488 		return false;
1489 
1490 	/*
1491 	 * reset stats when cumulative dt exceeds one second.
1492 	 */
1493 
1494 	if (realtime - lticks > 1.0)
1495 	{
1496 		if (lpackets > (int)sv_rconlim.value)
1497 			Sys_Printf("WARNING: Limiting rcon response from %d to %d rcon pequests per second from %s\n",
1498 			           lpackets, (int)sv_rconlim.value, NET_AdrToString(net_from));
1499 		lticks = realtime;
1500 		lpackets = 0;
1501 	}
1502 
1503 	/*
1504 	 * bump packet count
1505 	 */
1506 
1507 	if (++lpackets > (int)sv_rconlim.value)
1508 		return true;
1509 
1510 	return false;
1511 }
1512 
1513 //bliP: master rcon/logging ->
Rcon_Validate(char * client_string,char * password1)1514 int Rcon_Validate (char *client_string, char *password1)
1515 {
1516 	unsigned int i;
1517 
1518 	if (rcon_bandlim()) {
1519 		return 0;
1520 	}
1521 
1522 	if (!strlen(password1)) {
1523 		return 0;
1524 	}
1525 
1526 	if ((int)sv_crypt_rcon.value) {
1527 		const char* digest = Cmd_Argv(1);
1528 		const char* time_start = Cmd_Argv(1) + DIGEST_SIZE * 2;
1529 
1530 		if (strlen(digest) < DIGEST_SIZE * 2 + sizeof(time_t) * 2) {
1531 			return 0;
1532 		}
1533 
1534 		if ((int)sv_timestamplen.value) {
1535 			time_t server_time, client_time = 0;
1536 			double difftime_server_client;
1537 
1538 			time(&server_time);
1539 			for (i = 0; i < sizeof(client_time) * 2; i += 2) {
1540 				client_time += (char2int((unsigned char)time_start[i]) << (4 + i * 4)) +
1541 				               (char2int((unsigned char)time_start[i + 1]) << (i * 4));
1542 			}
1543 			difftime_server_client = difftime(server_time, client_time);
1544 
1545 			if (difftime_server_client > (double)sv_timestamplen.value || difftime_server_client < -(double)sv_timestamplen.value) {
1546 				return 0;
1547 			}
1548 		}
1549 		SHA1_Init();
1550 		SHA1_Update((unsigned char*)Cmd_Argv(0));
1551 		SHA1_Update((unsigned char*)" ");
1552 		SHA1_Update((unsigned char*)password1);
1553 		SHA1_Update((unsigned char*)time_start);
1554 		SHA1_Update((unsigned char*)" ");
1555 		for (i = 2; (int) i < Cmd_Argc(); i++) {
1556 			SHA1_Update((unsigned char*)Cmd_Argv(i));
1557 			SHA1_Update((unsigned char*)" ");
1558 		}
1559 		if (strncmp(digest, SHA1_Final(), DIGEST_SIZE * 2)) {
1560 			return 0;
1561 		}
1562 	}
1563 	else if (strcmp(Cmd_Argv(1), password1)) {
1564 		return 0;
1565 	}
1566 	return 1;
1567 }
1568 
Master_Rcon_Validate(void)1569 int Master_Rcon_Validate (void)
1570 {
1571 	int i, client_string_len = Cmd_Argc() + 1;
1572 	char *client_string;
1573 
1574 	for (i = 0; i < Cmd_Argc(); ++i) {
1575 		client_string_len += strlen(Cmd_Argv(i));
1576 	}
1577 	client_string = (char *) Q_malloc (client_string_len);
1578 
1579 	*client_string = 0;
1580 	for (i = 0; i < Cmd_Argc(); ++i) {
1581 		strlcat(client_string, Cmd_Argv(i), client_string_len);
1582 		strlcat(client_string, " ", client_string_len);
1583 	}
1584 	i = Rcon_Validate (client_string, master_rcon_password);
1585 	Q_free(client_string);
1586 	return i;
1587 }
1588 
1589 // QW262 -->
SV_Admin_f(void)1590 void SV_Admin_f (void)
1591 {
1592 	client_t *cl;
1593 	int i = 0;
1594 
1595 	if (Cmd_Argc () == 2 && !strcmp (Cmd_Argv (1), "off") && WatcherId &&
1596 			NET_CompareAdr (WatcherId->netchan.remote_address, net_from))
1597 	{
1598 		Con_Printf ("Rcon Watch stopped\n");
1599 		WatcherId = NULL;
1600 		return;
1601 	}
1602 
1603 	if (WatcherId)
1604 		Con_Printf ("Rcon Watch is already being made by %s\n", WatcherId->name);
1605 	else
1606 	{
1607 		for (cl = svs.clients; i < MAX_CLIENTS; i++, cl++)
1608 		{
1609 			if (cl->state != cs_spawned)
1610 				continue;
1611 
1612 			if (NET_CompareAdr (cl->netchan.remote_address, net_from))
1613 				break;
1614 		}
1615 
1616 		if (i == MAX_CLIENTS)
1617 		{
1618 			Con_Printf ("You are not connected to server!\n");
1619 			return;
1620 		}
1621 
1622 		WatcherId = cl;
1623 		Con_Printf ("Rcon Watch started for %s\n", cl->name);
1624 	}
1625 }
1626 // <-- QW262
1627 
1628 /*
1629 ===============
1630 SVC_RemoteCommand
1631 
1632 A client issued an rcon command.
1633 Shift down the remaining args
1634 Redirect all printfs
1635 ===============
1636 */
SVC_RemoteCommand(char * remote_command)1637 static void SVC_RemoteCommand (char *remote_command)
1638 {
1639 	int			i;
1640 	char		str[1024];
1641 	char		plain[32];
1642 	char		*p;
1643 	unsigned char *hide;
1644 	client_t	*cl;
1645 	qbool		admin_cmd = false;
1646 	qbool		do_cmd = false;
1647 	qbool		bad_cmd = false;
1648 	qbool		banned = false;
1649 
1650 
1651 	if (Rcon_Validate (remote_command, master_rcon_password))
1652 	{
1653 		if (SV_FilterPacket()) //banned players can't use rcon, but we log it
1654 			banned = true;
1655 		else
1656 			do_cmd = true;
1657 	}
1658 	else if (Rcon_Validate (remote_command, rcon_password.string))
1659 	{
1660 		admin_cmd = true;
1661 		if (SV_FilterPacket()) //banned players can't use rcon, but we log it
1662 		{
1663 			bad_cmd = true;
1664 			banned = true;
1665 		}
1666 		else
1667 		{
1668 			//
1669 			// the following line prevents exploits like:
1670 			//   coop rm
1671 			//   $coop . *
1672 			// which expands to:
1673 			//   rm . *
1674 
1675 			Cmd_ExpandString (remote_command, str); // check *expanded* command
1676 
1677 			//
1678 			// since the execution parser is not case sensitive, we
1679 			// must check not only for chmod, but also CHMOD, ChmoD, etc.
1680 			// so we lowercase the whole temporary line before checking
1681 
1682 			// VVD: strcmp => strcasecmp and we don't need to do this (yes?)
1683 			//for(i = 0; str[i]; i++)
1684 			//	str[i] = (char)tolower(str[i]);
1685 
1686 			Cmd_TokenizeString (str);		// must check *all* tokens, because
1687 											// a command/var may not be the first
1688 											// token -- example: "" ls .
1689 
1690 			//
1691 			// normal rcon can't use these commands
1692 			//
1693 			// NOTE: this would still be vulnerable to semicolons if
1694 			// they were still allowed, so keep that in mind before
1695 			// re-enabling them
1696 
1697 			for (i = 2; i < Cmd_Argc(); i++)
1698 			{
1699 				const char *tstr = Cmd_Argv(i);
1700 
1701 				if(!tstr[0]) // skip leading empty tokens
1702 					continue;
1703 
1704 				if (!strcasecmp(tstr, "rm") ||
1705 					!strcasecmp(tstr, "rmdir") ||
1706 					!strcasecmp(tstr, "ls") ||
1707 					!strcasecmp(tstr, "chmod") ||
1708 					!strcasecmp(tstr, "sv_admininfo") ||
1709 					!strcasecmp(tstr, "if") ||
1710 					!strcasecmp(tstr, "localcommand") ||
1711 					!strcasecmp(tstr, "sv_crypt_rcon") ||
1712 					!strcasecmp(tstr, "sv_timestamplen") ||
1713 					!strncasecmp(tstr, "log", 3) ||
1714 					!strcasecmp(tstr, "sys_command_line")
1715 					)
1716 				{
1717 					bad_cmd = true;
1718 				}
1719 				break; // stop after first non-empty token
1720 			}
1721 
1722 			Cmd_TokenizeString (remote_command); // restore original tokens
1723 		}
1724 		do_cmd = !bad_cmd;
1725 	}
1726 
1727 	//find player name if rcon came from someone on server
1728 	plain[0] = '\0';
1729 	for (i = 0, cl = svs.clients; i < MAX_CLIENTS; i++, cl++)
1730 	{
1731 		if (cl->state == cs_free)
1732 			continue;
1733 #ifdef USE_PR2
1734 		if (cl->isBot)
1735 			continue;
1736 #endif
1737 		if (!NET_CompareBaseAdr(net_from, cl->netchan.remote_address))
1738 			continue;
1739 		if (cl->netchan.remote_address.port != net_from.port)
1740 			continue;
1741 
1742 		strlcpy(plain, cl->name, sizeof(plain));
1743 		Q_normalizetext(plain);
1744 
1745 		// we found what we need
1746 		break;
1747 	}
1748 
1749 	if (do_cmd)
1750 	{
1751 		if (!(int)sv_crypt_rcon.value)
1752 		{
1753 			hide = net_message.data + 9;
1754 			p = admin_cmd ? rcon_password.string : master_rcon_password;
1755 			while (*p)
1756 			{
1757 				p++;
1758 				*hide++ = '*';
1759 			}
1760 		}
1761 
1762 		if (plain[0])
1763 			SV_Write_Log(RCON_LOG, 1, va("Rcon from %s (%s): %s\n", NET_AdrToString(net_from), plain, net_message.data + 4));
1764 		else
1765 			SV_Write_Log(RCON_LOG, 1, va("Rcon from %s: %s\n", NET_AdrToString(net_from), net_message.data + 4));
1766 
1767 		Con_Printf("Rcon from %s:\n%s\n", NET_AdrToString(net_from), net_message.data + 4);
1768 
1769 		SV_BeginRedirect(RD_PACKET);
1770 
1771 		str[0] = '\0';
1772 		for (i = 2; i < Cmd_Argc(); i++)
1773 		{
1774 			strlcat(str, Cmd_Argv(i), sizeof(str));
1775 			strlcat(str, " ", sizeof(str));
1776 		}
1777 
1778 		Cmd_ExecuteString(str);
1779 	}
1780 	else
1781 	{
1782 		if (admin_cmd && !(int)sv_crypt_rcon.value)
1783 		{
1784 			hide = net_message.data + 9;
1785 			p = admin_cmd ? rcon_password.string : master_rcon_password;
1786 			while (*p)
1787 			{
1788 				p++;
1789 				*hide++ = '*';
1790 			}
1791 		}
1792 
1793 		Con_Printf ("Bad rcon from %s: %s\n", NET_AdrToString(net_from), net_message.data + 4);
1794 
1795 		if (!banned)
1796 		{
1797 			if (plain[0])
1798 				SV_Write_Log(RCON_LOG, 1, va("Bad rcon from %s (%s):\n%s\n", NET_AdrToString(net_from), plain, net_message.data + 4));
1799 			else
1800 				SV_Write_Log(RCON_LOG, 1, va("Bad rcon from %s:\n%s\n",	NET_AdrToString (net_from), net_message.data + 4));
1801 		}
1802 		else
1803 		{
1804 			SV_Write_Log(RCON_LOG, 1, va("Rcon from banned IP: %s: %s\n", NET_AdrToString(net_from), net_message.data + 4));
1805 			SV_SendBan();
1806 			return;
1807 		}
1808 
1809 		SV_BeginRedirect (RD_PACKET);
1810 		if (admin_cmd)
1811 			Con_Printf ("Command not valid.\n");
1812 		else
1813 			Con_Printf ("Bad rcon_password.\n");
1814 	}
1815 	SV_EndRedirect ();
1816 }
1817 //<-
1818 
SVC_IP(void)1819 static void SVC_IP(void)
1820 {
1821 	int num;
1822 	client_t *client;
1823 
1824 	if (Cmd_Argc() < 3)
1825 		return;
1826 
1827 	num = Q_atoi(Cmd_Argv(1));
1828 
1829 	if (num < 0 || num >= MAX_CLIENTS)
1830 		return;
1831 
1832 	client = &svs.clients[num];
1833 	if (client->state != cs_preconnected)
1834 		return;
1835 
1836 	// prevent cheating
1837 	if (client->realip_num != Q_atoi(Cmd_Argv(2)))
1838 		return;
1839 
1840 	// don't override previously set ip
1841 	if (client->realip.ip[0])
1842 		return;
1843 
1844 	client->realip = net_from;
1845 
1846 	// if banned drop
1847 	if (SV_FilterPacket()/* && !client->vip*/)
1848 		SV_DropClient(client);
1849 
1850 }
1851 
1852 
1853 /*
1854 =================
1855 SV_ConnectionlessPacket
1856 
1857 A connectionless packet has four leading 0xff
1858 characters to distinguish it from a game channel.
1859 Clients that are in the game can still send
1860 connectionless packets.
1861 =================
1862 */
1863 
SV_ConnectionlessPacket(void)1864 static void SV_ConnectionlessPacket (void)
1865 {
1866 	char	*s;
1867 	char	*c;
1868 
1869 	MSG_BeginReading ();
1870 	MSG_ReadLong ();		// skip the -1 marker
1871 
1872 	s = MSG_ReadStringLine ();
1873 
1874 	Cmd_TokenizeString (s);
1875 
1876 	c = Cmd_Argv(0);
1877 
1878 	if (!strcmp(c, "ping") || ( c[0] == A2A_PING && (c[1] == 0 || c[1] == '\n')) )
1879 		SVC_Ping ();
1880 	else if (c[0] == A2A_ACK && (c[1] == 0 || c[1] == '\n') )
1881 		Con_Printf ("A2A_ACK from %s\n", NET_AdrToString (net_from));
1882 	else if (!strcmp(c,"status"))
1883 		SVC_Status ();
1884 	else if (!strcmp(c,"log"))
1885 		SVC_Log ();
1886 	else if (!strcmp(c, "rcon"))
1887 		SVC_RemoteCommand (s);
1888 	else if (!strcmp(c, "ip"))
1889 		SVC_IP();
1890 	else if (!strcmp(c,"connect"))
1891 		SVC_DirectConnect ();
1892 	else if (!strcmp(c,"getchallenge"))
1893 		SVC_GetChallenge ();
1894 	else if (!strcmp(c,"lastscores"))
1895 		SVC_LastScores ();
1896 	else if (!strcmp(c,"dlist"))
1897 		SVC_DemoList ();
1898 	else if (!strcmp(c,"dlistr"))
1899 		SVC_DemoListRegex ();
1900 	else if (!strcmp(c,"dlistregex"))
1901 		SVC_DemoListRegex ();
1902 	else if (!strcmp(c,"demolist"))
1903 		SVC_DemoList ();
1904 	else if (!strcmp(c,"demolistr"))
1905 		SVC_DemoListRegex ();
1906 	else if (!strcmp(c,"demolistregex"))
1907 		SVC_DemoListRegex ();
1908 	else if (!strcmp(c,"qtvusers"))
1909 		SVC_QTVUsers ();
1910 	else
1911 		Con_Printf ("bad connectionless packet from %s:\n%s\n"
1912 		            , NET_AdrToString (net_from), s);
1913 }
1914 
1915 /*
1916 ==============================================================================
1917 
1918 PACKET FILTERING
1919 
1920 
1921 You can add or remove addresses from the filter list with:
1922 
1923 addip <ip>
1924 removeip <ip>
1925 
1926 The ip address is specified in dot format, and any unspecified digits will match any value, so you can specify an entire class C network with "addip 192.246.40".
1927 
1928 Removeip will only remove an address specified exactly the same way.  You cannot addip a subnet, then removeip a single host.
1929 
1930 listip
1931 Prints the current list of filters.
1932 
1933 writeip
1934 Dumps "addip <ip>" commands to listip.cfg so it can be execed at a later date.  The filter lists are not saved and restored by default, because I beleive it would cause too much confusion.
1935 
1936 filterban <0 or 1>
1937 
1938 If 1 (the default), then ip addresses matching the current list will be prohibited from entering the game.  This is the default setting.
1939 
1940 If 0, then only addresses matching the list will be allowed.  This lets you easily set up a private game, or a game that only allows players from your local network.
1941 
1942 
1943 ==============================================================================
1944 */
1945 
1946 
1947 /*typedef struct
1948 {
1949 	unsigned	mask;
1950 	unsigned	compare;
1951 	int			level;
1952 } ipfilter_t;
1953 */
1954 
1955 #define	MAX_IPFILTERS	1024
1956 
1957 ipfilter_t	ipfilters[MAX_IPFILTERS];
1958 int		numipfilters;
1959 
1960 ipfilter_t	ipvip[MAX_IPFILTERS];
1961 int		numipvips;
1962 
1963 //bliP: cuff, mute ->
1964 penfilter_t	penfilters[MAX_PENFILTERS];
1965 int		numpenfilters;
1966 //<-
1967 
1968 cvar_t	filterban = {"filterban", "1"};
1969 
1970 /*
1971 =================
1972 StringToFilter
1973 =================
1974 */
StringToFilter(char * s,ipfilter_t * f)1975 qbool StringToFilter (char *s, ipfilter_t *f)
1976 {
1977 	char	num[128];
1978 	int		i, j;
1979 	byte	b[4];
1980 	byte	m[4];
1981 
1982 	for (i=0 ; i<4 ; i++)
1983 	{
1984 		b[i] = 0;
1985 		m[i] = 0;
1986 	}
1987 
1988 	for (i=0 ; i<4 ; i++)
1989 	{
1990 		if (*s < '0' || *s > '9')
1991 		{
1992 			//Con_Printf ("Bad filter address: %s\n", s);
1993 			return false;
1994 		}
1995 
1996 		j = 0;
1997 		while (*s >= '0' && *s <= '9')
1998 		{
1999 			num[j++] = *s++;
2000 		}
2001 		num[j] = 0;
2002 		b[i] = Q_atoi(num);
2003 		if (b[i] != 0)
2004 			m[i] = 255;
2005 
2006 		if (!*s)
2007 			break;
2008 		s++;
2009 	}
2010 
2011 	f->mask = *(unsigned *)m;
2012 	f->compare = *(unsigned *)b;
2013 
2014 	return true;
2015 }
2016 
2017 /*
2018 =================
2019 SV_AddIPVIP_f
2020 =================
2021 */
SV_AddIPVIP_f(void)2022 static void SV_AddIPVIP_f (void)
2023 {
2024 	int		i, l;
2025 	ipfilter_t f;
2026 
2027 	if (!StringToFilter (Cmd_Argv(1), &f))
2028 	{
2029 		Con_Printf ("Bad filter address: %s\n", Cmd_Argv(1));
2030 		return;
2031 	}
2032 
2033 	l = Q_atoi(Cmd_Argv(2));
2034 
2035 	if (l < 1) l = 1;
2036 
2037 	for (i=0 ; i<numipvips ; i++)
2038 		if (ipvip[i].compare == 0xffffffff || (ipvip[i].mask == f.mask
2039 		                                       && ipvip[i].compare == f.compare))
2040 			break;		// free spot
2041 	if (i == numipvips)
2042 	{
2043 		if (numipvips == MAX_IPFILTERS)
2044 		{
2045 			Con_Printf ("VIP spectator IP list is full\n");
2046 			return;
2047 		}
2048 		numipvips++;
2049 	}
2050 
2051 	ipvip[i] = f;
2052 	ipvip[i].level = l;
2053 }
2054 
2055 /*
2056 =================
2057 SV_RemoveIPVIP_f
2058 =================
2059 */
SV_RemoveIPVIP_f(void)2060 static void SV_RemoveIPVIP_f (void)
2061 {
2062 	ipfilter_t	f;
2063 	int		i, j;
2064 
2065 	if (!StringToFilter (Cmd_Argv(1), &f))
2066 	{
2067 		Con_Printf ("Bad filter address: %s\n", Cmd_Argv(1));
2068 		return;
2069 	}
2070 	for (i=0 ; i<numipvips ; i++)
2071 		if (ipvip[i].mask == f.mask
2072 		        && ipvip[i].compare == f.compare)
2073 		{
2074 			for (j=i+1 ; j<numipvips ; j++)
2075 				ipvip[j-1] = ipvip[j];
2076 			numipvips--;
2077 			Con_Printf ("Removed.\n");
2078 			return;
2079 		}
2080 	Con_Printf ("Didn't find %s.\n", Cmd_Argv(1));
2081 }
2082 
2083 /*
2084 =================
2085 SV_ListIP_f
2086 =================
2087 */
SV_ListIPVIP_f(void)2088 static void SV_ListIPVIP_f (void)
2089 {
2090 	int		i;
2091 	byte	b[4];
2092 
2093 	Con_Printf ("VIP list:\n");
2094 	for (i=0 ; i<numipvips ; i++)
2095 	{
2096 		*(unsigned *)b = ipvip[i].compare;
2097 		Con_Printf ("%3i.%3i.%3i.%3i   level %d\n", b[0], b[1], b[2], b[3], ipvip[i].level);
2098 	}
2099 }
2100 
2101 /*
2102 =================
2103 SV_WriteIPVIP_f
2104 =================
2105 */
SV_WriteIPVIP_f(void)2106 static void SV_WriteIPVIP_f (void)
2107 {
2108 	FILE	*f;
2109 	char	name[MAX_OSPATH];
2110 	byte	b[4];
2111 	int		i;
2112 
2113 	snprintf (name, MAX_OSPATH, "%s/vip_ip.cfg", fs_gamedir);
2114 
2115 	Con_Printf ("Writing %s.\n", name);
2116 
2117 	f = fopen (name, "wb");
2118 	if (!f)
2119 	{
2120 		Con_Printf ("Couldn't open %s\n", name);
2121 		return;
2122 	}
2123 
2124 	for (i=0 ; i<numipvips ; i++)
2125 	{
2126 		*(unsigned *)b = ipvip[i].compare;
2127 		fprintf (f, "vip_addip %i.%i.%i.%i %d\n", b[0], b[1], b[2], b[3], ipvip[i].level);
2128 	}
2129 
2130 	fclose (f);
2131 
2132 	// force cache rebuild.
2133 	FS_FlushFSHash();
2134 }
2135 
2136 
2137 /*
2138 =================
2139 SV_AddIP_f
2140 =================
2141 */
SV_AddIP_f(void)2142 static void SV_AddIP_f (void)
2143 {
2144 	int		i;
2145 	double	t = 0;
2146 	char	*s;
2147 	time_t	long_time = time(NULL);
2148 	ipfilter_t f;
2149 	ipfiltertype_t ipft = ipft_ban; // default is ban
2150 
2151 	if (!StringToFilter (Cmd_Argv(1), &f) || f.compare == 0)
2152 	{
2153 		Con_Printf ("Bad filter address: %s\n", Cmd_Argv(1));
2154 		return;
2155 	}
2156 
2157 	s = Cmd_Argv(2);
2158 	if ( !s[0] || !strcmp(s, "ban"))
2159 		ipft = ipft_ban;
2160 	else if (!strcmp(s, "safe"))
2161 		ipft = ipft_safe;
2162 	else {
2163 		Con_Printf ("Wrong filter type %s, use ban or safe\n", Cmd_Argv(2));
2164 		return;
2165 	}
2166 
2167 	s = Cmd_Argv(3);
2168 	if (long_time > 0) {
2169 		if (*s == '+')     // "addip 127.0.0.1 ban +10" will ban for 10 seconds from current time
2170 			s++;
2171 		else
2172 			long_time = 0; // "addip 127.0.0.1 ban 1234567" will ban for some seconds since 00:00:00 GMT, January 1, 1970
2173 
2174 		t = (sscanf(s, "%lf", &t) == 1) ? t + long_time : 0;
2175 	}
2176 
2177 	f.time = t;
2178 	f.type = ipft;
2179 
2180 	for (i=0 ; i<numipfilters ; i++)
2181 		if (ipfilters[i].compare == 0xffffffff || (ipfilters[i].mask == f.mask
2182 		        && ipfilters[i].compare == f.compare))
2183 			break;		// free spot
2184 	if (i == numipfilters)
2185 	{
2186 		if (numipfilters == MAX_IPFILTERS)
2187 		{
2188 			Con_Printf ("IP filter list is full\n");
2189 			return;
2190 		}
2191 		numipfilters++;
2192 	}
2193 
2194 	ipfilters[i] = f;
2195 }
2196 
2197 /*
2198 =================
2199 SV_RemoveIP_f
2200 =================
2201 */
SV_RemoveIP_f(void)2202 static void SV_RemoveIP_f (void)
2203 {
2204 	ipfilter_t	f;
2205 	int			i, j;
2206 
2207 	if (!StringToFilter (Cmd_Argv(1), &f))
2208 	{
2209 		Con_Printf ("Bad filter address: %s\n", Cmd_Argv(1));
2210 		return;
2211 	}
2212 
2213 	for (i=0 ; i<numipfilters ; i++)
2214 		if (ipfilters[i].mask == f.mask
2215 		        && ipfilters[i].compare == f.compare)
2216 		{
2217 			for (j=i+1 ; j<numipfilters ; j++)
2218 				ipfilters[j-1] = ipfilters[j];
2219 			numipfilters--;
2220 			Con_Printf ("Removed.\n");
2221 			return;
2222 		}
2223 	Con_Printf ("Didn't find %s.\n", Cmd_Argv(1));
2224 }
2225 
2226 /*
2227 =================
2228 SV_ListIP_f
2229 =================
2230 */
SV_ListIP_f(void)2231 static void SV_ListIP_f (void)
2232 {
2233 	time_t	long_time = time(NULL);
2234 	int		i;
2235 	byte	b[4];
2236 
2237 	Con_Printf ("Filter list:\n");
2238 	for (i=0 ; i<numipfilters ; i++)
2239 	{
2240 		*(unsigned *)b = ipfilters[i].compare;
2241 		Con_Printf ("%3i.%3i.%3i.%3i | ", b[0], b[1], b[2], b[3]);
2242 		switch((int)ipfilters[i].type){
2243 			case ipft_ban:  Con_Printf (" ban"); break;
2244 			case ipft_safe: Con_Printf ("safe"); break;
2245 			default: Con_Printf ("unkn"); break;
2246 		}
2247 		if (ipfilters[i].time)
2248 			Con_Printf (" | %i s", (int)(ipfilters[i].time-long_time));
2249 		Con_Printf ("\n");
2250 	}
2251 }
2252 
2253 /*
2254 =================
2255 SV_WriteIP_f
2256 =================
2257 */
SV_WriteIP_f(void)2258 static void SV_WriteIP_f (void)
2259 {
2260 	FILE	*f;
2261 	char	name[MAX_OSPATH], *s;
2262 	byte	b[4];
2263 	int		i;
2264 
2265 	snprintf (name, MAX_OSPATH, "%s/listip.cfg", fs_gamedir);
2266 
2267 	Con_Printf ("Writing %s.\n", name);
2268 
2269 	f = fopen (name, "wb");
2270 	if (!f)
2271 	{
2272 		Con_Printf ("Couldn't open %s\n", name);
2273 		return;
2274 	}
2275 
2276 	// write safe filters first
2277 	for (i=0 ; i<numipfilters ; i++)
2278 	{
2279 		if(ipfilters[i].type != ipft_safe)
2280 			continue;
2281 
2282 		*(unsigned *)b = ipfilters[i].compare;
2283 		fprintf (f, "addip %i.%i.%i.%i safe %.0f\n", b[0], b[1], b[2], b[3], ipfilters[i].time);
2284 	}
2285 
2286 	for (i=0 ; i<numipfilters ; i++)
2287 	{
2288 		if(ipfilters[i].type == ipft_safe)
2289 			continue; // ignore safe, we already save it
2290 
2291 		switch((int)ipfilters[i].type){
2292 			case ipft_ban:  s = " ban"; break;
2293 			case ipft_safe: s = "safe"; break;
2294 			default: s = "unkn"; break;
2295 		}
2296 		*(unsigned *)b = ipfilters[i].compare;
2297 		fprintf (f, "addip %i.%i.%i.%i %s %.0f\n", b[0], b[1], b[2], b[3], s, ipfilters[i].time);
2298 	}
2299 
2300 	fclose (f);
2301 
2302 	// force cache rebuild.
2303 	FS_FlushFSHash();
2304 }
2305 
2306 /*
2307 =================
2308 SV_SendBan
2309 =================
2310 */
SV_SendBan(void)2311 void SV_SendBan (void)
2312 {
2313 	char		data[128];
2314 
2315 	data[0] = data[1] = data[2] = data[3] = 0xff;
2316 	data[4] = A2C_PRINT;
2317 	data[5] = 0;
2318 	strlcat (data, "\nbanned.\n", sizeof(data));
2319 
2320 	NET_SendPacket (NS_SERVER, strlen(data), data, net_from);
2321 }
2322 
2323 /*
2324 =================
2325 SV_FilterPacket
2326 =================
2327 */
SV_FilterPacket(void)2328 qbool SV_FilterPacket (void)
2329 {
2330 	int		i;
2331 	unsigned	in;
2332 
2333 	in = *(unsigned *)net_from.ip;
2334 
2335 	for (i=0 ; i<numipfilters ; i++)
2336 		if ( ipfilters[i].type == ipft_ban && (in & ipfilters[i].mask) == ipfilters[i].compare )
2337 			return (int)filterban.value;
2338 
2339 	return !(int)filterban.value;
2340 }
2341 
2342 // { server internal BAN support
2343 
2344 #define AF_REAL_ADMIN    (1<<1)    // pass/vip granted admin.
2345 
Do_BanList(ipfiltertype_t ipft)2346 void Do_BanList(ipfiltertype_t ipft)
2347 {
2348 	time_t	long_time = time(NULL);
2349 	int		i;
2350 	byte	b[4];
2351 
2352 	for (i=0 ; i<numipfilters ; i++)
2353 	{
2354 		if (ipfilters[i].type != ipft)
2355 			continue;
2356 
2357 		*(unsigned *)b = ipfilters[i].compare;
2358 		Con_Printf ("%3i|%3i.%3i.%3i.%3i", i, b[0], b[1], b[2], b[3]);
2359 		switch((int)ipfilters[i].type){
2360 			case ipft_ban:  Con_Printf ("| ban"); break;
2361 			case ipft_safe: Con_Printf ("|safe"); break;
2362 			default: Con_Printf ("|unkn"); break;
2363 		}
2364 
2365 		if (ipfilters[i].time) {
2366 			long df = ipfilters[i].time-long_time;
2367 			long d, h, m, s;
2368 			d = df / (60*60*24);
2369 			df -= d * 60*60*24;
2370 			h = df / (60*60);
2371 			df -= h * 60*60;
2372 			m = df /  60;
2373 			df -= m * 60;
2374 			s = df;
2375 
2376 			if (d)
2377 				Con_Printf ("|%4ldd:%2ldh", d, h);
2378 			else if (h)
2379 				Con_Printf ("|%4ldh:%2ldm", h, m);
2380 			else
2381 				Con_Printf ("|%4ldm:%2lds", m, s);
2382 		}
2383 		else
2384 			Con_Printf ("|permanent");
2385 		Con_Printf ("\n");
2386 	}
2387 }
2388 
SV_BanList(void)2389 void SV_BanList (void)
2390 {
2391 	unsigned char blist[64] = "Ban list:", id[64] = "id", ipmask[64] = "ip mask", type[64] = "type", expire[64] = "expire";
2392 
2393 	if (numipfilters < 1) {
2394 		Con_Printf ("Ban list: empty\n");
2395 		return;
2396 	}
2397 
2398 	Con_Printf ("%s\n"
2399 				"\235\236\236\236\236\236\236\236\236\236\236\236\236\236\236\236"
2400 				"\236\236\236\236\236\236\236\236\236\236\236\236\236\236\236\236\236\237\n"
2401 				"%3.3s|%15.15s|%4.4s|%9.9s\n",
2402 				Q_redtext(blist), Q_redtext(id), Q_redtext(ipmask), Q_redtext(type), Q_redtext(expire));
2403 
2404 	Do_BanList(ipft_safe);
2405 	Do_BanList(ipft_ban);
2406 }
2407 
SV_CanAddBan(ipfilter_t * f)2408 qbool SV_CanAddBan (ipfilter_t *f)
2409 {
2410 	int i;
2411 
2412 	if (f->compare == 0)
2413 		return false;
2414 
2415 	for (i=0 ; i<numipfilters ; i++)
2416 		if (ipfilters[i].mask == f->mask && ipfilters[i].compare == f->compare && ipfilters[i].type == ipft_safe)
2417 			return false; // can't add filter f because present "safe" filter
2418 
2419 	return true;
2420 }
2421 
SV_RemoveBansIPFilter(int i)2422 void SV_RemoveBansIPFilter (int i)
2423 {
2424 	for (; i + 1 < numipfilters; i++)
2425 		ipfilters[i] = ipfilters[i + 1];
2426 
2427 	numipfilters--;
2428 }
2429 
SV_CleanBansIPList(void)2430 void SV_CleanBansIPList (void)
2431 {
2432 	time_t	long_time = time(NULL);
2433 	int     i;
2434 
2435 	if (sv.state != ss_active)
2436 		return;
2437 
2438 	for (i = 0; i < numipfilters;)
2439 	{
2440 		if (ipfilters[i].time && ipfilters[i].time <= long_time)
2441 		{
2442 			SV_RemoveBansIPFilter (i);
2443 		}
2444 		else
2445 			i++;
2446 	}
2447 }
2448 
SV_Cmd_Ban_f(void)2449 void SV_Cmd_Ban_f(void)
2450 {
2451 	edict_t	*ent;
2452 	eval_t *val;
2453 	double		d;
2454 	int			i, j, t;
2455 	client_t	*cl;
2456 	ipfilter_t  f;
2457 	int			uid;
2458 	int			c;
2459 	char		reason[80] = "", arg2[32], arg2c[sizeof(arg2)], *s;
2460 
2461 	// set up the edict
2462 	ent = sv_client->edict;
2463 
2464 // ============
2465 // get ADMIN rights from MOD via "mod_admin" field, mod MUST export such field if wanna server ban support
2466 // ============
2467 
2468 	val = PR_GetEdictFieldValue(ent, "mod_admin");
2469 	if (!val || !(val->_int & AF_REAL_ADMIN) ) {
2470 		Con_Printf("You are not an admin\n");
2471 		return;
2472 	}
2473 
2474 	c = Cmd_Argc ();
2475 	if (c < 3)
2476 	{
2477 		Con_Printf("usage: cmd ban <id/nick> <time<s m h d>> [reason]\n");
2478 		return;
2479 	}
2480 
2481 	uid = Q_atoi(Cmd_Argv(1));
2482 
2483 	strlcpy(arg2, Cmd_Argv(2), sizeof(arg2));
2484 
2485 	// sscanf safe here since sizeof(arg2) == sizeof(arg2c), right?
2486 	if (sscanf(arg2, "%d%s", &t, arg2c) != 2 || strlen(arg2c) != 1) {
2487 		Con_Printf("ban: wrong time arg\n");
2488 		return;
2489 	}
2490 
2491 	d = t = bound(0, t, 999);
2492 	switch(arg2c[0]) {
2493 		case 's': break; // seconds is seconds
2494 		case 'm': d *= 60; break; // 60 seconds per minute
2495 		case 'h': d *= 60*60; break; // 3600 seconds per hour
2496 		case 'd': d *= 60*60*24; break; // 86400 seconds per day
2497 		default:
2498 		Con_Printf("ban: wrong time arg\n");
2499 		return;
2500 	}
2501 
2502 	for (i = 0, cl = svs.clients; i < MAX_CLIENTS; i++, cl++)
2503 	{
2504 		if (!cl->state)
2505 			continue;
2506 		if (cl->userid == uid || !strcmp(Cmd_Argv(1), cl->name))
2507 		{
2508 			if (c > 3) // serve reason arguments
2509 			{
2510 				strlcpy (reason, " (", sizeof(reason));
2511 				for (j=3 ; j<c; j++)
2512 				{
2513 					strlcat (reason, Cmd_Argv(j), sizeof(reason)-4);
2514 					if (j < c-1)
2515 						strlcat (reason, " ", sizeof(reason)-4);
2516 				}
2517 				if (strlen(reason) < 3)
2518 					reason[0] = '\0';
2519 				else
2520 					strlcat (reason, ")", sizeof(reason));
2521 			}
2522 
2523 			s = NET_BaseAdrToString(cl->netchan.remote_address);
2524 			if (!StringToFilter (s, &f))
2525 			{
2526 				Con_Printf ("ban: bad ip address: %s\n", s);
2527 				return;
2528 			}
2529 
2530 			if (!SV_CanAddBan(&f))
2531 			{
2532 				Con_Printf ("ban: can't ban such ip: %s\n", s);
2533 				return;
2534 			}
2535 
2536 			SV_BroadcastPrintf (PRINT_HIGH, "%s was banned for %d%s%s\n", cl->name, t, arg2c, reason);
2537 
2538 			Cbuf_AddText(va("addip %s ban %s%.0lf\n", s, d ? "+" : "", d));
2539 			Cbuf_AddText("writeip\n");
2540 			return;
2541 		}
2542 	}
2543 
2544 	Con_Printf ("Couldn't find user %s\n", Cmd_Argv(1));
2545 }
2546 
SV_Cmd_Banip_f(void)2547 void SV_Cmd_Banip_f(void)
2548 {
2549 	edict_t	*ent;
2550 	eval_t *val;
2551 	byte	b[4];
2552 	double		d;
2553 	int			c, t;
2554 	ipfilter_t  f;
2555 	char		arg2[32], arg2c[sizeof(arg2)];
2556 
2557 	// set up the edict
2558 	ent = sv_client->edict;
2559 
2560 // ============
2561 // get ADMIN rights from MOD via "mod_admin" field, mod MUST export such field if wanna server ban support
2562 // ============
2563 
2564 	val = PR_GetEdictFieldValue(ent, "mod_admin");
2565 	if (!val || !(val->_int & AF_REAL_ADMIN) ) {
2566 		Con_Printf("You are not an admin\n");
2567 		return;
2568 	}
2569 
2570 	c = Cmd_Argc ();
2571 	if (c < 3)
2572 	{
2573 		Con_Printf("usage: cmd banip <ip> <time<s m h d>>\n");
2574 		return;
2575 	}
2576 
2577 	if (!StringToFilter (Cmd_Argv(1), &f))
2578 	{
2579 		Con_Printf ("ban: bad ip address: %s\n", Cmd_Argv(1));
2580 		return;
2581 	}
2582 
2583 	if (!SV_CanAddBan(&f))
2584 	{
2585 		Con_Printf ("ban: can't ban such ip: %s\n", Cmd_Argv(1));
2586 		return;
2587 	}
2588 
2589 	strlcpy(arg2, Cmd_Argv(2), sizeof(arg2));
2590 
2591 	// sscanf safe here since sizeof(arg2) == sizeof(arg2c), right?
2592 	if (sscanf(arg2, "%d%s", &t, arg2c) != 2 || strlen(arg2c) != 1) {
2593 		Con_Printf("ban: wrong time arg\n");
2594 		return;
2595 	}
2596 
2597 	d = t = bound(0, t, 999);
2598 	switch(arg2c[0]) {
2599 		case 's': break; // seconds is seconds
2600 		case 'm': d *= 60; break; // 60 seconds per minute
2601 		case 'h': d *= 60*60; break; // 3600 seconds per hour
2602 		case 'd': d *= 60*60*24; break; // 86400 seconds per day
2603 		default:
2604 		Con_Printf("ban: wrong time arg\n");
2605 		return;
2606 	}
2607 
2608 	*(unsigned *)b = f.compare;
2609 	SV_BroadcastPrintf (PRINT_HIGH, "%3i.%3i.%3i.%3i was banned for %d%s\n", b[0], b[1], b[2], b[3], t, arg2c);
2610 
2611 	Cbuf_AddText(va("addip %i.%i.%i.%i ban %s%.0lf\n", b[0], b[1], b[2], b[3], d ? "+" : "", d));
2612 	Cbuf_AddText("writeip\n");
2613 }
2614 
SV_Cmd_Banremove_f(void)2615 void SV_Cmd_Banremove_f(void)
2616 {
2617 	edict_t	*ent;
2618 	eval_t *val;
2619 	byte	b[4];
2620 	int		id;
2621 
2622 	// set up the edict
2623 	ent = sv_client->edict;
2624 
2625 // ============
2626 // get ADMIN rights from MOD via "mod_admin" field, mod MUST export such field if wanna server ban support
2627 // ============
2628 
2629 	val = PR_GetEdictFieldValue(ent, "mod_admin");
2630 	if (!val || !(val->_int & AF_REAL_ADMIN) ) {
2631 		Con_Printf("You are not an admin\n");
2632 		return;
2633 	}
2634 
2635 	if (Cmd_Argc () < 2)
2636 	{
2637 		Con_Printf("usage: cmd banrem [banid]\n");
2638 		SV_BanList();
2639 		return;
2640 	}
2641 
2642 	id = Q_atoi(Cmd_Argv(1));
2643 
2644 	if (id < 0 || id >= numipfilters) {
2645 		Con_Printf ("Wrong ban id: %d\n", id);
2646 		return;
2647 	}
2648 
2649 	if (ipfilters[id].type == ipft_safe) {
2650 		Con_Printf ("Can't remove such ban with id: %d\n", id);
2651 		return;
2652 	}
2653 
2654 	*(unsigned *)b = ipfilters[id].compare;
2655 	SV_BroadcastPrintf (PRINT_HIGH, "%3i.%3i.%3i.%3i was unbanned\n", b[0], b[1], b[2], b[3]);
2656 
2657 	SV_RemoveBansIPFilter (id);
2658 	Cbuf_AddText("writeip\n");
2659 }
2660 
2661 // } server internal BAN support
2662 
2663 /*
2664 =================
2665 SV_VIPbyIP
2666 =================
2667 */
SV_VIPbyIP(netadr_t adr)2668 int SV_VIPbyIP (netadr_t adr)
2669 {
2670 	int		i;
2671 	unsigned	in;
2672 
2673 	in = *(unsigned *)adr.ip;
2674 
2675 	for (i=0 ; i<numipvips ; i++)
2676 		if ( (in & ipvip[i].mask) == ipvip[i].compare)
2677 			return ipvip[i].level;
2678 
2679 	return 0;
2680 }
2681 
2682 /*
2683 =================
2684 SV_VIPbyPass
2685 =================
2686 */
SV_VIPbyPass(char * pass)2687 int SV_VIPbyPass (char *pass)
2688 {
2689 	qbool use_value = false;
2690 	int vip_value[MAX_ARGS];
2691 	int i;
2692 
2693 	if (!vip_password.string[0] || !strcasecmp(vip_password.string, "none"))
2694 		return 0;
2695 
2696 	if (vip_values.string[0]) {
2697 		use_value = true;
2698 		// 2VVD: vip_password count may be not equal vip_values count, what we must do in this case?
2699 		memset((void*)vip_value, 0, sizeof(vip_value));
2700 		Cmd_TokenizeString(vip_values.string);
2701 		for (i = 0; i < Cmd_Argc(); i++)
2702 			vip_value[i] = atoi(Cmd_Argv(i));
2703 	}
2704 
2705 	Cmd_TokenizeString(vip_password.string);
2706 
2707 	for (i = 0; i < Cmd_Argc(); i++)
2708 		if (!strcmp(Cmd_Argv(i), pass) && strcasecmp(Cmd_Argv(i), "none"))
2709 			return (use_value ? vip_value[i] : i+1);
2710 
2711 	return 0;
2712 }
2713 
DecodeArgs(char * args)2714 static char *DecodeArgs(char *args)
2715 {
2716 	static char string[1024];
2717 	char *p, key[32], *s, *value, ch, tmp_value[512];
2718 
2719 	string[0] = 0;
2720 	p = string;
2721 
2722 	while (*args)
2723 	{
2724 		// skip whitespaces
2725 		while (*args && *args <= 32)
2726 			*p++ = *args++;
2727 
2728 		if (*args == '\"')
2729 		{
2730 			do *p++ = *args++; while (*args && *args != '\"');
2731 			*p++ = '\"';
2732 			if (*args)
2733 				args++;
2734 		}
2735 		else if (*args == '@' || *args == '$')
2736 		{
2737 			// get the key and read value from localinfo
2738 			ch = *args;
2739 			s = key;
2740 			args++;
2741 			while (*args > 32)
2742 				*s++ = *args++;
2743 			*s = 0;
2744 
2745 			if ((value = Info_ValueForKey (svs.info, key)) == NULL || !*value)
2746 				value = Info_Get(&_localinfo_, key);
2747 
2748 			if (ch == '$' && value)
2749 			{
2750 				strlcpy(tmp_value, value, sizeof(tmp_value));
2751 				Q_normalizetext(tmp_value);
2752 				value = tmp_value;
2753 			}
2754 
2755 			*p++ = '\"';
2756 			if (value)
2757 			{
2758 				while (*value)
2759 					*p++ = *value++;
2760 			}
2761 			*p++ = '\"';
2762 		}
2763 		else {
2764 			while (*args > 32) {
2765 				*p++ = *args++;
2766 			}
2767 		}
2768 	}
2769 
2770 	*p = 0;
2771 
2772 	return string;
2773 }
2774 
SV_Script_f(void)2775 void SV_Script_f (void)
2776 {
2777 	char *path, *p;
2778 	extern redirect_t sv_redirected;
2779 
2780 	if (Cmd_Argc() < 2)
2781 	{
2782 		Con_Printf("usage: script <path> [<args>]\n");
2783 		return;
2784 	}
2785 
2786 	path = Cmd_Argv(1);
2787 
2788 	//bliP: 24/9 need subdirs here ->
2789 	if (!strncmp(path, "../", 3) || !strncmp(path, "..\\", 3))
2790 		path += 3;
2791 
2792 	if (strstr(path, ".."))
2793 	{
2794 		Con_Printf("Invalid path.\n");
2795 		return;
2796 	}
2797 	//<-
2798 
2799 	path = Cmd_Argv(1);
2800 
2801 	p = Cmd_Args();
2802 	while (*p > 32)
2803 		p++;
2804 	while (*p && *p <= 32)
2805 		p++;
2806 
2807 	p = DecodeArgs(p);
2808 
2809 	if (sv_redirected != RD_MOD)
2810 		Sys_Printf("Running %s.qws\n", path);
2811 
2812 	Sys_Script(path, va("%d %s", sv_redirected, p));
2813 
2814 }
2815 
2816 //============================================================================
2817 
2818 //bliP: cuff, mute ->
SV_RemoveIPFilter(int i)2819 void SV_RemoveIPFilter (int i)
2820 {
2821 	for (; i + 1 < numpenfilters; i++)
2822 		penfilters[i] = penfilters[i + 1];
2823 
2824 	numpenfilters--;
2825 }
2826 
SV_CleanIPList(void)2827 static void SV_CleanIPList (void)
2828 {
2829 	int     i;
2830 
2831 	if (sv.state != ss_active)
2832 		return;
2833 
2834 	for (i = 0; i < numpenfilters;)
2835 	{
2836 		if (penfilters[i].time && (penfilters[i].time <= realtime))
2837 		{
2838 			SV_RemoveIPFilter (i);
2839 		}
2840 		else
2841 			i++;
2842 	}
2843 }
2844 
SV_IPCompare(byte * a,byte * b)2845 static qbool SV_IPCompare (byte *a, byte *b)
2846 {
2847 	int i;
2848 
2849 	for (i = 0; i < 1; i++)
2850 		if (((unsigned int *)a)[i] != ((unsigned int *)b)[i])
2851 			return false;
2852 
2853 	return true;
2854 }
2855 
SV_IPCopy(byte * dest,byte * src)2856 static void SV_IPCopy (byte *dest, byte *src)
2857 {
2858 	int i;
2859 
2860 	for (i = 0; i < 1; i++)
2861 		((unsigned int *)dest)[i] = ((unsigned int *)src)[i];
2862 }
2863 
SV_SavePenaltyFilter(client_t * cl,filtertype_t type,double pentime)2864 void SV_SavePenaltyFilter (client_t *cl, filtertype_t type, double pentime)
2865 {
2866 	int i;
2867 
2868 	if (pentime < curtime)   // no point
2869 		return;
2870 
2871 	for (i = 0; i < numpenfilters; i++)
2872 		if (SV_IPCompare (penfilters[i].ip, cl->realip.ip)	&& penfilters[i].type == type)
2873 		{
2874 			return;
2875 		}
2876 
2877 	if (numpenfilters == MAX_IPFILTERS)
2878 	{
2879 		return;
2880 	}
2881 
2882 	SV_IPCopy (penfilters[numpenfilters].ip, cl->realip.ip);
2883 	penfilters[numpenfilters].time = pentime;
2884 	penfilters[numpenfilters].type = type;
2885 	numpenfilters++;
2886 }
2887 
SV_RestorePenaltyFilter(client_t * cl,filtertype_t type)2888 double SV_RestorePenaltyFilter (client_t *cl, filtertype_t type)
2889 {
2890 	int i;
2891 	double time1 = 0.0;
2892 
2893 	// search for existing penalty filter of same type
2894 	for (i = 0; i < numpenfilters; i++)
2895 	{
2896 		if (type == penfilters[i].type && SV_IPCompare (cl->realip.ip, penfilters[i].ip))
2897 		{
2898 			time1 = penfilters[i].time;
2899 			SV_RemoveIPFilter (i);
2900 			return time1;
2901 		}
2902 	}
2903 	return time1;
2904 }
2905 //<-
2906 
2907 //============================================================================
2908 
2909 /*
2910 =================
2911 SV_ReadPackets
2912 =================
2913 */
SV_ReadPackets(void)2914 static void SV_ReadPackets (void)
2915 {
2916 	client_t *cl;
2917 	int qport;
2918 	int i;
2919 
2920 	if (sv.state != ss_active)
2921 		return;
2922 
2923 	// first deal with delayed packets from connected clients
2924 	for (i = 0, cl=svs.clients; i < MAX_CLIENTS; i++, cl++)
2925 	{
2926 		if (cl->state == cs_free)
2927 			continue;
2928 
2929 		net_from = cl->netchan.remote_address;
2930 
2931 		while (cl->packets && (realtime - cl->packets->time >= cl->delay || sv.paused))
2932 		{
2933 			SZ_Clear(&net_message);
2934 			SZ_Write(&net_message, cl->packets->msg.data, cl->packets->msg.cursize);
2935 			SV_ExecuteClientMessage(cl);
2936 			SV_FreeHeadDelayedPacket(cl);
2937 		}
2938 	}
2939 
2940 	// now deal with new packets
2941 	while (NET_GetPacket(NS_SERVER))
2942 	{
2943 		if (SV_FilterPacket ())
2944 		{
2945 			SV_SendBan ();	// tell them we aren't listening...
2946 			continue;
2947 		}
2948 
2949 		// check for connectionless packet (0xffffffff) first
2950 		if (*(int *)net_message.data == -1)
2951 		{
2952 			SV_ConnectionlessPacket ();
2953 			continue;
2954 		}
2955 
2956 		// read the qport out of the message so we can fix up
2957 		// stupid address translating routers
2958 		MSG_BeginReading ();
2959 		MSG_ReadLong (); // sequence number
2960 		MSG_ReadLong (); // sequence number
2961 		qport = MSG_ReadShort () & 0xffff;
2962 
2963 		// check which client sent this packet
2964 		for (i=0, cl=svs.clients ; i<MAX_CLIENTS ; i++,cl++)
2965 		{
2966 			if (cl->state == cs_free)
2967 				continue;
2968 			if (!NET_CompareBaseAdr (net_from, cl->netchan.remote_address))
2969 				continue;
2970 			if (cl->netchan.qport != qport)
2971 				continue;
2972 			if (cl->netchan.remote_address.port != net_from.port)
2973 			{
2974 				Con_DPrintf ("SV_ReadPackets: fixing up a translated port\n");
2975 				cl->netchan.remote_address.port = net_from.port;
2976 			}
2977 
2978 			break;
2979 		}
2980 
2981 		if (i == MAX_CLIENTS)
2982 			continue;
2983 
2984 		// ok, we know who sent this packet, but do we need to delay executing it?
2985 		if (cl->delay > 0)
2986 		{
2987 			if (!svs.free_packets) // packet has to be dropped..
2988 				break;
2989 
2990 			// insert at end of list
2991 			if (!cl->packets) {
2992 				cl->last_packet = cl->packets = svs.free_packets;
2993 			} else {
2994 				// this works because '=' associates from right to left
2995 				cl->last_packet = cl->last_packet->next = svs.free_packets;
2996 			}
2997 
2998 			svs.free_packets = svs.free_packets->next;
2999 			cl->last_packet->next = NULL;
3000 
3001 			cl->last_packet->time = realtime;
3002 			SZ_Clear(&cl->last_packet->msg);
3003 			SZ_Write(&cl->last_packet->msg, net_message.data, net_message.cursize);
3004 		}
3005 		else
3006 		{
3007 			SV_ExecuteClientMessage (cl);
3008 		}
3009 	}
3010 }
3011 
3012 
3013 /*
3014 ==================
3015 SV_CheckTimeouts
3016 
3017 If a packet has not been received from a client in timeout.value
3018 seconds, drop the conneciton.
3019 
3020 When a client is normally dropped, the client_t goes into a zombie state
3021 for a few seconds to make sure any final reliable message gets resent
3022 if necessary
3023 ==================
3024 */
SV_CheckTimeouts(void)3025 static void SV_CheckTimeouts (void)
3026 {
3027 	int i, nclients;
3028 	float droptime;
3029 	client_t *cl;
3030 
3031 	if (sv.state != ss_active)
3032 		return;
3033 
3034 	droptime = curtime - timeout.value;
3035 	nclients = 0;
3036 
3037 	for (i=0,cl=svs.clients ; i<MAX_CLIENTS ; i++,cl++)
3038 	{
3039 #ifdef USE_PR2
3040 		if( cl->isBot )
3041 			continue;
3042 #endif
3043 		if (cl->state >= cs_preconnected /*|| cl->state == cs_spawned*/)
3044 		{
3045 			if (!cl->spectator)
3046 				nclients++;
3047 			if (cl->netchan.last_received < droptime)
3048 			{
3049 				SV_BroadcastPrintf (PRINT_HIGH, "%s timed out\n", cl->name);
3050 				SV_DropClient (cl);
3051 				cl->state = cs_free;	// don't bother with zombie state
3052 			}
3053 			if (!cl->logged && !cl->logged_in_via_web) {
3054 				SV_LoginCheckTimeOut(cl);
3055 			}
3056 		}
3057 		if (cl->state == cs_zombie && SV_ClientConnectedTime(cl) > zombietime.value)
3058 		{
3059 			cl->state = cs_free;	// can now be reused
3060 		}
3061 	}
3062 	if ((sv.paused & 1) && !nclients)
3063 	{
3064 		// nobody left, unpause the server
3065 		if (GE_ShouldPause) {
3066 			pr_global_struct->time = sv.time;
3067 			pr_global_struct->self = EDICT_TO_PROG(sv.edicts);
3068 			G_FLOAT(OFS_PARM0) = 0 /* newstate = false */;
3069 			PR_ExecuteProgram (GE_ShouldPause);
3070 			if (!G_FLOAT(OFS_RETURN))
3071 				return;		// progs said don't unpause
3072 		}
3073 		SV_TogglePause("Pause released since no players are left.\n", 1);
3074 	}
3075 }
3076 
3077 #ifdef SERVERONLY
3078 /*
3079 ===================
3080 SV_GetConsoleCommands
3081 
3082 Add them exactly as if they had been typed at the console
3083 ===================
3084 */
SV_GetConsoleCommands(void)3085 static void SV_GetConsoleCommands (void)
3086 {
3087 	char	*cmd;
3088 
3089 	while (1)
3090 	{
3091 		cmd = Sys_ConsoleInput ();
3092 		if (!cmd)
3093 			break;
3094 		Cbuf_AddText (cmd);
3095 		Cbuf_AddText ("\n");
3096 	}
3097 }
3098 #endif
3099 
3100 /*
3101 ===================
3102 SV_BoundRate
3103 ===================
3104 */
SV_BoundRate(qbool dl,int rate)3105 int SV_BoundRate (qbool dl, int rate)
3106 {
3107 	if (!rate)
3108 		rate = 2500;
3109 	if (dl)
3110 	{
3111 		if (!(int)sv_maxdownloadrate.value && (int)sv_maxrate.value && rate > (int)sv_maxrate.value)
3112 			rate = (int)sv_maxrate.value;
3113 
3114 		if (sv_maxdownloadrate.value && rate > sv_maxdownloadrate.value)
3115 			rate = (int)sv_maxdownloadrate.value;
3116 	}
3117 	else
3118 		if ((int)sv_maxrate.value && rate > (int) sv_maxrate.value)
3119 			rate = (int)sv_maxrate.value;
3120 
3121 	if (rate < 500)
3122 		rate = 500;
3123 
3124 	if (rate > 100000 * MAX_DUPLICATE_PACKETS)
3125 		rate = 100000 * MAX_DUPLICATE_PACKETS;
3126 
3127 	return rate;
3128 }
3129 
3130 
3131 /*
3132 ===================
3133 SV_CheckVars
3134 
3135 ===================
3136 */
3137 
SV_CheckVars(void)3138 static void SV_CheckVars (void)
3139 {
3140 	static char pw[MAX_KEY_STRING] = {0}, spw[MAX_KEY_STRING] = {0}, vspw[MAX_KEY_STRING]= {0};
3141 	static float old_maxrate = 0, old_maxdlrate = 0;
3142 	int v;
3143 
3144 	if (sv.state != ss_active)
3145 		return;
3146 
3147 	// check password and spectator_password
3148 	if (strcmp(password.string, pw) ||
3149 		strcmp(spectator_password.string, spw) || strcmp(vip_password.string, vspw))
3150 	{
3151 		strlcpy (pw, password.string, sizeof(pw));
3152 		strlcpy (spw, spectator_password.string, sizeof(spw));
3153 		strlcpy (vspw, vip_password.string, sizeof(vspw));
3154 		Cvar_Set (&password, pw);
3155 		Cvar_Set (&spectator_password, spw);
3156 		Cvar_Set (&vip_password, vspw);
3157 
3158 		v = 0;
3159 		if (pw[0] && strcmp(pw, "none"))
3160 			v |= 1;
3161 		if (spw[0] && strcmp(spw, "none"))
3162 			v |= 2;
3163 		if (vspw[0] && strcmp(vspw, "none"))
3164 			v |= 4;
3165 
3166 		Con_DPrintf ("Updated needpass.\n");
3167 		if (!v)
3168 			Info_SetValueForKey (svs.info, "needpass", "", MAX_SERVERINFO_STRING);
3169 		else
3170 			Info_SetValueForKey (svs.info, "needpass", va("%i",v), MAX_SERVERINFO_STRING);
3171 	}
3172 
3173 	// check sv_maxrate
3174 	if ((int)sv_maxrate.value != old_maxrate || (int)sv_maxdownloadrate.value != old_maxdlrate )
3175 	{
3176 		client_t	*cl;
3177 		int			i;
3178 		char		*val;
3179 
3180 		old_maxrate = (int)sv_maxrate.value;
3181 		old_maxdlrate = (int)sv_maxdownloadrate.value;
3182 
3183 		for (i=0, cl = svs.clients ; i<MAX_CLIENTS ; i++, cl++)
3184 		{
3185 			if (cl->state < cs_preconnected)
3186 				continue;
3187 
3188 			val = Info_Get (&cl->_userinfo_ctx_, cl->download ? "drate" : "rate");
3189 			cl->netchan.rate = 1.0 / SV_BoundRate (cl->download != NULL, Q_atoi(*val ? val : "99999"));
3190 		}
3191 	}
3192 }
3193 
PausedTic(void)3194 static void PausedTic (void)
3195 {
3196 	if (sv.state != ss_active)
3197 		return;
3198 
3199 	PR_PausedTic(Sys_DoubleTime() - sv.pausedsince);
3200 }
3201 
3202 /*
3203 ==================
3204 SV_Frame
3205 
3206 ==================
3207 */
3208 void SV_Map (qbool now);
SV_Frame(double time1)3209 void SV_Frame (double time1)
3210 {
3211 	static double start, end;
3212 	double demo_start, demo_end;
3213 
3214 	start = Sys_DoubleTime ();
3215 	svs.stats.idle += start - end;
3216 
3217 	// keep the random time dependent
3218 	rand ();
3219 
3220 	// decide the simulation time
3221 	if (!sv.paused)
3222 	{
3223 		realtime += time1;
3224 		sv.time += time1;
3225 	}
3226 
3227 	// check timeouts
3228 	SV_CheckTimeouts ();
3229 
3230 	//bliP: cuff, mute ->
3231 	// clean out expired cuffs/mutes
3232 	SV_CleanIPList ();
3233 	//<-
3234 
3235 	// clean out bans
3236 	SV_CleanBansIPList ();
3237 
3238 	// toggle the log buffer if full
3239 	SV_CheckLog ();
3240 
3241 	SV_MVDStream_Poll();
3242 
3243 #ifdef SERVERONLY
3244 	// check for commands typed to the host
3245 	SV_GetConsoleCommands ();
3246 
3247 	// process console commands
3248 	Cbuf_Execute ();
3249 #endif
3250 
3251 	// check for map change;
3252 	SV_Map(true);
3253 
3254 	SV_CheckVars ();
3255 
3256 	// get packets
3257 	SV_ReadPackets ();
3258 
3259 	// move autonomous things around if enough time has passed
3260 	if (!sv.paused) {
3261 		SV_Physics();
3262 #ifdef USE_PR2
3263 		SV_RunBots();
3264 #endif
3265 	}
3266 	else
3267 		PausedTic ();
3268 
3269 	// send messages back to the clients that had packets read this frame
3270 	SV_SendClientMessages ();
3271 
3272 #if defined(SERVERONLY) && defined(WWW_INTEGRATION)
3273 	Central_ProcessResponses();
3274 #endif
3275 
3276 	demo_start = Sys_DoubleTime ();
3277 	SV_SendDemoMessage();
3278 	demo_end = Sys_DoubleTime ();
3279 	svs.stats.demo += demo_end - demo_start;
3280 
3281 	// send a heartbeat to the master if needed
3282 	Master_Heartbeat ();
3283 
3284 	// collect timing statistics
3285 	end = Sys_DoubleTime ();
3286 	svs.stats.active += end-start;
3287 	if (++svs.stats.count == STATFRAMES)
3288 	{
3289 		svs.stats.latched_active = svs.stats.active;
3290 		svs.stats.latched_idle = svs.stats.idle;
3291 		svs.stats.latched_packets = svs.stats.packets;
3292 		svs.stats.latched_demo = svs.stats.demo;
3293 		svs.stats.active = 0;
3294 		svs.stats.idle = 0;
3295 		svs.stats.packets = 0;
3296 		svs.stats.count = 0;
3297 		svs.stats.demo = 0;
3298 	}
3299 }
3300 
3301 /*
3302 ===============
3303 SV_InitLocal
3304 ===============
3305 */
SV_InitLocal(void)3306 void SV_InitLocal (void)
3307 {
3308 	int		i;
3309 	char	cmd_line[1024] = {0};
3310 
3311 	extern	cvar_t	sv_maxvelocity;
3312 	extern	cvar_t	sv_gravity;
3313 	extern	cvar_t	sv_stopspeed;
3314 	extern	cvar_t	sv_spectatormaxspeed;
3315 	extern	cvar_t	sv_accelerate;
3316 	extern	cvar_t	sv_airaccelerate;
3317 	extern	cvar_t	sv_wateraccelerate;
3318 	extern	cvar_t	sv_friction;
3319 	extern	cvar_t	sv_waterfriction;
3320 	extern	cvar_t	sv_nailhack;
3321 
3322 	extern cvar_t	sv_maxpitch;
3323 	extern cvar_t	sv_minpitch;
3324 
3325 	extern	cvar_t	pm_airstep;
3326 	extern	cvar_t	pm_pground;
3327 	extern  cvar_t  pm_rampjump;
3328 	//extern	cvar_t	pm_slidefix;
3329 	extern	cvar_t	pm_ktjump;
3330 	//extern	cvar_t	pm_bunnyspeedcap;
3331 
3332 	// qws = QuakeWorld Server information
3333 	static cvar_t qws_name = { "qws_name", SERVER_NAME, CVAR_ROM };
3334 	static cvar_t qws_fullname = { "qws_fullname", SERVER_FULLNAME, CVAR_ROM };
3335 	static cvar_t qws_version = { "qws_version", SERVER_VERSION, CVAR_ROM };
3336 	static cvar_t qws_buildnum = { "qws_buildnum", "unknown", CVAR_ROM };
3337 	static cvar_t qws_platform = { "qws_platform", QW_PLATFORM_SHORT, CVAR_ROM };
3338 	static cvar_t qws_builddate = { "qws_builddate", BUILD_DATE, CVAR_ROM };
3339 	static cvar_t qws_homepage = { "qws_homepage", SERVER_HOME_URL, CVAR_ROM };
3340 	// qwm = QuakeWorld Mod information placeholders
3341 	static cvar_t qwm_name = { "qwm_name", "" };
3342 	static cvar_t qwm_fullname = { "qwm_fullname", "" };
3343 	static cvar_t qwm_version = { "qwm_version", "" };
3344 	static cvar_t qwm_buildnum = { "qwm_buildnum", "" };
3345 	static cvar_t qwm_platform = { "qwm_platform", "" };
3346 	static cvar_t qwm_builddate = { "qwm_builddate", "" };
3347 	static cvar_t qwm_homepage = { "qwm_homepage", "" };
3348 
3349 	packet_t *packet_freeblock; // initialise delayed packet free block
3350 
3351 	SV_InitOperatorCommands	();
3352 	SV_UserInit ();
3353 
3354 	Cvar_Register (&sv_getrealip);
3355 	Cvar_Register (&sv_maxdownloadrate);
3356 	Cvar_Register (&sv_serverip);
3357 	Cvar_Register (&sv_forcespec_onfull);
3358 
3359 #ifdef SERVERONLY
3360 	Cvar_Register (&rcon_password);
3361 	Cvar_Register (&password);
3362 #endif
3363 
3364 	Cvar_Register (&sv_hashpasswords);
3365 	//Added by VVD {
3366 	Cvar_Register (&sv_crypt_rcon);
3367 	Cvar_Register (&sv_timestamplen);
3368 	Cvar_Register (&sv_rconlim);
3369 
3370 	Cvar_Register (&telnet_log_level);
3371 
3372 	Cvar_Register (&frag_log_type);
3373 	Cvar_Register (&qconsole_log_say);
3374 	Cvar_Register (&sv_use_dns);
3375 
3376 	for (i = 0; i < COM_Argc(); i++)
3377 	{
3378 		if (i)
3379 			strlcat(cmd_line, " ", sizeof(cmd_line));
3380 		strlcat(cmd_line, COM_Argv(i), sizeof(cmd_line));
3381 	}
3382 	Cvar_Register (&sys_command_line);
3383 	Cvar_SetROM(&sys_command_line, cmd_line);
3384 
3385 	//Added by VVD }
3386 	Cvar_Register (&spectator_password);
3387 	Cvar_Register (&vip_password);
3388 	Cvar_Register (&vip_values);
3389 
3390 	Cvar_Register (&sv_nailhack);
3391 
3392 	Cvar_Register (&sv_mintic);
3393 	Cvar_Register (&sv_maxtic);
3394 	Cvar_Register (&sv_maxfps);
3395 	Cvar_Register (&sys_select_timeout);
3396 	Cvar_Register (&sys_restart_on_error);
3397 
3398 	Cvar_Register (&sv_maxpitch);
3399 	Cvar_Register (&sv_minpitch);
3400 
3401 	Cvar_Register (&skill);
3402 	Cvar_Register (&coop);
3403 
3404 	Cvar_Register (&fraglimit);
3405 	Cvar_Register (&timelimit);
3406 	Cvar_Register (&teamplay);
3407 	Cvar_Register (&samelevel);
3408 	Cvar_Register (&maxclients);
3409 	Cvar_Register (&maxspectators);
3410 	Cvar_Register (&maxvip_spectators);
3411 	Cvar_Register (&hostname);
3412 	Cvar_Register (&deathmatch);
3413 	Cvar_Register (&watervis);
3414 	Cvar_Register (&serverdemo);
3415 	Cvar_Register (&sv_paused);
3416 
3417 	Cvar_Register (&timeout);
3418 	Cvar_Register (&zombietime);
3419 
3420 	Cvar_Register (&sv_maxvelocity);
3421 	Cvar_Register (&sv_gravity);
3422 	Cvar_Register (&sv_stopspeed);
3423 	Cvar_Register (&sv_maxspeed);
3424 	Cvar_Register (&sv_spectatormaxspeed);
3425 	Cvar_Register (&sv_accelerate);
3426 	Cvar_Register (&sv_airaccelerate);
3427 	Cvar_Register (&sv_wateraccelerate);
3428 	Cvar_Register (&sv_friction);
3429 	Cvar_Register (&sv_waterfriction);
3430 
3431 	Cvar_Register (&sv_antilag);
3432 	Cvar_Register (&sv_antilag_no_pred);
3433 	Cvar_Register (&sv_antilag_projectiles);
3434 
3435 	//Cvar_Register (&pm_bunnyspeedcap);
3436 	Cvar_Register (&pm_ktjump);
3437 	//Cvar_Register (&pm_slidefix);
3438 	Cvar_Register (&pm_pground);
3439 	Cvar_Register (&pm_airstep);
3440 	Cvar_Register (&pm_rampjump);
3441 
3442 	Cvar_Register (&filterban);
3443 
3444 	Cvar_Register (&allow_download);
3445 	Cvar_Register (&allow_download_skins);
3446 	Cvar_Register (&allow_download_models);
3447 	Cvar_Register (&allow_download_sounds);
3448 	Cvar_Register (&allow_download_maps);
3449 	Cvar_Register (&allow_download_pakmaps);
3450 	Cvar_Register (&allow_download_demos);
3451 	Cvar_Register (&allow_download_other);
3452 	//bliP: init ->
3453 	Cvar_Register (&download_map_url);
3454 
3455 	Cvar_Register (&sv_specprint);
3456 	Cvar_Register (&sv_admininfo);
3457 	Cvar_Register (&sv_reconnectlimit);
3458 	Cvar_Register (&sv_maxlogsize);
3459 	//bliP: 24/9 ->
3460 	Cvar_Register (&sv_logdir);
3461 	Cvar_Register (&sv_speedcheck);
3462 	Cvar_Register (&sv_unfake); // kickfake to unfake
3463 	//<-
3464 	Cvar_Register (&sv_kicktop);
3465 	//<-
3466 	Cvar_Register (&sv_allowlastscores);
3467 //	Cvar_Register (&sv_highchars);
3468 	Cvar_Register (&sv_phs);
3469 	Cvar_Register (&pausable);
3470 	Cvar_Register (&sv_maxrate);
3471 	Cvar_Register (&sv_loadentfiles);
3472 	Cvar_Register (&sv_loadentfiles_dir);
3473 	Cvar_Register (&sv_default_name);
3474 	Cvar_Register (&sv_mod_msg_file);
3475 	Cvar_Register (&sv_forcenick);
3476 	Cvar_Register (&sv_registrationinfo);
3477 	Cvar_Register (&registered);
3478 
3479 	Cvar_Register (&sv_halflifebsp);
3480 	Cvar_Register (&sv_bspversion);
3481 	Cvar_Register (&sv_serveme_fix);
3482 
3483 #ifdef FTE_PEXT_FLOATCOORDS
3484 	Cvar_Register (&sv_bigcoords);
3485 #endif
3486 
3487 	Cvar_Register (&sv_extlimits);
3488 	Cvar_Register (&sv_pext_mvdsv_serversideweapon);
3489 
3490 	Cvar_Register (&sv_reliable_sound);
3491 
3492 	Cvar_Register(&qws_name);
3493 	Cvar_Register(&qws_fullname);
3494 	Cvar_Register(&qws_version);
3495 	if (GIT_COMMIT[0]) {
3496 		qws_buildnum.string = GIT_COMMIT;
3497 	}
3498 	Cvar_Register(&qws_buildnum);
3499 	Cvar_Register(&qws_platform);
3500 	Cvar_Register(&qws_builddate);
3501 	Cvar_Register(&qws_homepage);
3502 	Cvar_Register(&qwm_name);
3503 	Cvar_Register(&qwm_fullname);
3504 	Cvar_Register(&qwm_version);
3505 	Cvar_Register(&qwm_buildnum);
3506 	Cvar_Register(&qwm_platform);
3507 	Cvar_Register(&qwm_builddate);
3508 	Cvar_Register(&qwm_homepage);
3509 
3510 	Cvar_Register(&sv_mod_extensions);
3511 
3512 // QW262 -->
3513 	Cmd_AddCommand ("svadmin", SV_Admin_f);
3514 // <-- QW262
3515 
3516 	Cmd_AddCommand ("addip", SV_AddIP_f);
3517 	Cmd_AddCommand ("removeip", SV_RemoveIP_f);
3518 	Cmd_AddCommand ("listip", SV_ListIP_f);
3519 	Cmd_AddCommand ("writeip", SV_WriteIP_f);
3520 	Cmd_AddCommand ("vip_addip", SV_AddIPVIP_f);
3521 	Cmd_AddCommand ("vip_removeip", SV_RemoveIPVIP_f);
3522 	Cmd_AddCommand ("vip_listip", SV_ListIPVIP_f);
3523 	Cmd_AddCommand ("vip_writeip", SV_WriteIPVIP_f);
3524 
3525 
3526 	for (i=0 ; i<MAX_MODELS ; i++)
3527 		snprintf (localmodels[i], MODEL_NAME_LEN, "*%i", i);
3528 
3529 #ifdef FTE_PEXT_ACCURATETIMINGS
3530 	svs.fteprotocolextensions |= FTE_PEXT_ACCURATETIMINGS;
3531 #endif
3532 #ifdef FTE_PEXT_256PACKETENTITIES
3533 	svs.fteprotocolextensions |= FTE_PEXT_256PACKETENTITIES;
3534 #endif
3535 #ifdef FTE_PEXT_CHUNKEDDOWNLOADS
3536 	svs.fteprotocolextensions |= FTE_PEXT_CHUNKEDDOWNLOADS;
3537 #endif
3538 #ifdef FTE_PEXT_FLOATCOORDS
3539 	svs.fteprotocolextensions |= FTE_PEXT_FLOATCOORDS;
3540 #endif
3541 #ifdef FTE_PEXT_MODELDBL
3542 	svs.fteprotocolextensions |= FTE_PEXT_MODELDBL;
3543 #endif
3544 #ifdef FTE_PEXT_ENTITYDBL
3545 	svs.fteprotocolextensions |= FTE_PEXT_ENTITYDBL;
3546 #endif
3547 #ifdef FTE_PEXT_ENTITYDBL2
3548 	svs.fteprotocolextensions |= FTE_PEXT_ENTITYDBL2;
3549 #endif
3550 #ifdef FTE_PEXT_SPAWNSTATIC2
3551 	svs.fteprotocolextensions |= FTE_PEXT_SPAWNSTATIC2;
3552 #endif
3553 
3554 #ifdef FTE_PEXT2_VOICECHAT
3555 	svs.fteprotocolextensions2 |= FTE_PEXT2_VOICECHAT;
3556 #endif
3557 
3558 #ifdef MVD_PEXT1_FLOATCOORDS
3559 	svs.mvdprotocolextension1 |= MVD_PEXT1_FLOATCOORDS;
3560 #endif
3561 #ifdef MVD_PEXT1_HIGHLAGTELEPORT
3562 	svs.mvdprotocolextension1 |= MVD_PEXT1_HIGHLAGTELEPORT;
3563 #endif
3564 #ifdef MVD_PEXT1_SERVERSIDEWEAPON
3565 	svs.mvdprotocolextension1 |= MVD_PEXT1_SERVERSIDEWEAPON;
3566 #endif
3567 #ifdef MVD_PEXT1_HIDDEN_MESSAGES
3568 	svs.mvdprotocolextension1 |= MVD_PEXT1_HIDDEN_MESSAGES;
3569 #endif
3570 #ifdef MVD_PEXT1_SERVERSIDEWEAPON2
3571 	svs.mvdprotocolextension1 |= MVD_PEXT1_SERVERSIDEWEAPON2;
3572 #endif
3573 
3574 	Info_SetValueForStarKey (svs.info, "*version", SERVER_NAME " " SERVER_VERSION, MAX_SERVERINFO_STRING);
3575 	Info_SetValueForStarKey (svs.info, "*z_ext", va("%i", SERVER_EXTENSIONS), MAX_SERVERINFO_STRING);
3576 
3577 	// init fraglog stuff
3578 	svs.logsequence = 1;
3579 	svs.logtime = realtime;
3580 	svs.log[0].data = svs.log_buf[0];
3581 	svs.log[0].maxsize = sizeof(svs.log_buf[0]);
3582 	svs.log[0].cursize = 0;
3583 	svs.log[0].allowoverflow = true;
3584 	svs.log[1].data = svs.log_buf[1];
3585 	svs.log[1].maxsize = sizeof(svs.log_buf[1]);
3586 	svs.log[1].cursize = 0;
3587 	svs.log[1].allowoverflow = true;
3588 
3589 	packet_freeblock = (packet_t *) Hunk_AllocName (MAX_DELAYED_PACKETS * sizeof(packet_t), "delayed_packets");
3590 
3591 	for (i = 0; i < MAX_DELAYED_PACKETS; i++) {
3592 		SZ_Init (&packet_freeblock[i].msg, packet_freeblock[i].buf, sizeof(packet_freeblock[i].buf));
3593 		packet_freeblock[i].next = &packet_freeblock[i + 1];
3594 	}
3595 	packet_freeblock[MAX_DELAYED_PACKETS - 1].next = NULL;
3596 	svs.free_packets = &packet_freeblock[0];
3597 }
3598 
3599 
3600 //============================================================================
3601 
3602 /*
3603 =================
3604 SV_ExtractFromUserinfo
3605 
3606 Pull specific info from a newly changed userinfo string
3607 into a more C freindly form.
3608 =================
3609 */
SV_ExtractFromUserinfo(client_t * cl,qbool namechanged)3610 void SV_ExtractFromUserinfo (client_t *cl, qbool namechanged)
3611 {
3612 	char	*val, *p;
3613 	int		i;
3614 	client_t	*client;
3615 	int		dupc = 1;
3616 	char	newname[CLIENT_NAME_LEN];
3617 
3618 	if (namechanged)
3619 	{
3620 		// name for C code
3621 		val = Info_Get (&cl->_userinfo_ctx_, "name");
3622 
3623 		// trim user name
3624 		strlcpy (newname, val, sizeof(newname));
3625 
3626 		for (p = val; *p; p++)
3627 		{
3628 			if ((*p & 127) == '\\' || *p == '\r' || *p == '\n' || *p == '$' || *p == '#' || *p == '"' || *p == ';')
3629 			{ // illegal characters in name, set some default
3630 				strlcpy(newname, sv_default_name.string, sizeof(newname));
3631 				break;
3632 			}
3633 		}
3634 
3635 		for (p = newname; *p && (*p & 127) == ' '; p++)
3636 			; // empty operator
3637 
3638 		if (p != newname) // skip prefixed spaces, if any, even whole string of spaces
3639 			strlcpy(newname, p, sizeof(newname));
3640 
3641 		for (p = newname + strlen(newname) - 1; p >= newname; p--)
3642 		{
3643 			if (*p && (*p & 127) != ' ') // skip spaces in suffix, if any
3644 			{
3645 				p[1] = 0;
3646 				break;
3647 			}
3648 		}
3649 
3650 		if (strcmp(val, newname))
3651 		{
3652 			Info_Set (&cl->_userinfo_ctx_, "name", newname);
3653 			val = Info_Get (&cl->_userinfo_ctx_, "name");
3654 		}
3655 
3656 		if (!val[0] || !Q_namecmp(val, "console") || strstr(val, "&c") || strstr(val, "&r"))
3657 		{
3658 			Info_Set (&cl->_userinfo_ctx_, "name", sv_default_name.string);
3659 			val = Info_Get (&cl->_userinfo_ctx_, "name");
3660 		}
3661 
3662 		// check to see if another user by the same name exists
3663 		while ( 1 )
3664 		{
3665 			for (i = 0, client = svs.clients ; i<MAX_CLIENTS ; i++, client++)
3666 			{
3667 				if (client->state != cs_spawned || client == cl)
3668 					continue;
3669 
3670 				if (!Q_namecmp(client->name, val))
3671 					break;
3672 			}
3673 			if (i != MAX_CLIENTS)
3674 			{ // dup name
3675 				if (strlen(val) > CLIENT_NAME_LEN - 1)
3676 					val[CLIENT_NAME_LEN - 4] = 0;
3677 				p = val;
3678 
3679 				if (val[0] == '(')
3680 				{
3681 					if (val[2] == ')')
3682 						p = val + 3;
3683 					else if (val[3] == ')')
3684 						p = val + 4;
3685 				}
3686 
3687 				snprintf(newname, sizeof(newname), "(%d)%-.10s", dupc++, p);
3688 				Info_Set (&cl->_userinfo_ctx_, "name", newname);
3689 				val = Info_Get (&cl->_userinfo_ctx_, "name");
3690 			}
3691 			else
3692 				break;
3693 		}
3694 
3695 		if (strncmp(val, cl->name, strlen(cl->name) + 1))
3696 		{
3697 			if (!cl->lastnametime || curtime - cl->lastnametime > 5) {
3698 				cl->lastnamecount = 0;
3699 				cl->lastnametime = curtime;
3700 			}
3701 			else if (cl->lastnamecount++ > 4) {
3702 				SV_BroadcastPrintf(PRINT_HIGH, "%s was kicked for name spamming\n", cl->name);
3703 				SV_ClientPrintf(cl, PRINT_HIGH, "You were kicked from the game for name spamming\n");
3704 				SV_LogPlayer(cl, "name spam", 1); //bliP: player logging
3705 				SV_DropClient(cl);
3706 				return;
3707 			}
3708 
3709 			if (cl->state >= cs_spawned && !cl->spectator) {
3710 				SV_BroadcastPrintf(PRINT_HIGH, "%s changed name to %s\n", cl->name, val);
3711 			}
3712 		}
3713 
3714 		strlcpy(cl->name, val, CLIENT_NAME_LEN);
3715 
3716 		if (cl->state >= cs_spawned) //bliP: player logging
3717 			SV_LogPlayer(cl, "name change", 1);
3718 	}
3719 
3720 	// team
3721 	val = Info_Get (&cl->_userinfo_ctx_, "team");
3722 	if (strstr(val, "&c") || strstr(val, "&r"))
3723 		Info_Set (&cl->_userinfo_ctx_, "team", "none");
3724 	strlcpy (cl->team, Info_Get (&cl->_userinfo_ctx_, "team"), sizeof(cl->team));
3725 
3726 	// rate
3727 	val = Info_Get (&cl->_userinfo_ctx_, cl->download ? "drate" : "rate");
3728 	cl->netchan.rate = 1.0 / SV_BoundRate (cl->download != NULL, Q_atoi(*val ? val : "99999"));
3729 
3730 	// s2c packet dupes
3731 	val = Info_Get(&cl->_userinfo_ctx_, "dupe");
3732 	cl->dupe = atoi(val);
3733 	cl->dupe = (int)bound(0, cl->dupe, MAX_DUPLICATE_PACKETS); // 0=1 packet (aka: no dupes)
3734 	cl->netchan.dupe = (cl->download ? 0 : cl->dupe);
3735 
3736 	// message level
3737 	val = Info_Get (&cl->_userinfo_ctx_, "msg");
3738 	if (val[0])
3739 		cl->messagelevel = Q_atoi(val);
3740 
3741 	//spectator print
3742 	val = Info_Get(&cl->_userinfo_ctx_, "sp");
3743 	if (val[0])
3744 		cl->spec_print = Q_atoi(val);
3745 }
3746 
3747 
3748 //============================================================================
3749 
OnChange_sysselecttimeout_var(cvar_t * var,char * value,qbool * cancel)3750 void OnChange_sysselecttimeout_var (cvar_t *var, char *value, qbool *cancel)
3751 {
3752 	int t = Q_atoi (value);
3753 
3754 	if (t < 1000 || t > 1000000)
3755 	{
3756 		Con_Printf("WARNING: sys_select_timeout can't be less then 1000 (1 millisecond) and more then 1 000 000 (1 second).\n");
3757 		*cancel = true;
3758 		return;
3759 	}
3760 }
3761 
3762 //bliP: 24/9 logdir ->
OnChange_logdir_var(cvar_t * var,char * value,qbool * cancel)3763 void OnChange_logdir_var (cvar_t *var, char *value, qbool *cancel)
3764 {
3765 	if (strstr(value, ".."))
3766 	{
3767 		*cancel = true;
3768 		return;
3769 	}
3770 
3771 	if (value[0])
3772 		Sys_mkdir (value);
3773 }
3774 //<-
3775 
3776 //bliP: admininfo ->
OnChange_admininfo_var(cvar_t * var,char * value,qbool * cancel)3777 void OnChange_admininfo_var (cvar_t *var, char *value, qbool *cancel)
3778 {
3779 	if (value[0])
3780 		Info_SetValueForStarKey (svs.info, "*admin", value, MAX_SERVERINFO_STRING);
3781 	else
3782 		Info_RemoveKey (svs.info, "*admin");
3783 }
3784 //<-
3785 
3786 //bliP: telnet log level ->
OnChange_telnetloglevel_var(cvar_t * var,char * value,qbool * cancel)3787 void OnChange_telnetloglevel_var (cvar_t *var, char *value, qbool *cancel)
3788 {
3789 	logs[TELNET_LOG].log_level = Q_atoi(value);
3790 }
3791 //<-
OnChange_qconsolelogsay_var(cvar_t * var,char * value,qbool * cancel)3792 void OnChange_qconsolelogsay_var (cvar_t *var, char *value, qbool *cancel)
3793 {
3794 	logs[CONSOLE_LOG].log_level = Q_atoi(value);
3795 }
3796 
3797 #ifdef SERVERONLY
3798 
COM_Init(void)3799 void COM_Init (void)
3800 {
3801 	Cvar_Register (&developer);
3802 	Cvar_Register (&version);
3803 	Cvar_Register (&sys_simulation);
3804 
3805 	Cvar_SetROM(&version, SERVER_NAME " " SERVER_VERSION);
3806 }
3807 
3808 //Free hunk memory up to host_hunklevel
3809 //Can only be called when changing levels!
Host_ClearMemory(void)3810 void Host_ClearMemory (void)
3811 {
3812 	if (!host_initialized)
3813 		Sys_Error ("Host_ClearMemory before host initialized");
3814 
3815 	CM_InvalidateMap ();
3816 
3817 	// any data previously allocated on hunk is no longer valid
3818 	Hunk_FreeToLowMark (host_hunklevel);
3819 }
3820 
3821 //memsize is the recommended amount of memory to use for hunk
Host_InitMemory(int memsize)3822 void Host_InitMemory (int memsize)
3823 {
3824 	int t;
3825 
3826 	if (SV_CommandLineUseMinimumMemory())
3827 		memsize = MINIMUM_MEMORY;
3828 
3829 	if ((t = SV_CommandLineHeapSizeMemoryKB()) != 0 && t + 1 < COM_Argc())
3830 		memsize = Q_atoi (COM_Argv(t + 1)) * 1024;
3831 
3832 	if ((t = SV_CommandLineHeapSizeMemoryMB()) != 0 && t + 1 < COM_Argc())
3833 		memsize = Q_atoi (COM_Argv(t + 1)) * 1024 * 1024;
3834 
3835 	if (memsize < MINIMUM_MEMORY)
3836 		Sys_Error ("Only %4.1f megs of memory reported, can't execute game", memsize / (float)0x100000);
3837 
3838 	Memory_Init (Q_malloc(memsize), memsize);
3839 }
3840 
Host_Init(int argc,char ** argv,int default_memsize)3841 void Host_Init (int argc, char **argv, int default_memsize)
3842 {
3843 	extern int		hunk_size;
3844 	cvar_t			*v;
3845 
3846 	srand((unsigned)time(NULL));
3847 
3848 	COM_InitArgv (argc, argv);
3849 
3850 	Host_InitMemory (default_memsize);
3851 
3852 	Con_Printf ("============= Starting %s =============\n", VersionStringFull());
3853 
3854 	Cbuf_Init ();
3855 	Cmd_Init ();
3856 	Cvar_Init ();
3857 	COM_Init ();
3858 
3859 	FS_Init ();
3860 	NET_Init ();
3861 
3862 	Netchan_Init ();
3863 
3864 	Sys_Init ();
3865 	CM_Init ();
3866 
3867 	SV_Init ();
3868 
3869 	Hunk_AllocName (0, "-HOST_HUNKLEVEL-");
3870 	host_hunklevel = Hunk_LowMark ();
3871 
3872 	host_initialized = true;
3873 
3874 	// walk through all vars and forse OnChange event if cvar was modified,
3875 	// also apply that to variables which mirrored in userinfo because of cl_parsefunchars was't applyed as this moment,
3876 	// same for serverinfo and may be this fix something also.
3877 	for ( v = NULL; (v = Cvar_Next ( v )); )
3878 	{
3879 		if ( Cvar_GetFlags( v ) & (CVAR_ROM) )
3880 			continue;
3881 
3882 		Cvar_Set(v, v->string);
3883 	}
3884 
3885 	Con_Printf ("%4.1f megabyte heap\n", (float)hunk_size / (1024 * 1024));
3886 	Con_Printf ("QuakeWorld Initialized\n");
3887 
3888 	Cbuf_InsertText ("exec server.cfg\n");
3889 
3890 	// process command line arguments
3891 	Cmd_StuffCmds_f ();
3892 	Cbuf_Execute ();
3893 
3894 	host_everything_loaded = true;
3895 
3896 	SV_Map(true);
3897 
3898 	// if a map wasn't specified on the command line, spawn mvdsv-kg map
3899 	if (sv.state == ss_dead)
3900 	{
3901 		Cmd_ExecuteString ("map mvdsv-kg");
3902 		SV_Map(true);
3903 	}
3904 
3905 	// last resort - start map
3906 	if (sv.state == ss_dead)
3907 	{
3908 		Cmd_ExecuteString ("map start");
3909 		SV_Map(true);
3910 	}
3911 
3912 	if (sv.state == ss_dead)
3913 		SV_Error ("Couldn't spawn a server");
3914 
3915 #if defined (_WIN32) && !defined(_CONSOLE)
3916 	{
3917 		void SetWindowText_(char*);
3918 		SetWindowText_(va(SERVER_NAME ":%d - QuakeWorld server", NET_UDPSVPort()));
3919 	}
3920 #endif
3921 }
3922 
3923 #endif // SERVERONLY
3924 
3925 /*
3926 ====================
3927 SV_Init
3928 ====================
3929 */
3930 
SV_Init(void)3931 void SV_Init (void)
3932 {
3933 	memset(&_localinfo_, 0, sizeof(_localinfo_));
3934 	_localinfo_.max = MAX_LOCALINFOS;
3935 
3936 	PR_Init ();
3937 
3938 	// send immediately
3939 	svs.last_heartbeat = -99999;
3940 
3941 	SV_InitLocal ();
3942 
3943 	SV_MVDInit ();
3944 	Login_Init ();
3945 #ifndef SERVERONLY
3946 	server_cfg_done = true;
3947 #endif
3948 
3949 #if defined(SERVERONLY) && defined(WWW_INTEGRATION)
3950 	Central_Init ();
3951 #endif
3952 }
3953 
3954 /*
3955 ============
3956 SV_TimeOfDay
3957 ============
3958 */
SV_TimeOfDay(date_t * date,char * timeformat)3959 void SV_TimeOfDay(date_t *date, char *timeformat)
3960 {
3961 	struct tm *newtime;
3962 	time_t long_time;
3963 
3964 	time(&long_time);
3965 	newtime = localtime(&long_time);
3966 
3967 	//bliP: date check ->
3968 	if (!newtime)
3969 	{
3970 		date->day = 0;
3971 		date->mon = 0;
3972 		date->year = 0;
3973 		date->hour = 0;
3974 		date->min = 0;
3975 		date->sec = 0;
3976 		strlcpy(date->str, "#bad date#", sizeof(date->str));
3977 		return;
3978 	}
3979 	//<-
3980 
3981 	date->day = newtime->tm_mday;
3982 	date->mon = newtime->tm_mon;
3983 	date->year = newtime->tm_year + 1900;
3984 	date->hour = newtime->tm_hour;
3985 	date->min = newtime->tm_min;
3986 	date->sec = newtime->tm_sec;
3987 	strftime(date->str, sizeof(date->str)-1, timeformat, newtime);
3988 }
3989 
3990 //bliP: player logging ->
3991 /*
3992 ============
3993 SV_LogPlayer
3994 ============
3995 */
SV_LogPlayer(client_t * cl,char * msg,int level)3996 void SV_LogPlayer(client_t *cl, char *msg, int level)
3997 {
3998 	char info[MAX_EXT_INFO_STRING];
3999 	char name[CLIENT_NAME_LEN];
4000 
4001 	Info_ReverseConvert(&cl->_userinfo_ctx_, info, sizeof(info));
4002 	Q_normalizetext(info);
4003 	strlcpy(name, cl->name, sizeof(name));
4004 	Q_normalizetext(name);
4005 
4006 	SV_Write_Log(PLAYER_LOG, level,
4007 	             va("%s\\%s\\%i\\%s\\%s\\%i%s\n",
4008 	                msg,
4009 	                name,
4010 	                cl->userid,
4011 	                NET_BaseAdrToString(cl->netchan.remote_address),
4012 	                NET_BaseAdrToString(cl->realip),
4013 	                cl->netchan.remote_address.port,
4014 	                info
4015 	               )
4016 	            );
4017 }
4018 
4019 /*
4020 ============
4021 SV_Write_Log
4022 ============
4023 */
SV_Write_Log(int sv_log,int level,char * msg)4024 void SV_Write_Log(int sv_log, int level, char *msg)
4025 {
4026 	static date_t date;
4027 	char *log_msg, *error_msg;
4028 
4029 	if (!(logs[sv_log].sv_logfile && *msg))
4030 		return;
4031 
4032 	if (logs[sv_log].log_level < level)
4033 		return;
4034 
4035 	SV_TimeOfDay(&date, "%a %b %d, %H:%M:%S %Y");
4036 
4037 	switch (sv_log)
4038 	{
4039 	case FRAG_LOG:
4040 	case MOD_FRAG_LOG:
4041 		log_msg = msg; // these logs aren't in fs_gamedir
4042 		error_msg = va("Can't write in %s log file: "/*%s/ */"%sN.log.\n",
4043 		               /*fs_gamedir,*/ logs[sv_log].message_on,
4044 		               logs[sv_log].file_name);
4045 		break;
4046 	default:
4047 		log_msg = va("[%s].[%d] %s", date.str, level, msg);
4048 		error_msg = va("Can't write in %s log file: "/*%s/ */"%s%i.log.\n",
4049 		               /*fs_gamedir,*/ logs[sv_log].message_on,
4050 		               logs[sv_log].file_name, NET_UDPSVPort());
4051 	}
4052 
4053 	if (fprintf(logs[sv_log].sv_logfile, "%s", log_msg) < 0)
4054 	{
4055 		//bliP: Sys_Error to Con_DPrintf ->
4056 		//VVD: Con_DPrintf to Sys_Printf ->
4057 		Sys_Printf("%s", error_msg);
4058 		//<-
4059 		SV_Logfile(sv_log, false);
4060 	}
4061 	else
4062 	{
4063 		fflush(logs[sv_log].sv_logfile);
4064 		if ((int)sv_maxlogsize.value &&
4065 		        (FS_FileLength(logs[sv_log].sv_logfile) > (int)sv_maxlogsize.value))
4066 		{
4067 			SV_Logfile(sv_log, true);
4068 		}
4069 	}
4070 }
4071 
4072 /*
4073 ============
4074 Sys_compare_by functions for sort files in list
4075 ============
4076 */
Sys_compare_by_date(const void * a,const void * b)4077 int Sys_compare_by_date (const void *a, const void *b)
4078 {
4079 	return (int)(((file_t *)a)->time - ((file_t *)b)->time);
4080 }
4081 
Sys_compare_by_name(const void * a,const void * b)4082 int Sys_compare_by_name (const void *a, const void *b)
4083 {
4084 	return strncmp(((file_t *)a)->name, ((file_t *)b)->name, MAX_DEMO_NAME);
4085 }
4086 
4087 // real-world time passed
SV_ClientConnectedTime(client_t * client)4088 double SV_ClientConnectedTime(client_t* client)
4089 {
4090 	if (!client->connection_started_curtime) {
4091 		return 0;
4092 	}
4093 	return curtime - client->connection_started_curtime;
4094 }
4095 
4096 // affected by pause
SV_ClientGameTime(client_t * client)4097 double SV_ClientGameTime(client_t* client)
4098 {
4099 	if (!client->connection_started_realtime) {
4100 		return 0;
4101 	}
4102 
4103 	return realtime - client->connection_started_realtime;
4104 }
4105 
SV_SetClientConnectionTime(client_t * client)4106 void SV_SetClientConnectionTime(client_t* client)
4107 {
4108 	client->connection_started_realtime = realtime;
4109 	client->connection_started_curtime = curtime;
4110 }
4111 
4112 #endif // !CLIENTONLY
4113