#include "mdfour.h"
#include <time.h>
-int current_skill;
extern cvar_t sv_adminnick;
extern cvar_t sv_status_privacy;
extern cvar_t sv_status_show_qcstatus;
extern cvar_t sv_namechangetimer;
cvar_t rcon_password = {CVAR_CLIENT | CVAR_SERVER | CVAR_PRIVATE, "rcon_password", "", "password to authenticate rcon commands; NOTE: changing rcon_secure clears rcon_password, so set rcon_secure always before rcon_password; may be set to a string of the form user1:pass1 user2:pass2 user3:pass3 to allow multiple user accounts - the client then has to specify ONE of these combinations"};
-cvar_t rcon_secure = {CVAR_CLIENT | CVAR_SERVER | CVAR_NQUSERINFOHACK, "rcon_secure", "0", "force secure rcon authentication (1 = time based, 2 = challenge based); NOTE: changing rcon_secure clears rcon_password, so set rcon_secure always before rcon_password"};
+cvar_t rcon_secure = {CVAR_CLIENT | CVAR_SERVER, "rcon_secure", "0", "force secure rcon authentication (1 = time based, 2 = challenge based); NOTE: changing rcon_secure clears rcon_password, so set rcon_secure always before rcon_password"};
cvar_t rcon_secure_challengetimeout = {CVAR_CLIENT, "rcon_secure_challengetimeout", "5", "challenge-based secure rcon: time out requests if no challenge came within this time interval"};
cvar_t rcon_address = {CVAR_CLIENT, "rcon_address", "", "server address to send rcon commands to (when not connected to a server)"};
-cvar_t team = {CVAR_CLIENT | CVAR_USERINFO | CVAR_SAVE, "team", "none", "QW team (4 character limit, example: blue)"};
-cvar_t skin = {CVAR_CLIENT | CVAR_USERINFO | CVAR_SAVE, "skin", "", "QW player skin name (example: base)"};
-cvar_t noaim = {CVAR_CLIENT | CVAR_USERINFO | CVAR_SAVE, "noaim", "1", "QW option to disable vertical autoaim"};
+cvar_t cl_name = {CVAR_CLIENT | CVAR_SAVE | CVAR_USERINFO, "name", "player", "change your player name"};
+cvar_t cl_topcolor = {CVAR_CLIENT | CVAR_SAVE | CVAR_USERINFO, "topcolor", "0", "change the color of your shirt"};
+cvar_t cl_bottomcolor = {CVAR_CLIENT | CVAR_SAVE | CVAR_USERINFO, "bottomcolor", "0", "change the color of your pants"};
+cvar_t cl_team = {CVAR_CLIENT | CVAR_USERINFO | CVAR_SAVE, "team", "none", "QW team (4 character limit, example: blue)"};
+cvar_t cl_skin = {CVAR_CLIENT | CVAR_USERINFO | CVAR_SAVE, "skin", "", "QW player skin name (example: base)"};
+cvar_t cl_playermodel = {CVAR_CLIENT | CVAR_SERVER | CVAR_USERINFO | CVAR_SAVE, "playermodel", "", "current player model in Nexuiz/Xonotic"};
+cvar_t cl_playerskin = {CVAR_CLIENT | CVAR_SERVER | CVAR_USERINFO | CVAR_SAVE, "playerskin", "", "current player skin in Nexuiz/Xonotic"};
+cvar_t cl_noaim = {CVAR_CLIENT | CVAR_USERINFO | CVAR_SAVE, "noaim", "1", "QW option to disable vertical autoaim"};
+cvar_t cl_pmodel = {CVAR_CLIENT | CVAR_USERINFO | CVAR_SAVE, "pmodel", "0", "current player model number in nehahra"};
cvar_t r_fixtrans_auto = {CVAR_CLIENT, "r_fixtrans_auto", "0", "automatically fixtrans textures (when set to 2, it also saves the fixed versions to a fixtrans directory)"};
//============================================================================
-/*
-======================
-CL_Name_f
-======================
-*/
-cvar_t cl_name = {CVAR_CLIENT | CVAR_SAVE | CVAR_NQUSERINFOHACK, "_cl_name", "player", "internal storage cvar for current player name (changed by name command)"};
-static void CL_Name_f(cmd_state_t *cmd)
-{
- prvm_prog_t *prog = SVVM_prog;
- int i, j;
- qboolean valid_colors;
- const char *newNameSource;
- char newName[sizeof(host_client->name)];
-
- if (Cmd_Argc (cmd) == 1)
- {
- if (cmd->source == src_command)
- {
- Con_Printf("name: %s\n", cl_name.string);
- }
- return;
- }
-
- if (Cmd_Argc (cmd) == 2)
- newNameSource = Cmd_Argv(cmd, 1);
- else
- newNameSource = Cmd_Args(cmd);
-
- strlcpy(newName, newNameSource, sizeof(newName));
-
- if (cmd->source == src_command)
- {
- Cvar_Set (&cvars_all, "_cl_name", newName);
- if (strlen(newNameSource) >= sizeof(newName)) // overflowed
- {
- Con_Printf("Your name is longer than %i chars! It has been truncated.\n", (int) (sizeof(newName) - 1));
- Con_Printf("name: %s\n", cl_name.string);
- }
- return;
- }
-
- if (host.realtime < host_client->nametime)
- {
- SV_ClientPrintf("You can't change name more than once every %.1f seconds!\n", max(0.0f, sv_namechangetimer.value));
- return;
- }
-
- host_client->nametime = host.realtime + max(0.0f, sv_namechangetimer.value);
-
- // point the string back at updateclient->name to keep it safe
- strlcpy (host_client->name, newName, sizeof (host_client->name));
-
- for (i = 0, j = 0;host_client->name[i];i++)
- if (host_client->name[i] != '\r' && host_client->name[i] != '\n')
- host_client->name[j++] = host_client->name[i];
- host_client->name[j] = 0;
-
- if(host_client->name[0] == 1 || host_client->name[0] == 2)
- // may interfere with chat area, and will needlessly beep; so let's add a ^7
- {
- memmove(host_client->name + 2, host_client->name, sizeof(host_client->name) - 2);
- host_client->name[sizeof(host_client->name) - 1] = 0;
- host_client->name[0] = STRING_COLOR_TAG;
- host_client->name[1] = '0' + STRING_COLOR_DEFAULT;
- }
-
- u8_COM_StringLengthNoColors(host_client->name, 0, &valid_colors);
- if(!valid_colors) // NOTE: this also proves the string is not empty, as "" is a valid colored string
- {
- size_t l;
- l = strlen(host_client->name);
- if(l < sizeof(host_client->name) - 1)
- {
- // duplicate the color tag to escape it
- host_client->name[i] = STRING_COLOR_TAG;
- host_client->name[i+1] = 0;
- //Con_DPrintf("abuse detected, adding another trailing color tag\n");
- }
- else
- {
- // remove the last character to fix the color code
- host_client->name[l-1] = 0;
- //Con_DPrintf("abuse detected, removing a trailing color tag\n");
- }
- }
-
- // find the last color tag offset and decide if we need to add a reset tag
- for (i = 0, j = -1;host_client->name[i];i++)
- {
- if (host_client->name[i] == STRING_COLOR_TAG)
- {
- if (host_client->name[i+1] >= '0' && host_client->name[i+1] <= '9')
- {
- j = i;
- // if this happens to be a reset tag then we don't need one
- if (host_client->name[i+1] == '0' + STRING_COLOR_DEFAULT)
- j = -1;
- i++;
- continue;
- }
- if (host_client->name[i+1] == STRING_COLOR_RGB_TAG_CHAR && isxdigit(host_client->name[i+2]) && isxdigit(host_client->name[i+3]) && isxdigit(host_client->name[i+4]))
- {
- j = i;
- i += 4;
- continue;
- }
- if (host_client->name[i+1] == STRING_COLOR_TAG)
- {
- i++;
- continue;
- }
- }
- }
- // does not end in the default color string, so add it
- if (j >= 0 && strlen(host_client->name) < sizeof(host_client->name) - 2)
- memcpy(host_client->name + strlen(host_client->name), STRING_COLOR_DEFAULT_STR, strlen(STRING_COLOR_DEFAULT_STR) + 1);
-
- PRVM_serveredictstring(host_client->edict, netname) = PRVM_SetEngineString(prog, host_client->name);
- if (strcmp(host_client->old_name, host_client->name))
- {
- if (host_client->begun)
- SV_BroadcastPrintf("%s ^7changed name to %s\n", host_client->old_name, host_client->name);
- strlcpy(host_client->old_name, host_client->name, sizeof(host_client->old_name));
- // send notification to all clients
- MSG_WriteByte (&sv.reliable_datagram, svc_updatename);
- MSG_WriteByte (&sv.reliable_datagram, host_client - svs.clients);
- MSG_WriteString (&sv.reliable_datagram, host_client->name);
- SV_WriteNetnameIntoDemo(host_client);
- }
-}
-
/*
======================
CL_Playermodel_f
======================
*/
-cvar_t cl_playermodel = {CVAR_CLIENT | CVAR_SAVE | CVAR_NQUSERINFOHACK, "_cl_playermodel", "", "internal storage cvar for current player model in Nexuiz/Xonotic (changed by playermodel command)"};
// the old cl_playermodel in cl_main has been renamed to __cl_playermodel
static void CL_Playermodel_f(cmd_state_t *cmd)
{
CL_Playerskin_f
======================
*/
-cvar_t cl_playerskin = {CVAR_CLIENT | CVAR_SAVE | CVAR_NQUSERINFOHACK, "_cl_playerskin", "", "internal storage cvar for current player skin in Nexuiz/Xonotic (changed by playerskin command)"};
static void CL_Playerskin_f(cmd_state_t *cmd)
{
prvm_prog_t *prog = SVVM_prog;
CL_Color_f
==================
*/
-cvar_t cl_color = {CVAR_CLIENT | CVAR_SAVE | CVAR_NQUSERINFOHACK, "_cl_color", "0", "internal storage cvar for current player colors (changed by color command)"};
-static void CL_Color(cmd_state_t *cmd, int changetop, int changebottom)
-{
- prvm_prog_t *prog = SVVM_prog;
- int top, bottom, playercolor;
-
- // get top and bottom either from the provided values or the current values
- // (allows changing only top or bottom, or both at once)
- top = changetop >= 0 ? changetop : (cl_color.integer >> 4);
- bottom = changebottom >= 0 ? changebottom : cl_color.integer;
+cvar_t cl_color = {CVAR_READONLY | CVAR_CLIENT | CVAR_SAVE, "_cl_color", "0", "internal storage cvar for current player colors (changed by color command)"};
- top &= 15;
- bottom &= 15;
- // LadyHavoc: allowing skin colormaps 14 and 15 by commenting this out
- //if (top > 13)
- // top = 13;
- //if (bottom > 13)
- // bottom = 13;
-
- playercolor = top*16 + bottom;
+// Ignore the callbacks so this two-to-three way synchronization doesn't cause an infinite loop.
+static void CL_Color_c(cvar_t *var)
+{
+ char vabuf[1024];
+
+ Cvar_Set_NoCallback(&cl_topcolor, va(vabuf, sizeof(vabuf), "%i", ((var->integer >> 4) & 15)));
+ Cvar_Set_NoCallback(&cl_bottomcolor, va(vabuf, sizeof(vabuf), "%i", (var->integer & 15)));
+}
- if (cmd->source == src_command)
- {
- Cvar_SetValueQuick(&cl_color, playercolor);
- return;
- }
+static void CL_Topcolor_c(cvar_t *var)
+{
+ char vabuf[1024];
+
+ Cvar_Set_NoCallback(&cl_color, va(vabuf, sizeof(vabuf), "%i", var->integer*16 + cl_bottomcolor.integer));
+}
- if (cls.protocol == PROTOCOL_QUAKEWORLD)
- return;
+static void CL_Bottomcolor_c(cvar_t *var)
+{
+ char vabuf[1024];
- if (host_client->edict && PRVM_serverfunction(SV_ChangeTeam))
- {
- Con_DPrint("Calling SV_ChangeTeam\n");
- prog->globals.fp[OFS_PARM0] = playercolor;
- PRVM_serverglobalfloat(time) = sv.time;
- PRVM_serverglobaledict(self) = PRVM_EDICT_TO_PROG(host_client->edict);
- prog->ExecuteProgram(prog, PRVM_serverfunction(SV_ChangeTeam), "QC function SV_ChangeTeam is missing");
- }
- else
- {
- if (host_client->edict)
- {
- PRVM_serveredictfloat(host_client->edict, clientcolors) = playercolor;
- PRVM_serveredictfloat(host_client->edict, team) = bottom + 1;
- }
- host_client->colors = playercolor;
- if (host_client->old_colors != host_client->colors)
- {
- host_client->old_colors = host_client->colors;
- // send notification to all clients
- MSG_WriteByte (&sv.reliable_datagram, svc_updatecolors);
- MSG_WriteByte (&sv.reliable_datagram, host_client - svs.clients);
- MSG_WriteByte (&sv.reliable_datagram, host_client->colors);
- }
- }
+ Cvar_Set_NoCallback(&cl_color, va(vabuf, sizeof(vabuf), "%i", cl_topcolor.integer*16 + var->integer));
}
static void CL_Color_f(cmd_state_t *cmd)
{
- int top, bottom;
+ int top, bottom;
if (Cmd_Argc(cmd) == 1)
{
if (cmd->source == src_command)
{
- Con_Printf("\"color\" is \"%i %i\"\n", cl_color.integer >> 4, cl_color.integer & 15);
+ Con_Printf("\"color\" is \"%i %i\"\n", cl_topcolor.integer, cl_bottomcolor.integer);
Con_Print("color <0-15> [0-15]\n");
}
return;
top = atoi(Cmd_Argv(cmd, 1));
bottom = atoi(Cmd_Argv(cmd, 2));
}
- CL_Color(cmd, top, bottom);
-}
-
-static void CL_TopColor_f(cmd_state_t *cmd)
-{
- if (Cmd_Argc(cmd) == 1)
- {
- if (cmd->source == src_command)
- {
- Con_Printf("\"topcolor\" is \"%i\"\n", (cl_color.integer >> 4) & 15);
- Con_Print("topcolor <0-15>\n");
- }
- return;
- }
-
- CL_Color(cmd, atoi(Cmd_Argv(cmd, 1)), -1);
-}
-
-static void CL_BottomColor_f(cmd_state_t *cmd)
-{
- if (Cmd_Argc(cmd) == 1)
- {
- if (cmd->source == src_command)
- {
- Con_Printf("\"bottomcolor\" is \"%i\"\n", cl_color.integer & 15);
- Con_Print("bottomcolor <0-15>\n");
- }
- return;
- }
-
- CL_Color(cmd, -1, atoi(Cmd_Argv(cmd, 1)));
-}
+ /*
+ * This is just a convenient way to change topcolor and bottomcolor
+ * We can't change cl_color from here directly because topcolor and
+ * bottomcolor may be changed separately and do not call this function.
+ * So it has to be changed when the userinfo strings are updated, which
+ * happens twice here. Perhaps find a cleaner way?
+ */
-cvar_t cl_rate = {CVAR_CLIENT | CVAR_SAVE | CVAR_NQUSERINFOHACK, "_cl_rate", "20000", "internal storage cvar for current rate (changed by rate command)"};
-cvar_t cl_rate_burstsize = {CVAR_CLIENT | CVAR_SAVE | CVAR_NQUSERINFOHACK, "_cl_rate_burstsize", "1024", "internal storage cvar for current rate control burst size (changed by rate_burstsize command)"};
-static void CL_Rate_f(cmd_state_t *cmd)
-{
- int rate;
+ top = top >= 0 ? top : cl_topcolor.integer;
+ bottom = bottom >= 0 ? bottom : cl_bottomcolor.integer;
- if (Cmd_Argc(cmd) != 2)
- {
- if (cmd->source == src_command)
- {
- Con_Printf("\"rate\" is \"%i\"\n", cl_rate.integer);
- Con_Print("rate <bytespersecond>\n");
- }
- return;
- }
+ top &= 15;
+ bottom &= 15;
- rate = atoi(Cmd_Argv(cmd, 1));
+ // LadyHavoc: allowing skin colormaps 14 and 15 by commenting this out
+ //if (top > 13)
+ // top = 13;
+ //if (bottom > 13)
+ // bottom = 13;
if (cmd->source == src_command)
{
- Cvar_SetValue (&cvars_all, "_cl_rate", max(NET_MINRATE, rate));
+ Cvar_SetValueQuick(&cl_topcolor, top);
+ Cvar_SetValueQuick(&cl_bottomcolor, bottom);
return;
}
-
- host_client->rate = rate;
}
-static void CL_Rate_BurstSize_f(cmd_state_t *cmd)
-{
- int rate_burstsize;
-
- if (Cmd_Argc(cmd) != 2)
- {
- Con_Printf("\"rate_burstsize\" is \"%i\"\n", cl_rate_burstsize.integer);
- Con_Print("rate_burstsize <bytes>\n");
- return;
- }
-
- rate_burstsize = atoi(Cmd_Argv(cmd, 1));
-
- if (cmd->source == src_command)
- {
- Cvar_SetValue (&cvars_all, "_cl_rate_burstsize", rate_burstsize);
- return;
- }
-
- host_client->rate_burstsize = rate_burstsize;
-}
+cvar_t cl_rate = {CVAR_CLIENT | CVAR_SAVE | CVAR_USERINFO, "rate", "20000", "change your connection speed"};
+cvar_t cl_rate_burstsize = {CVAR_CLIENT | CVAR_SAVE | CVAR_USERINFO, "rate_burstsize", "1024", "internal storage cvar for current rate control burst size (changed by rate_burstsize command)"};
/*
======================
LadyHavoc: correction, Mindcrime will be removing pmodel in the future, but it's still stuck here for compatibility.
======================
*/
-cvar_t cl_pmodel = {CVAR_CLIENT | CVAR_SAVE | CVAR_NQUSERINFOHACK, "_cl_pmodel", "0", "internal storage cvar for current player model number in nehahra (changed by pmodel command)"};
static void CL_PModel_f(cmd_state_t *cmd)
{
prvm_prog_t *prog = SVVM_prog;
}
}
+static void CL_RCon_ClearPassword_c(cvar_t *var)
+{
+ // whenever rcon_secure is changed to 0, clear rcon_password for
+ // security reasons (prevents a send-rcon-password-as-plaintext
+ // attack based on NQ protocol session takeover and svc_stufftext)
+ if(var->integer <= 0)
+ Cvar_SetQuick(&rcon_password, "");
+}
+
/*
==================
CL_FullServerinfo_f
dpsnprintf(cls.userinfo, sizeof(cls.userinfo), "\\name\\player\\team\\none\\topcolor\\0\\bottomcolor\\0\\rate\\10000\\msg\\1\\noaim\\1\\*ver\\dp");
Cvar_RegisterVariable(&cl_name);
+ Cvar_RegisterAlias(&cl_name, "_cl_name");
Cvar_RegisterVariable(&cl_color);
+ Cvar_RegisterCallback(&cl_color, CL_Color_c);
+ Cvar_RegisterVariable(&cl_topcolor);
+ Cvar_RegisterCallback(&cl_topcolor, CL_Topcolor_c);
+ Cvar_RegisterVariable(&cl_bottomcolor);
+ Cvar_RegisterCallback(&cl_bottomcolor, CL_Bottomcolor_c);
Cvar_RegisterVariable(&cl_rate);
+ Cvar_RegisterAlias(&cl_rate, "_cl_rate");
Cvar_RegisterVariable(&cl_rate_burstsize);
+ Cvar_RegisterAlias(&cl_rate_burstsize, "_cl_rate_burstsize");
Cvar_RegisterVariable(&cl_pmodel);
+ Cvar_RegisterAlias(&cl_pmodel, "_cl_pmodel");
Cvar_RegisterVariable(&cl_playermodel);
+ Cvar_RegisterAlias(&cl_playermodel, "_cl_playermodel");
Cvar_RegisterVariable(&cl_playerskin);
+ Cvar_RegisterAlias(&cl_playerskin, "_cl_playerskin");
Cvar_RegisterVariable(&rcon_password);
Cvar_RegisterVariable(&rcon_address);
Cvar_RegisterVariable(&rcon_secure);
+ Cvar_RegisterCallback(&rcon_secure, CL_RCon_ClearPassword_c);
Cvar_RegisterVariable(&rcon_secure_challengetimeout);
Cvar_RegisterVariable(&r_fixtrans_auto);
- Cvar_RegisterVariable(&team);
- Cvar_RegisterVariable(&skin);
- Cvar_RegisterVariable(&noaim);
-
- Cmd_AddCommand(CMD_CLIENT | CMD_SERVER_FROM_CLIENT, "name", CL_Name_f, "change your player name");
- Cmd_AddCommand(CMD_CLIENT | CMD_SERVER_FROM_CLIENT, "color", CL_Color_f, "change your player shirt and pants colors");
- Cmd_AddCommand(CMD_CLIENT | CMD_SERVER_FROM_CLIENT, "rate", CL_Rate_f, "change your network connection speed");
- Cmd_AddCommand(CMD_CLIENT | CMD_SERVER_FROM_CLIENT, "rate_burstsize", CL_Rate_BurstSize_f, "change your network connection speed");
- Cmd_AddCommand(CMD_CLIENT | CMD_SERVER_FROM_CLIENT, "pmodel", CL_PModel_f, "(Nehahra-only) change your player model choice");
- Cmd_AddCommand(CMD_CLIENT | CMD_SERVER_FROM_CLIENT, "playermodel", CL_Playermodel_f, "change your player model");
- Cmd_AddCommand(CMD_CLIENT | CMD_SERVER_FROM_CLIENT, "playerskin", CL_Playerskin_f, "change your player skin number");
+ Cvar_RegisterVariable(&cl_team);
+ Cvar_RegisterVariable(&cl_skin);
+ Cvar_RegisterVariable(&cl_noaim);
+
+ Cmd_AddCommand(CMD_CLIENT, "color", CL_Color_f, "change your player shirt and pants colors");
+ Cmd_AddCommand(CMD_USERINFO, "pmodel", CL_PModel_f, "(Nehahra-only) change your player model choice");
+ Cmd_AddCommand(CMD_USERINFO, "playermodel", CL_Playermodel_f, "change your player model");
+ Cmd_AddCommand(CMD_USERINFO, "playerskin", CL_Playerskin_f, "change your player skin number");
Cmd_AddCommand(CMD_CLIENT, "sendcvar", CL_SendCvar_f, "sends the value of a cvar to the server as a sentcvar command, for use by QuakeC");
Cmd_AddCommand(CMD_CLIENT, "rcon", CL_Rcon_f, "sends a command to the server console (if your rcon_password matches the server's rcon_password), or to the address specified by rcon_address when not connected (again rcon_password must match the server's); note: if rcon_secure is set, client and server clocks must be synced e.g. via NTP");
Cmd_AddCommand(CMD_CLIENT, "pqrcon", CL_PQRcon_f, "sends a command to a proquake server console (if your rcon_password matches the server's rcon_password), or to the address specified by rcon_address when not connected (again rcon_password must match the server's)");
Cmd_AddCommand(CMD_CLIENT, "fullinfo", CL_FullInfo_f, "allows client to modify their userinfo");
Cmd_AddCommand(CMD_CLIENT, "setinfo", CL_SetInfo_f, "modifies your userinfo");
- Cmd_AddCommand(CMD_CLIENT | CMD_CLIENT_FROM_SERVER, "packet", CL_Packet_f, "send a packet to the specified address:port containing a text string");
- Cmd_AddCommand(CMD_CLIENT | CMD_CLIENT_FROM_SERVER, "topcolor", CL_TopColor_f, "QW command to set top color without changing bottom color");
- Cmd_AddCommand(CMD_CLIENT, "bottomcolor", CL_BottomColor_f, "QW command to set bottom color without changing top color");
+ Cmd_AddCommand(CMD_CLIENT, "packet", CL_Packet_f, "send a packet to the specified address:port containing a text string");
Cmd_AddCommand(CMD_CLIENT, "fixtrans", Image_FixTransparentPixels_f, "change alpha-zero pixels in an image file to sensible values, and write out a new TGA (warning: SLOW)");
// commands that are only sent by server to client for execution