2005-09-25 04:49:02 +00:00
/*
Copyright ( C ) 1996 - 1997 Id Software , Inc .
This program is free software ; you can redistribute it and / or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation ; either version 2
of the License , or ( at your option ) any later version .
This program is distributed in the hope that it will be useful ,
but WITHOUT ANY WARRANTY ; without even the implied warranty of
2005-09-25 20:50:57 +00:00
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE .
2005-09-25 04:49:02 +00:00
See the GNU General Public License for more details .
You should have received a copy of the GNU General Public License
along with this program ; if not , write to the Free Software
Foundation , Inc . , 59 Temple Place - Suite 330 , Boston , MA 02111 - 1307 , USA .
*/
2005-09-24 04:45:24 +00:00
# include "qtv.h"
2010-03-14 14:35:56 +00:00
# ifdef _WIN32
# include <direct.h>
# else
# include <unistd.h>
# endif
2005-09-24 04:45:24 +00:00
2007-12-27 15:18:40 +00:00
# include "bsd_string.h"
2007-07-23 10:53:59 +00:00
2005-09-24 04:45:24 +00:00
# define MAX_INFO_KEY 64
2006-09-17 01:27:32 +00:00
//I apologise for this if it breaks your formatting or anything
2006-06-11 12:09:29 +00:00
# define HELPSTRING "\
FTEQTV proxy commands : ( build " __DATE__ " ) \ n \
- - - - - - - - - - - - - - - - - - - - - - \ n \
connect , qtv , addserver \ n \
2007-03-03 21:39:06 +00:00
connect to a MVD stream ( TCP ) \ n \
qtvlist \ n \
lists available streams on a proxy \ n \
2006-06-11 12:09:29 +00:00
qw \ n \
2007-03-03 21:39:06 +00:00
connect to a server as a player ( UDP ) \ n \
2006-06-11 12:09:29 +00:00
adddemo \ n \
2007-03-03 21:39:06 +00:00
play a demo from a MVD file \ n \
2006-06-11 12:09:29 +00:00
port \ n \
2007-03-03 21:39:06 +00:00
UDP port for QuakeWorld client connections \ n \
2006-06-11 12:09:29 +00:00
mvdport \ n \
2007-03-03 21:39:06 +00:00
specify TCP port for MVD broadcasting \ n \
2006-06-11 12:09:29 +00:00
maxviewers , maxproxies \ n \
2007-03-03 21:39:06 +00:00
limit number of connections \ n \
status , choke , late , talking , nobsp , reconnect , exec , password , master , hostname , record , stop , quit \ n \
other random commands \ n \
\ n "
2006-06-11 12:09:29 +00:00
2006-09-17 01:27:32 +00:00
2005-09-24 04:45:24 +00:00
char * Info_ValueForKey ( char * s , const char * key , char * buffer , int buffersize )
{
char pkey [ 1024 ] ;
char * o ;
2005-09-25 20:50:57 +00:00
2005-09-24 04:45:24 +00:00
if ( * s = = ' \\ ' )
s + + ;
while ( 1 )
{
o = pkey ;
while ( * s ! = ' \\ ' )
{
if ( ! * s )
{
* buffer = ' \0 ' ;
return buffer ;
}
* o + + = * s + + ;
if ( o + 2 > = pkey + sizeof ( pkey ) ) //hrm. hackers at work..
{
* buffer = ' \0 ' ;
return buffer ;
}
}
* o = 0 ;
s + + ;
o = buffer ;
while ( * s ! = ' \\ ' & & * s )
{
if ( ! * s )
{
* buffer = ' \0 ' ;
return buffer ;
}
* o + + = * s + + ;
2005-09-25 20:50:57 +00:00
2005-09-24 04:45:24 +00:00
if ( o + 2 > = buffer + buffersize ) //hrm. hackers at work..
{
* buffer = ' \0 ' ;
return buffer ;
}
}
* o = 0 ;
if ( ! strcmp ( key , pkey ) )
return buffer ;
if ( ! * s )
{
* buffer = ' \0 ' ;
return buffer ;
}
s + + ;
}
}
void Info_RemoveKey ( char * s , const char * key )
{
char * start ;
char pkey [ 1024 ] ;
char value [ 1024 ] ;
char * o ;
if ( strstr ( key , " \\ " ) )
{
2005-10-07 02:02:15 +00:00
// printf ("Key has a slash\n");
2005-09-24 04:45:24 +00:00
return ;
}
while ( 1 )
{
start = s ;
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 ( ! strcmp ( key , pkey ) )
{
strcpy ( start , s ) ; // remove this part
return ;
}
if ( ! * s )
return ;
}
}
void Info_SetValueForStarKey ( char * s , const char * key , const char * value , int maxsize )
{
char newv [ 1024 ] , * v ;
int c ;
# ifdef SERVERONLY
extern cvar_t sv_highchars ;
# endif
if ( strstr ( key , " \\ " ) | | strstr ( value , " \\ " ) )
{
2005-10-07 02:02:15 +00:00
// printf ("Key has a slash\n");
2005-09-24 04:45:24 +00:00
return ;
}
if ( strstr ( key , " \" " ) | | strstr ( value , " \" " ) )
{
2005-10-07 02:02:15 +00:00
// printf ("Key has a quote\n");
2005-09-24 04:45:24 +00:00
return ;
}
if ( strlen ( key ) > = MAX_INFO_KEY | | strlen ( value ) > = MAX_INFO_KEY )
{
2005-10-07 02:02:15 +00:00
// printf ("Key or value is too long\n");
2005-09-24 04:45:24 +00:00
return ;
}
// this next line is kinda trippy
2006-10-20 14:17:56 +00:00
if ( * ( v = Info_ValueForKey ( s , key , newv , sizeof ( newv ) ) ) )
2005-09-24 04:45:24 +00:00
{
// 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 )
{
2013-11-29 14:36:47 +00:00
// Con_Printf ("Info string length exceeded\n");
2005-09-24 04:45:24 +00:00
return ;
}
}
2006-10-20 14:17:56 +00:00
2005-09-24 04:45:24 +00:00
Info_RemoveKey ( s , key ) ;
if ( ! value | | ! strlen ( value ) )
return ;
2005-09-25 20:50:57 +00:00
snprintf ( newv , sizeof ( newv ) - 1 , " \\ %s \\ %s " , key , value ) ;
2005-09-24 04:45:24 +00:00
if ( ( int ) ( strlen ( newv ) + strlen ( s ) + 1 ) > maxsize )
{
2005-10-07 02:02:15 +00:00
// printf ("info buffer is too small\n");
2005-09-24 04:45:24 +00:00
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 ;
}
# define DEFAULT_PUNCTUATION "(,{})(\':;=!><&|+"
char * COM_ParseToken ( char * data , char * out , int outsize , const char * punctuation )
{
int c ;
int len ;
if ( ! punctuation )
punctuation = DEFAULT_PUNCTUATION ;
2005-09-25 20:50:57 +00:00
2005-09-24 04:45:24 +00:00
len = 0 ;
out [ 0 ] = 0 ;
2005-09-25 20:50:57 +00:00
2005-09-24 04:45:24 +00:00
if ( ! data )
return NULL ;
2005-09-25 20:50:57 +00:00
2005-09-24 04:45:24 +00:00
// skip whitespace
skipwhite :
while ( ( c = * data ) < = ' ' )
{
if ( c = = 0 )
return NULL ; // end of file;
data + + ;
}
2005-09-25 20:50:57 +00:00
2005-09-24 04:45:24 +00:00
// skip // comments
if ( c = = ' / ' )
{
if ( data [ 1 ] = = ' / ' )
{
while ( * data & & * data ! = ' \n ' )
data + + ;
goto skipwhite ;
}
else if ( data [ 1 ] = = ' * ' )
{
data + = 2 ;
while ( * data & & ( * data ! = ' * ' | | data [ 1 ] ! = ' / ' ) )
data + + ;
data + = 2 ;
goto skipwhite ;
}
}
2005-09-25 20:50:57 +00:00
2005-09-24 04:45:24 +00:00
// handle quoted strings specially
if ( c = = ' \" ' )
{
data + + ;
while ( 1 )
{
if ( len > = outsize - 1 )
{
out [ len ] = ' \0 ' ;
return data ;
}
c = * data + + ;
if ( c = = ' \" ' | | ! c )
{
out [ len ] = 0 ;
return data ;
}
out [ len ] = c ;
len + + ;
}
}
// parse single characters
if ( strchr ( punctuation , c ) )
{
out [ len ] = c ;
len + + ;
out [ len ] = 0 ;
return data + 1 ;
}
// parse a regular word
do
{
if ( len > = outsize - 1 )
break ;
out [ len ] = c ;
data + + ;
len + + ;
c = * data ;
if ( strchr ( punctuation , c ) )
break ;
} while ( c > 32 ) ;
2005-09-25 20:50:57 +00:00
2005-09-24 04:45:24 +00:00
out [ len ] = 0 ;
return data ;
}
2006-09-17 01:27:32 +00:00
2007-07-23 10:53:59 +00:00
void Cmd_Printf ( cmdctxt_t * ctx , char * fmt , . . . )
{
va_list argptr ;
char string [ 2048 ] ;
2011-07-15 16:31:53 +00:00
2007-07-23 10:53:59 +00:00
va_start ( argptr , fmt ) ;
vsnprintf ( string , sizeof ( string ) - 1 , fmt , argptr ) ;
string [ sizeof ( string ) - 1 ] = 0 ;
va_end ( argptr ) ;
2006-09-17 01:27:32 +00:00
2007-07-23 10:53:59 +00:00
if ( ctx - > printfunc )
ctx - > printfunc ( ctx , string ) ;
else if ( ctx - > qtv )
QTV_Printf ( ctx - > qtv , " %s " , string ) ;
else
Sys_Printf ( ctx - > cluster , " %s " , string ) ;
}
2006-09-17 01:27:32 +00:00
2007-07-23 10:53:59 +00:00
void Cmd_Hostname ( cmdctxt_t * ctx )
2006-09-17 01:27:32 +00:00
{
2007-07-23 10:53:59 +00:00
if ( Cmd_Argc ( ctx ) < 2 )
2006-10-20 14:17:56 +00:00
{
2007-07-23 10:53:59 +00:00
if ( * ctx - > cluster - > hostname )
2007-12-12 11:17:18 +00:00
Cmd_Printf ( ctx , " Current hostname is \" %s \" \n " , ctx - > cluster - > hostname ) ;
2006-10-20 14:17:56 +00:00
else
2007-07-23 10:53:59 +00:00
Cmd_Printf ( ctx , " No master server is currently set. \n " ) ;
2006-10-20 14:17:56 +00:00
}
2007-07-23 10:53:59 +00:00
else
{
2007-12-27 15:18:40 +00:00
strlcpy ( ctx - > cluster - > hostname , Cmd_Argv ( ctx , 1 ) , sizeof ( ctx - > cluster - > hostname ) ) ;
2007-05-28 02:31:48 +00:00
2007-07-23 10:53:59 +00:00
Cmd_Printf ( ctx , " hostname set to \" %s \" \n " , ctx - > cluster - > hostname ) ;
}
2006-09-17 01:27:32 +00:00
}
2007-07-23 10:53:59 +00:00
void Cmd_Master ( cmdctxt_t * ctx )
2006-09-17 01:27:32 +00:00
{
2012-04-20 14:41:40 +00:00
SOCKET s ;
2007-07-23 10:53:59 +00:00
char * newval = Cmd_Argv ( ctx , 1 ) ;
2006-09-17 01:27:32 +00:00
netadr_t addr ;
2007-07-23 10:53:59 +00:00
if ( Cmd_Argc ( ctx ) < 2 )
2006-10-20 14:17:56 +00:00
{
2007-07-23 10:53:59 +00:00
if ( * ctx - > cluster - > master )
Cmd_Printf ( ctx , " Subscribed to a master server (use '-' to clear) \n " ) ;
2006-10-20 14:17:56 +00:00
else
2007-07-23 10:53:59 +00:00
Cmd_Printf ( ctx , " No master server is currently set. \n " ) ;
return ;
2006-10-20 14:17:56 +00:00
}
2007-07-23 10:53:59 +00:00
if ( ! strcmp ( newval , " - " ) )
2006-10-20 14:17:56 +00:00
{
2007-12-27 15:18:40 +00:00
strlcpy ( ctx - > cluster - > master , " " , sizeof ( ctx - > cluster - > master ) ) ;
2007-07-23 10:53:59 +00:00
Cmd_Printf ( ctx , " Master server cleared \n " ) ;
return ;
2006-10-20 14:17:56 +00:00
}
2007-07-23 10:53:59 +00:00
if ( ! NET_StringToAddr ( newval , & addr , 27000 ) ) //send a ping like a qw server does. this is kinda pointless of course.
2006-10-20 14:17:56 +00:00
{
2007-07-23 10:53:59 +00:00
Cmd_Printf ( ctx , " Couldn't resolve address \n " ) ;
return ;
2006-10-20 14:17:56 +00:00
}
2007-12-27 15:18:40 +00:00
strlcpy ( ctx - > cluster - > master , newval , sizeof ( ctx - > cluster - > master ) ) ;
2007-07-23 10:53:59 +00:00
ctx - > cluster - > mastersendtime = ctx - > cluster - > curtime ;
2006-09-17 01:27:32 +00:00
2012-04-20 14:41:40 +00:00
s = NET_ChooseSocket ( ctx - > cluster - > qwdsocket , & addr ) ;
if ( s ! = INVALID_SOCKET )
NET_SendPacket ( ctx - > cluster , s , 1 , " k " , addr ) ;
2007-07-23 10:53:59 +00:00
Cmd_Printf ( ctx , " Master server set. \n " ) ;
2006-09-17 01:27:32 +00:00
}
2007-07-23 10:53:59 +00:00
void Cmd_UDPPort ( cmdctxt_t * ctx )
2006-09-17 01:27:32 +00:00
{
2007-07-23 10:53:59 +00:00
int newp = atoi ( Cmd_Argv ( ctx , 1 ) ) ;
2012-04-20 14:41:40 +00:00
NET_InitUDPSocket ( ctx - > cluster , newp , true ) ;
NET_InitUDPSocket ( ctx - > cluster , newp , false ) ;
2006-09-17 01:27:32 +00:00
}
2007-07-23 10:53:59 +00:00
void Cmd_AdminPassword ( cmdctxt_t * ctx )
2006-09-17 01:27:32 +00:00
{
2007-07-23 10:53:59 +00:00
if ( ! Cmd_IsLocal ( ctx ) )
{
Cmd_Printf ( ctx , " Rejecting remote password change. \n " ) ;
return ;
}
2006-09-17 01:27:32 +00:00
2007-07-23 10:53:59 +00:00
if ( Cmd_Argc ( ctx ) < 2 )
2006-10-20 14:17:56 +00:00
{
2007-07-23 10:53:59 +00:00
if ( * ctx - > cluster - > adminpassword )
Cmd_Printf ( ctx , " An admin password is currently set \n " ) ;
2006-10-20 14:17:56 +00:00
else
2007-12-12 11:17:18 +00:00
Cmd_Printf ( ctx , " No admin password is currently set \n " ) ;
2007-07-23 10:53:59 +00:00
}
else
{
2007-12-27 15:18:40 +00:00
strlcpy ( ctx - > cluster - > adminpassword , Cmd_Argv ( ctx , 1 ) , sizeof ( ctx - > cluster - > adminpassword ) ) ;
2007-07-23 10:53:59 +00:00
Cmd_Printf ( ctx , " Password changed. \n " ) ;
2006-10-20 14:17:56 +00:00
}
2006-09-17 01:27:32 +00:00
}
2007-03-03 21:39:06 +00:00
2007-07-23 10:53:59 +00:00
void Cmd_GenericQuery ( cmdctxt_t * ctx , int dataset )
2007-03-03 21:39:06 +00:00
{
2007-07-23 10:53:59 +00:00
char * method = " tcp: " ;
char * address , * password ;
if ( Cmd_Argc ( ctx ) < 2 )
{
Cmd_Printf ( ctx , " %s requires an ip:port parameter \n " , Cmd_Argv ( ctx , 0 ) ) ;
return ;
}
2007-03-03 21:39:06 +00:00
2007-07-23 10:53:59 +00:00
address = Cmd_Argv ( ctx , 1 ) ;
password = Cmd_Argv ( ctx , 2 ) ;
//this is evil
2007-12-27 15:18:40 +00:00
/* Holy crap, Spike... Holy crap. */
2007-07-23 10:53:59 +00:00
memmove ( address + strlen ( method ) , address , ARG_LEN - ( 1 + strlen ( method ) ) ) ;
strncpy ( address , method , strlen ( method ) ) ;
2007-03-03 21:39:06 +00:00
2010-03-14 14:35:56 +00:00
if ( ! QTV_NewServerConnection ( ctx - > cluster , ctx - > streamid , address , password , false , AD_NO , false , dataset ) )
2007-07-23 10:53:59 +00:00
Cmd_Printf ( ctx , " Failed to connect to \" %s \" , connection aborted \n " , address ) ;
2007-03-03 21:39:06 +00:00
2007-07-23 10:53:59 +00:00
Cmd_Printf ( ctx , " Querying \" %s \" \n " , address ) ;
2007-03-03 21:39:06 +00:00
}
2006-09-17 01:27:32 +00:00
2007-07-23 10:53:59 +00:00
void Cmd_QTVList ( cmdctxt_t * ctx )
{
Cmd_GenericQuery ( ctx , 1 ) ;
2006-09-17 01:27:32 +00:00
}
2007-07-23 10:53:59 +00:00
void Cmd_QTVDemoList ( cmdctxt_t * ctx )
2006-09-17 01:27:32 +00:00
{
2007-07-23 10:53:59 +00:00
Cmd_GenericQuery ( ctx , 2 ) ;
2006-09-17 01:27:32 +00:00
}
2007-07-23 10:53:59 +00:00
2010-03-14 14:35:56 +00:00
void Cmd_GenericConnect ( cmdctxt_t * ctx , char * method , enum autodisconnect_e autoclose )
2006-09-17 01:27:32 +00:00
{
2007-12-12 11:17:18 +00:00
sv_t * sv ;
2007-07-23 10:53:59 +00:00
char * address , * password ;
if ( Cmd_Argc ( ctx ) < 2 )
{
if ( ! strncmp ( method , " file " , 4 ) )
Cmd_Printf ( ctx , " %s requires a demo name parameter \n " , Cmd_Argv ( ctx , 0 ) ) ;
2014-11-21 18:10:29 +00:00
else if ( ! strncmp ( method , " dir " , 3 ) )
Cmd_Printf ( ctx , " %s requires a demo directory parameter \n " , Cmd_Argv ( ctx , 0 ) ) ;
2007-07-23 10:53:59 +00:00
else
Cmd_Printf ( ctx , " %s requires an ip:port parameter \n " , Cmd_Argv ( ctx , 0 ) ) ;
return ;
}
2006-09-17 01:27:32 +00:00
2007-07-23 10:53:59 +00:00
address = Cmd_Argv ( ctx , 1 ) ;
password = Cmd_Argv ( ctx , 2 ) ;
//this is evil
2007-12-27 15:18:40 +00:00
/* Holy crap, Spike... Holy crap. */
2007-07-23 10:53:59 +00:00
memmove ( address + strlen ( method ) , address , ARG_LEN - ( 1 + strlen ( method ) ) ) ;
strncpy ( address , method , strlen ( method ) ) ;
2006-09-17 01:27:32 +00:00
2010-03-14 14:35:56 +00:00
sv = QTV_NewServerConnection ( ctx - > cluster , ctx - > streamid ? ctx - > streamid : 1 , address , password , false , autoclose , false , false ) ;
2007-12-12 11:17:18 +00:00
if ( ! sv )
2007-07-23 10:53:59 +00:00
Cmd_Printf ( ctx , " Failed to connect to \" %s \" , connection aborted \n " , address ) ;
2007-12-12 11:17:18 +00:00
else
Cmd_Printf ( ctx , " Source registered \" %s \" as stream %i \n " , address , sv - > streamid ) ;
2007-07-23 10:53:59 +00:00
}
2007-05-28 02:31:48 +00:00
2007-07-23 10:53:59 +00:00
void Cmd_QTVConnect ( cmdctxt_t * ctx )
{
2010-03-14 14:35:56 +00:00
Cmd_GenericConnect ( ctx , " tcp: " , AD_NO ) ;
2007-07-23 10:53:59 +00:00
}
void Cmd_QWConnect ( cmdctxt_t * ctx )
{
2010-03-14 14:35:56 +00:00
Cmd_GenericConnect ( ctx , " udp: " , AD_STATUSPOLL ) ;
2006-09-17 01:27:32 +00:00
}
2007-07-23 10:53:59 +00:00
void Cmd_MVDConnect ( cmdctxt_t * ctx )
{
2010-03-14 14:35:56 +00:00
Cmd_GenericConnect ( ctx , " file: " , AD_NO ) ;
2007-07-23 10:53:59 +00:00
}
2014-11-21 18:10:29 +00:00
void Cmd_DirMVDConnect ( cmdctxt_t * ctx )
{
Cmd_GenericConnect ( ctx , " dir: " , AD_NO ) ;
}
2007-07-23 10:53:59 +00:00
void Cmd_Exec ( cmdctxt_t * ctx )
2006-09-17 01:27:32 +00:00
{
FILE * f ;
2007-07-23 10:53:59 +00:00
char line [ 512 ] , * l ;
char * fname = Cmd_Argv ( ctx , 1 ) ;
2006-09-17 01:27:32 +00:00
2007-07-23 10:53:59 +00:00
if ( ! Cmd_IsLocal ( ctx ) )
2006-10-20 14:17:56 +00:00
{
2007-07-23 10:53:59 +00:00
if ( * fname = = ' \\ ' | | * fname = = ' / ' | | strstr ( fname , " .. " ) | | fname [ 1 ] = = ' : ' )
{
Cmd_Printf ( ctx , " Absolute paths are prohibited. \n " ) ;
return ;
}
if ( ! strncmp ( fname , " usercfg/ " , 8 ) ) //this is how we stop users from execing a 50gb pk3..
{
Cmd_Printf ( ctx , " Remote-execed configs must be in the usercfg directory \n " ) ;
return ;
}
2006-10-20 14:17:56 +00:00
}
2006-09-17 01:27:32 +00:00
2007-07-23 10:53:59 +00:00
f = fopen ( fname , " rt " ) ;
2006-09-17 01:27:32 +00:00
if ( ! f )
{
2007-07-23 10:53:59 +00:00
Cmd_Printf ( ctx , " Couldn't exec \" %s \" \n " , fname ) ;
return ;
2006-09-17 01:27:32 +00:00
}
else
{
2007-07-23 10:53:59 +00:00
Cmd_Printf ( ctx , " Execing \" %s \" \n " , fname ) ;
2006-09-17 01:27:32 +00:00
while ( fgets ( line , sizeof ( line ) - 1 , f ) )
{
2007-05-28 02:31:48 +00:00
l = line ;
while ( * ( unsigned char * ) l < = ' ' & & * l )
l + + ;
if ( * l & & l [ 0 ] ! = ' / ' & & l [ 1 ] ! = ' / ' )
2006-10-27 10:57:06 +00:00
{
2007-07-23 10:53:59 +00:00
Cmd_ExecuteNow ( ctx , l ) ;
2006-10-27 10:57:06 +00:00
}
2006-09-17 01:27:32 +00:00
}
fclose ( f ) ;
}
}
2006-10-07 22:29:31 +00:00
void catbuffer ( char * buffer , int bufsize , char * format , . . . )
{
2007-12-27 15:18:40 +00:00
va_list argptr ;
unsigned int buflen ;
2006-10-07 22:29:31 +00:00
2007-12-27 15:18:40 +00:00
buflen = strlen ( buffer ) ;
2006-10-07 22:29:31 +00:00
2007-12-27 15:18:40 +00:00
va_start ( argptr , format ) ;
vsnprintf ( buffer + buflen , bufsize - buflen , format , argptr ) ;
va_end ( argptr ) ;
2006-10-07 22:29:31 +00:00
}
2006-12-26 21:26:10 +00:00
2007-07-23 10:53:59 +00:00
void Cmd_Say ( cmdctxt_t * ctx )
2006-12-26 21:26:10 +00:00
{
int i ;
viewer_t * v ;
char message [ 8192 ] ;
message [ 0 ] = ' \0 ' ;
2007-07-23 10:53:59 +00:00
for ( i = 1 ; i < Cmd_Argc ( ctx ) ; i + + )
catbuffer ( message , sizeof ( message ) - 1 , " %s%s " , i = = 1 ? " " : " " , Cmd_Argv ( ctx , i ) ) ;
if ( ctx - > qtv )
{
if ( ! SV_SayToUpstream ( ctx - > qtv , message ) )
SV_SayToViewers ( ctx - > qtv , message ) ;
}
else
2006-12-26 21:26:10 +00:00
{
2007-07-23 10:53:59 +00:00
//we don't have to remember the client proxies here... no streams = no active client proxies
for ( v = ctx - > cluster - > viewers ; v ; v = v - > next )
{
2006-12-26 21:26:10 +00:00
QW_PrintfToViewer ( v , " proxy: %s \n " , message ) ;
2007-07-23 10:53:59 +00:00
}
2006-12-26 21:26:10 +00:00
}
2007-07-23 10:53:59 +00:00
Cmd_Printf ( ctx , " proxy: %s \n " , message ) ;
2006-12-26 21:26:10 +00:00
}
2007-07-23 10:53:59 +00:00
void Cmd_Status ( cmdctxt_t * ctx )
2006-09-17 01:27:32 +00:00
{
2007-12-12 11:17:18 +00:00
Cmd_Printf ( ctx , " QTV Status: \n " ) ;
Cmd_Printf ( ctx , " %i sources \n " , ctx - > cluster - > numservers ) ;
Cmd_Printf ( ctx , " %i viewers \n " , ctx - > cluster - > numviewers ) ;
Cmd_Printf ( ctx , " %i proxies \n " , ctx - > cluster - > numproxies ) ;
2006-10-07 22:29:31 +00:00
2007-12-12 11:17:18 +00:00
Cmd_Printf ( ctx , " Common Options: \n " ) ;
2007-07-23 10:53:59 +00:00
Cmd_Printf ( ctx , " Hostname %s \n " , ctx - > cluster - > hostname ) ;
2011-07-15 16:31:53 +00:00
2007-07-23 10:53:59 +00:00
if ( ctx - > cluster - > chokeonnotupdated )
Cmd_Printf ( ctx , " Choke \n " ) ;
if ( ctx - > cluster - > lateforward )
Cmd_Printf ( ctx , " Late forwarding \n " ) ;
if ( ! ctx - > cluster - > notalking )
Cmd_Printf ( ctx , " Talking allowed \n " ) ;
if ( ctx - > cluster - > nobsp )
Cmd_Printf ( ctx , " No BSP loading \n " ) ;
2012-04-20 14:41:40 +00:00
if ( ctx - > cluster - > tcpsocket [ 0 ] ! = INVALID_SOCKET | | ctx - > cluster - > tcpsocket [ 1 ] ! = INVALID_SOCKET )
2007-01-06 09:46:32 +00:00
{
2007-07-23 10:53:59 +00:00
Cmd_Printf ( ctx , " tcp port %i \n " , ctx - > cluster - > tcplistenportnum ) ;
2007-01-06 09:46:32 +00:00
}
2012-04-20 14:41:40 +00:00
if ( ctx - > cluster - > qwdsocket [ 0 ] ! = INVALID_SOCKET | | ctx - > cluster - > qwdsocket [ 1 ] ! = INVALID_SOCKET )
2007-01-06 09:46:32 +00:00
{
2007-07-23 10:53:59 +00:00
Cmd_Printf ( ctx , " udp port %i \n " , ctx - > cluster - > qwlistenportnum ) ;
2007-01-06 09:46:32 +00:00
}
2007-07-23 10:53:59 +00:00
Cmd_Printf ( ctx , " user connections are %sallowed \n " , ctx - > cluster - > nouserconnects ? " NOT " : " " ) ;
Cmd_Printf ( ctx , " \n " ) ;
2006-09-17 01:27:32 +00:00
2007-07-23 10:53:59 +00:00
if ( ctx - > qtv )
2006-09-17 01:27:32 +00:00
{
2007-07-23 10:53:59 +00:00
Cmd_Printf ( ctx , " Selected server: %s \n " , ctx - > qtv - > server ) ;
if ( ctx - > qtv - > sourcefile )
2007-12-12 11:17:18 +00:00
Cmd_Printf ( ctx , " Playing from file \n " ) ;
2007-07-23 10:53:59 +00:00
if ( ctx - > qtv - > sourcesock ! = INVALID_SOCKET )
2007-12-12 11:17:18 +00:00
Cmd_Printf ( ctx , " Connected \n " ) ;
2007-07-23 10:53:59 +00:00
if ( ctx - > qtv - > parsingqtvheader | | ctx - > qtv - > parsingconnectiondata )
2007-12-12 11:17:18 +00:00
Cmd_Printf ( ctx , " Waiting for gamestate \n " ) ;
2007-07-23 10:53:59 +00:00
if ( ctx - > qtv - > usequakeworldprotocols )
2006-09-17 01:27:32 +00:00
{
2007-12-12 11:17:18 +00:00
Cmd_Printf ( ctx , " QuakeWorld protocols \n " ) ;
2007-07-23 10:53:59 +00:00
if ( ctx - > qtv - > controller )
2006-11-03 15:53:04 +00:00
{
2007-12-12 11:17:18 +00:00
Cmd_Printf ( ctx , " Controlled by %s \n " , ctx - > qtv - > controller - > name ) ;
2006-11-03 15:53:04 +00:00
}
2006-09-17 01:27:32 +00:00
}
2007-07-23 10:53:59 +00:00
else if ( ctx - > qtv - > sourcesock = = INVALID_SOCKET & & ! ctx - > qtv - > sourcefile )
2007-12-12 11:17:18 +00:00
Cmd_Printf ( ctx , " Connection not established \n " ) ;
2006-11-03 15:53:04 +00:00
2009-07-07 23:40:06 +00:00
if ( * ctx - > qtv - > map . modellist [ 1 ] . name )
2006-09-17 01:27:32 +00:00
{
2009-07-07 23:40:06 +00:00
Cmd_Printf ( ctx , " Map name %s \n " , ctx - > qtv - > map . modellist [ 1 ] . name ) ;
2006-09-17 01:27:32 +00:00
}
2007-07-23 10:53:59 +00:00
if ( * ctx - > qtv - > connectpassword )
2007-12-12 11:17:18 +00:00
Cmd_Printf ( ctx , " Using a password \n " ) ;
if ( ctx - > qtv - > errored = = ERR_DISABLED )
Cmd_Printf ( ctx , " Stream is disabled \n " ) ;
2006-09-17 01:27:32 +00:00
2010-03-14 14:35:56 +00:00
if ( ctx - > qtv - > autodisconnect = = AD_WHENEMPTY )
Cmd_Printf ( ctx , " Stream is user created \n " ) ;
else if ( ctx - > qtv - > autodisconnect = = AD_REVERSECONNECT )
Cmd_Printf ( ctx , " Stream is server created \n " ) ;
2007-01-06 09:46:32 +00:00
2007-07-23 10:53:59 +00:00
/* if (ctx->qtv->tcpsocket != INVALID_SOCKET)
2006-09-17 01:27:32 +00:00
{
2007-12-12 11:17:18 +00:00
Cmd_Printf ( ctx , " Listening for proxies (%i) \n " , ctx - > qtv - > tcplistenportnum ) ;
2006-09-17 01:27:32 +00:00
}
2007-01-09 05:24:03 +00:00
*/
2006-09-17 01:27:32 +00:00
2009-07-07 23:40:06 +00:00
if ( ctx - > qtv - > map . bsp )
2006-09-17 01:27:32 +00:00
{
2009-07-07 23:40:06 +00:00
Cmd_Printf ( ctx , " BSP (%s) is loaded \n " , ctx - > qtv - > map . mapname ) ;
2006-09-17 01:27:32 +00:00
}
}
}
2007-07-23 10:53:59 +00:00
void Cmd_UserConnects ( cmdctxt_t * ctx )
{
if ( Cmd_Argc ( ctx ) < 2 )
{
Cmd_Printf ( ctx , " userconnects is set to %i \n " , ! ctx - > cluster - > nouserconnects ) ;
}
else
{
ctx - > cluster - > nouserconnects = ! atoi ( Cmd_Argv ( ctx , 1 ) ) ;
Cmd_Printf ( ctx , " userconnects is now %i \n " , ! ctx - > cluster - > nouserconnects ) ;
}
}
void Cmd_Choke ( cmdctxt_t * ctx )
2006-09-17 01:27:32 +00:00
{
2007-07-23 10:53:59 +00:00
if ( Cmd_Argc ( ctx ) < 2 )
2006-10-20 14:17:56 +00:00
{
2007-07-23 10:53:59 +00:00
if ( ctx - > cluster - > chokeonnotupdated )
Cmd_Printf ( ctx , " proxy will not interpolate packets \n " ) ;
2006-10-20 14:17:56 +00:00
else
2007-07-23 10:53:59 +00:00
Cmd_Printf ( ctx , " proxy will smooth action at the expense of extra packets \n " ) ;
return ;
2006-10-20 14:17:56 +00:00
}
2007-07-23 10:53:59 +00:00
ctx - > cluster - > chokeonnotupdated = ! ! atoi ( Cmd_Argv ( ctx , 1 ) ) ;
Cmd_Printf ( ctx , " choke-until-update set to %i \n " , ctx - > cluster - > chokeonnotupdated ) ;
2006-09-17 01:27:32 +00:00
}
2007-07-23 10:53:59 +00:00
void Cmd_Late ( cmdctxt_t * ctx )
2006-09-17 01:27:32 +00:00
{
2007-07-23 10:53:59 +00:00
if ( Cmd_Argc ( ctx ) < 2 )
2006-10-20 14:17:56 +00:00
{
2007-07-23 10:53:59 +00:00
if ( ctx - > cluster - > lateforward )
Cmd_Printf ( ctx , " forwarded streams will be artificially delayed \n " ) ;
2006-10-20 14:17:56 +00:00
else
2007-07-23 10:53:59 +00:00
Cmd_Printf ( ctx , " forwarded streams are forwarded immediatly \n " ) ;
return ;
2006-10-20 14:17:56 +00:00
}
2007-07-23 10:53:59 +00:00
ctx - > cluster - > lateforward = ! ! atoi ( Cmd_Argv ( ctx , 1 ) ) ;
Cmd_Printf ( ctx , " late forwarding set \n " ) ;
2006-09-17 01:27:32 +00:00
}
2007-07-23 10:53:59 +00:00
void Cmd_Talking ( cmdctxt_t * ctx )
2006-09-17 01:27:32 +00:00
{
2007-07-23 10:53:59 +00:00
if ( Cmd_Argc ( ctx ) < 2 )
2006-10-20 14:17:56 +00:00
{
2007-07-23 10:53:59 +00:00
if ( ctx - > cluster - > notalking )
Cmd_Printf ( ctx , " viewers may not talk \n " ) ;
2006-10-20 14:17:56 +00:00
else
2007-07-23 10:53:59 +00:00
Cmd_Printf ( ctx , " viewers may talk freely \n " ) ;
return ;
2006-10-20 14:17:56 +00:00
}
2007-07-23 10:53:59 +00:00
ctx - > cluster - > notalking = ! atoi ( Cmd_Argv ( ctx , 1 ) ) ;
Cmd_Printf ( ctx , " talking permissions set \n " ) ;
2006-09-17 01:27:32 +00:00
}
2007-07-23 10:53:59 +00:00
void Cmd_NoBSP ( cmdctxt_t * ctx )
2006-09-17 01:27:32 +00:00
{
2007-07-23 10:53:59 +00:00
char * val = Cmd_Argv ( ctx , 1 ) ;
if ( ! * val )
2006-10-20 14:17:56 +00:00
{
2007-07-23 10:53:59 +00:00
if ( ctx - > cluster - > nobsp )
Cmd_Printf ( ctx , " no bsps will be loaded \n " ) ;
2006-10-20 14:17:56 +00:00
else
2007-07-23 10:53:59 +00:00
Cmd_Printf ( ctx , " attempting to load bsp files \n " ) ;
}
else
{
ctx - > cluster - > nobsp = ! ! atoi ( val ) ;
Cmd_Printf ( ctx , " nobsp will change at start of next map \n " ) ;
2006-10-20 14:17:56 +00:00
}
2006-09-17 01:27:32 +00:00
}
2007-07-23 10:53:59 +00:00
void Cmd_MaxViewers ( cmdctxt_t * ctx )
2006-09-17 01:27:32 +00:00
{
2007-07-23 10:53:59 +00:00
char * val = Cmd_Argv ( ctx , 1 ) ;
if ( ! * val )
2006-10-20 14:17:56 +00:00
{
2007-07-23 10:53:59 +00:00
if ( ctx - > cluster - > maxviewers )
Cmd_Printf ( ctx , " maxviewers is currently %i \n " , ctx - > cluster - > maxviewers ) ;
2006-10-20 14:17:56 +00:00
else
2007-07-23 10:53:59 +00:00
Cmd_Printf ( ctx , " maxviewers is currently unlimited \n " ) ;
}
else
{
ctx - > cluster - > maxviewers = atoi ( val ) ;
Cmd_Printf ( ctx , " maxviewers set \n " ) ;
2006-10-20 14:17:56 +00:00
}
2006-09-17 01:27:32 +00:00
}
2007-07-23 10:53:59 +00:00
void Cmd_AllowNQ ( cmdctxt_t * ctx )
2006-10-22 20:31:10 +00:00
{
2007-07-23 10:53:59 +00:00
char * val = Cmd_Argv ( ctx , 1 ) ;
if ( ! * val )
{
Cmd_Printf ( ctx , " allownq is currently %i \n " , ctx - > cluster - > allownqclients ) ;
}
else
2006-10-22 20:31:10 +00:00
{
2007-07-23 10:53:59 +00:00
ctx - > cluster - > allownqclients = ! ! atoi ( val ) ;
Cmd_Printf ( ctx , " allownq set \n " ) ;
2006-10-22 20:31:10 +00:00
}
}
2012-04-20 14:41:40 +00:00
void Cmd_InitialDelay ( cmdctxt_t * ctx )
{
char * val = Cmd_Argv ( ctx , 1 ) ;
if ( ! * val )
{
Cmd_Printf ( ctx , " initialdelay is currently %g seconds \n " , ctx - > cluster - > anticheattime / 1000.f ) ;
}
else
{
ctx - > cluster - > anticheattime = atof ( val ) * 1000 ;
if ( ctx - > cluster - > anticheattime < 1 )
ctx - > cluster - > anticheattime = 1 ;
Cmd_Printf ( ctx , " initialdelay set \n " ) ;
}
}
void Cmd_SlowDelay ( cmdctxt_t * ctx )
{
char * val = Cmd_Argv ( ctx , 1 ) ;
if ( ! * val )
{
Cmd_Printf ( ctx , " slowdelay is currently %g seconds \n " , ctx - > cluster - > tooslowdelay / 1000.f ) ;
}
else
{
ctx - > cluster - > tooslowdelay = atof ( val ) * 1000 ;
if ( ctx - > cluster - > tooslowdelay < 1 )
ctx - > cluster - > tooslowdelay = 1 ;
Cmd_Printf ( ctx , " slowdelay set \n " ) ;
}
}
2007-07-23 10:53:59 +00:00
void Cmd_MaxProxies ( cmdctxt_t * ctx )
2006-09-17 01:27:32 +00:00
{
2007-07-23 10:53:59 +00:00
char * val = Cmd_Argv ( ctx , 1 ) ;
if ( ! * val )
2006-10-20 14:17:56 +00:00
{
2007-07-23 10:53:59 +00:00
if ( ctx - > cluster - > maxproxies )
Cmd_Printf ( ctx , " maxproxies is currently %i \n " , ctx - > cluster - > maxproxies ) ;
2006-10-20 14:17:56 +00:00
else
2007-07-23 10:53:59 +00:00
Cmd_Printf ( ctx , " maxproxies is currently unlimited \n " ) ;
}
else
{
ctx - > cluster - > maxproxies = atoi ( val ) ;
Cmd_Printf ( ctx , " maxproxies set \n " ) ;
2006-10-20 14:17:56 +00:00
}
2006-09-17 01:27:32 +00:00
}
2007-07-23 10:53:59 +00:00
void Cmd_Ping ( cmdctxt_t * ctx )
2006-09-17 01:27:32 +00:00
{
netadr_t addr ;
2007-07-23 10:53:59 +00:00
char * val = Cmd_Argv ( ctx , 1 ) ;
if ( NET_StringToAddr ( val , & addr , 27500 ) )
2006-09-17 01:27:32 +00:00
{
2010-03-14 14:35:56 +00:00
NET_SendPacket ( ctx - > cluster , NET_ChooseSocket ( ctx - > cluster - > qwdsocket , & addr ) , 1 , " k " , addr ) ;
2007-07-23 10:53:59 +00:00
Cmd_Printf ( ctx , " pinged \n " ) ;
2006-09-17 01:27:32 +00:00
}
2007-07-23 10:53:59 +00:00
Cmd_Printf ( ctx , " couldn't resolve \n " ) ;
2006-09-17 01:27:32 +00:00
}
2007-07-23 10:53:59 +00:00
void Cmd_Help ( cmdctxt_t * ctx )
2006-09-17 01:27:32 +00:00
{
2007-07-23 10:53:59 +00:00
Cmd_Printf ( ctx , HELPSTRING ) ;
2006-09-17 01:27:32 +00:00
}
2007-07-23 10:53:59 +00:00
void Cmd_Echo ( cmdctxt_t * ctx )
2006-09-17 01:27:32 +00:00
{
2007-07-23 10:53:59 +00:00
Cmd_Printf ( ctx , " %s " , Cmd_Argv ( ctx , 1 ) ) ;
2006-09-17 01:27:32 +00:00
}
2011-07-15 16:31:53 +00:00
2007-07-23 10:53:59 +00:00
void Cmd_Quit ( cmdctxt_t * ctx )
2006-09-17 01:27:32 +00:00
{
2007-07-23 10:53:59 +00:00
if ( ! Cmd_IsLocal ( ctx ) )
Cmd_Printf ( ctx , " Remote shutdown refused. \n " ) ;
ctx - > cluster - > wanttoexit = true ;
Cmd_Printf ( ctx , " Shutting down. \n " ) ;
2006-09-17 01:27:32 +00:00
}
2007-07-23 10:53:59 +00:00
void Cmd_Streams ( cmdctxt_t * ctx )
2006-10-07 22:29:31 +00:00
{
2007-07-23 10:53:59 +00:00
sv_t * qtv ;
2007-12-12 11:17:18 +00:00
char * status ;
2007-07-23 10:53:59 +00:00
Cmd_Printf ( ctx , " Streams: \n " ) ;
2006-10-07 22:29:31 +00:00
2007-07-23 10:53:59 +00:00
for ( qtv = ctx - > cluster - > servers ; qtv ; qtv = qtv - > next )
2006-10-07 22:29:31 +00:00
{
2007-12-12 11:17:18 +00:00
switch ( qtv - > errored )
{
case ERR_NONE :
if ( qtv - > controller )
status = " (player controlled) " ;
2011-01-04 02:56:16 +00:00
else if ( qtv - > autodisconnect = = AD_STATUSPOLL )
status = " (polling) " ;
2007-12-12 11:17:18 +00:00
else if ( qtv - > parsingconnectiondata )
status = " (connecting) " ;
else
status = " " ;
break ;
2009-07-07 23:40:06 +00:00
case ERR_PAUSED :
status = " (paused) " ;
2010-03-14 14:35:56 +00:00
break ;
2007-12-12 11:17:18 +00:00
case ERR_DISABLED :
status = " (disabled) " ;
break ;
case ERR_DROP : //a user should never normally see this, but there is a chance
status = " (dropping) " ;
break ;
case ERR_RECONNECT : //again, rare
status = " (reconnecting) " ;
break ;
default : //some other kind of error, transitioning
status = " (errored) " ;
break ;
}
Cmd_Printf ( ctx , " %i: %s%s \n " , qtv - > streamid , qtv - > server , status ) ;
if ( qtv - > upstreamacceptschat )
Cmd_Printf ( ctx , " (dbg) can chat! \n " ) ;
2006-10-07 22:29:31 +00:00
}
}
2006-09-17 01:27:32 +00:00
2007-07-23 10:53:59 +00:00
void Cmd_DemoSpeed ( cmdctxt_t * ctx )
2006-09-17 01:27:32 +00:00
{
2007-07-23 10:53:59 +00:00
char * val = Cmd_Argv ( ctx , 1 ) ;
if ( * val )
{
ctx - > qtv - > parsespeed = atof ( val ) * 1000 ;
Cmd_Printf ( ctx , " Setting demo speed to %f \n " , ctx - > qtv - > parsespeed / 1000.0f ) ;
}
else
Cmd_Printf ( ctx , " Playing demo at %f speed \n " , ctx - > qtv - > parsespeed / 1000.0f ) ;
2006-09-17 01:27:32 +00:00
}
2007-07-23 10:53:59 +00:00
void Cmd_Disconnect ( cmdctxt_t * ctx )
2006-09-17 01:27:32 +00:00
{
2012-04-23 04:37:33 +00:00
QTV_ShutdownStream ( ctx - > qtv ) ;
2007-07-23 10:53:59 +00:00
Cmd_Printf ( ctx , " Disconnected \n " ) ;
}
2006-09-17 01:27:32 +00:00
2007-12-12 11:17:18 +00:00
void Cmd_Halt ( cmdctxt_t * ctx )
{
if ( ctx - > qtv - > errored = = ERR_DISABLED | | ctx - > qtv - > errored = = ERR_PERMANENT )
{
Cmd_Printf ( ctx , " Stream is already halted \n " ) ;
}
else
{
ctx - > qtv - > errored = ERR_PERMANENT ;
Cmd_Printf ( ctx , " Stream will disconnect \n " ) ;
}
}
2009-07-07 23:40:06 +00:00
void Cmd_Pause ( cmdctxt_t * ctx )
{
if ( ctx - > qtv - > errored = = ERR_PAUSED )
{
ctx - > qtv - > errored = ERR_NONE ;
Cmd_Printf ( ctx , " Stream unpaused. \n " ) ;
}
else if ( ctx - > qtv - > errored = = ERR_NONE )
{
if ( ctx - > qtv - > sourcetype = = SRC_DEMO )
{
ctx - > qtv - > errored = ERR_PAUSED ;
Cmd_Printf ( ctx , " Stream paused. \n " ) ;
}
else
Cmd_Printf ( ctx , " Sorry, only demos may be paused. \n " ) ;
}
}
2007-12-12 11:17:18 +00:00
void Cmd_Resume ( cmdctxt_t * ctx )
{
2009-07-07 23:40:06 +00:00
if ( ctx - > qtv - > errored = = ERR_PAUSED )
{
ctx - > qtv - > errored = ERR_NONE ;
Cmd_Printf ( ctx , " Stream unpaused. \n " ) ;
}
else
{
if ( ctx - > qtv - > errored = = ERR_NONE )
Cmd_Printf ( ctx , " Stream is already functional \n " ) ;
2007-12-12 11:17:18 +00:00
2009-07-07 23:40:06 +00:00
ctx - > qtv - > errored = ERR_RECONNECT ;
Cmd_Printf ( ctx , " Stream will attempt to reconnect \n " ) ;
}
2007-12-12 11:17:18 +00:00
}
2007-07-23 10:53:59 +00:00
void Cmd_Record ( cmdctxt_t * ctx )
{
char * fname = Cmd_Argv ( ctx , 1 ) ;
if ( ! * fname )
Cmd_Printf ( ctx , " record requires a filename on the proxy's machine \n " ) ;
if ( ! Cmd_IsLocal ( ctx ) )
{
if ( * fname = = ' \\ ' | | * fname = = ' / ' | | strstr ( fname , " .. " ) | | fname [ 1 ] = = ' : ' )
{
Cmd_Printf ( ctx , " Absolute paths are prohibited. \n " ) ;
return ;
}
}
2006-09-17 01:27:32 +00:00
2007-07-23 10:53:59 +00:00
if ( Net_FileProxy ( ctx - > qtv , fname ) )
Cmd_Printf ( ctx , " Recording to disk \n " ) ;
2006-09-17 01:27:32 +00:00
else
2007-07-23 10:53:59 +00:00
Cmd_Printf ( ctx , " Failed to open file \n " ) ;
2006-09-17 01:27:32 +00:00
}
2007-07-23 10:53:59 +00:00
void Cmd_Stop ( cmdctxt_t * ctx )
2006-09-17 01:27:32 +00:00
{
2007-07-23 10:53:59 +00:00
if ( Net_StopFileProxy ( ctx - > qtv ) )
Cmd_Printf ( ctx , " stopped \n " ) ;
2006-09-17 01:27:32 +00:00
else
2007-07-23 10:53:59 +00:00
Cmd_Printf ( ctx , " not recording to disk \n " ) ;
2006-09-17 01:27:32 +00:00
}
2007-07-23 10:53:59 +00:00
void Cmd_Reconnect ( cmdctxt_t * ctx )
2006-09-17 01:27:32 +00:00
{
2010-03-14 14:35:56 +00:00
if ( ctx - > qtv - > autodisconnect = = AD_REVERSECONNECT )
2007-07-23 10:53:59 +00:00
Cmd_Printf ( ctx , " Stream is a reverse connection (command rejected) \n " ) ;
2010-03-14 14:35:56 +00:00
// else if (ctx->qtv->autodisconnect == AD_STATUSPOLL && !ctx->qtv->numviewers && !ctx->qtv->proxies)
// Cmd_Printf(ctx, "Not reconnecting to idle server\n");
2012-04-23 04:37:33 +00:00
else if ( QTV_ConnectStream ( ctx - > qtv , ctx - > qtv - > server ) )
2007-07-23 10:53:59 +00:00
Cmd_Printf ( ctx , " Reconnected \n " ) ;
2006-09-17 01:27:32 +00:00
else
2007-07-23 10:53:59 +00:00
Cmd_Printf ( ctx , " Failed to reconnect (will keep trying) \n " ) ;
2006-09-17 01:27:32 +00:00
}
2007-07-23 10:53:59 +00:00
void Cmd_MVDPort ( cmdctxt_t * ctx )
2006-09-17 01:27:32 +00:00
{
2007-07-23 10:53:59 +00:00
char * val = Cmd_Argv ( ctx , 1 ) ;
int newp = atoi ( val ) ;
2006-09-17 01:27:32 +00:00
2012-09-30 05:52:03 +00:00
if ( ! * val )
{
Cmd_Printf ( ctx , " Listening for tcp connections on port %i \n " , ctx - > cluster - > tcplistenportnum ) ;
return ;
}
2006-09-17 01:27:32 +00:00
if ( ! newp )
{
2010-03-14 14:35:56 +00:00
if ( ctx - > cluster - > tcpsocket [ 0 ] ! = INVALID_SOCKET & & ctx - > cluster - > tcpsocket [ 1 ] ! = INVALID_SOCKET )
Cmd_Printf ( ctx , " Already closed \n " ) ;
2006-09-17 01:27:32 +00:00
}
2010-03-14 14:35:56 +00:00
2012-09-30 05:52:03 +00:00
Net_TCPListen ( ctx - > cluster , newp , true ) ;
Net_TCPListen ( ctx - > cluster , newp , false ) ;
ctx - > cluster - > tcplistenportnum = newp ;
2006-09-17 01:27:32 +00:00
}
2007-07-23 10:53:59 +00:00
void Cmd_DemoList ( cmdctxt_t * ctx )
{
int i ;
int count ;
Cluster_BuildAvailableDemoList ( ctx - > cluster ) ;
count = ctx - > cluster - > availdemoscount ;
Cmd_Printf ( ctx , " %i demos \n " , count ) ;
for ( i = 0 ; i < count ; i + + )
{
Cmd_Printf ( ctx , " %7i %s \n " , ctx - > cluster - > availdemos [ i ] . size , ctx - > cluster - > availdemos [ i ] . name ) ;
}
}
2007-08-01 14:55:28 +00:00
void Cmd_BaseDir ( cmdctxt_t * ctx )
{
char * val ;
val = Cmd_Argv ( ctx , 1 ) ;
if ( ! Cmd_IsLocal ( ctx ) )
2009-07-07 23:40:06 +00:00
Cmd_Printf ( ctx , " Sorry, you may not use this command remotely \n " ) ;
2007-08-01 14:55:28 +00:00
if ( * val )
chdir ( val ) ;
else
{
char buffer [ 256 ] ;
val = getcwd ( buffer , sizeof ( buffer ) ) ;
if ( val )
Cmd_Printf ( ctx , " basedir is: %s \n " , val ) ;
else
Cmd_Printf ( ctx , " system error getting basedir \n " ) ;
}
}
2007-07-23 10:53:59 +00:00
void Cmd_DemoDir ( cmdctxt_t * ctx )
{
char * val ;
val = Cmd_Argv ( ctx , 1 ) ;
if ( * val )
{
if ( ! Cmd_IsLocal ( ctx ) )
{
Cmd_Printf ( ctx , " Sorry, but I don't trust this code that well! \n " ) ;
return ;
}
while ( * val > 0 & & * val < = ' ' )
val + + ;
if ( strchr ( val , ' . ' ) | | strchr ( val , ' : ' ) | | * val = = ' / ' )
Cmd_Printf ( ctx , " Rejecting path \n " ) ;
else
{
2007-12-27 15:18:40 +00:00
strlcpy ( ctx - > cluster - > demodir , val , sizeof ( ctx - > cluster - > demodir ) ) ;
2007-07-23 10:53:59 +00:00
Cmd_Printf ( ctx , " Changed demo dir to \" %s \" \n " , ctx - > cluster - > demodir ) ;
}
}
else
{
Cmd_Printf ( ctx , " Current demo directory is \" %s \" \n " , ctx - > cluster - > demodir ) ;
}
}
2010-03-14 14:35:56 +00:00
void Cmd_DLDir ( cmdctxt_t * ctx )
{
char * val ;
val = Cmd_Argv ( ctx , 1 ) ;
if ( ! Cmd_IsLocal ( ctx ) )
{
Cmd_Printf ( ctx , " dldir may not be used remotely \n " ) ;
return ;
}
if ( * val )
{
while ( * val > 0 & & * val < = ' ' )
val + + ;
// if (strchr(val, '.') || strchr(val, ':') || *val == '/')
// Cmd_Printf(ctx, "Rejecting path\n");
// else
{
strlcpy ( ctx - > cluster - > downloaddir , val , sizeof ( ctx - > cluster - > downloaddir ) ) ;
Cmd_Printf ( ctx , " Changed download dir to \" %s \" \n " , ctx - > cluster - > downloaddir ) ;
}
}
else
{
Cmd_Printf ( ctx , " Current download directory is \" %s \" \n " , ctx - > cluster - > downloaddir ) ;
}
}
2011-01-04 02:56:16 +00:00
void Cmd_PluginDataSource ( cmdctxt_t * ctx )
{
char * val ;
val = Cmd_Argv ( ctx , 1 ) ;
if ( ! Cmd_IsLocal ( ctx ) )
{
Cmd_Printf ( ctx , " plugindatasource may not be used remotely \n " ) ;
return ;
}
if ( * val )
{
while ( * val > 0 & & * val < = ' ' )
val + + ;
strlcpy ( ctx - > cluster - > plugindatasource , val , sizeof ( ctx - > cluster - > plugindatasource ) ) ;
Cmd_Printf ( ctx , " Changed plugindatasource to \" %s \" \n " , ctx - > cluster - > plugindatasource ) ;
}
else
{
Cmd_Printf ( ctx , " Current plugindatasource is \" %s \" \n " , ctx - > cluster - > plugindatasource ) ;
}
}
void Cmd_MapSource ( cmdctxt_t * ctx )
{
char * val ;
val = Cmd_Argv ( ctx , 1 ) ;
if ( ! Cmd_IsLocal ( ctx ) )
{
Cmd_Printf ( ctx , " mapsource may not be used remotely \n " ) ;
return ;
}
if ( * val )
{
while ( * val > 0 & & * val < = ' ' )
val + + ;
strlcpy ( ctx - > cluster - > mapsource , val , sizeof ( ctx - > cluster - > mapsource ) ) ;
Cmd_Printf ( ctx , " Changed mapsource url to \" %s \" \n " , ctx - > cluster - > mapsource ) ;
}
else
{
Cmd_Printf ( ctx , " Current mapsource url is \" %s \" \n " , ctx - > cluster - > mapsource ) ;
}
}
2007-07-23 10:53:59 +00:00
void Cmd_MuteStream ( cmdctxt_t * ctx )
{
char * val ;
val = Cmd_Argv ( ctx , 1 ) ;
2007-08-03 14:40:09 +00:00
if ( * val )
{
ctx - > qtv - > silentstream = atoi ( val ) ;
2007-12-12 11:17:18 +00:00
Cmd_Printf ( ctx , " Stream is now %smuted \n " , ctx - > qtv - > silentstream ? " " : " un " ) ;
2007-08-03 14:40:09 +00:00
}
else
2007-12-12 11:17:18 +00:00
Cmd_Printf ( ctx , " Stream is currently %smuted \n " , ctx - > qtv - > silentstream ? " " : " un " ) ;
2007-07-23 10:53:59 +00:00
}
2006-12-26 21:26:10 +00:00
# ifdef VIEWER
2007-07-23 10:53:59 +00:00
void Cmd_Watch ( cmdctxt_t * ctx )
2006-12-26 21:26:10 +00:00
{
if ( ! localcommand )
2007-07-23 10:53:59 +00:00
{
Cmd_Printf ( ctx , " watch is not permitted remotly \n " ) ;
}
2006-12-26 21:26:10 +00:00
if ( cluster - > viewserver = = qtv )
{
cluster - > viewserver = NULL ;
2007-07-23 10:53:59 +00:00
Cmd_Printf ( ctx , " Stopped watching \n " ) ;
}
else
{
cluster - > viewserver = qtv ;
Cmd_Printf ( ctx , " Watching \n " ) ;
2006-12-26 21:26:10 +00:00
}
}
# endif
2007-07-23 10:53:59 +00:00
2006-09-17 01:27:32 +00:00
typedef struct rconcommands_s {
char * name ;
qboolean serverspecific ; //works within a qtv context
qboolean clusterspecific ; //works without a qtv context (ignores context)
2007-07-23 10:53:59 +00:00
consolecommand_t func ;
2007-12-12 11:17:18 +00:00
char * description ;
2006-09-17 01:27:32 +00:00
} rconcommands_t ;
2007-12-12 11:17:18 +00:00
extern const rconcommands_t rconcommands [ ] ;
void Cmd_Commands ( cmdctxt_t * ctx )
{
2010-03-14 14:35:56 +00:00
const rconcommands_t * cmd ;
2007-12-12 11:17:18 +00:00
consolecommand_t lastfunc = NULL ;
Cmd_Printf ( ctx , " Commands: \n " ) ;
2007-12-27 15:31:27 +00:00
for ( cmd = rconcommands ; cmd - > name ; cmd + + )
2007-12-12 11:17:18 +00:00
{
if ( cmd - > func = = lastfunc )
continue ; //no spamming alternative command names
Cmd_Printf ( ctx , " %s: %s \n " , cmd - > name , cmd - > description ? cmd - > description : " no description available " ) ;
lastfunc = cmd - > func ;
}
}
2006-09-17 01:27:32 +00:00
const rconcommands_t rconcommands [ ] =
{
2007-12-12 11:17:18 +00:00
{ " exec " , 1 , 1 , Cmd_Exec , " executes a config file " } ,
{ " status " , 1 , 1 , Cmd_Status , " prints proxy/stream status " } ,
{ " say " , 1 , 1 , Cmd_Say , " says to a stream " } ,
{ " help " , 0 , 1 , Cmd_Help , " shows the brief intro help text " } ,
{ " commands " , 0 , 1 , Cmd_Commands , " prints the list of commands " } ,
{ " hostname " , 0 , 1 , Cmd_Hostname , " changes the hostname seen in server browsers " } ,
{ " master " , 0 , 1 , Cmd_Master , " specifies which master server to use " } ,
{ " udpport " , 0 , 1 , Cmd_UDPPort , " specifies to listen on a provided udp port for regular qw clients " } ,
2006-09-17 01:27:32 +00:00
{ " port " , 0 , 1 , Cmd_UDPPort } ,
2007-12-12 11:17:18 +00:00
{ " adminpassword " , 0 , 1 , Cmd_AdminPassword , " specifies the password for qtv administrators " } ,
{ " rconpassword " , 0 , 1 , Cmd_AdminPassword } ,
{ " qtvlist " , 0 , 1 , Cmd_QTVList , " queries a seperate proxy for a list of available streams " } ,
{ " qtvdemolist " , 0 , 1 , Cmd_QTVDemoList , " queries a seperate proxy for a list of available demos " } ,
{ " qtv " , 0 , 1 , Cmd_QTVConnect , " adds a new tcp/qtv stream " } ,
{ " addserver " , 0 , 1 , Cmd_QTVConnect } ,
{ " connect " , 0 , 1 , Cmd_QTVConnect } ,
{ " qw " , 0 , 1 , Cmd_QWConnect , " adds a new udp/qw stream " } ,
{ " observe " , 0 , 1 , Cmd_QWConnect } ,
{ " demos " , 0 , 1 , Cmd_DemoList , " shows the list of demos available on this proxy " } ,
{ " demo " , 0 , 1 , Cmd_MVDConnect , " adds a demo as a new stream " } ,
{ " playdemo " , 0 , 1 , Cmd_MVDConnect } ,
2014-11-21 18:10:29 +00:00
{ " dir " , 0 , 1 , Cmd_DirMVDConnect , " adds a directory of demos as a new stream " } ,
{ " playdir " , 0 , 1 , Cmd_DirMVDConnect } ,
2007-12-12 11:17:18 +00:00
{ " choke " , 0 , 1 , Cmd_Choke , " chokes packets to the data rate in the stream, disables proxy-side interpolation " } ,
{ " late " , 0 , 1 , Cmd_Late , " enforces a time delay on packets sent through this proxy " } ,
{ " talking " , 0 , 1 , Cmd_Talking , " permits viewers to talk to each other " } ,
{ " nobsp " , 0 , 1 , Cmd_NoBSP , " disables loading of bsp files " } ,
{ " userconnects " , 0 , 1 , Cmd_UserConnects , " prevents users from creating thier own streams " } ,
{ " maxviewers " , 0 , 1 , Cmd_MaxViewers , " sets a limit on udp/qw client connections " } ,
{ " maxproxies " , 0 , 1 , Cmd_MaxProxies , " sets a limit on tcp/qtv client connections " } ,
{ " demodir " , 0 , 1 , Cmd_DemoDir , " specifies where to get the demo list from " } ,
{ " basedir " , 0 , 1 , Cmd_BaseDir , " specifies where to get any files required by the game. this is prefixed to the server-specified game dir. " } ,
{ " ping " , 0 , 1 , Cmd_Ping , " sends a udp ping to a qtv proxy or server " } ,
{ " reconnect " , 0 , 1 , Cmd_Reconnect , " forces a stream to reconnect to its server (restarts demos) " } ,
{ " echo " , 0 , 1 , Cmd_Echo , " a useless command that echos a string " } ,
{ " quit " , 0 , 1 , Cmd_Quit , " closes the qtv " } ,
2007-07-23 10:53:59 +00:00
{ " exit " , 0 , 1 , Cmd_Quit } ,
2007-12-12 11:17:18 +00:00
{ " streams " , 0 , 1 , Cmd_Streams , " shows a list of active streams " } ,
{ " allownq " , 0 , 1 , Cmd_AllowNQ , " permits nq clients to connect. This can be disabled as this code is less tested than the rest " } ,
2012-04-20 14:41:40 +00:00
{ " initialdelay " , 0 , 1 , Cmd_InitialDelay , " Specifies the duration for which new connections will be buffered. Large values prevents players from spectating their enemies as a cheap wallhack. " } ,
{ " slowdelay " , 0 , 1 , Cmd_SlowDelay , " If a server is not sending enough data, the proxy will delay parsing for this long. " } ,
2006-09-17 01:27:32 +00:00
2009-07-07 23:40:06 +00:00
{ " halt " , 1 , 0 , Cmd_Halt , " disables a stream, preventing it from reconnecting until someone tries watching it anew. Boots current spectators " } ,
2007-12-12 11:17:18 +00:00
{ " disable " , 1 , 0 , Cmd_Halt } ,
2009-07-07 23:40:06 +00:00
{ " pause " , 1 , 0 , Cmd_Pause , " Pauses a demo stream. " } ,
2007-12-12 11:17:18 +00:00
{ " resume " , 1 , 0 , Cmd_Resume , " reactivates a stream, allowing it to reconnect " } ,
{ " enable " , 1 , 0 , Cmd_Resume } ,
{ " mute " , 1 , 0 , Cmd_MuteStream , " hides prints that come from the game server " } ,
2007-07-23 10:53:59 +00:00
{ " mutestream " , 1 , 0 , Cmd_MuteStream } ,
2007-12-12 11:17:18 +00:00
{ " disconnect " , 1 , 0 , Cmd_Disconnect , " fully closes a stream " } ,
{ " record " , 1 , 0 , Cmd_Record , " records a stream to a demo " } ,
{ " stop " , 1 , 0 , Cmd_Stop , " stops recording of a demo " } ,
{ " demospeed " , 1 , 0 , Cmd_DemoSpeed , " changes the rate the demo is played at " } ,
{ " tcpport " , 0 , 1 , Cmd_MVDPort , " specifies which port to listen on for tcp/qtv connections " } ,
{ " mvdport " , 0 , 1 , Cmd_MVDPort } ,
2006-12-26 21:26:10 +00:00
2011-01-04 02:56:16 +00:00
{ " dldir " , 0 , 1 , Cmd_DLDir , " specifies the path to download stuff from (http://server/file/ maps to this native path) " } ,
{ " plugindatasource " , 0 , 1 , Cmd_PluginDataSource , " Specifies the dataDownload property for plugins in the web server " } ,
{ " mapsource " , 0 , 1 , Cmd_MapSource , " Public URL for where to download missing maps from " } ,
2006-12-26 21:26:10 +00:00
# ifdef VIEWER
2007-12-12 11:17:18 +00:00
{ " watch " , 1 , 0 , Cmd_Watch , " specifies to watch that stream in the built-in viewer " } ,
2006-12-26 21:26:10 +00:00
# endif
2011-07-15 16:31:53 +00:00
2006-09-17 01:27:32 +00:00
{ NULL }
} ;
2007-07-23 10:53:59 +00:00
void Cmd_ExecuteNow ( cmdctxt_t * ctx , char * command )
2005-10-07 02:02:15 +00:00
{
# define TOKENIZE_PUNCTUATION ""
2005-09-24 04:45:24 +00:00
2006-10-07 22:29:31 +00:00
int i ;
char arg [ MAX_ARGS ] [ ARG_LEN ] ;
char * sid ;
2007-07-23 10:53:59 +00:00
char * cmdname ;
2005-09-24 04:45:24 +00:00
2007-07-23 10:53:59 +00:00
for ( sid = command ; * sid ; sid + + )
2005-09-24 04:45:24 +00:00
{
2006-10-07 22:29:31 +00:00
if ( * sid = = ' : ' )
break ;
if ( * sid < ' 0 ' | | * sid > ' 9 ' )
break ;
2005-09-24 04:45:24 +00:00
}
2006-10-07 22:29:31 +00:00
if ( * sid = = ' : ' )
2005-09-24 04:45:24 +00:00
{
2006-10-07 22:29:31 +00:00
i = atoi ( command ) ;
command = sid + 1 ;
2011-07-15 16:31:53 +00:00
2009-07-07 23:40:06 +00:00
ctx - > streamid = i ;
2005-09-24 04:45:24 +00:00
2007-07-23 10:53:59 +00:00
for ( ctx - > qtv = ctx - > cluster - > servers ; ctx - > qtv ; ctx - > qtv = ctx - > qtv - > next )
if ( ctx - > qtv - > streamid = = i )
2006-10-07 22:29:31 +00:00
break ;
2005-09-24 04:45:24 +00:00
}
2009-07-07 23:40:06 +00:00
else
ctx - > streamid = 0 ;
2005-10-07 02:02:15 +00:00
2007-07-23 10:53:59 +00:00
ctx - > argc = 0 ;
2005-10-07 02:02:15 +00:00
for ( i = 0 ; i < MAX_ARGS ; i + + )
{
command = COM_ParseToken ( command , arg [ i ] , ARG_LEN , TOKENIZE_PUNCTUATION ) ;
2007-07-23 10:53:59 +00:00
ctx - > arg [ i ] = arg [ i ] ;
if ( command )
ctx - > argc + + ;
2005-09-24 04:45:24 +00:00
}
2007-07-23 10:53:59 +00:00
cmdname = Cmd_Argv ( ctx , 0 ) ;
2006-09-17 01:27:32 +00:00
2007-12-12 11:17:18 +00:00
//if there's only one stream, set that as the selected stream
2007-07-23 10:53:59 +00:00
if ( ! ctx - > qtv & & ctx - > cluster - > numservers = = 1 )
ctx - > qtv = ctx - > cluster - > servers ;
2006-09-17 01:27:32 +00:00
2007-07-23 10:53:59 +00:00
if ( ctx - > qtv )
2005-10-07 02:02:15 +00:00
{ //if there is a specific connection targetted
2006-09-17 01:27:32 +00:00
for ( i = 0 ; rconcommands [ i ] . name ; i + + )
{
if ( rconcommands [ i ] . serverspecific )
2007-07-23 10:53:59 +00:00
if ( ! strcmp ( rconcommands [ i ] . name , cmdname ) )
{
rconcommands [ i ] . func ( ctx ) ;
return ;
}
2006-09-17 01:27:32 +00:00
}
2005-10-07 02:02:15 +00:00
}
2006-09-17 01:27:32 +00:00
for ( i = 0 ; rconcommands [ i ] . name ; i + + )
{
2007-07-23 10:53:59 +00:00
if ( ! strcmp ( rconcommands [ i ] . name , cmdname ) )
2006-09-17 01:27:32 +00:00
{
if ( rconcommands [ i ] . clusterspecific )
2007-07-23 10:53:59 +00:00
{
rconcommands [ i ] . func ( ctx ) ;
return ;
}
2006-09-17 01:27:32 +00:00
else if ( rconcommands [ i ] . serverspecific )
{
2007-07-23 10:53:59 +00:00
Cmd_Printf ( ctx , " Command \" %s \" requires a targeted server. \n " , cmdname ) ;
return ;
2006-09-17 01:27:32 +00:00
}
}
2005-10-07 02:02:15 +00:00
}
2007-07-23 10:53:59 +00:00
Cmd_Printf ( ctx , " Command \" %s \" not recognised. \n " , cmdname ) ;
2005-09-24 04:45:24 +00:00
}
2007-07-23 10:53:59 +00:00
void Rcon_PrintToBuffer ( cmdctxt_t * ctx , char * msg )
{
if ( ctx - > printcookiesize < 1 )
return ;
while ( ctx - > printcookiesize > 2 & & * msg )
{
ctx - > printcookiesize - - ;
* ( char * ) ctx - > printcookie = * msg + + ;
ctx - > printcookie = ( ( char * ) ctx - > printcookie ) + 1 ;
}
ctx - > printcookiesize - - ;
* ( char * ) ctx - > printcookie = 0 ;
}
char * Rcon_Command ( cluster_t * cluster , sv_t * source , char * command , char * resultbuffer , int resultbuffersize , int islocalcommand )
{
cmdctxt_t ctx ;
ctx . cluster = cluster ;
ctx . qtv = source ;
ctx . argc = 0 ;
ctx . printfunc = Rcon_PrintToBuffer ;
ctx . printcookie = resultbuffer ;
ctx . printcookiesize = resultbuffersize ;
ctx . localcommand = islocalcommand ;
* ( char * ) ctx . printcookie = 0 ;
Cmd_ExecuteNow ( & ctx , command ) ;
return resultbuffer ;
}