merged patch from pelish. shouldn't break anything if you don't activate IRC/WOL support ;-)

This commit is contained in:
pandaemonium 2006-11-05 16:02:35 +00:00
parent c56ef37a25
commit e5ed8427a7
21 changed files with 421 additions and 856 deletions

View file

@ -16,13 +16,15 @@ PROGRAMMING CONTRIBUTORS
Bryan Biedenkapp (gatekeep@gmail.com)
Westwood Online (WOL) support. Lot's of IRC fixes and enhancements.
WOL and IRC maintainer.
pandaemonium a.k.a. aaron
W3 ladders, binary ladders, commands aliases, channel topics,
channel tmp ops/voices, anongame infos language support, SQL db
creator, bnchat cleanup, WIN32 build files maintenance and lots others.
Pelish (pelish@gmail.com)
WOL/IRC rework and many bugfixes
Soar
Clans, friends codes optimization, D2 stuff, w3 gameinfo etc.

View file

@ -506,12 +506,14 @@ initkill_timer = 120
# NOTE: WOL support is still experimental!
# This specifies the addresses where IRC connections should be accepted. See
# This specifies the addresses where WOL connections should be accepted. See
# the description of servaddrs for formatting information. Leave this field
# blank if you do not want to accept IRC connections. If the port is not
# specifed then 4005 will be used. Note: DO NOT SET THE PORT TO ANYTHING OTHER
# THEN 4005, WOL WILL FAIL IF YOU DO!
#woladdrs = ":4005"
# blank if you do not want to accept WOL connections. If the WSERV port is not
# specifed then 4005 and WOL port is not specifed then 4000 will be used.
# Note: DO NOT SET THE PORT TO ANYTHING OTHER THEN 4005 and 4000, WOL WILL FAIL IF YOU DO!
#woladdrs = ":4000"
#wservaddrs = ":4005"
# Just leave these as default (unless you know the timezone, longitiude and latitude
# of your server

View file

@ -484,12 +484,14 @@ initkill_timer = 120
# NOTE: WOL support is still experimental!
# This specifies the addresses where IRC connections should be accepted. See
# This specifies the addresses where WOL connections should be accepted. See
# the description of servaddrs for formatting information. Leave this field
# blank if you do not want to accept IRC connections. If the port is not
# specifed then 4005 will be used. Note: DO NOT SET THE PORT TO ANYTHING OTHER
# THEN 4005, WOL WILL FAIL IF YOU DO!
#woladdrs = ":4005"
# blank if you do not want to accept WOL connections. If the WSERV port is not
# specifed then 4005 and WOL port is not specifed then 4000 will be used.
# Note: DO NOT SET THE PORT TO ANYTHING OTHER THEN 4005 and 4000, WOL WILL FAIL IF YOU DO!
#woladdrs = ":4000"
#wservaddrs = ":4005"
# Just leave these as default (unless you know the timezone, longitiude and latitude
# of your server

View file

@ -45,23 +45,53 @@ NONE "Diablo II" D2XP true false false NULL NULL -1 false
# Westwood Online Channels #
#----------------------------------------------------------------------------#
# Note: The Westwood channels should be formatted like this! Do not set the last number above 5.
# The proper game type numbers are as follows:
# - 18 = Tiberian Sun game channels
# - 21 = Red alert 1 channels
# - 33 = Red alert 2 channels
# - 41 = Yuri's Revenge
# The proper game type numbers are as follows:
# - 12 = C&C Renegade channels
# - 14 = Dune 2000 channels
# - 16 = Nox channels
# - 18 = Tiberian Sun channels
# - 21 = Red Alert 1 channels
# - 33 = Red Alert 2 channels
# - 37 = Nox Quest channels
# - 41 = Yuri's Revenge channels
#
##### Westwood Chat Channels ###################################################################################
"Command n Conqr" "Command n Conqr" WCHT false false false NULL NULL -1 false
"Monopoly" "Monopoly" WCHT false false false NULL NULL -1 false
"Red Alert" "Red Alert" WCHT false false false NULL NULL -1 false
##### C&C Renegade Support #####################################################################################
"Lob 12 0" "GDI Barracks" RNGD false false false NULL NULL -1 false
##### Dune 2000 Support ########################################################################################
"Lob 14 0" "Alman" DN2K false false false NULL NULL -1 false
##### Nox Support ##############################################################################################
"Lob 16 0" "Brin" NOXX false false false NULL NULL -1 false
"Lob 16 1" "Ix" NOXX false false false NULL NULL -1 false
##### Tiberian Sun Support #####################################################################################
"Lob 18 0" "GDI Barracks" WWOL false false false NULL NULL -1 false
"Lob 18 1" "NOD Barracks" WWOL false false false NULL NULL -1 false
"Lob 18 2" "GDI Comm. Center" WWOL false false false NULL NULL -1 false
"Lob 18 0" "GDI Barracks" TSUN false false false NULL NULL -1 false
"Lob 18 1" "NOD Barracks" TSUN false false false NULL NULL -1 false
"Lob 18 2" "GDI Comm. Center" TSUN false false false NULL NULL -1 false
##### Red Alert 1 Support ######################################################################################
"Lob 21 0" "Combat Alley" WWOL false false false NULL NULL -1 false
##### Red Alert 2 Support ######################################################################################
"Lob 33 0" "USA Command" CHAT false false false NULL NULL -1 false
"Lob 33 1" "Korean Bunker" CHAT false false false NULL NULL -1 false
"Lob 33 0" "USA Command" RAL2 false false false NULL NULL -1 false
"Lob 33 1" "Korean Bunker" RAL2 false false false NULL NULL -1 false
##### Nox Quest Support ########################################################################################
"Lob 37 0" "Brin" NOXQ false false false NULL NULL -1 false
##### Yuri's Revenge Support ###################################################################################
"Lob 41 0" "Unknown" CHAT false false false NULL NULL -1 false
"Lob 41 1" "Unknown" CHAT false false false NULL NULL -1 false
"Lob 41 0" "Unknown" YURI false false false NULL NULL -1 false
"Lob 41 1" "Unknown" YURI false false false NULL NULL -1 false
##### Emperor: Battle for Dune #################################################################################
"Emperor-1" "Unknown" EMPR false false false NULL NULL -1 false
# #
##############################################################################

View file

@ -10,6 +10,9 @@ track of the changes made - and possible implications to users/admins.
Changes:
--------
bnetd/handle_irc*, bnetd_handle_wol*, bnetd/irc.*:
- merged WOL specific patch (better WOL support, cleaner code seperation)
bnetd/ladder*:
- no longer supports output of xml ladder files (at least so far)

View file

@ -14,7 +14,7 @@ bnetd_SOURCES = account.cpp account_wrap.cpp adbanner.cpp alias_command.cpp anon
sql_mysql.cpp sql_odbc.cpp sql_pgsql.cpp sql_sqlite3.cpp storage.cpp \
storage_file.cpp storage_sql.cpp support.cpp team.cpp tick.cpp timer.cpp topic.cpp \
tournament.cpp tracker.cpp udptest_send.cpp versioncheck.cpp watch.cpp \
storage_sql2.cpp sql_common.cpp
storage_sql2.cpp sql_common.cpp handle_wol.cpp
bnetd_LDADD = $(top_builddir)/src/common/libcommon.a \
$(top_builddir)/src/compat/libcompat.a \
@ -33,4 +33,4 @@ noinst_HEADERS = account.h account_wrap.h adbanner.h alias_command.h \
sql_dbcreator.h sql_mysql.h sql_odbc.h sql_pgsql.h sql_sqlite3.h \
storage_file.h storage.h storage_sql.h support.h team.h tick.h \
timer.h topic.h tournament.h udptest_send.h versioncheck.h watch.h \
tracker.h storage_sql2.h sql_common.h
tracker.h storage_sql2.h sql_common.h handle_wol.h

View file

@ -114,8 +114,7 @@ static void conn_send_welcome(t_connection * c)
if (c->protocol.cflags & conn_flags_welcomed)
return;
if ((conn_get_class(c)==conn_class_irc)||
(conn_get_class(c)==conn_class_wol))
if ((conn_get_class(c)==conn_class_irc)||(conn_get_class(c)==conn_class_wol)||(conn_get_class(c)==conn_class_wserv))
{
c->protocol.cflags|= conn_flags_welcomed;
return;
@ -197,8 +196,7 @@ extern void conn_test_latency(t_connection * c, std::time_t now, t_timer_data de
return; // state_destroy: do nothing
if ((conn_get_class(c)==conn_class_irc)||
(conn_get_class(c)==conn_class_wol)) {
if ((conn_get_class(c)==conn_class_irc)||(conn_get_class(c)==conn_class_wol)||(conn_get_class(c)==conn_class_wserv)) {
/* We should start pinging the client after we received the first line ... */
/* NOTE: RFC2812 only suggests that PINGs are being sent
* if no other activity is detected. However it explecitly
@ -282,6 +280,8 @@ extern char const * conn_class_get_str(t_conn_class cclass)
return "irc";
case conn_class_wol:
return "wol";
case conn_class_wserv:
return "wserv";
case conn_class_none:
return "none";
case conn_class_w3route:
@ -1949,7 +1949,7 @@ extern int conn_set_channel(t_connection * c, char const * channelname)
}
if (channel_get_topic(channel_get_name(c->protocol.chat.channel)) && ((conn_get_class(c)!=conn_class_irc) ||
(conn_get_class(c)!=conn_class_wol)))
(conn_get_class(c)!=conn_class_wol) || (conn_get_class(c)!=conn_class_wserv)))
{
char msgtemp[MAX_MESSAGE_LEN];
@ -3467,7 +3467,7 @@ extern unsigned int connlist_login_get_length(void)
{
c = (const t_connection*)elem_get_data(curr);
if ((c->protocol.state==conn_state_loggedin)&&
((c->protocol.cclass==conn_class_bnet)||(c->protocol.cclass==conn_class_bot)||(c->protocol.cclass==conn_class_telnet)||(c->protocol.cclass==conn_class_irc)||(c->protocol.cclass==conn_class_wol)))
((c->protocol.cclass==conn_class_bnet)||(c->protocol.cclass==conn_class_bot)||(c->protocol.cclass==conn_class_telnet)||(c->protocol.cclass==conn_class_irc)||(c->protocol.cclass==conn_class_wol)||(c->protocol.cclass==conn_class_wserv)))
count++;
}

View file

@ -72,6 +72,7 @@ typedef enum
conn_class_telnet,
conn_class_irc, /* Internet Relay Chat */
conn_class_wol, /* Westwood Online */
conn_class_wserv, /* Westwood Server */
conn_class_d2cs_bnetd,
conn_class_w3route,
conn_class_none

View file

@ -1,6 +1,7 @@
/*
* Copyright (C) 2001 Marco Ziech (mmz@gmx.net)
* Copyright (C) 2005 Bryan Biedenkapp (gatekeep@gmail.com)
* Copyright (C) 2006 Pelish (pelish@gmail.com)
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@ -81,26 +82,6 @@ static int _handle_whois_command(t_connection * conn, int numparams, char ** par
static int _handle_part_command(t_connection * conn, int numparams, char ** params, char * text);
static int _handle_cvers_command(t_connection * conn, int numparams, char ** params, char * text);
static int _handle_verchk_command(t_connection * conn, int numparams, char ** params, char * text);
static int _handle_lobcount_command(t_connection * conn, int numparams, char ** params, char * text);
static int _handle_whereto_command(t_connection * conn, int numparams, char ** params, char * text);
static int _handle_apgar_command(t_connection * conn, int numparams, char ** params, char * text);
static int _handle_serial_command(t_connection * conn, int numparams, char ** params, char * text);
static int _handle_squadinfo_command(t_connection * conn, int numparams, char ** params, char * text);
static int _handle_setopt_command(t_connection * conn, int numparams, char ** params, char * text);
static int _handle_setcodepage_command(t_connection * conn, int numparams, char ** params, char * text);
static int _handle_setlocale_command(t_connection * conn, int numparams, char ** params, char * text);
static int _handle_getcodepage_command(t_connection * conn, int numparams, char ** params, char * text);
static int _handle_getlocale_command(t_connection * conn, int numparams, char ** params, char * text);
static int _handle_joingame_command(t_connection * conn, int numparams, char ** params, char * text);
static int _handle_gameopt_command(t_connection * conn, int numparams, char ** params, char * text);
static int _handle_finduserex_command(t_connection * conn, int numparams, char ** params, char * text);
static int _handle_page_command(t_connection * conn, int numparams, char ** params, char * text);
static int _handle_startg_command(t_connection * conn, int numparams, char ** params, char * text);
static int _handle_listsearch_command(t_connection * conn, int numparams, char ** params, char * text);
/* state "connected" handlers */
static const t_irc_command_table_row irc_con_command_table[] =
{
@ -113,13 +94,6 @@ static const t_irc_command_table_row irc_con_command_table[] =
{ "NOTICE" , _handle_notice_command },
{ "QUIT" , _handle_quit_command },
{ "CVERS" , _handle_cvers_command },
{ "VERCHK" , _handle_verchk_command },
{ "LOBCOUNT" , _handle_lobcount_command },
{ "WHERETO" , _handle_whereto_command },
{ "APGAR" , _handle_apgar_command },
{ "SERIAL" , _handle_serial_command },
{ NULL , NULL }
};
@ -137,19 +111,6 @@ static const t_irc_command_table_row irc_log_command_table[] =
{ "WHOIS" , _handle_whois_command },
{ "PART" , _handle_part_command },
{ "SQUADINFO" , _handle_squadinfo_command },
{ "SETOPT" , _handle_setopt_command },
{ "SETCODEPAGE" , _handle_setcodepage_command },
{ "SETLOCALE" , _handle_setlocale_command },
{ "GETCODEPAGE" , _handle_getcodepage_command },
{ "GETLOCALE" , _handle_getlocale_command },
{ "JOINGAME" , _handle_joingame_command },
{ "GAMEOPT" , _handle_gameopt_command },
{ "FINDUSEREX" , _handle_finduserex_command },
{ "PAGE" , _handle_page_command },
{ "STARTG" , _handle_startg_command },
{ "LISTSEARCH" , _handle_listsearch_command },
{ NULL , NULL }
};
@ -313,6 +274,81 @@ static int handle_irc_line(t_connection * conn, char const * ircline)
return 0;
}
static int handle_irc_welcome(t_connection * conn)
{
char temp[MAX_IRC_MESSAGE_LEN];
std::time_t temptime;
char const * tempname;
char const * temptimestr;
char const * filename;
std::FILE *fp;
char * line, * formatted_line;
char send_line[MAX_IRC_MESSAGE_LEN];
char motd_failed = 0;
if (!conn) {
eventlog(eventlog_level_error,__FUNCTION__,"got NULL connection");
return -1;
}
tempname = conn_get_loggeduser(conn);
if ((34+std::strlen(tempname)+1)<=MAX_IRC_MESSAGE_LEN)
std::sprintf(temp,":Welcome to the %s IRC Network %s",prefs_get_irc_network_name(), tempname);
else
std::sprintf(temp,":Maximum length exceeded");
irc_send(conn,RPL_WELCOME,temp);
if ((14+std::strlen(server_get_hostname())+10+std::strlen(PVPGN_SOFTWARE" "PVPGN_VERSION)+1)<=MAX_IRC_MESSAGE_LEN)
std::sprintf(temp,":Your host is %s, running "PVPGN_SOFTWARE" "PVPGN_VERSION,server_get_hostname());
else
std::sprintf(temp,":Maximum length exceeded");
irc_send(conn,RPL_YOURHOST,temp);
temptime = server_get_starttime(); /* FIXME: This should be build time */
temptimestr = std::ctime(&temptime);
if ((25+std::strlen(temptimestr)+1)<=MAX_IRC_MESSAGE_LEN)
std::sprintf(temp,":This server was created %s",temptimestr); /* FIXME: is ctime() portable? */
else
std::sprintf(temp,":Maximum length exceeded");
irc_send(conn,RPL_CREATED,temp);
/* we don't give mode information on MYINFO we give it on ISUPPORT */
if ((std::strlen(server_get_hostname())+7+std::strlen(PVPGN_SOFTWARE" "PVPGN_VERSION)+9+1)<=MAX_IRC_MESSAGE_LEN)
std::sprintf(temp,"%s "PVPGN_SOFTWARE" "PVPGN_VERSION" - -",server_get_hostname());
else
std::sprintf(temp,":Maximum length exceeded");
irc_send(conn,RPL_MYINFO,temp);
std::sprintf(temp,"NICKLEN=%d TOPICLEN=%d CHANNELLEN=%d PREFIX="CHANNEL_PREFIX" CHANTYPES="CHANNEL_TYPE" NETWORK=%s IRCD="PVPGN_SOFTWARE,
MAX_CHARNAME_LEN, MAX_TOPIC_LEN, MAX_CHANNELNAME_LEN, prefs_get_irc_network_name());
if((std::strlen(temp))<=MAX_IRC_MESSAGE_LEN)
irc_send(conn,RPL_ISUPPORT,temp);
else {
std::sprintf(temp,":Maximum length exceeded");
irc_send(conn,RPL_ISUPPORT,temp);
}
irc_send_motd(conn);
irc_send_cmd(conn,"NOTICE",":This is an experimental service.");
conn_set_state(conn,conn_state_bot_password);
if (connlist_find_connection_by_accountname(conn_get_loggeduser(conn))) {
irc_send_cmd(conn,"NOTICE","This account is already logged in, use another account.");
return -1;
}
if (conn_get_ircpass(conn)) {
irc_send_cmd(conn,"NOTICE",":Trying to authenticate with PASS ...");
irc_authenticate(conn,conn_get_ircpass(conn));
} else {
irc_send_cmd(conn,"NOTICE",":No PASS command received. Please identify yourself by /msg NICKSERV identify <password>.");
}
return 0;
}
extern int handle_irc_packet(t_connection * conn, t_packet const * const packet)
{
unsigned int i;
@ -323,8 +359,7 @@ extern int handle_irc_packet(t_connection * conn, t_packet const * const packet)
eventlog(eventlog_level_error,__FUNCTION__,"got NULL packet");
return -1;
}
if ((conn_get_class(conn) != conn_class_irc) &&
(conn_get_class(conn) != conn_class_wol)) {
if (conn_get_class(conn) != conn_class_irc) {
eventlog(eventlog_level_error,__FUNCTION__,"FIXME: handle_irc_packet without any reason (conn->class != conn_class_irc)");
return -1;
}
@ -386,7 +421,7 @@ static int _handle_nick_command(t_connection * conn, int numparams, char ** para
else
irc_send(conn,ERR_NEEDMOREPARAMS,":Too few arguments to NICK");
if ((conn_get_user(conn))&&(conn_get_loggeduser(conn)))
irc_welcome(conn); /* only send the welcome if we have USER and NICK */
handle_irc_welcome(conn); /* only send the welcome if we have USER and NICK */
}
return 0;
}
@ -408,53 +443,16 @@ static int _handle_user_command(t_connection * conn, int numparams, char ** para
user = params[0];
realname = text;
if (conn_get_wol(conn) == 1) {
user = (char *)conn_get_loggeduser(conn);
realname = (char *)conn_get_loggeduser(conn);
if (conn_get_user(conn)) {
irc_send(conn,ERR_ALREADYREGISTRED,":You are already registred");
}
else {
eventlog(eventlog_level_debug,__FUNCTION__,"[%d][** WOL **] got USER: user=\"%s\"",conn_get_socket(conn),user);
a = accountlist_find_account(user);
if (!a) {
if((conn_get_wol(conn) == 1)) {
t_account * tempacct;
t_hash pass_hash;
char * pass = "supersecret";
for (unsigned j=0; j<std::strlen(pass); j++)
if (std::isupper((int)pass[j])) pass[j] = std::tolower((int)pass[j]);
bnet_hash(&pass_hash,std::strlen(pass),pass);
tempacct = accountlist_create_account(user,hash_get_str(pass_hash));
if (!tempacct) {
return 0;
}
}
}
if (conn_get_user(conn)) {
irc_send(conn,ERR_ALREADYREGISTRED,":You are already registred");
}
else {
eventlog(eventlog_level_debug,__FUNCTION__,"[%d] got USER: user=\"%s\" realname=\"%s\"",conn_get_socket(conn),user,realname);
conn_set_user(conn,user);
conn_set_owner(conn,realname);
if (conn_get_loggeduser(conn))
irc_welcome(conn); /* only send the welcome if we have USER and NICK */
}
}
else {
if (conn_get_user(conn)) {
irc_send(conn,ERR_ALREADYREGISTRED,":You are already registred");
}
else {
eventlog(eventlog_level_debug,__FUNCTION__,"[%d] got USER: user=\"%s\" realname=\"%s\"",conn_get_socket(conn),user,realname);
conn_set_user(conn,user);
conn_set_owner(conn,realname);
if (conn_get_loggeduser(conn))
irc_welcome(conn); /* only send the welcome if we have USER and NICK */
}
}
handle_irc_welcome(conn); /* only send the welcome if we have USER and NICK */
}
}
else {
irc_send(conn,ERR_NEEDMOREPARAMS,":Too few arguments to USER");
@ -464,9 +462,6 @@ static int _handle_user_command(t_connection * conn, int numparams, char ** para
static int _handle_ping_command(t_connection * conn, int numparams, char ** params, char * text)
{
if((conn_get_wol(conn) == 1))
return 0;
/* Dizzy: just ignore this because RFC says we should not reply client PINGs
* NOTE: RFC2812 doesn't seem to be very expressive about this ... */
if (numparams)
@ -478,9 +473,6 @@ static int _handle_ping_command(t_connection * conn, int numparams, char ** para
static int _handle_pong_command(t_connection * conn, int numparams, char ** params, char * text)
{
if((conn_get_wol(conn) == 1))
return 0;
/* NOTE: RFC2812 doesn't seem to be very expressive about this ... */
if (conn_get_ircping(conn)==0) {
eventlog(eventlog_level_warn,__FUNCTION__,"[%d] PONG without PING",conn_get_socket(conn));
@ -725,87 +717,7 @@ static int _handle_list_command(t_connection * conn, int numparams, char ** para
{
char temp[MAX_IRC_MESSAGE_LEN];
irc_send(conn,RPL_LISTSTART,"Channel :Users Name"); /* backward compatibility */
if((conn_get_wol(conn) == 1)) {
t_elem const * curr;
if(std::strcmp(params[0], "0") == 0) {
/* HACK: Currently, this is the best way to set the game type... */
conn_wol_set_game_type(conn,std::atoi(params[1]));
eventlog(eventlog_level_debug,__FUNCTION__,"[** WOL **] LIST [Channel]");
LIST_TRAVERSE_CONST(channellist(),curr)
{
t_channel const * channel = (t_channel const *)elem_get_data(curr);
char const * tempname;
tempname = irc_convert_channel(channel);
if(std::strstr(tempname,"Lob") != NULL) {
eventlog(eventlog_level_debug,__FUNCTION__,"[** WOL **] LIST [Channel: \"Lob\"] (%s)",tempname);
if (std::strlen(tempname)+1+20+1+1<MAX_IRC_MESSAGE_LEN)
snprintf(temp, sizeof(temp), "%s %u 0 388",tempname,channel_get_length(channel));
else
eventlog(eventlog_level_warn,__FUNCTION__,"LISTREPLY length exceeded");
irc_send(conn,RPL_CHANNEL,temp);
}
}
}
/**
* 18 = Tiberian Sun game channels, 21 = Red alert 1 channels,
* 33 = Red alert 2 channels, 41 = Yuri's Revenge
*/
else if((std::strcmp(params[0], "18") == 0) ||
(std::strcmp(params[0], "21") == 0) ||
(std::strcmp(params[0], "33") == 0) ||
(std::strcmp(params[0], "41"))) {
eventlog(eventlog_level_debug,__FUNCTION__,"[** WOL **] LIST [Game]");
LIST_TRAVERSE_CONST(channellist(),curr)
{
t_channel const * channel = (const t_channel*)elem_get_data(curr);
t_connection * m;
char const * tempname;
char * topic = channel_get_topic(channel_get_name(channel));
tempname = irc_convert_channel(channel);
if(std::strstr(tempname,"_game") != NULL) {
m = channel_get_first(channel);
if(channel_wol_get_game_type(channel) == conn_wol_get_game_type(conn)) {
eventlog(eventlog_level_debug,__FUNCTION__,"[** WOL **] List [Channel: \"_game\"] (%s)",tempname);
if (topic) {
eventlog(eventlog_level_debug,__FUNCTION__,"[** WOL **] List [Channel: \"_game\"] %s %u 0 %u %u 0 %u 128::%s",tempname,
channel_get_length(channel),channel_wol_get_game_type(channel),channel_wol_get_game_tournament(channel),
channel_wol_get_game_ownerip(channel),topic);
/**
* The layout of the game list entry is something like this:
*
* #game_channel_name users unknown gameType gameIsTournment unknown longIP 128::topic
*/
if (std::strlen(tempname)+1+20+1+1+std::strlen(topic)<MAX_IRC_MESSAGE_LEN)
snprintf(temp, sizeof(temp), "%s %u 0 %u %u 0 %u 128::%s",tempname,
channel_get_length(channel),channel_wol_get_game_type(channel),channel_wol_get_game_tournament(channel),
channel_wol_get_game_ownerip(channel),topic);
else
eventlog(eventlog_level_warn,__FUNCTION__,"LISTREPLY length exceeded");
}
else {
if (std::strlen(tempname)+1+20+1+1<MAX_IRC_MESSAGE_LEN)
snprintf(temp, sizeof(temp), "%s %u 0 %u %u 0 %u 128::",tempname,channel_get_length(channel),channel_wol_get_game_type(channel),
channel_wol_get_game_tournament(channel),channel_wol_get_game_ownerip(channel));
else
eventlog(eventlog_level_warn,__FUNCTION__,"LISTREPLY length exceeded");
}
}
irc_send(conn,RPL_GAME_CHANNEL,temp);
}
}
}
irc_send(conn,RPL_LISTEND,":End of LIST command");
return 0;
}
irc_send(conn,RPL_LISTSTART,"Channel :Users Names"); /* backward compatibility */
if (numparams==0) {
t_elem const * curr;
@ -882,11 +794,6 @@ static int _handle_topic_command(t_connection * conn, int numparams, char ** par
{
char ** e = NULL;
if((conn_get_wol(conn) == 1)) {
t_channel * channel = conn_get_channel(conn);
channel_set_topic(channel_get_name(channel),text,NO_SAVE_TOPIC);
}
if (params!=NULL) e = irc_get_listelems(params[0]);
if ((e)&&(e[0])) {
@ -940,49 +847,35 @@ static int _handle_join_command(t_connection * conn, int numparams, char ** para
t_channel * channel;
channel = conn_get_channel(conn);
if ((conn_get_wol(conn) == 1)) {
channel_set_userflags(conn);
message_send_text(conn,message_type_join,conn,NULL); /* we have to send the JOIN acknowledgement */
ircname=irc_convert_channel(channel);
if (channel!=old_channel) {
char * topic;
channel_set_userflags(conn);
message_send_text(conn,message_type_join,conn,NULL); /* we have to send the JOIN acknowledgement */
ircname=irc_convert_channel(channel);
irc_send_rpl_namreply(conn,channel);
if ((topic = channel_get_topic(channel_get_name(channel)))) {
if ((std::strlen(ircname)+1+1+std::strlen(topic)+1)<MAX_IRC_MESSAGE_LEN) {
snprintf(temp, sizeof(temp), "%s :%s", ircname, topic);
irc_send(conn,RPL_TOPIC,temp);
}
if ((std::strlen(ircname)+1+std::strlen(":End of NAMES list")+1)<MAX_IRC_MESSAGE_LEN) {
snprintf(temp, sizeof(temp), "%s :End of NAMES list",ircname);
irc_send(conn,RPL_ENDOFNAMES,temp);
if ((std::strlen(ircname)+1+std::strlen("FIXME 0")+1)<MAX_IRC_MESSAGE_LEN) {
snprintf(temp, sizeof(temp), "%s FIXME 0",ircname);
irc_send(conn,RPL_TOPICWHOTIME,temp); /* FIXME: this in an undernet extension but other servers support it too */
}
}
else {
if (channel!=old_channel) {
char * topic;
channel_set_userflags(conn);
message_send_text(conn,message_type_join,conn,NULL); /* we have to send the JOIN acknowledgement */
ircname=irc_convert_channel(channel);
if ((topic = channel_get_topic(channel_get_name(channel)))) {
if ((std::strlen(ircname)+1+1+std::strlen(topic)+1)<MAX_IRC_MESSAGE_LEN) {
snprintf(temp, sizeof(temp), "%s :%s", ircname, topic);
irc_send(conn,RPL_TOPIC,temp);
}
if ((std::strlen(ircname)+1+std::strlen("FIXME 0")+1)<MAX_IRC_MESSAGE_LEN) {
snprintf(temp, sizeof(temp), "%s FIXME 0",ircname);
irc_send(conn,RPL_TOPICWHOTIME,temp); /* FIXME: this in an undernet extension but other servers support it too */
}
}
else
irc_send(conn,RPL_NOTOPIC,":No topic is set");
}
else
irc_send(conn,RPL_NOTOPIC,":No topic is set");
irc_send_rpl_namreply(conn,channel);
irc_send(conn,RPL_ENDOFNAMES,":End of NAMES list");
if (old_channel_name) {
if (old_channel_name) {
irc_send_cmd2(conn,conn_get_loggeduser(conn),"PART",old_channel_name,"only one channel at once");
}
}
}
}
}
}
if (old_channel_name) xfree((void *)old_channel_name);
}
if (e)
@ -1136,478 +1029,10 @@ static int _handle_whois_command(t_connection * conn, int numparams, char ** par
static int _handle_part_command(t_connection * conn, int numparams, char ** params, char * text)
{
if ((conn_get_wol(conn) == 1))
if ((conn_wol_get_ingame(conn) == 1))
conn_wol_set_ingame(conn,0);
message_send_text(conn,message_type_part,conn,NULL);
return 0;
}
/**
* Westwood Online Extensions
*/
static int _handle_cvers_command(t_connection * conn, int numparams, char ** params, char * text)
{
// Ignore command
return 0;
}
static int _handle_verchk_command(t_connection * conn, int numparams, char ** params, char * text)
{
// Ignore command
return 0;
}
static int _handle_lobcount_command(t_connection * conn, int numparams, char ** params, char * text)
{
// Ignore command but, return 1
irc_send(conn,RPL_LOBCOUNT,"1");
return 0;
}
static int _handle_whereto_command(t_connection * conn, int numparams, char ** params, char * text)
{
// Ignore command, but output proper server information...
char temp[MAX_IRC_MESSAGE_LEN];
// Casted to avoid warnings
const char * ircip = addr_num_to_ip_str(conn_get_real_local_addr(conn));
const char * ircname = prefs_get_servername();
const char * irctimezone = prefs_get_wol_timezone();
const char * irclong = prefs_get_wol_longitude();
const char * irclat = prefs_get_wol_latitude();
snprintf(temp, sizeof(temp), ":%s %d '0:%s' %s %s %s", ircip, BNETD_WOL_PORT, ircname, irctimezone, irclong, irclat);
irc_send(conn,RPL_IRCSERV,temp);
snprintf(temp, sizeof(temp), ":%s %d 'Live chat server' %s %s %s", ircip, BNETD_IRC_PORT, irctimezone, irclong, irclat);
irc_send(conn,RPL_IRCSERV,temp);
snprintf(temp, sizeof(temp), ":%s %d 'Gameres server' %s %s %s", ircip, BNETD_WOL_PORT, irctimezone, irclong, irclat);
irc_send(conn,RPL_GAMERESSERV,temp);
snprintf(temp, sizeof(temp), ":%s %d 'Ladder server' %s %s %s", ircip, BNETD_WOL_PORT, irctimezone, irclong, irclat);
irc_send(conn,RPL_LADDERSERV,temp);
irc_send(conn,RPL_ENDSERVLIST,"");
return 0;
}
static int _handle_apgar_command(t_connection * conn, int numparams, char ** params, char * text)
{
char * apgar = NULL;
if((numparams>=1)&&params[0]) {
apgar = params[0];
conn_wol_set_apgar(conn,apgar);
}
return 0;
}
static int _handle_serial_command(t_connection * conn, int numparams, char ** params, char * text)
{
// Ignore command
return 0;
}
static int _handle_squadinfo_command(t_connection * conn, int numparams, char ** params, char * text)
{
// FIXME: Not implemented
return 0;
}
static int _handle_setopt_command(t_connection * conn, int numparams, char ** params, char * text)
{
// Ignore this command
return 0;
}
static int _handle_setcodepage_command(t_connection * conn, int numparams, char ** params, char * text)
{
char * codepage = NULL;
if((numparams>=1)&&params[0]) {
codepage = params[0];
conn_wol_set_codepage(conn,std::atoi(codepage));
}
irc_send(conn,RPL_SET_CODEPAGE,codepage);
return 0;
}
static int _handle_setlocale_command(t_connection * conn, int numparams, char ** params, char * text)
{
char * locale = NULL;
if((numparams>=1)&&params[0]) {
locale = params[0];
conn_wol_set_locale(conn,std::atoi(locale));
}
irc_send(conn,RPL_SET_LOCALE,locale);
return 0;
}
static int _handle_getcodepage_command(t_connection * conn, int numparams, char ** params, char * text)
{
char temp[MAX_IRC_MESSAGE_LEN];
char _temp[MAX_IRC_MESSAGE_LEN];
std::memset(temp,0,sizeof(temp));
std::memset(_temp,0,sizeof(_temp));
if((numparams>=1)) {
int i;
for (i=0; i<numparams; i++) {
t_connection * user;
int codepage;
char const * name;
if((user = connlist_find_connection_by_accountname(params[i]))) {
codepage = conn_wol_get_codepage(user);
name = conn_get_chatname(user);
snprintf(_temp, sizeof(_temp), "%s`%u", name, codepage);
std::strcat(temp,_temp);
if(i < numparams-1)
std::strcat(temp,"`");
}
}
irc_send(conn,RPL_GET_CODEPAGE,temp);
}
return 0;
}
static int _handle_getlocale_command(t_connection * conn, int numparams, char ** params, char * text)
{
char temp[MAX_IRC_MESSAGE_LEN];
char _temp[MAX_IRC_MESSAGE_LEN];
std::memset(temp,0,sizeof(temp));
std::memset(_temp,0,sizeof(_temp));
if((numparams>=1)) {
int i;
for (i=0; i<numparams; i++) {
t_connection * user;
int locale;
char const * name;
if((user = connlist_find_connection_by_accountname(params[i]))) {
locale = conn_wol_get_locale(user);
name = conn_get_chatname(user);
snprintf(_temp, sizeof(_temp), "%s`%u", name, locale);
std::strcat(temp,_temp);
if(i < numparams-1)
std::strcat(temp,"`");
}
}
irc_send(conn,RPL_GET_LOCALE,temp);
}
return 0;
}
static int _handle_joingame_command(t_connection * conn, int numparams, char ** params, char * text)
{
char _temp[MAX_IRC_MESSAGE_LEN];
std::memset(_temp,0,sizeof(_temp));
/**
* Basically this has 2 modes, Join Game and Create Game output is pretty much
* the same...input and output of JOINGAME is listed below. By the way, there is a
* hack in here, for Red Alert 1, it use's JOINGAME for some reason to join a lobby channel.
*
* Here is the input expected:
* JOINGAME #user's_game unknown numberOfPlayers gameType unknown unknown gameIsTournament unknown password
*
* Heres the output expected:
* user!WWOL@hostname JOINGAME unknown numberOfPlayers gameType unknown clanID longIP gameIsTournament :#game_channel_name
*/
if((numparams==2)) {
char ** e;
eventlog(eventlog_level_debug,__FUNCTION__,"[** WOL **] JOINGAME: * Join * (%s, %s)",
params[0],params[1]);
e = irc_get_listelems(params[0]);
if ((e)&&(e[0])) {
char const * ircname = irc_convert_ircname(e[0]);
char * old_channel_name = NULL;
t_channel * old_channel = conn_get_channel(conn);
if (old_channel)
old_channel_name = xstrdup(irc_convert_channel(old_channel));
if ((!(ircname)) || (conn_set_channel(conn,ircname)<0)) {
irc_send(conn,ERR_NOSUCHCHANNEL,":JOINGAME failed");
}
else {
t_channel * channel;
char const * gameOptions;
int gameType;
conn_wol_set_ingame(conn,1);
channel = conn_get_channel(conn);
gameOptions = channel_wol_get_game_options(channel);
gameType = channel_wol_get_game_type(channel);
if (gameType == conn_wol_get_game_type(conn)) {
eventlog(eventlog_level_debug,__FUNCTION__,"[** WOL **] JOINGAME [Game Options] (%s) [Game Type] (%u) [Game Owner] (%s)",gameOptions,gameType,channel_wol_get_game_owner(channel));
if (channel!=old_channel) {
char temp[MAX_IRC_MESSAGE_LEN];
channel_set_userflags(conn);
message_send_text(conn,message_wol_joingame,conn,gameOptions); /* we have to send the JOINGAME acknowledgement */
ircname=irc_convert_channel(channel);
irc_send_rpl_namreply(conn,channel);
if ((std::strlen(ircname)+1+std::strlen(":End of NAMES list")+1)<MAX_IRC_MESSAGE_LEN) {
snprintf(temp, sizeof(temp), "%s :End of NAMES list",ircname);
irc_send(conn,RPL_ENDOFNAMES,temp);
}
}
}
else {
irc_send(conn,ERR_NOSUCHCHANNEL,":JOINGAME failed");
}
}
if (old_channel_name) xfree((void *)old_channel_name);
}
if (e)
irc_unget_listelems(e);
return 0;
}
/**
* HACK: Check for 3 params, because in that case we must be running RA1
* then just forward to _handle_join_command
*/
else if((numparams==3)) {
_handle_join_command(conn,numparams,params,text);
}
else if((numparams>=8)) {
char ** e;
eventlog(eventlog_level_debug,__FUNCTION__,"[** WOL **] JOINGAME: * Create * (%s, %s)",
params[0],params[1]);
snprintf(_temp, sizeof(_temp), "%s %s %s %s 0 %u %s :%s",params[1],params[2],params[3],params[4],conn_get_addr(conn),params[6],params[0]);
eventlog(eventlog_level_debug,__FUNCTION__,"[** WOL **] JOINGAME [Game Options] (%s)",_temp);
e = irc_get_listelems(params[0]);
if ((e)&&(e[0])) {
char const * ircname = irc_convert_ircname(e[0]);
char * old_channel_name = NULL;
t_channel * old_channel = conn_get_channel(conn);
if (old_channel)
old_channel_name = xstrdup(irc_convert_channel(old_channel));
if ((!(ircname)) || (conn_set_channel(conn,ircname)<0)) {
irc_send(conn,ERR_NOSUCHCHANNEL,":JOINGAME failed"); /* FIXME: be more precise; what is the real error code for that? */
}
else {
t_channel * channel;
channel = conn_get_channel(conn);
if (channel!=old_channel) {
char temp[MAX_IRC_MESSAGE_LEN];
char * topic;
channel_set_userflags(conn);
channel_wol_set_game_options(channel,_temp);
channel_wol_set_game_owner(channel,conn_get_chatname(conn));
channel_wol_set_game_ownerip(channel,conn_get_addr(conn));
channel_wol_set_game_type(channel,conn_wol_get_game_type(conn));
channel_wol_set_game_tournament(channel,std::atoi(params[6]));
message_send_text(conn,message_wol_joingame,conn,_temp); /* we have to send the JOINGAME acknowledgement */
ircname=irc_convert_channel(channel);
if ((topic = channel_get_topic(channel_get_name(channel)))) {
if ((std::strlen(ircname)+1+1+std::strlen(topic)+1)<MAX_IRC_MESSAGE_LEN) {
snprintf(temp, sizeof(temp), "%s :%s", ircname, topic);
irc_send(conn,RPL_TOPIC,temp);
}
}
irc_send_rpl_namreply(conn,channel);
if ((std::strlen(ircname)+1+std::strlen(":End of NAMES list")+1)<MAX_IRC_MESSAGE_LEN) {
snprintf(temp, sizeof(temp), "%s :End of NAMES list", ircname);
irc_send(conn,RPL_ENDOFNAMES,temp);
}
}
}
if (old_channel_name) xfree((void *)old_channel_name);
}
if (e)
irc_unget_listelems(e);
}
else
irc_send(conn,ERR_NEEDMOREPARAMS,":Too few arguments to JOINGAME");
return 0;
}
static int _handle_gameopt_command(t_connection * conn, int numparams, char ** params, char * text)
{
char temp[MAX_IRC_MESSAGE_LEN];
/**
* Basically this has 2 modes, Game Owner Change and Game Joinee Change what the output
* on this does is pretty much unknown, we just dump this to the client to deal with...
*
* Heres the output expected (from game owner):
* user!WWOL@hostname GAMEOPT #game_channel_name :gameOptions
*
* Heres the output expected (from game joinee):
* user!WWOL@hostname GAMEOPT game_owner_name :gameOptions
*/
if ((numparams>=1)&&(text)) {
int i;
char ** e;
e = irc_get_listelems(params[0]);
/* FIXME: support wildcards! */
eventlog(eventlog_level_debug,__FUNCTION__,"[** WOL **] GAMEOPT: (%s :%s)",params[0],text);
conn_wol_set_game_options(conn,text);
for (i=0;((e)&&(e[i]));i++) {
if (e[i][0]=='#') {
/* game owner change */
t_channel * channel;
if ((channel = channellist_find_channel_by_name(irc_convert_ircname(params[0]),NULL,NULL))) {
snprintf(temp, sizeof(temp), ":%s", text);
channel_message_send(channel,message_wol_gameopt_owner,conn,temp);
}
else {
irc_send(conn,ERR_NOSUCHCHANNEL,":No such channel");
}
}
else
{
/* user change */
t_connection * user;
if ((user = connlist_find_connection_by_accountname(e[i]))) {
snprintf(temp, sizeof(temp), ":%s", text);
message_send_text(user,message_wol_gameopt_join,conn,temp);
}
else {
irc_send(conn,ERR_NOSUCHNICK,":No such user");
}
}
}
}
else
irc_send(conn,ERR_NEEDMOREPARAMS,":Too few arguments to GAMEOPT");
return 0;
}
static int _handle_finduserex_command(t_connection * conn, int numparams, char ** params, char * text)
{
char _temp[MAX_IRC_MESSAGE_LEN];
char const * ircname = NULL;
std::memset(_temp,0,sizeof(_temp));
if ((numparams>=1)) {
t_connection * user;
if((user = connlist_find_connection_by_accountname(params[0]))) {
ircname = irc_convert_channel(conn_get_channel(user));
}
snprintf(_temp, sizeof(_temp), "0 :%s,0", ircname);
irc_send(conn,RPL_FIND_USER_EX,_temp);
}
return 0;
}
static int _handle_page_command(t_connection * conn, int numparams, char ** params, char * text)
{
char _temp[MAX_IRC_MESSAGE_LEN];
std::memset(_temp,0,sizeof(_temp));
if ((numparams>=1)&&(text)) {
t_connection * user;
snprintf(_temp, sizeof(_temp), ":%s", text);
if((user = connlist_find_connection_by_accountname(params[0]))) {
message_send_text(user,message_wol_page,conn,_temp);
}
}
return 0;
}
static int _handle_startg_command(t_connection * conn, int numparams, char ** params, char * text)
{
char temp[MAX_IRC_MESSAGE_LEN];
char _temp_a[MAX_IRC_MESSAGE_LEN];
t_channel * channel;
std::time_t now;
/**
* Heres the output expected (this can have up-to 8 entries (ie 8 players):
* (we are assuming for this example that user1 is the game owner)
*
* user1!WWOL@hostname STARTG u :user1 xxx.xxx.xxx.xxx user2 xxx.xxx.xxx.xxx :gameNumber cTime
*/
if((numparams>=1)) {
int i;
char ** e;
std::memset(temp,0,sizeof(temp));
std::memset(_temp_a,0,sizeof(_temp_a));
e = irc_get_listelems(params[1]);
/* FIXME: support wildcards! */
std::strcat(temp,":");
for (i=0;((e)&&(e[i]));i++) {
t_connection * user;
const char * addr = NULL;
if((user = connlist_find_connection_by_accountname(e[i]))) {
addr = addr_num_to_ip_str(conn_get_addr(user));
}
snprintf(_temp_a, sizeof(_temp_a), "%s %s ", e[i], addr);
std::strcat(temp,_temp_a);
}
std::strcat(temp,":");
std::strcat(temp,"1337"); /* yes, ha ha funny, i just don't generate game numbers yet */
std::strcat(temp," ");
now = std::time(NULL);
std::strcat(temp,std::ctime(&now));
eventlog(eventlog_level_debug,__FUNCTION__,"[** WOL **] STARTG: (%s)",temp);
if ((channel = channellist_find_channel_by_name(irc_convert_ircname(params[0]),NULL,NULL))) {
channel_message_send(channel,message_wol_start_game,conn,temp);
}
else {
irc_send(conn,ERR_NOSUCHCHANNEL,":No such channel");
}
}
return 0;
}
static int _handle_listsearch_command(t_connection * conn, int numparams, char ** params, char * text)
{
// FIXME: Not implemented
return 0;
}
}
}

View file

@ -1,6 +1,7 @@
/*
* Copyright (C) 2001 Marco Ziech (mmz@gmx.net)
* Copyright (C) 2005 Bryan Biedenkapp (gatekeep@gmail.com)
* Copyright (C) 2006 Pelish (pelish@gmail.com)
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@ -194,14 +195,16 @@ extern int irc_send_ping(t_connection * conn)
eventlog(eventlog_level_error,__FUNCTION__,"got NULL connection");
return -1;
}
if ((conn_get_clienttag(conn) != CLIENTTAG_WCHAT_UINT) &&
(conn_get_clienttag(conn) != CLIENTTAG_IIRC_UINT))
return 0;
if (!(p = packet_create(packet_class_raw))) {
eventlog(eventlog_level_error,__FUNCTION__,"could not create packet");
return -1;
}
if((conn_get_wol(conn) == 1))
return 0;
conn_set_ircping(conn,get_ticks());
if (conn_get_state(conn)==conn_state_bot_username)
std::sprintf(data,"PING :%u\r\n",conn_get_ircping(conn)); /* Undernet doesn't reveal the servername yet ... neither do we */
@ -249,6 +252,7 @@ extern int irc_send_pong(t_connection * conn, char const * params)
extern int irc_authenticate(t_connection * conn, char const * passhash)
{
char temp[MAX_IRC_MESSAGE_LEN];
t_hash h1;
t_hash h2;
t_account * a;
@ -295,18 +299,20 @@ extern int irc_authenticate(t_connection * conn, char const * passhash)
}
if(tempapgar == NULL) {
irc_send_cmd(conn,"NOTICE",":Authentication failed."); /* bad APGAR */
std::sprintf(temp,":Closing Link %s[Some.host]:(Password needed for that nickname.)",conn_get_loggeduser(conn));
irc_send_cmd(conn,"ERROR",temp); /* bad APGAR */
conn_increment_passfail_count(conn);
return 0;
}
if(std::strcmp(temphash,tempapgar) == 0) {
conn_login(conn,a,username);
conn_set_state(conn,conn_state_loggedin);
conn_set_clienttag(conn,CLIENTTAG_WWOL_UINT); /* WWOL hope here is ok */
return 1;
}
else {
std::sprintf(temp,":Closing Link %s[Some.host]:(Password needed for that nickname.)",conn_get_loggeduser(conn));
irc_send_cmd(conn,"ERROR",temp); /* bad APGAR */
conn_increment_passfail_count(conn);
return 0;
}
@ -329,116 +335,6 @@ extern int irc_authenticate(t_connection * conn, char const * passhash)
return 0;
}
extern int irc_welcome(t_connection * conn)
{
char temp[MAX_IRC_MESSAGE_LEN];
std::time_t temptime;
char const * tempname;
char const * temptimestr;
char const * filename;
std::FILE *fp;
char * line, * formatted_line;
char send_line[MAX_IRC_MESSAGE_LEN];
char motd_failed = 0;
if (!conn) {
eventlog(eventlog_level_error,__FUNCTION__,"got NULL connection");
return -1;
}
tempname = conn_get_loggeduser(conn);
if ((34+std::strlen(tempname)+1)<=MAX_IRC_MESSAGE_LEN)
std::sprintf(temp,":Welcome to the %s IRC Network %s",prefs_get_irc_network_name(), tempname);
else
std::sprintf(temp,":Maximum length exceeded");
irc_send(conn,RPL_WELCOME,temp);
if ((14+std::strlen(server_get_hostname())+10+std::strlen(PVPGN_SOFTWARE" "PVPGN_VERSION)+1)<=MAX_IRC_MESSAGE_LEN)
std::sprintf(temp,":Your host is %s, running "PVPGN_SOFTWARE" "PVPGN_VERSION,server_get_hostname());
else
std::sprintf(temp,":Maximum length exceeded");
irc_send(conn,RPL_YOURHOST,temp);
temptime = server_get_starttime(); /* FIXME: This should be build time */
temptimestr = std::ctime(&temptime);
if ((25+std::strlen(temptimestr)+1)<=MAX_IRC_MESSAGE_LEN)
std::sprintf(temp,":This server was created %s",temptimestr); /* FIXME: is ctime() portable? */
else
std::sprintf(temp,":Maximum length exceeded");
irc_send(conn,RPL_CREATED,temp);
/* we don't give mode information on MYINFO we give it on ISUPPORT */
if ((std::strlen(server_get_hostname())+7+std::strlen(PVPGN_SOFTWARE" "PVPGN_VERSION)+9+1)<=MAX_IRC_MESSAGE_LEN)
std::sprintf(temp,"%s "PVPGN_SOFTWARE" "PVPGN_VERSION" - -",server_get_hostname());
else
std::sprintf(temp,":Maximum length exceeded");
irc_send(conn,RPL_MYINFO,temp);
if((conn_get_wol(conn) == 1))
std::sprintf(temp,"NICKLEN=%d TOPICLEN=%d CHANNELLEN=%d PREFIX="CHANNEL_PREFIX" CHANTYPES="CHANNEL_TYPE" NETWORK=%s IRCD="PVPGN_SOFTWARE,
WOL_NICKNAME_LEN, MAX_TOPIC_LEN, MAX_CHANNELNAME_LEN, prefs_get_irc_network_name());
else
std::sprintf(temp,"NICKLEN=%d TOPICLEN=%d CHANNELLEN=%d PREFIX="CHANNEL_PREFIX" CHANTYPES="CHANNEL_TYPE" NETWORK=%s IRCD="PVPGN_SOFTWARE,
MAX_CHARNAME_LEN, MAX_TOPIC_LEN, MAX_CHANNELNAME_LEN, prefs_get_irc_network_name());
if((std::strlen(temp))<=MAX_IRC_MESSAGE_LEN)
irc_send(conn,RPL_ISUPPORT,temp);
else {
std::sprintf(temp,":Maximum length exceeded");
irc_send(conn,RPL_ISUPPORT,temp);
}
if ((3+std::strlen(server_get_hostname())+22+1)<=MAX_IRC_MESSAGE_LEN)
std::sprintf(temp,":- %s, "PVPGN_SOFTWARE" "PVPGN_VERSION", built on %s",server_get_hostname(),temptimestr);
else
std::sprintf(temp,":Maximum length exceeded");
irc_send(conn,RPL_MOTDSTART,temp);
if ((filename = prefs_get_motdfile())) {
if ((fp = std::fopen(filename,"r"))) {
while ((line=file_get_line(fp))) {
if ((formatted_line = message_format_line(conn,line))) {
formatted_line[0]=' ';
std::sprintf(send_line,":-%s",formatted_line);
irc_send(conn,RPL_MOTD,send_line);
xfree(formatted_line);
}
}
file_get_line(NULL); // clear file_get_line buffer
std::fclose(fp);
}
else
motd_failed = 1;
}
else
motd_failed = 1;
if (motd_failed) {
irc_send(conn,RPL_MOTD,":- Failed to load motd, sending default motd ");
irc_send(conn,RPL_MOTD,":- ====================================================== ");
irc_send(conn,RPL_MOTD,":- http://www.pvpgn.org ");
irc_send(conn,RPL_MOTD,":- ====================================================== ");
}
irc_send(conn,RPL_ENDOFMOTD,":End of /MOTD command");
irc_send_cmd(conn,"NOTICE",":This is an experimental service.");
conn_set_state(conn,conn_state_bot_password);
if (connlist_find_connection_by_accountname(conn_get_loggeduser(conn))) {
irc_send_cmd(conn,"NOTICE","This account is already logged in, use another account.");
return -1;
}
if (conn_get_ircpass(conn)) {
irc_send_cmd(conn,"NOTICE",":Trying to authenticate with PASS ...");
irc_authenticate(conn,conn_get_ircpass(conn));
} else {
irc_send_cmd(conn,"NOTICE",":No PASS command received. Please identify yourself by /msg NICKSERV identify <password>.");
}
return 0;
}
/* Channel name conversion rules: */
/* Not allowed in IRC (RFC2812): NUL, BELL, CR, LF, ' ', ':' and ','*/
/* ' ' -> '_' */
@ -793,18 +689,30 @@ extern int irc_message_format(t_packet * packet, t_message_type type, t_connecti
from.user = ctag;
from.host = addr_num_to_ip_str(conn_get_addr(me));
if((conn_get_wol(me) == 1))
if((conn_get_wol(me) == 1) && (conn_get_clienttag(me) != CLIENTTAG_WCHAT_UINT))
{
char temp[MAX_IRC_MESSAGE_LEN];
std::memset(temp,0,sizeof(temp));
/**
* For WOL the channel JOIN output must be like the following:
* user!WWOL@hostname JOIN :clanID,longIP channelName
* For WOLv2 the channel JOIN output must be like the following:
* user!WWOL@hostname JOIN :clanID,longIP channelName
*/
std::sprintf(temp,":0,%u",conn_get_addr(me));
msg = irc_message_preformat(&from,"JOIN",temp,irc_convert_channel(conn_get_channel(me)));
conn_unget_chatname(me,from.nick);
break;
}
else if (conn_get_clienttag(me) == CLIENTTAG_WCHAT_UINT) {
char temp[MAX_IRC_MESSAGE_LEN];
std::memset(temp,0,sizeof(temp));
if (conn_wol_get_ingame(me) == 1)
msg = irc_message_preformat(&from,"JOINGAME",":",irc_convert_channel(conn_get_channel(me)));
else
msg = irc_message_preformat(&from,"JOIN","\r",irc_convert_channel(conn_get_channel(me)));
conn_unget_chatname(me,from.nick);
break;
}
else
msg = irc_message_preformat(&from,"JOIN","\r",irc_convert_channel(conn_get_channel(me)));
conn_unget_chatname(me,from.nick);
@ -890,8 +798,8 @@ extern int irc_message_format(t_packet * packet, t_message_type type, t_connecti
case message_wol_joingame:
from.nick = conn_get_chatname(me);
from.user = ctag;
from.host = addr_num_to_ip_str(conn_get_addr(me));
msg = irc_message_preformat(&from,"JOINGAME",text,"\r");
from.host = addr_num_to_ip_str(conn_get_addr(me));
msg = irc_message_preformat(&from,"JOINGAME","\r",text);
conn_unget_chatname(me,from.nick);
break;
case message_wol_gameopt_owner:
@ -919,9 +827,16 @@ extern int irc_message_format(t_packet * packet, t_message_type type, t_connecti
from.nick = conn_get_chatname(me);
from.user = ctag;
from.host = addr_num_to_ip_str(conn_get_addr(me));
msg = irc_message_preformat(&from,"PAGE","u",text);
msg = irc_message_preformat(&from,"PAGE","",text);
conn_unget_chatname(me,from.nick);
break;
case message_wol_advertr:
from.nick = conn_get_chatname(me);
from.user = ctag;
from.host = addr_num_to_ip_str(conn_get_addr(me));
msg = irc_message_preformat(&from,"ADVERTR","\r",text);
conn_unget_chatname(me,from.nick);
break;
default:
eventlog(eventlog_level_warn,__FUNCTION__,"%d not yet implemented",type);
return -1;
@ -981,16 +896,16 @@ extern int irc_send_rpl_namreply(t_connection * c, t_channel const * channel)
if ((std::strlen(temp)+((!first)?(1):(0))+std::strlen(flg)+std::strlen(name)+1)<=sizeof(temp)) {
if (!first) std::strcat(temp," ");
if((conn_get_wol(c) == 1))
{
if((conn_wol_get_ingame(c) == 0))
{
if ((flags & MF_BLIZZARD))
std::strcat(temp,"@");
if ((flags & MF_BNET) || (flags & MF_GAVEL))
std::strcat(temp,"@");
}
std::sprintf(temp,"%s%s,0,%u",temp,name,conn_get_addr(m));
if((conn_get_wol(c) == 1)) {
if ((channel_wol_get_game_owner(channel) != NULL) && (std::strcmp(channel_wol_get_game_owner(channel),name) == 0)) {
std::strcat(temp,"@");
}
if (conn_get_clienttag(c) != CLIENTTAG_WCHAT_UINT) {
std::sprintf(temp,"%s%s,0,%u",temp,name,conn_get_addr(m));
}
else {
std::sprintf(temp,"%s%s",temp,name);
}
}
else
{
@ -1104,6 +1019,54 @@ extern int irc_who(t_connection * c, char const * name)
return 0;
}
extern int irc_send_motd(t_connection * conn)
{
char const * tempname;
char const * filename;
std::FILE *fp;
char * line, * formatted_line;
char send_line[MAX_IRC_MESSAGE_LEN];
char motd_failed = 0;
if (!conn) {
eventlog(eventlog_level_error,__FUNCTION__,"got NULL connection");
return -1;
}
tempname = conn_get_loggeduser(conn);
irc_send(conn,RPL_MOTDSTART,":-");
if ((filename = prefs_get_motdfile())) {
if ((fp = std::fopen(filename,"r"))) {
while ((line=file_get_line(fp))) {
if ((formatted_line = message_format_line(conn,line))) {
formatted_line[0]=' ';
std::sprintf(send_line,":-%s",formatted_line);
irc_send(conn,RPL_MOTD,send_line);
xfree(formatted_line);
}
}
file_get_line(NULL); // clear file_get_line buffer
std::fclose(fp);
}
else
motd_failed = 1;
}
else
motd_failed = 1;
if (motd_failed) {
irc_send(conn,RPL_MOTD,":- Failed to load motd, sending default motd ");
irc_send(conn,RPL_MOTD,":- ====================================================== ");
irc_send(conn,RPL_MOTD,":- http://www.pvpgn.org ");
irc_send(conn,RPL_MOTD,":- ====================================================== ");
}
irc_send(conn,RPL_ENDOFMOTD,":End of /MOTD command");
return 0;
}
}
}

View file

@ -39,7 +39,6 @@ extern int irc_send(t_connection * conn, int code, char const * params);
extern int irc_send_ping(t_connection * conn);
extern int irc_send_pong(t_connection * conn, char const * params);
extern int irc_authenticate(t_connection * conn, char const * passhash);
extern int irc_welcome(t_connection * conn);
extern char const * irc_convert_channel(t_channel const * channel);
extern char const * irc_convert_ircname(char const * pircname);
extern char ** irc_get_listelems(char * list);
@ -50,6 +49,7 @@ extern int irc_message_postformat(t_packet * packet, t_connection const * dest);
extern int irc_message_format(t_packet * packet, t_message_type type, t_connection * me, t_connection * dst, char const * text, unsigned int dstflags);
extern int irc_send_rpl_namreply(t_connection * c, t_channel const * channel);
extern int irc_who(t_connection * c, char const * name);
extern int irc_send_motd(t_connection * conn);
}

View file

@ -1392,6 +1392,7 @@ static t_packet * message_cache_lookup(t_message * message, t_connection *dst, u
break;
case conn_class_irc:
case conn_class_wol:
case conn_class_wserv:
if (!(packet = packet_create(packet_class_raw)))
{
eventlog(eventlog_level_error,__FUNCTION__,"could not create packet");
@ -1460,7 +1461,7 @@ extern int message_send(t_message * message, t_connection * dst)
return -1;
/* FIXME: this is not needed now, message has dst */
if ((conn_get_class(dst)==conn_class_irc)||(conn_get_class(dst)==conn_class_wol)) {
if ((conn_get_class(dst)==conn_class_irc)||(conn_get_class(dst)==conn_class_wol)||(conn_get_class(dst)==conn_class_wserv)) {
/* HACK: IRC message always need the recipient and are therefore bad to cache. */
/* So we only cache a pseudo packet and convert it to a real packet later ... */
packet = packet_duplicate(packet); /* we want to modify packet so we have to create a copy ... */
@ -1472,7 +1473,7 @@ extern int message_send(t_message * message, t_connection * dst)
conn_push_outqueue(dst,packet);
if ((conn_get_class(dst)==conn_class_irc)||(conn_get_class(dst)==conn_class_wol))
if ((conn_get_class(dst)==conn_class_irc)||(conn_get_class(dst)==conn_class_wol)||(conn_get_class(dst)==conn_class_wserv))
packet_del_ref(packet); /* we don't need the previously created copy anymore ... */
return 0;

View file

@ -67,6 +67,7 @@ typedef enum
message_wol_gameopt_join,
message_wol_start_game,
message_wol_page,
message_wol_advertr,
message_type_null
} t_message_type;

View file

@ -160,6 +160,7 @@ static struct {
char const * irc_network_name;
char const * woladdrs;
char const * wservaddrs;
char const * woltimezone;
char const * wollongitude;
char const * wollatitude;
@ -634,6 +635,10 @@ static int conf_set_irc_network_name(const char *valstr);
static const char *conf_get_irc_network_name(void);
static int conf_setdef_wserv_addrs(void);
static int conf_set_wserv_addrs(const char *valstr);
static const char *conf_get_wserv_addrs(void);
static int conf_setdef_wol_addrs(void);
static int conf_set_wol_addrs(const char *valstr);
static const char *conf_get_wol_addrs(void);
@ -771,6 +776,7 @@ static t_conf_entry conf_table[] =
{ "ladder_prefix", conf_set_ladder_prefix, conf_get_ladder_prefix,conf_setdef_ladder_prefix},
{ "irc_network_name", conf_set_irc_network_name, conf_get_irc_network_name, conf_setdef_irc_network_name},
{ "wservaddrs", conf_set_wserv_addrs, conf_get_wserv_addrs, conf_setdef_wserv_addrs},
{ "woladdrs", conf_set_wol_addrs, conf_get_wol_addrs, conf_setdef_wol_addrs},
{ "woltimezone", conf_set_wol_timezone, conf_get_wol_timezone, conf_setdef_wol_timezone},
{ "wollongitude", conf_set_wol_longitude, conf_get_wol_longitude, conf_setdef_wol_longitude},
@ -3315,6 +3321,26 @@ static const char* conf_get_irc_network_name(void)
/**
* Westwood Online Extensions
*/
extern char const * prefs_get_wserv_addrs(void)
{
return prefs_runtime_config.wservaddrs;
}
static int conf_set_wserv_addrs(const char *valstr)
{
return conf_set_str(&prefs_runtime_config.wservaddrs,valstr,NULL);
}
static int conf_setdef_wserv_addrs(void)
{
return conf_set_str(&prefs_runtime_config.wservaddrs,NULL,BNETD_WOL_ADDRS);
}
static const char* conf_get_wserv_addrs(void)
{
return prefs_runtime_config.wservaddrs;
}
extern char const * prefs_get_wol_addrs(void)
{
return prefs_runtime_config.woladdrs;

View file

@ -181,6 +181,7 @@ extern char const * prefs_get_irc_network_name(void);
/**
* Westwood Online Extensions
*/
extern char const * prefs_get_wserv_addrs(void);
extern char const * prefs_get_wol_addrs(void);
extern char const * prefs_get_wol_timezone(void);
extern char const * prefs_get_wol_longitude(void);

View file

@ -60,6 +60,7 @@
#include "handle_init.h"
#include "handle_d2cs.h"
#include "handle_irc.h"
#include "handle_wol.h"
#include "handle_udp.h"
#include "anongame.h"
#include "clan.h"
@ -201,6 +202,8 @@ static char const * laddr_type_get_str(t_laddr_type laddr_type)
return "irc";
case laddr_type_wol:
return "wol";
case laddr_type_wserv:
return "wserv";
case laddr_type_telnet:
return "telnet";
default:
@ -351,6 +354,10 @@ static int sd_accept(t_addr const * curr_laddr, t_laddr_info const * laddr_info,
conn_set_class(c,conn_class_wol);
conn_set_state(c,conn_state_connected);
break;
case laddr_type_wserv:
conn_set_class(c,conn_class_wserv);
conn_set_state(c,conn_state_connected);
break;
case laddr_type_w3route:
conn_set_class(c,conn_class_w3route);
conn_set_state(c,conn_state_connected);
@ -522,6 +529,7 @@ static int sd_tcpinput(t_connection * c)
case conn_class_bot:
case conn_class_irc:
case conn_class_wol:
case conn_class_wserv:
case conn_class_telnet:
if (!(packet = packet_create(packet_class_raw)))
{
@ -636,9 +644,12 @@ static int sd_tcpinput(t_connection * c)
ret = handle_file_packet(c,packet);
break;
case conn_class_irc:
case conn_class_wol:
ret = handle_irc_packet(c,packet);
break;
case conn_class_wserv:
case conn_class_wol:
ret = handle_wol_packet(c,packet);
break;
case conn_class_w3route:
ret = handle_w3route_packet(c,packet);
break;
@ -1452,6 +1463,14 @@ extern int server_process(void)
_shutdown_addrs(laddrs);
return -1;
}
/* Append list of addresses to listen for WSERV IRC connections */
if (_setup_add_addrs(&laddrs, prefs_get_wserv_addrs(),INADDR_ANY,BNETD_WSERV_PORT, laddr_type_wserv))
{
eventlog(eventlog_level_error,__FUNCTION__,"could not create %s server address list from \"%s\"",laddr_type_get_str(laddr_type_wserv),prefs_get_wserv_addrs());
_shutdown_addrs(laddrs);
return -1;
}
/* Append list of addresses to listen for W3ROUTE connections */
if (_setup_add_addrs(&laddrs,prefs_get_w3route_addr(),INADDR_ANY,BNETD_W3ROUTE_PORT, laddr_type_w3route))

View file

@ -34,7 +34,8 @@ typedef enum
laddr_type_bnet, /* classic battle.net service (usually on port 6112) */
laddr_type_w3route, /* warcraft 3 playgame routing (def. port 6200) */
laddr_type_irc, /* Internet Relay Chat service (port is varying; mostly on port 6667 or 7000) */
laddr_type_wol, /* Westwood Online (IRC) Chat Services (port is 4005) */
laddr_type_wol, /* Westwood Online (IRC) Chat Services (port is 4000) */
laddr_type_wserv, /* Westwood Server (IRC) Services (port is 4005) */
laddr_type_telnet /* telnet service (usually on port 23) */
} t_laddr_type;

View file

@ -1,6 +1,7 @@
/*
* Copyright (C) 2001 Marco Ziech (mmz@gmx.net)
* Copyright (C) 2005 Bryan Biedenkapp (gatekeep@gmail.com)
* Copyright (C) 2006 Ondrej Pelikan (pelish@gmail.com)
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@ -326,28 +327,41 @@
/**
* Westwood Online Extensions
*/
#define RPL_GET_LOCALE 309
#define RPL_SET_LOCALE 310
#define RPL_GAME_CHANNEL 326
#define RPL_CHANNEL 327
#define RPL_GET_CODEPAGE 328
#define RPL_SET_CODEPAGE 329
#define RPL_GET_LOCALE 309
#define RPL_SET_LOCALE 310
#define RPL_GET_BUDDY 333
#define RPL_BATTLECLAN 358
#define RPL_VERCHK_NONREQ 379 /* for WCHAT */
#define RPL_FIND_USER_EX 398
#define RPL_UPDATE_RECORD 602
#define RPL_GET_INSIDER 399
#define RPL_IRCSERV 605
#define RPL_UPDATE_NONEX 602 /* for WOL */
#define RPL_WOLSERV 605
#define RPL_UPDATE_EXIST 606 /* for WOL */
#define RPL_ENDSERVLIST 607
#define RPL_GAMERESSERV 608
#define RPL_LADDERSERV 609
#define RPL_LOBCOUNT 610
#define RPL_MANGLERSERV 612
#define RPL_PINGSERVER 615
#define RPL_IDNOEXIST 439
/** error's */
/*
* Errors are in the range from 400-599 currently and are grouped by what

View file

@ -181,7 +181,9 @@ const char * const BNETD_IRC_ADDRS = ""; /* this means none */
const int BNETD_IRC_PORT = 6667; /* used if port not specified */
const char * const BNETD_IRC_NETWORK_NAME = "PvPGN";
const char * const BNETD_WOL_ADDRS = "";
const int BNETD_WOL_PORT = 4005;
const int BNETD_WOL_PORT = 4000;
const char * const BNETD_WSERV_ADDRS = "";
const int BNETD_WSERV_PORT = 4005;
const char * const BNETD_TRACK_ADDRS = "track.pvpgn.org";
const int BNETD_TRACK_PORT = 6114; /* use this port if not specified */
const int BNETD_DEF_TEST_PORT = 6112; /* default guess for UDP test port */

View file

@ -73,6 +73,26 @@ extern char const * clienttag_uint_to_str(t_clienttag clienttag)
return CLIENTTAG_WAR3XP;
case CLIENTTAG_IIRC_UINT:
return CLIENTTAG_IIRC;
case CLIENTTAG_WCHAT_UINT:
return CLIENTTAG_WCHAT;
case CLIENTTAG_TIBERNSUN_UINT:
return CLIENTTAG_TIBERNSUN;
case CLIENTTAG_TIBSUNXP_UINT:
return CLIENTTAG_TIBSUNXP;
case CLIENTTAG_REDALERT2_UINT:
return CLIENTTAG_REDALERT2;
case CLIENTTAG_DUNE2000_UINT:
return CLIENTTAG_DUNE2000;
case CLIENTTAG_NOX_UINT:
return CLIENTTAG_NOX;
case CLIENTTAG_NOXQUEST_UINT:
return CLIENTTAG_NOXQUEST;
case CLIENTTAG_RENEGADE_UINT:
return CLIENTTAG_RENEGADE;
case CLIENTTAG_YURISREV_UINT:
return CLIENTTAG_YURISREV;
case CLIENTTAG_EMPERORBD_UINT:
return CLIENTTAG_EMPERORBD;
case CLIENTTAG_WWOL_UINT:
return CLIENTTAG_WWOL;
default:
@ -184,6 +204,16 @@ extern int tag_check_client(t_tag tag_uint)
case CLIENTTAG_WARCRAFT3_UINT:
case CLIENTTAG_WAR3XP_UINT:
case CLIENTTAG_IIRC_UINT:
case CLIENTTAG_WCHAT_UINT:
case CLIENTTAG_TIBERNSUN_UINT:
case CLIENTTAG_TIBSUNXP_UINT:
case CLIENTTAG_REDALERT2_UINT:
case CLIENTTAG_DUNE2000_UINT:
case CLIENTTAG_NOX_UINT:
case CLIENTTAG_NOXQUEST_UINT:
case CLIENTTAG_RENEGADE_UINT:
case CLIENTTAG_YURISREV_UINT:
case CLIENTTAG_EMPERORBD_UINT:
case CLIENTTAG_WWOL_UINT:
return 1;
default:
@ -243,6 +273,26 @@ extern char const * clienttag_get_title(t_clienttag clienttag)
return "Chat";
case CLIENTTAG_IIRC_UINT:
return "Internet Relay Chat";
case CLIENTTAG_WCHAT_UINT:
return "Westwood Chat";
case CLIENTTAG_TIBERNSUN_UINT:
return "Tiberian Sun";
case CLIENTTAG_TIBSUNXP_UINT:
return "Tiberian Sun: Firestorm";
case CLIENTTAG_REDALERT2_UINT:
return "Red Alert 2";
case CLIENTTAG_DUNE2000_UINT:
return "Dune 2000";
case CLIENTTAG_NOX_UINT:
return "Nox";
case CLIENTTAG_NOXQUEST_UINT:
return "Nox Quest";
case CLIENTTAG_RENEGADE_UINT:
return "Renegade";
case CLIENTTAG_YURISREV_UINT:
return "Yuri's Revenge";
case CLIENTTAG_EMPERORBD_UINT:
return "Emepror: Battle for Dune";
case CLIENTTAG_WWOL_UINT:
return "Westwood Online";
default:

View file

@ -79,7 +79,29 @@ typedef t_tag t_gamelang;
#define CLIENTTAG_IIRC "IIRC"/* IRC */
#define CLIENTTAG_IIRC_UINT 0x49495243
#define CLIENTTAG_WWOL "WWOL"/* Westwood Online */
/* Westwood Online tags: */
#define CLIENTTAG_WCHAT "WCHT" /* Westwood Chat */
#define CLIENTTAG_WCHAT_UINT 0x57434854
#define CLIENTTAG_TIBERNSUN "TSUN" /* Tiberian Sun */
#define CLIENTTAG_TIBERNSUN_UINT 0x5453554E
#define CLIENTTAG_TIBSUNXP "TSXP" /* Tiberian Sun Extension Pack */
#define CLIENTTAG_TIBSUNXP_UINT 0x54535850
#define CLIENTTAG_REDALERT2 "RAL2" /* Red Alert 2 */
#define CLIENTTAG_REDALERT2_UINT 0x52414C32
#define CLIENTTAG_DUNE2000 "DN2K" /* Dune 2000 */
#define CLIENTTAG_DUNE2000_UINT 0x444E324B
#define CLIENTTAG_NOX "NOXX" /* NOX */
#define CLIENTTAG_NOX_UINT 0x4E4F5858
#define CLIENTTAG_NOXQUEST "NOXQ" /* NOX Quest*/
#define CLIENTTAG_NOXQUEST_UINT 0x4E4F5851
#define CLIENTTAG_RENEGADE "RNGD" /* C&C Renegade */
#define CLIENTTAG_RENEGADE_UINT 0x524E4744
#define CLIENTTAG_YURISREV "YURI" /* Yuri's Revenge */
#define CLIENTTAG_YURISREV_UINT 0x59555249
#define CLIENTTAG_EMPERORBD "EMPR" /* Emperor: Battle for Dune */
#define CLIENTTAG_EMPERORBD_UINT 0x454D5052
#define CLIENTTAG_WWOL "WWOL" /* Other Westwood Online games */
#define CLIENTTAG_WWOL_UINT 0x57574F4C
/* BNETD-specific software tags - we try to use lowercase to avoid collisions */