예제 #1
0
static void
CL_RemoveQFInfoKeys (void)
{
	Info_RemoveKey (cls.userinfo, "*cap");
	Info_RemoveKey (cls.userinfo, "*qf_version");
	Info_RemoveKey (cls.userinfo, "*qsg_version");
}
static void ResetMiscCommands(void)
{
	Cbuf_AddText("mapgroup clear\n");
	Cbuf_AddText("skygroup clear\n");

	MarkDefaultSources();

	Info_RemoveKey(cls.userinfo, "ec");
	Info_RemoveKey(cls.userinfo, "exec_class");
	Info_RemoveKey(cls.userinfo, "em");
	Info_RemoveKey(cls.userinfo, "exec_map");
}
예제 #3
0
파일: IW4.cpp 프로젝트: TheMcSebi/iw4-test
/*
==================
Info_SetValueForKey

Changes or adds a key/value pair
==================
*/
void Info_SetValueForKey( char *s, const char *key, const char *value ) {
	char    newi[MAX_INFO_STRING];
	const char* blacklist = "\\;\"";

	if ( strlen( s ) >= MAX_INFO_STRING ) {
		Com_Printf( 0, "Info_SetValueForKey: oversize infostring");
		return;
	}

	for(; *blacklist; ++blacklist)
	{
		if (strchr (key, *blacklist) || strchr (value, *blacklist))
		{
			Com_Printf (0, "Can't use keys or values with a '%c': %s = %s\n", *blacklist, key, value);
			return;
		}
	}

	Info_RemoveKey (s, key);
	if (!value || !strlen(value))
		return;

	_snprintf (newi, sizeof(newi), "\\%s\\%s", key, value);

	if (strlen(newi) + strlen(s) >= MAX_INFO_STRING)
	{
		Com_Printf (0, "Info string length exceeded\n");
		return;
	}

	strcat (newi, s);
	strcpy (s, newi);
}
예제 #4
0
/*
==================
SV_ForceCvar_f_helper

Called internally by SV_ForceCvar_f.
==================
*/
static void SV_ForceCvar_f_helper( client_t *cl ) {
	int		oldInfoLen;
	int		newInfoLen;
	qboolean	touchedUserinfo = qfalse;

	// Who knows what would happen if we called the VM with a GAME_CLIENT_USERINFO_CHANGED
	// when this client wasn't connected.
	if (cl->state < CS_CONNECTED) {
		return;
	}

	// First remove all keys; there might exist more than one in the userinfo.
	oldInfoLen = strlen(cl->userinfo);
	while (qtrue) {
		Info_RemoveKey(cl->userinfo, Cmd_Argv(2));
		newInfoLen = strlen(cl->userinfo);
		if (oldInfoLen == newInfoLen) { break; } // userinfo wasn't modified.
		oldInfoLen = newInfoLen;
		touchedUserinfo = qtrue;
	}

	if (strlen(Cmd_Argv(3)) > 0) {
		if (strlen(Cmd_Argv(2)) + strlen(Cmd_Argv(3)) + 2 + newInfoLen >= MAX_INFO_STRING) {
			SV_DropClient(cl, "userinfo string length exceeded");
			return;
		}
		Info_SetValueForKey(cl->userinfo, Cmd_Argv(2), Cmd_Argv(3));
		touchedUserinfo = qtrue;
	}

	if (touchedUserinfo) {
		SV_UserinfoChanged(cl);
		VM_Call(gvm, GAME_CLIENT_USERINFO_CHANGED, cl - svs.clients);
	}
}
예제 #5
0
파일: sv_ccmds.c 프로젝트: luaman/qforge-1
void
SV_SetLocalinfo (const char *key, const char *value)
{
	char       *oldvalue = 0;

	if (sv_funcs.LocalinfoChanged)
		oldvalue = strdup (Info_ValueForKey (localinfo, key));

	if (*value)
		Info_SetValueForKey (localinfo, key, value, !sv_highchars->int_val);
	else
		Info_RemoveKey (localinfo, key);

	if (sv_funcs.LocalinfoChanged) {
		*sv_globals.time = sv.time;
		*sv_globals.self = 0;
		PR_PushFrame (&sv_pr_state);
		PR_RESET_PARAMS (&sv_pr_state);
		P_STRING (&sv_pr_state, 0) = PR_SetTempString (&sv_pr_state, key);
		P_STRING (&sv_pr_state, 1) = PR_SetTempString (&sv_pr_state, oldvalue);
		P_STRING (&sv_pr_state, 2) = PR_SetTempString (&sv_pr_state, value);
		PR_ExecuteProgram (&sv_pr_state, sv_funcs.LocalinfoChanged);
		PR_PopFrame (&sv_pr_state);
	}

	if (oldvalue)
		free (oldvalue);
}
예제 #6
0
void Info_RemovePrefixedKeys (char *start, char prefix) {
	char *s, pkey[512], value[512], *o;

	s = start;

	while (1) {
		if (*s == '\\')
			s++;
		o = pkey;
		while (*s != '\\') {
			if (!*s)
				return;
			*o++ = *s++;
		}
		*o = 0;
		s++;

		o = value;
		while (*s != '\\' && *s) {
			if (!*s)
				return;
			*o++ = *s++;
		}
		*o = 0;

		if (pkey[0] == prefix) {
			Info_RemoveKey (start, pkey);
			s = start;
		}

		if (!*s)
			return;
	}

}
예제 #7
0
/*
==================
Info_SetValueForKey

Changes or adds a key/value pair
==================
*/
void Info_SetValueForKey( char *s, const char *key, const char *value ) {
	char	newi[MAX_INFO_STRING];

	Info_RemoveKey (s, key);
	if (!value || !strlen(value))
		return;

	_snprintf (newi, sizeof(newi), "\\%s\\%s", key, value);

	strcat (newi, s);
	strcpy (s, newi);
}
예제 #8
0
/*
 =================
 Info_SetValueForKey
 =================
*/
void Info_SetValueForKey (char *string, char *key, char *value){

	char	newString[MAX_INFO_STRING], *s;
	int		c;

	if (strchr(key, '\\') || strchr(value, '\\')){
		Com_Printf("Can't use keys or values with a \\\n");
		return;
	}

	if (strchr(key, ';') || strchr(value, ';')){
		Com_Printf("Can't use keys or values with a ;\n");
		return;
	}

	if (strchr(key, '\"') || strchr(value, '\"')){
		Com_Printf("Can't use keys or values with a \"\n");
		return;
	}

	if (strlen(key) >= MAX_INFO_KEY){
		Com_Printf("Keys must be < %i characters\n", MAX_INFO_KEY);
		return;
	}
	if (strlen(value) >= MAX_INFO_VALUE){
		Com_Printf("Values must be < %i characters\n", MAX_INFO_VALUE);
		return;
	}

	Info_RemoveKey(string, key);
	if (!value || !value[0])
		return;

	Q_snprintfz(newString, sizeof(newString), "\\%s\\%s", key, value);

	if (strlen(newString) + strlen(string) > MAX_INFO_STRING){
		Com_Printf("Info string length exceeded\n");
		return;
	}

	// Only copy ASCII values
	string += strlen(string);
	s = newString;
	while (*s){
		c = *s++;

		c &= 127;		// Strip high bits
		if (c >= 32 && c < 127)
			*string++ = c;
	}
	*string = 0;
}
예제 #9
0
void Info_RemovePrefixedKeys (char *start, char prefix)
{
	char	*s;
	char	pkey[512];
	char	value[512];
	char	*o;

	s = start;

	while (1)
	{
		int nCount;

		if (*s == '\\')
			s++;

		nCount = 0;
		o = pkey;
		while ( (*s != '\\') && (nCount < sizeof(pkey)-1) )
		{
			if (!*s)
				return;

			*o++ = *s++;
			nCount++;
		}
		*o = 0;
		s++;

		nCount = 0;
		o = value;
		while ( (*s != '\\') && *s && (nCount < sizeof(value)-1) )
		{
			if (!*s)
				return;

			*o++ = *s++;
			nCount++;
		}
		*o = 0;

		if (pkey[0] == prefix)
		{
			Info_RemoveKey (start, pkey);
			s = start;
		}

		if (!*s)
			return;
	}
}
예제 #10
0
파일: sv_main.c 프로젝트: matatk/agrip
/*
===================
SV_FullClientUpdate

Writes all update values to a sizebuf
===================
*/
void SV_FullClientUpdate (client_t *client, sizebuf_t *buf)
{
	int		i;
	char	info[MAX_INFO_STRING];

	i = client - svs.clients;

	if (client->state == cs_free && sv_fastconnect.value)
		return;

	MSG_WriteByte (buf, svc_updatefrags);
	MSG_WriteByte (buf, i);
	MSG_WriteShort (buf, client->old_frags);
	
	MSG_WriteByte (buf, svc_updateping);
	MSG_WriteByte (buf, i);
	MSG_WriteShort (buf, SV_CalcPing (client));
	
	MSG_WriteByte (buf, svc_updatepl);
	MSG_WriteByte (buf, i);
	MSG_WriteByte (buf, client->lossage);
	
	MSG_WriteByte (buf, svc_updateentertime);
	MSG_WriteByte (buf, i);
	MSG_WriteFloat (buf, svs.realtime - client->connection_started);

	strcpy (info, client->userinfo);
	Info_RemovePrefixedKeys (info, '_');	// server passwords, etc
	Info_RemoveKey (info, "pmodel");
	Info_RemoveKey (info, "emodel");

	MSG_WriteByte (buf, svc_updateuserinfo);
	MSG_WriteByte (buf, i);
	MSG_WriteLong (buf, client->userid);
	MSG_WriteString (buf, info);
}
예제 #11
0
void Info_SetValueForKey(VStr& s, const VStr& key, const VStr& value)
{
    guard(Info_SetValueForKey);
    if (s.Length() >= MAX_INFO_STRING)
    {
        Host_Error("Info_SetValueForKey: oversize infostring");
    }

    if (strchr(*key, '\\') || strchr(*value, '\\'))
    {
        GCon->Log("Can't use keys or values with a \\");
        return;
    }

    if (strchr(*key, '\"') || strchr(*value, '\"'))
    {
        GCon->Log("Can't use keys or values with a \"");
        return;
    }

    // this next line is kinda trippy
    VStr v = Info_ValueForKey(s, key);
    if (v.IsNotEmpty())
    {
        //	Key exists, make sure we have enough room for new value, if we
        // don't, don't change it!
        if (value.Length() - v.Length() + s.Length() > MAX_INFO_STRING)
        {
            GCon->Log("Info string length exceeded");
            return;
        }
    }

    Info_RemoveKey(s, key);
    if (value.IsEmpty())
        return;

    VStr newi = VStr("\\") + key + "\\" +  value;

    if (newi.Length() + s.Length() > MAX_INFO_STRING)
    {
        GCon->Log("Info string length exceeded");
        return;
    }

    s = s + newi;
    unguard;
}
예제 #12
0
파일: q_shared.c 프로젝트: Bad-ptr/q2pro
/*
==================
Info_SetValueForKey
==================
*/
qboolean Info_SetValueForKey( char *s, const char *key, const char *value ) {
    char    newi[MAX_INFO_STRING], *v;
    size_t  l, kl, vl;
    int     c;

    // validate key
    kl = Info_SubValidate( key );
    if( kl >= MAX_QPATH ) {
        return qfalse;
    }

    // validate value
    vl = Info_SubValidate( value );
    if( vl >= MAX_QPATH ) {
        return qfalse;
    }

    Info_RemoveKey( s, key );
    if( !vl ) {
        return qtrue;
    }

    l = strlen( s );
    if( l + kl + vl + 2 >= MAX_INFO_STRING ) {
        return qfalse;
    }

    newi[0] = '\\';
    memcpy( newi + 1, key, kl );
    newi[kl + 1] = '\\';
    memcpy( newi + kl + 2, value, vl + 1 );

    // only copy ascii values
    s += l;
    v = newi;
    while( *v ) {
        c = *v++;
        c &= 127;        // strip high bits
        if( Q_isprint( c ) )
            *s++ = c;
    }
    *s = 0;

    return qtrue;
}
예제 #13
0
/*
==================
Info_SetValueForKey

Changes or adds a key/value pair
==================
*/
void Info_SetValueForKey( char *s, const char *key, const char *value ) {
	char	newi[MAX_INFO_STRING];

	if ( strlen( s ) >= MAX_INFO_STRING ) {
		Com_Error( ERR_DROP, "Info_SetValueForKey: oversize infostring" );
        return;
	}

	if (strchr (key, '\\') || strchr (value, '\\'))
	{
		Com_Printf ("Can't use keys or values with a \\\n");
		return;
	}

	if (strchr (key, ';') || strchr (value, ';'))
	{
		Com_Printf ("Can't use keys or values with a semicolon\n");
		return;
	}

	if (strchr (key, '\"') || strchr (value, '\"'))
	{
		Com_Printf ("Can't use keys or values with a \"\n");
		return;
	}

	Info_RemoveKey (s, key);
	if (!value || !strlen(value))
		return;

	snprintf (newi, sizeof(newi), "\\%s\\%s", key, value);

	if (strlen(newi) + strlen(s) > MAX_INFO_STRING)
	{
		Com_Printf ("Info string length exceeded\n");
		return;
	}

	strcat (newi, s);
	strcpy (s, newi);
}
예제 #14
0
파일: infostring.cpp 프로젝트: yason/ufoai
/**
 * @brief Adds a new entry into string with given value.
 * @note Removed any old version of the key
 * @param[in,out] s The target info string
 * @param[in] size The size of @c s
 * @param[in] key The key to set
 * @param[in] value The value to set for the given key
 * @sa Info_RemoveKey
 * @sa Info_SetValueForKeyAsInteger
 */
void Info_SetValueForKey (char* s, const size_t size, const char* key, const char* value)
{
	char newi[MAX_INFO_STRING];

	if (strstr(key, "\\") || strstr(value, "\\")) {
		Com_Printf("Can't use keys or values with a \\\n");
		return;
	}

	if (strstr(key, ";")) {
		Com_Printf("Can't use keys or values with a semicolon\n");
		return;
	}

	if (strstr(key, "\"") || strstr(value, "\"")) {
		Com_Printf("Can't use keys or values with a \"\n");
		return;
	}

	if (strlen(key) > MAX_INFO_KEY - 1) {
		Com_Printf("Keys must be < " DOUBLEQUOTE(MAX_INFO_KEY) " characters.\n");
		return;
	}

	if (strlen(key) > MAX_INFO_VALUE - 1) {
		Com_Printf("Values must be < " DOUBLEQUOTE(MAX_INFO_VALUE) " characters.\n");
		return;
	}

	Info_RemoveKey(s, key);
	if (Q_strnull(value))
		return;

	Com_sprintf(newi, sizeof(newi), "\\%s\\%s%s", key, value, s);
	Q_strncpyz(s, newi, size);
}
예제 #15
0
/*
==================
SV_DirectConnect

A "connect" OOB command has been received
==================
*/
void SV_DirectConnect( netadr_t from, const Cmd::Args& args )
{
	char                userinfo[ MAX_INFO_STRING ];
	int                 i;
	client_t            *cl, *newcl;
	client_t            temp;
	sharedEntity_t      *ent;
	int                 clientNum;
	int                 version;
	int                 qport;
	int                 challenge;
	const char                *password;
	int                 startIndex;
	bool            denied;
	char                reason[ MAX_STRING_CHARS ];
	int                 count;
	const char          *ip;
#ifdef HAVE_GEOIP
	const char          *country = nullptr;
#endif

	if ( args.Argc() < 2 )
	{
		return;
	}

	Log::Debug( "SVC_DirectConnect ()" );

	Q_strncpyz( userinfo, args.Argv(1).c_str(), sizeof( userinfo ) );

	// DHM - Nerve :: Update Server allows any protocol to connect
	// NOTE TTimo: but we might need to store the protocol around for potential non http/ftp clients
	version = atoi( Info_ValueForKey( userinfo, "protocol" ) );

	if ( version != PROTOCOL_VERSION )
	{
		NET_OutOfBandPrint( netsrc_t::NS_SERVER, from, "print\nServer uses protocol version %i (yours is %i).", PROTOCOL_VERSION, version );
		Log::Debug( "    rejected connect from version %i", version );
		return;
	}

	challenge = atoi( Info_ValueForKey( userinfo, "challenge" ) );
	qport = atoi( Info_ValueForKey( userinfo, "qport" ) );

	// quick reject
	for ( i = 0, cl = svs.clients; i < sv_maxclients->integer; i++, cl++ )
	{
		// DHM - Nerve :: This check was allowing clients to reconnect after zombietime(2 secs)
		//if ( cl->state == CS_FREE ) {
		//continue;
		//}
		if ( NET_CompareBaseAdr( from, cl->netchan.remoteAddress )
		     && ( cl->netchan.qport == qport
		          || from.port == cl->netchan.remoteAddress.port ) )
		{
			if ( ( svs.time - cl->lastConnectTime )
			     < ( sv_reconnectlimit->integer * 1000 ) )
			{
				Log::Debug( "%s: reconnect rejected: too soon", NET_AdrToString( from ) );
				return;
			}

			break;
		}
	}

	if ( NET_IsLocalAddress( from ) )
	{
		ip = "localhost";
	}
	else
	{
		ip = NET_AdrToString( from );
	}

	if ( ( strlen( ip ) + strlen( userinfo ) + 4 ) >= MAX_INFO_STRING )
	{
		NET_OutOfBandPrint( netsrc_t::NS_SERVER, from,
		                    "print\nUserinfo string length exceeded.  "
		                    "Try removing setu cvars from your config." );
		return;
	}

	Info_SetValueForKey( userinfo, "ip", ip, false );

	// see if the challenge is valid (local clients don't need to challenge)
	if ( !NET_IsLocalAddress( from ) )
	{
		int ping;

		for ( i = 0; i < MAX_CHALLENGES; i++ )
		{
			if ( NET_CompareAdr( from, svs.challenges[ i ].adr ) )
			{
				if ( challenge == svs.challenges[ i ].challenge )
				{
					break; // good
				}
			}
		}

		if ( i == MAX_CHALLENGES )
		{
			NET_OutOfBandPrint( netsrc_t::NS_SERVER, from, "print\n[err_dialog]No or bad challenge for address." );
			return;
		}

		// force the IP address key/value pair, so the game can filter based on it
		Info_SetValueForKey( userinfo, "ip", NET_AdrToString( from ), false );

		if ( svs.challenges[ i ].firstPing == 0 )
		{
			ping = svs.time - svs.challenges[ i ].pingTime;
			svs.challenges[ i ].firstPing = ping;
		}
		else
		{
			ping = svs.challenges[ i ].firstPing;
		}

#ifdef HAVE_GEOIP
		country = NET_GeoIP_Country( &from );

		if ( country )
		{
			Log::Notice( "Client %i connecting from %s with %i challenge ping\n", i, country, ping );
		}
		else
		{
			Log::Notice( "Client %i connecting from somewhere unknown with %i challenge ping\n", i, ping );
		}
#else
		Log::Notice( "Client %i connecting with %i challenge ping\n", i, ping );
#endif

		svs.challenges[ i ].connected = true;

		// never reject a LAN client based on ping
		if ( !Sys_IsLANAddress( from ) )
		{
			if ( sv_minPing->value && ping < sv_minPing->value )
			{
				NET_OutOfBandPrint( netsrc_t::NS_SERVER, from, "print\n[err_dialog]Server is for high pings only" );
				Log::Debug( "Client %i rejected on a too low ping", i );
				return;
			}

			if ( sv_maxPing->value && ping > sv_maxPing->value )
			{
				NET_OutOfBandPrint( netsrc_t::NS_SERVER, from, "print\n[err_dialog]Server is for low pings only" );
				Log::Debug( "Client %i rejected on a too high ping: %i", i, ping );
				return;
			}
		}
	}
	else
	{
		// force the "ip" info key to "localhost"
		Info_SetValueForKey( userinfo, "ip", "localhost", false );
	}

	newcl = &temp;
	memset( newcl, 0, sizeof( client_t ) );

	// if there is already a slot for this IP address, reuse it
	for ( i = 0, cl = svs.clients; i < sv_maxclients->integer; i++, cl++ )
	{
		if ( cl->state == clientState_t::CS_FREE )
		{
			continue;
		}

		if ( NET_CompareBaseAdr( from, cl->netchan.remoteAddress )
		     && ( cl->netchan.qport == qport
		          || from.port == cl->netchan.remoteAddress.port ) )
		{
			Log::Notice( "%s:reconnect\n", NET_AdrToString( from ) );
			newcl = cl;

			// this doesn't work because it nukes the players userinfo

//			// disconnect the client from the game first so any flags the
//			// player might have are dropped
//			VM_Call( gvm, GAME_CLIENT_DISCONNECT, newcl - svs.clients );
			//
			goto gotnewcl;
		}
	}

	// find a client slot
	// if "sv_privateClients" is set > 0, then that number
	// of client slots will be reserved for connections that
	// have "password" set to the value of "sv_privatePassword"
	// Info requests will report the maxclients as if the private
	// slots didn't exist, to prevent people from trying to connect
	// to a full server.
	// This is to allow us to reserve a couple slots here on our
	// servers so we can play without having to kick people.

	// check for privateClient password
	password = Info_ValueForKey( userinfo, "password" );

	if ( !strcmp( password, sv_privatePassword->string ) )
	{
		startIndex = 0;
	}
	else
	{
		// skip past the reserved slots
		startIndex = sv_privateClients->integer;
	}

	newcl = nullptr;

	for ( i = startIndex; i < sv_maxclients->integer; i++ )
	{
		cl = &svs.clients[ i ];

		if ( cl->state == clientState_t::CS_FREE )
		{
			newcl = cl;
			break;
		}
	}

	if ( !newcl )
	{
		if ( NET_IsLocalAddress( from ) )
		{
			count = 0;

			for ( i = startIndex; i < sv_maxclients->integer; i++ )
			{
				cl = &svs.clients[ i ];

				if ( SV_IsBot(cl) )
				{
					count++;
				}
			}

			// if they're all bots
			if ( count >= sv_maxclients->integer - startIndex )
			{
				SV_DropClient( &svs.clients[ sv_maxclients->integer - 1 ], "only bots on server" );
				newcl = &svs.clients[ sv_maxclients->integer - 1 ];
			}
			else
			{
				Com_Error( errorParm_t::ERR_FATAL, "server is full on local connect" );
			}
		}
		else
		{
			NET_OutOfBandPrint( netsrc_t::NS_SERVER, from, "print\n%s", sv_fullmsg->string );
			Log::Debug( "Rejected a connection." );
			return;
		}
	}

	// we got a newcl, so reset the reliableSequence and reliableAcknowledge
	cl->reliableAcknowledge = 0;
	cl->reliableSequence = 0;

gotnewcl:
	// build a new connection
	// accept the new client
	// this is the only place a client_t is ever initialized
	*newcl = std::move(temp);
	clientNum = newcl - svs.clients;
	ent = SV_GentityNum( clientNum );
	newcl->gentity = ent;
	ent->r.svFlags = 0;

#ifdef HAVE_GEOIP

	if ( country )
	{
		Info_SetValueForKey( userinfo, "geoip", country, false );
	}
#endif

	// save the challenge
	newcl->challenge = challenge;

	// save the address
	Netchan_Setup( netsrc_t::NS_SERVER, &newcl->netchan, from, qport );
	// init the netchan queue

	// Save the pubkey
	Q_strncpyz( newcl->pubkey, Info_ValueForKey( userinfo, "pubkey" ), sizeof( newcl->pubkey ) );
	Info_RemoveKey( userinfo, "pubkey", false );
	// save the userinfo
	Q_strncpyz( newcl->userinfo, userinfo, sizeof( newcl->userinfo ) );

	// get the game a chance to reject this connection or modify the userinfo
	denied = gvm.GameClientConnect( reason, sizeof( reason ), clientNum, true, false );  // firstTime = true

	if ( denied )
	{
		NET_OutOfBandPrint( netsrc_t::NS_SERVER, from, "print\n[err_dialog]%s", reason );
		Log::Debug( "Game rejected a connection: %s.", reason );
		return;
	}

	SV_UserinfoChanged( newcl );

	// DHM - Nerve :: Clear out firstPing now that client is connected
	svs.challenges[ i ].firstPing = 0;

	// send the connect packet to the client
	NET_OutOfBandPrint( netsrc_t::NS_SERVER, from, "connectResponse" );

	Log::Debug( "Going from CS_FREE to CS_CONNECTED for %s", newcl->name );

	newcl->state = clientState_t::CS_CONNECTED;
	newcl->nextSnapshotTime = svs.time;
	newcl->lastPacketTime = svs.time;
	newcl->lastConnectTime = svs.time;

	// when we receive the first packet from the client, we will
	// notice that it is from a different serverid and that the
	// gamestate message was not just sent, forcing a retransmit
	newcl->gamestateMessageNum = -1;

	// if this was the first client on the server, or the last client
	// the server can hold, send a heartbeat to the master.
	count = 0;

	for ( i = 0, cl = svs.clients; i < sv_maxclients->integer; i++, cl++ )
	{
		if ( svs.clients[ i ].state >= clientState_t::CS_CONNECTED )
		{
			count++;
		}
	}

	if ( count == 1 || count == sv_maxclients->integer )
	{
		SV_Heartbeat_f();
	}
}
예제 #16
0
파일: sv_main.c 프로젝트: matatk/agrip
/*
==================
SVC_DirectConnect

A connection request that did not come from the master
==================
*/
void SVC_DirectConnect (void)
{
	char		userinfo[1024];
	netadr_t	adr;
	int			i;
	client_t	*cl, *newcl;
	edict_t		*ent;
	int			edictnum;
	char		*s;
	int			clients, spectators;
	qbool		spectator;
	int			qport;
	int			version;
	int			challenge;

	version = atoi(Cmd_Argv(1));
	if (version != PROTOCOL_VERSION)
	{
		Netchan_OutOfBandPrint (NS_SERVER, net_from, "%c\nServer is version %4.2f.\n", A2C_PRINT, QW_VERSION);
		Com_Printf ("* rejected connect from version %i\n", version);
		return;
	}

	qport = atoi(Cmd_Argv(2));
	challenge = atoi(Cmd_Argv(3));

	// note an extra byte is needed to replace spectator key
	strlcpy (userinfo, Cmd_Argv(4), sizeof(userinfo)-1);

	// see if the challenge is valid
	if (net_from.type != NA_LOOPBACK)
	{
		for (i=0 ; i<MAX_CHALLENGES ; i++)
		{
			if (NET_CompareBaseAdr (net_from, svs.challenges[i].adr))
			{
				if (challenge == svs.challenges[i].challenge)
					break;		// good
				Netchan_OutOfBandPrint (NS_SERVER, net_from, "%c\nBad challenge.\n", A2C_PRINT);
				return;
			}
		}
		if (i == MAX_CHALLENGES)
		{
			Netchan_OutOfBandPrint (NS_SERVER, net_from, "%c\nNo challenge for address.\n", A2C_PRINT);
			return;
		}
	}

	// check for password or spectator_password
	s = Info_ValueForKey (userinfo, "spectator");
	if (s[0] && strcmp(s, "0"))
	{
		if (sv_spectatorPassword.string[0] && 
			Q_stricmp(sv_spectatorPassword.string, "none") &&
			strcmp(sv_spectatorPassword.string, s) )
		{	// failed
			Com_Printf ("%s:spectator password failed\n", NET_AdrToString (net_from));
			Netchan_OutOfBandPrint (NS_SERVER, net_from, "%c\nrequires a spectator password\n\n", A2C_PRINT);
			return;
		}
		Info_RemoveKey (userinfo, "spectator");
		Info_SetValueForStarKey (userinfo, "*spectator", "1", MAX_INFO_STRING);
		spectator = true;
	}
	else
	{
		s = Info_ValueForKey (userinfo, "password");
		if (sv_password.string[0] && 
			Q_stricmp(sv_password.string, "none") &&
			strcmp(sv_password.string, s) )
		{
			Com_Printf ("%s:password failed\n", NET_AdrToString (net_from));
			Netchan_OutOfBandPrint (NS_SERVER, net_from, "%c\nserver requires a password\n\n", A2C_PRINT);
			return;
		}
		spectator = false;
		Info_RemoveKey (userinfo, "password");
	}

#ifdef MAUTH
    // Check that the client is allowed to connect...
	if( net_from.type != NA_LOOPBACK && !COM_CheckParm("-nomauth") )
    {
        authclient_t *authclient;
    
        // Try the auth token queue first...
        authclient = SV_AuthListFind(&authtokq, Info_ValueForKey(userinfo, "name"));
        if( authclient == NULL )
        {
            // Fall back to checking if they had already connected and are in the
            // client queue already (i.e. were on here before a map change)...
            authclient = SV_AuthListFind(&authclientq, Info_ValueForKey(userinfo, "name"));
            if( authclient == NULL )
            {
                // FIXME drop with reason
                Com_Printf ("MAUTH: Client %s not in a queue; connect refused.\n", Info_ValueForKey(userinfo, "name"));
                return;
            }
        }
        else
        {
            // They're valid, so move them to the main client queue from the
            // auth cache queue...
            SV_AuthListMove(&authtokq, &authclientq, authclient);
        }

        // Move to auth'd clients queue if they're valid...
        if( !authclient->valid )
        {
            // FIXME drop with reason
            Com_Printf ("MAUTH: Client %s not validated yet; connect refused.\n", Info_ValueForKey(userinfo, "name"));
            return;
        }
        
        //SV_AuthListPrint(&authtokq);
        //SV_AuthListPrint(&authclientq);
        
        Com_Printf ("MAUTH: Client %s connection allowed.\n", Info_ValueForKey(userinfo, "name"));
    }
    else
    {
        Com_Printf("MAUTH: loopback or disabled; allowing client connection.\n");
    }
#endif

	adr = net_from;

	// if there is already a slot for this ip, reuse it
	for (i = 0, cl = svs.clients; i < MAX_CLIENTS; i++, cl++)
	{
		if (cl->state == cs_free)
			continue;
		if (NET_CompareBaseAdr (adr, cl->netchan.remote_address)
			&& ( cl->netchan.qport == qport 
			|| adr.port == cl->netchan.remote_address.port ))
		{
			if (cl->state == cs_connected) {
				Com_Printf ("%s:dup connect\n", NET_AdrToString (adr));
				return;
			}

			Com_Printf ("%s:reconnect\n", NET_AdrToString (adr));
			if (cl->state == cs_spawned)
			{
				SV_DropClient (cl);
				SV_ClearReliable (cl);	// don't send the disconnect
			}
			cl->state = cs_free;
			break;
		}
	}

	// count up the clients and spectators and find an empty client slot
	clients = spectators = 0;
	newcl = NULL;
	for (i = 0, cl = svs.clients; i < MAX_CLIENTS; i++,cl++)
	{
		if (cl->state == cs_free) {
			if (!newcl)
				newcl = cl;		// grab first available slot
			continue;
		}
		if (cl->spectator)
			spectators++;
		else
			clients++;
	}

	// if at server limits, refuse connection
	if ( (spectator && spectators >= (int)maxspectators.value)
		|| (!spectator && clients >= (int)maxclients.value)
		|| !newcl)
	{
		Com_Printf ("%s:full connect\n", NET_AdrToString (adr));
		Netchan_OutOfBandPrint (NS_SERVER, adr, "%c\nserver is full\n\n", A2C_PRINT);
		return;
	}

	// build a new connection
	// accept the new client
	// this is the only place a client_t is ever initialized
	memset (newcl, 0, sizeof(*newcl));
	newcl->userid = SV_GenerateUserID();

	strlcpy (newcl->userinfo, userinfo, sizeof(newcl->userinfo));

	Netchan_OutOfBandPrint (NS_SERVER, adr, "%c", S2C_CONNECTION );

	Netchan_Setup (NS_SERVER, &newcl->netchan, adr, qport);

	newcl->state = cs_connected;

	SZ_Init (&newcl->datagram, newcl->datagram_buf, sizeof(newcl->datagram_buf));
	newcl->datagram.allowoverflow = true;

	// spectator mode can ONLY be set at join time
	newcl->spectator = spectator;

	// extract extensions bits
	newcl->extensions = atoi(Info_ValueForKey(newcl->userinfo, "*z_ext"));
	Info_RemoveKey (newcl->userinfo, "*z_ext");

#ifdef VWEP_TEST
	newcl->extensions |= atoi(Info_ValueForKey(newcl->userinfo, "*vwtest")) ? Z_EXT_VWEP : 0;
	Info_RemoveKey (newcl->userinfo, "*vwtest");
#endif

	// See if the client is using a proxy. The best test I can come up with for now...
	newcl->uses_proxy = *Info_ValueForKey(newcl->userinfo, "Qizmo") ? true : false;

	edictnum = (newcl - svs.clients) + 1;
	ent = EDICT_NUM(edictnum);	
	ent->inuse = true;
	newcl->edict = ent;
	
	// parse some info from the info strings
	SV_ExtractFromUserinfo (newcl);

	// JACK: Init the floodprot stuff.
	for (i=0; i<10; i++)
		newcl->whensaid[i] = 0.0;
	newcl->whensaidhead = 0;
	newcl->lockedtill = 0;

	// call the progs to get default spawn parms for the new client
	PR_ExecuteProgram (pr_global_struct->SetNewParms);
	for (i=0 ; i<NUM_SPAWN_PARMS ; i++)
		newcl->spawn_parms[i] = (&pr_global_struct->parm1)[i];

	if (newcl->spectator)
		Com_Printf ("Spectator %s connected\n", newcl->name);
	else
		Com_DPrintf ("Client %s connected\n", newcl->name);

	newcl->sendinfo = true;
}
예제 #17
0
void Info_SetValueForStarKey ( char *s, const char *key, const char *value, int maxsize )
{
	char	news[1024], *v;
	int		c;

	if (strstr (key, "\\") || strstr (value, "\\") )
	{
		return;
	}

	if (strstr (key, "..") || strstr (value, "..") )
	{
//		Con_Printf ("Can't use keys or values with a ..\n");
		return;
	}

	if (strstr (key, "\"") || strstr (value, "\"") )
	{
		return;
	}

	if (strlen(key) > MAX_KV_LEN || strlen(value) > MAX_KV_LEN)
	{
		return;
	}
	Info_RemoveKey (s, key);
	if (!value || !strlen(value))
		return;

	sprintf (news, "\\%s\\%s", key, value);

 	if ( (int)(strlen(news) + strlen(s)) >= maxsize)
	{
		// no more room in buffer to add key/value
		if ( Info_IsKeyImportant( key ) )
		{
			// keep removing the largest key/values until we have room
			char *largekey;
			do {
				largekey = Info_FindLargestKey( s, maxsize );
				Info_RemoveKey( s, largekey );
			} while ( ((int)(strlen(news) + strlen(s)) >= maxsize) && *largekey != 0 );

			if ( largekey[0] == 0 )
			{
				// no room to add setting
				return;
			}
		}
		else
		{
			// no room to add setting
			return;
		}
	}

	// only copy ascii values
	s += strlen(s);
	v = news;
	while (*v)
	{
		c = (unsigned char)*v++;

		// Strip out high ascii characters
		c &= 127;

		if (c > 13)
		{
			*s++ = c;
		}
	}
	*s = 0;
}
예제 #18
0
파일: info.cpp 프로젝트: ChunHungLiu/rehlds
/* <41063> ../engine/info.c:275 */
void Info_SetValueForStarKey(char *s, const char *key, const char *value, int maxsize)
{
	char newArray[MAX_INFO_STRING];
	char *v;
	int c;

	if (!key || !value)
	{
		Con_Printf("Keys and values can't be null\n");
		return;
	}

	if (key[0] == 0)
	{
		Con_Printf("Keys can't be an empty string\n");
		return;
	}

	if (Q_strstr(key, "\\") || Q_strstr(value, "\\"))
	{
		Con_Printf("Can't use keys or values with a \\\n");
		return;
	}

	if (Q_strstr(key, "..") || Q_strstr(value, ".."))
	{
		// TODO: Why silently return?
		//Con_Printf("Can't use keys or values with a ..\n");
		return;
	}

	if (Q_strstr(key, "\"") || Q_strstr(value, "\""))
	{
		Con_Printf("Can't use keys or values with a \"\n");
		return;
	}

	int keyLen = Q_strlen(key);
	int valueLan = Q_strlen(value);

	if (keyLen >= MAX_KV_LEN || valueLan >= MAX_KV_LEN)
	{
		Con_Printf("Keys and values must be < %i characters\n", MAX_KV_LEN);
		return;
	}

	if (!Q_UnicodeValidate(key) || !Q_UnicodeValidate(value))
	{
		Con_Printf("Keys and values must be valid utf8 text\n");
		return;
	}

	// Remove current key/value and return if we doesn't specified to set a value
	Info_RemoveKey(s, key);
	if (value[0] == 0)
	{
		return;
	}

	// Create key/value pair
	Q_snprintf(newArray, MAX_INFO_STRING - 1, "\\%s\\%s", key, value);
	newArray[MAX_INFO_STRING - 1] = 0;

	int neededLength = Q_strlen(newArray);
	if ((int)Q_strlen(s) + neededLength >= maxsize)
	{
		// no more room in the buffer to add key/value
		if (!Info_IsKeyImportant(key))
		{
			// no room to add setting
			Con_Printf("Info string length exceeded\n");
			return;
		}

		// keep removing the largest key/values until we have a room
		char *largekey;
		do
		{
			largekey = Info_FindLargestKey(s, maxsize);
			if (largekey[0] == 0)
			{
				// no room to add setting
				Con_Printf("Info string length exceeded\n");
				return;
			}
			Info_RemoveKey(s, largekey);
		} while ((int)Q_strlen(s) + neededLength >= maxsize);
	}

	// auto lowercase team
	bool lowerCaseValue = Q_stricmp(key, "team") == 0;
	s += Q_strlen(s);
	v = newArray;
	while (*v)
	{
		c = (unsigned char)*v++;
		if (lowerCaseValue)
		{
			c = tolower(c);
		}
		*s++ = c;
	}
	*s = 0;
}
예제 #19
0
파일: sv_main.c 프로젝트: hettoo/racesow
/*
* SV_UserinfoChanged
* 
* Pull specific info from a newly changed userinfo string
* into a more C friendly form.
*/
void SV_UserinfoChanged( client_t *client )
{
	char *val;
	int ival;

	assert( client );
	assert( Info_Validate( client->userinfo ) );

	if( !client->edict || !( client->edict->r.svflags & SVF_FAKECLIENT ) )
	{
		// force the IP key/value pair so the game can filter based on ip
		if( !Info_SetValueForKey( client->userinfo, "socket", NET_SocketTypeToString( client->netchan.socket->type ) ) )
		{
			SV_DropClient( client, DROP_TYPE_GENERAL, "Error: Couldn't set userinfo (socket)\n" );
			return;
		}
		if( !Info_SetValueForKey( client->userinfo, "ip", NET_AddressToString( &client->netchan.remoteAddress ) ) )
		{
			SV_DropClient( client, DROP_TYPE_GENERAL, "Error: Couldn't set userinfo (ip)\n" );
			return;
		}
	}

	// mm session
	ival = 0;
	val = Info_ValueForKey( client->userinfo, "cl_mm_session" );
	if( val )
		ival = atoi( val );
	if( !val || ival != client->mm_session )
		Info_SetValueForKey( client->userinfo, "cl_mm_session", va("%d", client->mm_session ) );

	// mm login
	if( client->mm_login[0] != '\0' ) {
		Info_SetValueForKey( client->userinfo, "cl_mm_login", client->mm_login );
	}
	else {
		Info_RemoveKey( client->userinfo, "cl_mm_login" );
	}

	// call prog code to allow overrides
	ge->ClientUserinfoChanged( client->edict, client->userinfo );

	if( !Info_Validate( client->userinfo ) )
	{
		SV_DropClient( client, DROP_TYPE_GENERAL, "Error: Invalid userinfo (after game)" );
		return;
	}

	// we assume that game module deals with setting a correct name
	val = Info_ValueForKey( client->userinfo, "name" );
	if( !val || !val[0] )
	{
		SV_DropClient( client, DROP_TYPE_GENERAL, "Error: No name set" );
		return;
	}
	Q_strncpyz( client->name, val, sizeof( client->name ) );

#ifndef RATEKILLED
	// rate command
	if( NET_IsLANAddress( &client->netchan.remoteAddress ) )
	{
		client->rate = 99999; // lans should not rate limit
	}
	else
	{
		val = Info_ValueForKey( client->userinfo, "rate" );
		if( val && val[0] )
		{
			int newrate;

			newrate = atoi( val );
			if( sv_maxrate->integer && newrate > sv_maxrate->integer )
				newrate = sv_maxrate->integer;
			else if( newrate > 90000 )
				newrate = 90000;
			if( newrate < 1000 )
				newrate = 1000;
			if( client->rate != newrate )
			{
				client->rate = newrate;
				Com_Printf( "%s%s has rate %i\n", client->name, S_COLOR_WHITE, client->rate );
			}
		}
		else
			client->rate = 5000;
	}
#endif
}
예제 #20
0
/*
==================
SVC_DirectConnect

A connection request that did not come from the master
==================
*/
static void SVC_DirectConnect (void)
{
	char		userinfo[1024];
	static		int	userid;
	netadr_t	adr;
	int			i;
	client_t	*cl, *newcl;
	client_t	temp;
	edict_t		*ent;
	int			edictnum;
	const char		*s;
	int			clients, spectators;
	qboolean	spectator;

	q_strlcpy (userinfo, Cmd_Argv(2), sizeof(userinfo));

	// check for password or spectator_password
	s = Info_ValueForKey (userinfo, "spectator");
	if (s[0] && strcmp(s, "0"))
	{
		if (spectator_password.string[0] && 
			q_strcasecmp(spectator_password.string, "none") &&
			strcmp(spectator_password.string, s) )
		{	// failed
			Con_Printf ("%s:spectator password failed\n", NET_AdrToString (net_from));
			Netchan_OutOfBandPrint (net_from, "%c\nrequires a spectator password\n\n", A2C_PRINT);
			return;
		}
		Info_SetValueForStarKey (userinfo, "*spectator", "1", MAX_INFO_STRING);
		spectator = true;
		Info_RemoveKey (userinfo, "spectator"); // remove passwd
	}
	else
	{
		s = Info_ValueForKey (userinfo, "password");
		if (password.string[0] && 
			q_strcasecmp(password.string, "none") &&
			strcmp(password.string, s) )
		{
			Con_Printf ("%s:password failed\n", NET_AdrToString (net_from));
			Netchan_OutOfBandPrint (net_from, "%c\nserver requires a password\n\n", A2C_PRINT);
			return;
		}
		spectator = false;
		Info_RemoveKey (userinfo, "password"); // remove passwd
	}

	adr = net_from;
	userid++;	// so every client gets a unique id

	newcl = &temp;
	memset (newcl, 0, sizeof(client_t));

	newcl->userid = userid;
	newcl->portals = atoi(Cmd_Argv(1));

	// works properly
	if (!sv_highchars.integer)
	{
		byte	*p, *q;

		for (p = (byte *)newcl->userinfo, q = (byte *)userinfo;
			*q && p < (byte *)newcl->userinfo + sizeof(newcl->userinfo)-1; q++)
		{
			if (*q > 31 && *q <= 127)
				*p++ = *q;
		}
	}
	else
	{
		q_strlcpy (newcl->userinfo, userinfo, sizeof(newcl->userinfo));
	}

	// if there is already a slot for this ip, drop it
	for (i = 0, cl = svs.clients; i < MAX_CLIENTS; i++, cl++)
	{
		if (cl->state == cs_free)
			continue;
		if (NET_CompareAdr (adr, cl->netchan.remote_address))
		{
			Con_Printf ("%s:reconnect\n", NET_AdrToString (adr));
			SV_DropClient (cl);
			break;
		}
	}

	// count up the clients and spectators
	clients = 0;
	spectators = 0;
	for (i = 0, cl = svs.clients; i < MAX_CLIENTS; i++, cl++)
	{
		if (cl->state == cs_free)
			continue;
		if (cl->spectator)
			spectators++;
		else
			clients++;
	}

	// if at server limits, refuse connection
	if (maxclients.integer > MAX_CLIENTS)
		Cvar_SetValue ("maxclients", MAX_CLIENTS);
	if (maxspectators.integer > MAX_CLIENTS)
		Cvar_SetValue ("maxspectators", MAX_CLIENTS);
	if (maxspectators.integer + maxclients.integer > MAX_CLIENTS)
		Cvar_SetValue ("maxspectators", MAX_CLIENTS - maxspectators.integer + maxclients.integer);
	if ( (spectator && spectators >= maxspectators.integer)
		|| (!spectator && clients >= maxclients.integer) )
	{
		Con_Printf ("%s:full connect\n", NET_AdrToString (adr));
		Netchan_OutOfBandPrint (adr, "%c\nserver is full\n\n", A2C_PRINT);
		return;
	}

	// find a client slot
	newcl = NULL;
	for (i = 0, cl = svs.clients; i < MAX_CLIENTS; i++, cl++)
	{
		if (cl->state == cs_free)
		{
			newcl = cl;
			break;
		}
	}
	if (!newcl)
	{
		Con_Printf ("WARNING: miscounted available clients\n");
		return;
	}

	// build a new connection
	// accept the new client
	// this is the only place a client_t is ever initialized
	*newcl = temp;

	Netchan_OutOfBandPrint (adr, "%c", S2C_CONNECTION );

	edictnum = (newcl-svs.clients)+1;

	Netchan_Setup (&newcl->netchan, adr);

	newcl->state = cs_connected;

	SZ_Init (&newcl->datagram, newcl->datagram_buf, sizeof(newcl->datagram_buf));
	newcl->datagram.allowoverflow = true;

	// spectator mode can ONLY be set at join time
	newcl->spectator = spectator;

	ent = EDICT_NUM(edictnum);
	newcl->edict = ent;
	ED_ClearEdict (ent);

	// parse some info from the info strings
	SV_ExtractFromUserinfo (newcl);

	// JACK: Init the floodprot stuff.
	for (i = 0; i < 10; i++)
		newcl->whensaid[i] = 0.0;
	newcl->whensaidhead = 0;
	newcl->lockedtill = 0;

	// call the progs to get default spawn parms for the new client
	PR_ExecuteProgram (pr_global_struct->SetNewParms);
	for (i = 0; i < NUM_SPAWN_PARMS; i++)
		newcl->spawn_parms[i] = (&pr_global_struct->parm1)[i];

	if (newcl->spectator)
		Con_Printf ("Spectator %s connected\n", newcl->name);
	else
		Con_DPrintf ("Client %s connected\n", newcl->name);
}
예제 #21
0
void Info_SetValueForStarKey ( char *s, const char *key, const char *value, int maxsize )
{
	char	newch[1024], *v;
	int		c;
#ifdef SERVERONLY
	extern cvar_t sv_highchars;
#endif

	if (strstr (key, "\\") || strstr (value, "\\") )
	{
		return;
	}

	if (strstr (key, "\"") || strstr (value, "\"") )
	{
		return;
	}

	if (strlen(key) > MAX_KV_LEN || strlen(value) > MAX_KV_LEN)
	{
		return;
	}
	Info_RemoveKey (s, key);
	if (!value || !strlen(value))
		return;

	sprintf (newch, "\\%s\\%s", key, value);

 	if ( (int)(strlen(newch) + strlen(s)) >= maxsize)
	{
		return;
	}

	// only copy ascii values
	s += strlen(s);
	v = newch;
	while (*v)
	{
		c = (unsigned char)*v++;
#ifndef SERVERONLY
		// client only allows highbits on name
		if (stricmp(key, "name") != 0) {
			c &= 127;
			if (c < 32 || c > 127)
				continue;
			// auto lowercase team
			if (stricmp(key, "team") == 0)
				c = tolower(c);
		}
#else
		if (!sv_highchars.value) {
			c &= 127;
			if (c < 32 || c > 127)
				continue;
		}
#endif
//		c &= 127;		// strip high bits
		if (c > 13) // && c < 127)
			*s++ = (char)c;
	}
	*s = 0;
}
예제 #22
0
/*
* SV_LongInfoString
* Builds the string that is sent as heartbeats and status replies
*/
static char *SV_LongInfoString( qboolean fullStatus )
{
	char tempstr[1024] = { 0 };
	const char *gametype;
	static char status[MAX_MSGLEN - 16];
	int i, bots, count;
	client_t *cl;
	size_t statusLength;
	size_t tempstrLength;

	Q_strncpyz( status, Cvar_Serverinfo(), sizeof( status ) );

	// convert "g_gametype" to "gametype"
	gametype = Info_ValueForKey( status, "g_gametype" );
	if( gametype )
	{
		Info_RemoveKey( status, "g_gametype" );
		Info_SetValueForKey( status, "gametype", gametype );
	}

	statusLength = strlen( status );

	bots = 0;
	count = 0;
	for( i = 0; i < sv_maxclients->integer; i++ )
	{
		cl = &svs.clients[i];
		if( cl->state >= CS_CONNECTED )
		{
			if( cl->edict->r.svflags & SVF_FAKECLIENT || cl->tvclient )
				bots++;
			count++;
		}
	}

	if( bots )
		Q_snprintfz( tempstr, sizeof( tempstr ), "\\bots\\%i", bots );
	Q_snprintfz( tempstr + strlen( tempstr ), sizeof( tempstr ) - strlen( tempstr ), "\\clients\\%i%s", count, fullStatus ? "\n" : "" );
	tempstrLength = strlen( tempstr );
	if( statusLength + tempstrLength >= sizeof( status ) )
		return status; // can't hold any more
	Q_strncpyz( status + statusLength, tempstr, sizeof( status ) - statusLength );
	statusLength += tempstrLength;

	if ( fullStatus )
	{
		for( i = 0; i < sv_maxclients->integer; i++ )
		{
			cl = &svs.clients[i];
			if( cl->state >= CS_CONNECTED )
			{
				Q_snprintfz( tempstr, sizeof( tempstr ), "%i %i \"%s\" %i\n",
					cl->edict->r.client->r.frags, cl->ping, cl->name, cl->edict->s.team );
				tempstrLength = strlen( tempstr );
				if( statusLength + tempstrLength >= sizeof( status ) )
					break; // can't hold any more
				Q_strncpyz( status + statusLength, tempstr, sizeof( status ) - statusLength );
				statusLength += tempstrLength;
			}
		}
	}

	return status;
}
예제 #23
0
파일: info.c 프로젝트: jite/qtv
void Info_SetValueForStarKey (char *s, const char *key, const char *value, int maxsize)
{
	char	newv[1024], *v;
	int		c;

	if (strstr (key, "\\") || strstr (value, "\\") )
	{
//		printf ("Key has a slash\n");
		return;
	}

	if (strstr (key, "\"") || strstr (value, "\"") )
	{
//		printf ("Key has a quote\n");
		return;
	}

	if (strlen(key) >= MAX_INFO_KEY || strlen(value) >= MAX_INFO_KEY)
	{
//		printf ("Key or value is too long\n");
		return;
	}

	// this next line is kinda trippy
	if (*(v = Info_ValueForKey(s, key, newv, sizeof(newv))))
	{
		// key exists, make sure we have enough room for new value, if we don't,
		// don't change it!
		if (strlen(value) - strlen(v) + strlen(s) + 1 > maxsize)
		{
	//		Con_TPrintf (TL_INFOSTRINGTOOLONG);
			return;
		}
	}


	Info_RemoveKey (s, key);
	if (!value || !strlen(value))
		return;

	snprintf (newv, sizeof(newv), "\\%s\\%s", key, value);

	if ((int)(strlen(newv) + strlen(s) + 1) > maxsize)
	{
//		printf ("info buffer is too small\n");
		return;
	}

	// only copy ascii values
	s += strlen(s);
	v = newv;
	while (*v)
	{
		c = (unsigned char)*v++;

//		c &= 127;		// strip high bits
		if (c > 13) // && c < 127)
			*s++ = c;
	}
	*s = 0;
}