コード例 #1
0
ファイル: sv_ccmds.c プロジェクト: OpenArena/legacy
/*
==================
SV_KickNum_f

Kick a user off of the server  FIXME: move to game
==================
*/
static void SV_KickNum_f( void ) {
	client_t	*cl;

	// make sure server is running
	if ( !com_sv_running->integer ) {
		Com_Printf( "Server is not running.\n" );
		return;
	}

	if ( Cmd_Argc() != 2 ) {
		Com_Printf ("Usage: kicknum <client number>\n");
		return;
	}

	cl = SV_GetPlayerByNum();
	if ( !cl ) {
		return;
	}
	if( cl->netchan.remoteAddress.type == NA_LOOPBACK ) {
		SV_SendServerCommand(NULL, "print \"%s\"", "Cannot kick host player\n");
		return;
	}

	SV_DropClient( cl, "was kicked" );
	cl->lastPacketTime = svs.time;	// in case there is a funny zombie
}
コード例 #2
0
ファイル: sv_ccmds.c プロジェクト: Lrns123/jkaq3
/*
==================
SV_ConTell_f
==================
*/
static void SV_ConTell_f(void) {
	char	*p;
	char	text[1024];
	client_t	*cl;

	// make sure server is running
	if ( !com_sv_running->integer ) {
		Com_Printf( "Server is not running.\n" );
		return;
	}

	if ( Cmd_Argc() < 3 ) {
		Com_Printf ("Usage: tell <client number> <text>\n");
		return;
	}

	cl = SV_GetPlayerByNum();
	if ( !cl ) {
		return;
	}

	strcpy (text, "console_tell: ");
	p = Cmd_ArgsFrom(2);

	if ( *p == '"' ) {
		p++;
		p[strlen(p)-1] = 0;
	}

	strcat(text, p);

	SV_SendServerCommand(cl, "chat \"%s\"", text);
}
コード例 #3
0
ファイル: sv_ccmds.c プロジェクト: coltongit/spearmint
/*
==================
SV_KickNum_f

Kick a user off of the server
==================
*/
static void SV_KickNum_f( void ) {
	player_t	*player;
	client_t	*client;

	// make sure server is running
	if ( !com_sv_running->integer ) {
		Com_Printf( "Server is not running.\n" );
		return;
	}

	if ( Cmd_Argc() != 2 ) {
		Com_Printf ("Usage: %s <client number>\n", Cmd_Argv(0));
		return;
	}

	player = SV_GetPlayerByNum();
	if ( !player ) {
		return;
	}

	client = player->client;

	if( client->netchan.remoteAddress.type == NA_LOOPBACK ) {
		Com_Printf("Cannot kick host player\n");
		return;
	}

	SV_DropPlayer( player, "was kicked" );

	client->lastPacketTime = svs.time;	// in case there is a funny zombie
}
コード例 #4
0
ファイル: sv_ccmds.cpp プロジェクト: Promethius457/OpenJK
/*
==================
SV_KickNum_f

Kick a user off of the server
==================
*/
static void SV_KickNum_f( void ) {
	client_t	*cl;

	// make sure server is running
	if ( !com_sv_running->integer ) {
		Com_Printf( "Server is not running.\n" );
		return;
	}

	if ( Cmd_Argc() != 2 ) {
		Com_Printf ("Usage: %s <client number>\n", Cmd_Argv(0));
		return;
	}

	cl = SV_GetPlayerByNum();
	if ( !cl ) {
		return;
	}
	if( cl->netchan.remoteAddress.type == NA_LOOPBACK ) {
		Com_Printf("Cannot kick host player\n");
		return;
	}

	SV_DropClient( cl, SV_GetStringEdString("MP_SVGAME","WAS_KICKED"));	// "was kicked" );
	cl->lastPacketTime = svs.time;	// in case there is a funny zombie
}
コード例 #5
0
ファイル: sv_ccmds.cpp プロジェクト: adnanfzafar/OpenJK
/*
==================
SV_ConTell_f
==================
*/
static void SV_ConTell_f(void) {
	char	text[MAX_SAY_TEXT] = {0};
	client_t	*cl;

	if( !com_dedicated->integer ) {
		Com_Printf( "Server is not dedicated.\n" );
		return;
	}

	// make sure server is running
	if ( !com_sv_running->integer ) {
		Com_Printf( "Server is not running.\n" );
		return;
	}

	if ( Cmd_Argc () < 3 ) {
		Com_Printf ("Usage: svtell <client number> <text>\n");
		return;
	}

	cl = SV_GetPlayerByNum();
	if ( !cl ) {
		return;
	}

	Cmd_ArgsFromBuffer( 2, text, sizeof(text) );

	Com_Printf ("tell: svtell to %s" S_COLOR_WHITE ": %s\n", cl->name, SV_ExpandNewlines((char *)text) );
	SV_SendServerCommand(cl, "chat \"" SVTELL_PREFIX S_COLOR_MAGENTA "%s" S_COLOR_WHITE "\"\n", text);
}
コード例 #6
0
ファイル: sv_ccmds.c プロジェクト: Lrns123/jkaq3
/*
==================
SV_KickNum_f

Kick a user off of the server
==================
*/
static void SV_KickNum_f( void ) {
	client_t	*cl;

	// make sure server is running
	if ( !com_sv_running->integer ) {
		Com_Printf( "Server is not running.\n" );
		return;
	}

	if ( Cmd_Argc() != 2 ) {
		Com_Printf( "Usage: %s <client number>\n", Cmd_Argv( 0 ) );
		return;
	}

	cl = SV_GetPlayerByNum();
	if ( !cl ) {
		return;
	}
	if( cl->netchan.remoteAddress.type == NA_LOOPBACK ) {
		SV_SendServerCommand(NULL, "print \"%s\"", SV_StringEdString("CANNOT_KICK_HOST"));
		return;
	}

	SV_DropClient( cl, SV_StringEdString("WAS_KICKED") );
	cl->lastPacketTime = svs.time;	// in case there is a funny zombie
}
コード例 #7
0
ファイル: sv_ccmds.c プロジェクト: OADoctor/SmokinGuns
/*
==================
SV_ForceName_f

Sets a user's name
==================
*/
static void SV_ForceName_f( void ) {
	client_t	*cl;
	const char	*name;

	// make sure server is running
	if ( !com_sv_running->integer ) {
		Com_Printf( "Server is not running.\n" );
		return;
	}

	if ( Cmd_Argc() >= 2 ) {
		cl = SV_GetPlayerByNum();
		if ( !cl ) {
			return;
		}
		if ( Cmd_Argc() == 2 ) {
			Com_Printf ("forcename: %s: %s\n",Cmd_Argv(1),cl->name);
			return;
		} else {
			name = Cmd_ArgsFrom(2);
			cl->forcename = 2;
			Q_strncpyz( cl->name, name, sizeof(cl->name) );
			SV_UserinfoChanged( cl );
			VM_Call( gvm, GAME_CLIENT_USERINFO_CHANGED, cl - svs.clients );
			Com_Printf ("forcename: %s: %s\n",Cmd_Argv(1),cl->name);
			return;
		}
	}
	Com_Printf ("Usage: forcename <client number> [<name>]\n");
	return;
}
コード例 #8
0
ファイル: sv_ccmds.cpp プロジェクト: Joanxt/OpenJK
/*
==================
SV_KickNum_f

Kick a user off of the server
==================
*/
static void SV_KickNum_f( void ) {
	client_t	*cl;

	// make sure server is running
	if ( !com_sv_running->integer ) {
		Com_Printf( "Server is not running.\n" );
		return;
	}

	if ( Cmd_Argc() != 2 ) {
		Com_Printf ("Usage: %s <client number>\n", Cmd_Argv(0));
		return;
	}

	cl = SV_GetPlayerByNum();
	if ( !cl ) {
		return;
	}
	if( cl->netchan.remoteAddress.type == NA_LOOPBACK ) {
		// Ensiform: RAVEN BUT THIS IS SERVER CONSOLE SO... WHY DO WE WANT @@@ TO APPEAR
//		SV_SendServerCommand(NULL, "print \"%s\"", "Cannot kick host player\n");
//		SV_SendServerCommand(NULL, "print \"%s\"", SV_GetStringEdString("MP_SVGAME","CANNOT_KICK_HOST"));
		Com_Printf("Cannot kick host player\n");
		return;
	}

	SV_DropClient( cl, SV_GetStringEdString("MP_SVGAME","WAS_KICKED"));	// "was kicked" );
	cl->lastPacketTime = svs.time;	// in case there is a funny zombie
}
コード例 #9
0
ファイル: sv_ccmds.c プロジェクト: OADoctor/SmokinGuns
void SVCL_SaveRecord_f( void ) {
	char		*s;
	client_t	*cl;
	int         clientnum;


	s = 0;
	// make sure server is running
	if ( !com_sv_running->integer ) {
		Com_Printf( "Server is not running.\n" );
		return;
	}

	if ( Cmd_Argc() != 2) {
		Com_Printf ("saverecord <clientnumber>\n");
		return;
	}

	cl = SV_GetPlayerByNum();
	if ( !cl ) {
		// error message was printed by SV_GetPlayerByNum
		return;
	}
	if ( !cl->demorecording ) {
		Com_Printf ("Not recording a demo for client %i.\n", cl - svs.clients);
		return;
	}
	clientnum = cl - svs.clients;
	cl->savedemo = qtrue;
	Com_Printf ("Saverecord: %i: %s\n", clientnum, cl->name);
}
コード例 #10
0
ファイル: sv_ccmds.c プロジェクト: OADoctor/SmokinGuns
/*
==================
SV_ConTell_f

Based on Urban Terror implementation
==================
*/
static void SV_ConTell_f(void) {
	char	*p;
	char	text[MAX_STRING_CHARS-18];// OK?
	client_t	*cl;

	// make sure server is running
	if ( !com_sv_running->integer ) {
		Com_Printf( "Server is not running.\n" );
		return;
	}

	if ( Cmd_Argc() < 3 ) {
		Com_Printf ("Usage: tell <client number> <text>\n");
		return;
	}

	cl = SV_GetPlayerByNum();
	if ( !cl ) {
		return;
	}

	strcpy (text, "^3private:^7 ");
	p = Cmd_ArgsFrom(2);

	if ( *p == '"' ) {
		p++;
		p[strlen(p)-1] = 0;
	}

	strcat(text, p);

	SV_SendServerCommand(cl, "print \"%s\n\"", SV_ConvertNewlines((char *)text));
}
コード例 #11
0
ファイル: sv_ccmds.c プロジェクト: OADoctor/SmokinGuns
void SVCL_Record_f( void ) {
	char		*s;
	client_t	*cl;

	s = 0;
	// make sure server is running
	if ( !com_sv_running->integer ) {
		Com_Printf( "Server is not running.\n" );
		return;
	}

	if ( Cmd_Argc() < 2 || Cmd_Argc() > 3) {
		Com_Printf ("record <clientnumber> [<demoname>]\n");
		return;
	}

	cl = SV_GetPlayerByNum();
	if ( !cl ) {
		// error message was printed by SV_GetPlayerByNum
		return;
	}

	if ( Cmd_Argc() == 3 ) {
		s = Cmd_Argv(2);
//		Com_sprintf (name, sizeof(name), "demos/%s.dm_%d", s, PROTOCOL_VERSION );
		CL_Record(cl,s);
	} else {
		CL_Record(cl,0);
	}
}
コード例 #12
0
ファイル: sv_ccmds.c プロジェクト: OADoctor/SmokinGuns
/*
==================
SV_ForceName_f

Sets a user's name
==================
*/
static void SV_LockName_f( void ) {
	client_t	*cl;

	// make sure server is running
	if ( !com_sv_running->integer ) {
		Com_Printf( "Server is not running.\n" );
		return;
	}

	if ( Cmd_Argc() >= 2 ) {
		cl = SV_GetPlayerByNum();
		if ( !cl ) {
			return;
		}
		if ( Cmd_Argc() == 2 ) {
			Com_Printf ("lockname: %s: %d\n",Cmd_Argv(1),cl->forcename);
			return;
		} else {
			cl->forcename = atoi(Cmd_Argv(2));
			Com_Printf ("lockname: %s: %d\n",Cmd_Argv(1),cl->forcename);
			return;
		}
	}
	Com_Printf ("Usage: lockname <client number>\n");
	return;
}
コード例 #13
0
ファイル: sv_ccmds.c プロジェクト: morsik/war-territory
/*
==================
SV_BanNum_f

Ban a user from being able to play on this server through the auth
server
==================
*/
static void SV_BanNum_f(void)
{
	client_t *cl;

	// make sure server is running
	if (!com_sv_running->integer)
	{
		Com_Printf("Server is not running.\n");
		return;
	}

	if (Cmd_Argc() != 2)
	{
		Com_Printf("Usage: banClient <client number>\n");
		return;
	}

	cl = SV_GetPlayerByNum();
	if (!cl)
	{
		return;
	}
	if (cl->netchan.remoteAddress.type == NA_LOOPBACK)
	{
		SV_SendServerCommand(NULL, "print \"%s\"", "Cannot kick host player\n");
		return;
	}

	// look up the authorize server's IP
	if (!svs.authorizeAddress.ip[0] && svs.authorizeAddress.type != NA_BAD)
	{
		Com_Printf("Resolving %s\n", AUTHORIZE_SERVER_NAME);
		if (!NET_StringToAdr(AUTHORIZE_SERVER_NAME, &svs.authorizeAddress))
		{
			Com_Printf("Couldn't resolve address\n");
			return;
		}
		svs.authorizeAddress.port = BigShort(PORT_AUTHORIZE);
		Com_Printf("%s resolved to %i.%i.%i.%i:%i\n", AUTHORIZE_SERVER_NAME,
		           svs.authorizeAddress.ip[0], svs.authorizeAddress.ip[1],
		           svs.authorizeAddress.ip[2], svs.authorizeAddress.ip[3],
		           BigShort(svs.authorizeAddress.port));
	}

	// otherwise send their ip to the authorize server
	if (svs.authorizeAddress.type != NA_BAD)
	{
		NET_OutOfBandPrint(NS_SERVER, svs.authorizeAddress,
		                   "banUser %i.%i.%i.%i", cl->netchan.remoteAddress.ip[0], cl->netchan.remoteAddress.ip[1],
		                   cl->netchan.remoteAddress.ip[2], cl->netchan.remoteAddress.ip[3]);
		Com_Printf("%s was banned from coming back\n", rc(cl->name));
	}
}
コード例 #14
0
ファイル: sv_ccmds.c プロジェクト: OADoctor/SmokinGuns
/*
==================
SV_BanNum_f

Ban a user from being able to play on this server through the auth
server
==================
*/
static void SV_BanNum_f( void ) {
	client_t	*cl;

	// make sure server is running
	if ( !com_sv_running->integer ) {
		Com_Printf( "Server is not running.\n" );
		return;
	}

	if ( Cmd_Argc() != 2 ) {
		Com_Printf ("Usage: banClient <client number>\n");
		return;
	}

	cl = SV_GetPlayerByNum();
	if ( !cl ) {
		return;
	}
	if( cl->netchan.remoteAddress.type == NA_LOOPBACK ) {
		SV_SendServerCommand(NULL, "print \"%s\"", "Cannot kick host player\n");
		return;
	}

	// look up the authorize server's IP
	if ( !svs.authorizeAddress.ip[0] && svs.authorizeAddress.type != NA_BAD ) {
		Com_Printf( "Resolving %s\n", AUTHORIZE_SERVER_NAME );
		if ( !NET_StringToAdr( AUTHORIZE_SERVER_NAME, &svs.authorizeAddress, NA_IP ) ) {
			Com_Printf( "Couldn't resolve address\n" );
			return;
		}
		svs.authorizeAddress.port = BigShort( PORT_AUTHORIZE );
		Com_Printf( "%s resolved to %i.%i.%i.%i:%i\n", AUTHORIZE_SERVER_NAME,
			svs.authorizeAddress.ip[0], svs.authorizeAddress.ip[1],
			svs.authorizeAddress.ip[2], svs.authorizeAddress.ip[3],
			BigShort( svs.authorizeAddress.port ) );
	}

	// otherwise send their ip to the authorize server
	if ( svs.authorizeAddress.type != NA_BAD ) {
#ifndef SMOKINGUNS
		NET_OutOfBandPrint( NS_SERVER, svs.authorizeAddress,
			"banUser %i.%i.%i.%i", cl->netchan.remoteAddress.ip[0], cl->netchan.remoteAddress.ip[1], 
								   cl->netchan.remoteAddress.ip[2], cl->netchan.remoteAddress.ip[3] );
#else
		// Tequila comment: Provide also the guid to ban in case of ip change
		char *guid = Info_ValueForKey ( cl->userinfo, "cl_guid" );
		NET_OutOfBandPrint( NS_SERVER, svs.authorizeAddress,
			"banUser %i.%i.%i.%i %s", cl->netchan.remoteAddress.ip[0], cl->netchan.remoteAddress.ip[1], 
								   cl->netchan.remoteAddress.ip[2], cl->netchan.remoteAddress.ip[3], guid );
#endif
		Com_Printf("%s was banned from coming back\n", cl->name);
	}
}
コード例 #15
0
ファイル: sv_ccmds.c プロジェクト: OADoctor/SmokinGuns
static void SV_ConBig_f(void) {
	char	*p;
	char	text[1024];
	client_t	*cl;

	// make sure server is running
	if ( !com_sv_running->integer ) {
		Com_Printf( "Server is not running.\n" );
		return;
	}

	if ( Cmd_Argc() < 3 ) {
		Com_Printf ("Usage: big <clientid> <text>\n");
		return;
	}

	cl = SV_GetPlayerByNum();
	if (atoi(Cmd_Argv(1)) < 0) {
		cl = NULL;
	}


//	if (atoi(Cmd_Argv(1))) {
//	    Com_Printf ("Hi1 -1\n");

////	    Com_Printf ("Hi2 -1\n");
//	    if ( !cl ) {
//		    return;
//	    }
////	    Com_Printf ("Hi3 -1\n");
//	}


	strcpy (text, "^3");
	p = Cmd_ArgsFrom(2);

	if ( *p == '"' ) {
		p++;
		p[strlen(p)-1] = 0;
	}

	strcat(text, p);

	SV_SendServerCommand(cl, "cp \"" S_COLOR_WHITE "%s\n\"", text);
}
コード例 #16
0
ファイル: sv_ccmds.c プロジェクト: OADoctor/SmokinGuns
/*
==================
SV_KickNum_f

Kick a user off of the server  FIXME: move to game
==================
*/
static void SV_KickNum_f( void ) {
	client_t	*cl;
	char		cmd_args[MAX_STRING_CHARS];// patch servercommands: enable the ability to provide a reason with clientkicks
	int		i;

	// make sure server is running
	if ( !com_sv_running->integer ) {
		Com_Printf( "Server is not running.\n" );
		return;
	}

	if ( Cmd_Argc() < 2 ) {
#ifndef SMOKINGUNS
		Com_Printf ("Usage: kicknum <client number>\n");
#else
		Com_Printf ("Usage: clientkick <client number> [<reason>]\n");
#endif
		return;
	}

	cl = SV_GetPlayerByNum();
	if ( !cl ) {
		return;
	}
	if( cl->netchan.remoteAddress.type == NA_LOOPBACK ) {
		SV_SendServerCommand(NULL, "print \"%s\"", "Cannot kick host player\n");
		return;
	}

	if ( Cmd_Argc() == 2 ) {
		SV_DropClient( cl, "was ^3kicked^7!");
		cl->lastPacketTime = svs.time;	// in case there is a funny zombie
	} else {
		cmd_args[0]=0;
		for ( i=2 ; i<Cmd_Argc() ; i++ ) {
			Q_strcat( cmd_args, sizeof(cmd_args), Cmd_Argv(i) );
			if ( i != Cmd_Argc()-1 ) {
				Q_strcat( cmd_args, sizeof(cmd_args), " " );
			}
		}
		SV_DropClient( cl, cmd_args);
	cl->lastPacketTime = svs.time;	// in case there is a funny zombie
}
}
コード例 #17
0
ファイル: sv_ccmds.c プロジェクト: OADoctor/SmokinGuns
void SVCL_StopRecord_f( void ) {
	client_t	*cl;

	// make sure server is running
	if ( !com_sv_running->integer ) {
		Com_Printf( "Server is not running.\n" );
		return;
	}

	if ( Cmd_Argc() < 2 ) {
		Com_Printf ("Usage: stoprecord <clientnumber>\n");
		return;
	}

	cl = SV_GetPlayerByNum();
	if ( !cl ) {
		// error message was printed by SV_GetPlayerByNum
		return;
	}
	CL_StopRecord(cl);
}
コード例 #18
0
ファイル: sv_ccmds.c プロジェクト: OADoctor/SmokinGuns
static void SV_AddBanToList(qboolean isexception)
{
	char *banstring;
	char addy2[NET_ADDRSTRMAXLEN];
	netadr_t ip;
	int index, argc, mask;
	serverBan_t *curban;
	
	argc = Cmd_Argc();
	
	if(argc < 2 || argc > 3)
	{
		Com_Printf ("Usage: %s (ip[/subnet] | clientnum [subnet])\n", Cmd_Argv(0));
		return;
	}

	if(serverBansCount > ARRAY_LEN(serverBans))
	{
		Com_Printf ("Error: Maximum number of bans/exceptions exceeded.\n");
		return;
	}

	banstring = Cmd_Argv(1);
	
	if(strchr(banstring, '.') || strchr(banstring, ':'))
	{
		// This is an ip address, not a client num.
		
		if(SV_ParseCIDRNotation(&ip, &mask, banstring))
		{
			Com_Printf("Error: Invalid address %s\n", banstring);
			return;
		}
	}
	else
	{
		client_t *cl;
		
		// client num.
		if(!com_sv_running->integer)
		{
			Com_Printf("Server is not running.\n");
			return;
		}
		
		cl = SV_GetPlayerByNum();

		if(!cl)
		{
			Com_Printf("Error: Playernum %s does not exist.\n", Cmd_Argv(1));
			return;
		}
		
		ip = cl->netchan.remoteAddress;
		
		if(argc == 3)
		{
			mask = atoi(Cmd_Argv(2));
			
			if(ip.type == NA_IP)
			{
				if(mask < 1 || mask > 32)
					mask = 32;
			}
			else
			{
				if(mask < 1 || mask > 128)
					mask = 128;
			}
		}
		else
			mask = (ip.type == NA_IP6) ? 128 : 32;
	}

	if(ip.type != NA_IP && ip.type != NA_IP6)
	{
		Com_Printf("Error: Can ban players connected via the internet only.\n");
		return;
	}

	// first check whether a conflicting ban exists that would supersede the new one.
	for(index = 0; index < serverBansCount; index++)
	{
		curban = &serverBans[index];
		
		if(curban->subnet <= mask)
		{
			if((curban->isexception || !isexception) && NET_CompareBaseAdrMask(curban->ip, ip, curban->subnet))
			{
				Q_strncpyz(addy2, NET_AdrToString(ip), sizeof(addy2));
				
				Com_Printf("Error: %s %s/%d supersedes %s %s/%d\n", curban->isexception ? "Exception" : "Ban",
					   NET_AdrToString(curban->ip), curban->subnet,
					   isexception ? "exception" : "ban", addy2, mask);
				return;
			}
		}
		if(curban->subnet >= mask)
		{
			if(!curban->isexception && isexception && NET_CompareBaseAdrMask(curban->ip, ip, mask))
			{
				Q_strncpyz(addy2, NET_AdrToString(curban->ip), sizeof(addy2));
			
				Com_Printf("Error: %s %s/%d supersedes already existing %s %s/%d\n", isexception ? "Exception" : "Ban",
					   NET_AdrToString(ip), mask,
					   curban->isexception ? "exception" : "ban", addy2, curban->subnet);
				return;
			}
		}
	}

	// now delete bans that are superseded by the new one
	index = 0;
	while(index < serverBansCount)
	{
		curban = &serverBans[index];
		
		if(curban->subnet > mask && (!curban->isexception || isexception) && NET_CompareBaseAdrMask(curban->ip, ip, mask))
			SV_DelBanEntryFromList(index);
		else
			index++;
	}

	serverBans[serverBansCount].ip = ip;
	serverBans[serverBansCount].subnet = mask;
	serverBans[serverBansCount].isexception = isexception;
	
	serverBansCount++;
	
	SV_WriteBans();

	Com_Printf("Added %s: %s/%d\n", isexception ? "ban exception" : "ban",
		   NET_AdrToString(ip), mask);
}
コード例 #19
0
ファイル: sv_ccmds.c プロジェクト: shawnd/urt-bumpy-engine
static void SV_AddBanToList(qboolean isexception)
{
	char *banstring, *suffix;
	netadr_t ip;
	int argc, mask;
	fileHandle_t writeto;
	
	argc = Cmd_Argc();
	
	if(argc < 2 || argc > 3)
	{
		Com_Printf ("Usage: %s (ip[/subnet] | clientnum [subnet])\n", Cmd_Argv(0));
		return;
	}

	if(serverBansCount > sizeof(serverBans) / sizeof(*serverBans))
	{
		Com_Printf ("Error: Maximum number of bans/exceptions exceeded.\n");
		return;
	}

	banstring = Cmd_Argv(1);
	
	if(strchr(banstring, '.') || strchr(banstring, ':'))
	{
		// This is an ip address, not a client num.
		
		// Look for a CIDR-Notation suffix
		suffix = strchr(banstring, '/');
		if(suffix)
		{
			*suffix = '\0';
			suffix++;
		}
		
		if(!NET_StringToAdr(banstring, &ip, NA_UNSPEC))
		{
			Com_Printf("Error: Invalid address %s\n", banstring);
			return;
		}
	}
	else
	{
		client_t *cl;
		
		// client num.
		if(!com_sv_running->integer)
		{
			Com_Printf("Server is not running.\n");
			return;
		}
		
		cl = SV_GetPlayerByNum();

		if(!cl)
		{
			Com_Printf("Error: Playernum %s does not exist.\n", Cmd_Argv(1));
			return;
		}
		
		ip = cl->netchan.remoteAddress;
		
		if(argc == 3)
			suffix = Cmd_Argv(2);
		else
			suffix = NULL;
	}

	if(ip.type != NA_IP && ip.type != NA_IP6)
	{
		Com_Printf("Error: Can ban players connected via the internet only.\n");
		return;
	}

	if(suffix)
	{
		mask = atoi(suffix);
		
		if(ip.type == NA_IP)
		{
			if(mask < 0 || mask > 32)
				mask = 32;
		}
		else
		{
			if(mask < 0 || mask > 128)
				mask = 128;
		}
	}
	else if(ip.type == NA_IP)
		mask = 32;
	else
		mask = 128;
	
	serverBans[serverBansCount].ip = ip;
	serverBans[serverBansCount].subnet = mask;
	serverBans[serverBansCount].isexception = isexception;
	
	Com_Printf("Added %s: %s/%d\n", isexception ? "ban exception" : "ban",
		   NET_AdrToString(ip), mask);

	// Write out the ban information.
	if((writeto = FS_FOpenFileAppend(SERVER_BANFILE)))
	{
		char writebuf[128];
		
		Com_sprintf(writebuf, sizeof(writebuf), "%d %s %d\n", isexception, NET_AdrToString(ip), mask);
		FS_Write(writebuf, strlen(writebuf), writeto);
		FS_FCloseFile(writeto);
	}
	
	serverBansCount++;
}