diff --git a/conf/CMakeLists.txt b/conf/CMakeLists.txt index 7e6e786..811af65 100644 --- a/conf/CMakeLists.txt +++ b/conf/CMakeLists.txt @@ -4,10 +4,10 @@ set(OUTPUT_CONFS ad.conf anongame_infos.conf address_translation.conf bnhelp.conf bnissue.txt bnmaps.conf bnxpcalc.conf bnmotd-enUS.txt bnmotd-csCZ.txt bnmotd-deDE.txt bnmotd-esES.txt bnmotd-frFR.txt bnmotd-nlNL.txt bnmotd-plPL.txt bnmotd-ruRU.txt bnmotd-zhCN.txt - bnmotd-zhTW.txt bnmotd-ptBR.txt + bnmotd-zhTW.txt bnmotd-ptBR.txt bnmotd_w3.txt bnxplevel.conf channel.conf command_groups.conf news.txt realm.conf sql_DB_layout2.conf sql_DB_layout.conf supportfile.conf topics.conf - tournament.conf versioncheck.conf) + tournament.conf versioncheck.conf icons.conf) foreach(CONF ${OUTPUT_CONFS}) configure_file(${CMAKE_CURRENT_SOURCE_DIR}/${CONF}.in ${CMAKE_CURRENT_BINARY_DIR}/${CONF} @ONLY) endforeach(CONF) @@ -23,18 +23,18 @@ if(WITH_BNETD) bnetd_default_user.plain bnhelp.conf bnissue.txt bnmaps.conf bnmotd-enUS.txt bnmotd-csCZ.txt bnmotd-deDE.txt bnmotd-esES.txt bnmotd-frFR.txt bnmotd-nlNL.txt bnmotd-plPL.txt bnmotd-ruRU.txt bnmotd-zhCN.txt bnmotd-zhTW.txt bnmotd-ptBR.txt - bnxpcalc.conf bnxplevel.conf channel.conf command_groups.conf news.txt + bnxpcalc.conf bnxplevel.conf channel.conf command_groups.conf news.txt bnmotd_w3.txt realm.conf sql_DB_layout.conf sql_DB_layout2.conf supportfile.conf topics.conf - tournament.conf versioncheck.conf) + tournament.conf versioncheck.conf icons.conf) - # special treatement for non .in files + # special treatment for non .in files install(FILES bnetd_default_user.cdb DESTINATION ${SYSCONFDIR}) endif(WITH_BNETD) if(WITH_D2CS) set(D2CS_CONFS d2cs.conf anongame_infos.conf) - # special treatement for non .in files + # special treatment for non .in files install(FILES d2server.ini DESTINATION ${SYSCONFDIR}) endif(WITH_D2CS) diff --git a/conf/bnetd.conf.in b/conf/bnetd.conf.in index a27c780..5ae4659 100644 --- a/conf/bnetd.conf.in +++ b/conf/bnetd.conf.in @@ -81,7 +81,8 @@ storage_path = "file:mode=plain;dir=${LOCALSTATEDIR}/users;clan=${LOCALSTATEDIR} filedir = "${LOCALSTATEDIR}/files" reportdir = "${LOCALSTATEDIR}/reports" chanlogdir = "${LOCALSTATEDIR}/chanlogs" -motdfile = "${SYSCONFDIR}/bnmotd-enUS.txt" +motdfile = "${SYSCONFDIR}/bnmotd.txt" +motdw3file = "${SYSCONFDIR}/bnmotd_w3.txt" issuefile = "${SYSCONFDIR}/bnissue.txt" channelfile = "${SYSCONFDIR}/channel.conf" newsfile = "${SYSCONFDIR}/news.txt" @@ -107,6 +108,7 @@ anongame_infos_file = "${SYSCONFDIR}/anongame_infos.conf" DBlayoutfile = "${SYSCONFDIR}/sql_DB_layout.conf" supportfile = "${SYSCONFDIR}/supportfile.conf" transfile = "${SYSCONFDIR}/address_translation.conf" +customicons_file = "${SYSCONFDIR}/icons.conf" fortunecmd = /usr/games/fortune diff --git a/conf/bnetd.conf.win32 b/conf/bnetd.conf.win32 index edca171..7b5880e 100644 --- a/conf/bnetd.conf.win32 +++ b/conf/bnetd.conf.win32 @@ -62,6 +62,7 @@ filedir = files reportdir = var\reports chanlogdir = var\chanlogs motdfile = conf\bnmotd.txt +motdw3file = conf\bnmotd_w3.txt issuefile = conf\bnissue.txt channelfile = conf\channel.conf newsfile = conf\news.txt @@ -85,6 +86,7 @@ aliasfile = conf\bnalias.conf anongame_infos_file = conf\anongame_infos.conf DBlayoutfile = conf\sql_DB_layout.conf supportfile = conf\supportfile.conf +customicons_file = conf\icons.conf fortunecmd = bin\fortune.exe diff --git a/conf/bnhelp.conf.in b/conf/bnhelp.conf.in index e3632bc..95fb216 100644 --- a/conf/bnhelp.conf.in +++ b/conf/bnhelp.conf.in @@ -53,7 +53,8 @@ whois <player> - looks up some basic information on a user, including their acco %lusers /lusers - shows list of banned players in this channel %games -/games [<gametag>] - displays current game list +/games [<gametag>] - displays current game list of client type gametag, e.g. W3XP - Warcraft 3 TFT +/games [lobby], /games [l] - displays current list of games that are in the lobby (i.e. haven't started) %channels chs /channels /chs [all] - displays current channel list %connections con @@ -114,6 +115,7 @@ whois <player> - looks up some basic information on a user, including their acco /friends promote <username> - promote user in your friends list /friends demote <username> - demote user in your friends list /friends list - list all users in your friends list +/friends online - list all online users in your friends list /friends msg <msgtext> - whispers to all your online friends %mail /mail <command> [<options>] - mail management commands @@ -200,5 +202,12 @@ Disband your clan /clearstats - used to clear game statistics of a given user/clienttag Syntax: /clearstats <user> <clienttag> <clienttag> can be one of DSHR,DRTL,SSHR,STAR,SEXP,W2BNE,WAR3,W3XP,ALL +%find +/find - used to find users with similar name +Syntax: /find <substring to find> + <substring to find> needs to be in lower case +%save +/save - used to force save accounts changes from a cache into database +Syntax: /save # # ############################################################################## diff --git a/conf/bnmotd-bgBG.txt.in b/conf/bnmotd-bgBG.txt.in index 2778516..c21507f 100644 --- a/conf/bnmotd-bgBG.txt.in +++ b/conf/bnmotd-bgBG.txt.in @@ -1,4 +1,4 @@ -%IЗдравей %l, добре дошъл в %s! +%EЗдравей %l, добре дошъл в %s! %IВерсията на сървъра е %v на %h. %IТози сървър се хоства от %H %I @@ -8,4 +8,6 @@ %IИмате проблем с команда? Въведете /help за да %Iнаучите повече за нея. %I +%I(edit this text in conf/bnmotd-bgBG.txt) +%I %I%m \ No newline at end of file diff --git a/conf/bnmotd-csCZ.txt.in b/conf/bnmotd-csCZ.txt.in index b5f4745..879d6f9 100644 --- a/conf/bnmotd-csCZ.txt.in +++ b/conf/bnmotd-csCZ.txt.in @@ -1,14 +1,14 @@ -%IAhoj %l, +%EAhoj %l, %IVitej na serveru %s, verze %v. %I -%I %IMomentalne je zde registrovanych %a uzivatelu, z toho je %u online, hrajicich %g hry. %I %I%N si muzes zahrat s %U hraci, v %G prave probihajicich hrach nebo si muzes pokecat v %c chatech. %I -%I %INevis si rady ? Napis /help pro napovedu. %I -%I %ITvoje IP adresa: %r, tvoje ID %i a tvuj klient %t. -%ICZ MOTD by Machy_CZ \ No newline at end of file +%I +%I(edit this text in conf/bnmotd-csCZ.txt) +%I +%M%m \ No newline at end of file diff --git a/conf/bnmotd-deDE.txt.in b/conf/bnmotd-deDE.txt.in index 369cac5..b28467b 100644 --- a/conf/bnmotd-deDE.txt.in +++ b/conf/bnmotd-deDE.txt.in @@ -1,4 +1,4 @@ -%IHallo %l, willkommen zu %s! +%EHallo %l, willkommen zu %s! %ILaufende Version %v auf %h. %IDer Server ist von %H gehostet %I @@ -8,4 +8,6 @@ %IEin Problem mit den Kommandos? Schreibe /help und %Ilerne mehr über die Kommandos. %I -%I%m \ No newline at end of file +%I(edit this text in conf/bnmotd-deDE.txt) +%I +%M%m \ No newline at end of file diff --git a/conf/bnmotd-enUS.txt.in b/conf/bnmotd-enUS.txt.in index 82e84ec..43d8600 100644 --- a/conf/bnmotd-enUS.txt.in +++ b/conf/bnmotd-enUS.txt.in @@ -1,4 +1,4 @@ -%IHello %l, welcome to %s! +%EHello %l, welcome to %s! %IRunning version %v on %h. %IThis server is hosted by %H %I @@ -8,4 +8,6 @@ %IHaving trouble with a command? Type /help to %Ilearn more about it. %I -%I%m \ No newline at end of file +%I(edit this text in conf/bnmotd-enUS.txt) +%I +%M%m \ No newline at end of file diff --git a/conf/bnmotd-esES.txt.in b/conf/bnmotd-esES.txt.in index 220a43d..de6fe58 100644 --- a/conf/bnmotd-esES.txt.in +++ b/conf/bnmotd-esES.txt.in @@ -1,4 +1,4 @@ -%IHola %l, bienvenido a %s! +%EHola %l, bienvenido a %s! %IEn %h se usa la versión %v %IEste servidor es alojado por %H %I @@ -8,4 +8,6 @@ %ITiene problemas con algun comando? Teclee "/help" para %Iaprender más sobre los comandos. %I -%I%m \ No newline at end of file +%I(edit this text in conf/bnmotd-ptBR.txt) +%I +%M%m \ No newline at end of file diff --git a/conf/bnmotd-frFR.txt.in b/conf/bnmotd-frFR.txt.in index c264825..974fa78 100644 --- a/conf/bnmotd-frFR.txt.in +++ b/conf/bnmotd-frFR.txt.in @@ -1,4 +1,4 @@ -%IBonjour %l, bienvenue sur %s! +%EBonjour %l, bienvenue sur %s! %IUtilisant la version %v sur %h. %ICe serveur est hébergé par %H %I @@ -8,4 +8,6 @@ %IUn problème avec une commande ? Tappez /help pour %Ien savoir plus. %I -%I%m \ No newline at end of file +%I(edit this text in conf/bnmotd-ptBR.txt) +%I +%M%m \ No newline at end of file diff --git a/conf/bnmotd-jpJA.txt.in b/conf/bnmotd-jpJA.txt.in index 1e4c45a..d9db629 100644 --- a/conf/bnmotd-jpJA.txt.in +++ b/conf/bnmotd-jpJA.txt.in @@ -1,4 +1,4 @@ -%I%l さん, PvPGN サーバへようこそ! +%E%l さん, PvPGN サーバへようこそ! %I%h さんが %v を運用します。 %Iこのサーバは今 %H さんがホスティング中です。 %I @@ -8,4 +8,6 @@ %I%c 個のチャンネが生成しました。 %Iコマンド・リストは「/help」をタイプして下さい。 %I -%I%m \ No newline at end of file +%I(edit this text in conf/bnmotd-ptBR.txt) +%I +%M%m \ No newline at end of file diff --git a/conf/bnmotd-koKR.txt.in b/conf/bnmotd-koKR.txt.in index 76ad1f7..902c6a3 100644 --- a/conf/bnmotd-koKR.txt.in +++ b/conf/bnmotd-koKR.txt.in @@ -1,4 +1,4 @@ -%I안녕하세요 %l 님, PvPGN 서버에 오신것을 환영합니다! +%E안녕하세요 %l 님, PvPGN 서버에 오신것을 환영합니다! %I%h 님이 %v 를 구동하고 계십니다. %I본 서버는 %H 님이 호스팅하고 계십니다. %I @@ -8,4 +8,6 @@ %I명령어의 대해 궁금한 사항이 있으시다구요? %I/help 명령어를 이용해 보세요. %I -%I%m \ No newline at end of file +%I(edit this text in conf/bnmotd-ptBR.txt) +%I +%M%m \ No newline at end of file diff --git a/conf/bnmotd-nlNL.txt.in b/conf/bnmotd-nlNL.txt.in index 4515144..cbf3f50 100644 --- a/conf/bnmotd-nlNL.txt.in +++ b/conf/bnmotd-nlNL.txt.in @@ -1,5 +1,5 @@ %IHallo %l, welom bij %s! -%IWe draaien versie %v op %h. +%EWe draaien versie %v op %h. %IDeze server wordt gehost bij %H %I %IEr zijn %a gebruikers accounts op deze server. @@ -8,4 +8,6 @@ %IProblemen met een commando? Type /help om %Ier meer te weten over te komen. %I -%I%m \ No newline at end of file +%I(edit this text in conf/bnmotd-nlNL.txt) +%I +%M%m \ No newline at end of file diff --git a/conf/bnmotd-plPL.txt.in b/conf/bnmotd-plPL.txt.in index 4537cf9..818bc53 100644 --- a/conf/bnmotd-plPL.txt.in +++ b/conf/bnmotd-plPL.txt.in @@ -1,4 +1,4 @@ -%ICześć %l, witaj w %s! +%ECześć %l, witaj w %s! %IWersja serwera %v uruchomiona na %h. %ISerwer obsługuje %H %I @@ -8,4 +8,6 @@ %IJeśli masz jakieś problemy z poleceniami, to napiszsz /help aby %Idowiedzieć się wiecej. %I -%I%m \ No newline at end of file +%I(edit this text in conf/bnmotd-plPL.txt) +%I +%M%m \ No newline at end of file diff --git a/conf/bnmotd-ptBR.txt.in b/conf/bnmotd-ptBR.txt.in index 8bb264c..527def5 100644 --- a/conf/bnmotd-ptBR.txt.in +++ b/conf/bnmotd-ptBR.txt.in @@ -1,4 +1,4 @@ -%IOlá %l, Bem vindo a %s! +%EOlá %l, Bem vindo a %s! %IRodando a versão %v em %h. %IEste servidor é hosteado por %H %I @@ -8,4 +8,6 @@ %ITendo algum problema com comando? Digite /help ra %Aprender mais sobre. %I -%I%m \ No newline at end of file +%I(edit this text in conf/bnmotd-ptBR.txt) +%I +%M%m \ No newline at end of file diff --git a/conf/bnmotd-ruRU.txt.in b/conf/bnmotd-ruRU.txt.in index 1c4fd52..65344ea 100644 --- a/conf/bnmotd-ruRU.txt.in +++ b/conf/bnmotd-ruRU.txt.in @@ -1,11 +1,13 @@ -%IПривет %l, добро пожаловать на %s! +%EПривет %l, добро пожаловать на %s! %IВерсия сервера %v. -%IСервер расположен у %h (%H) +%IСервер расположен у %H (%h) %I -%IСейчас на сервере %a игроков. -%IВ %G играх находятся %U игроков %N -%Iиз них %u играют в %g играх и сидят на %c каналах. +%IНа сервере зарегистрировано %a аккаунтов. +%IСейчас %G игр и %U игроков в %N +%Iиз них %u находятся в %g играх и общаются на %c каналах. %I -%IВведите /help для получения помощи по командам чата +%IВведите /help для получения помощи по командам чата %I -%I%m \ No newline at end of file +%I(измените этот текст в файле conf/bnmotd-ruRU.txt) +%I +%M%m \ No newline at end of file diff --git a/conf/bnmotd-svSE.txt.in b/conf/bnmotd-svSE.txt.in index 9c95920..29ded59 100644 --- a/conf/bnmotd-svSE.txt.in +++ b/conf/bnmotd-svSE.txt.in @@ -1,4 +1,4 @@ -%IHej %l, välkommen till %s! +%EHej %l, välkommen till %s! %IKör version %v på %h. %IVärden för den här servern är %H %I @@ -8,4 +8,6 @@ %IHar du problem med ett kommando? Skriv /help för %Iatt lära dig mer om det. %I -%I%m \ No newline at end of file +%I(edit this text in conf/bnmotd-svSE.txt) +%I +%M%m \ No newline at end of file diff --git a/conf/bnmotd-zhCN.txt.in b/conf/bnmotd-zhCN.txt.in index 67e42a2..716cccb 100644 --- a/conf/bnmotd-zhCN.txt.in +++ b/conf/bnmotd-zhCN.txt.in @@ -1,4 +1,4 @@ -%I%l,你好。欢迎来到 %s! +%E%l,你好。欢迎来到 %s! %I现在 %h 正在运行的版本为 %v %I本服务器由 %H 管理维护 %I @@ -8,4 +8,6 @@ %I还不了解可以使用哪些命令? %I输入 /help 就可以学习了 %I -%I%m \ No newline at end of file +%I(edit this text in conf/bnmotd-zhCB.txt) +%I +%M%m \ No newline at end of file diff --git a/conf/bnmotd-zhTW.txt.in b/conf/bnmotd-zhTW.txt.in index 23b08f6..54c5a5f 100644 --- a/conf/bnmotd-zhTW.txt.in +++ b/conf/bnmotd-zhTW.txt.in @@ -1,4 +1,4 @@ -%I哈囉! %l, 歡迎蒞臨 %s! +%E哈囉! %l, 歡迎蒞臨 %s! %I本伺服器由 %H 架設於 %h. %I現行的伺服器版本是 %v. %I @@ -7,4 +7,6 @@ %I其中有 %u 個玩家一邊在玩 %g 個遊戲一邊在 %c 個聊天頻道. %I不懂使用指令? 請輸入 /help 來了解更多... %I -%I%m \ No newline at end of file +%I(edit this text in conf/bnmotd-zhTW.txt) +%I +%M%m \ No newline at end of file diff --git a/conf/bnmotd_w3.txt.in b/conf/bnmotd_w3.txt.in new file mode 100644 index 0000000..ba7710d --- /dev/null +++ b/conf/bnmotd_w3.txt.in @@ -0,0 +1,12 @@ +Welcome to the greatest PvPGN server! + +|c00FF0000Here |c00FF9933you |c0000CCFFcan |c00A8A8A8 use |c0000CC00coloured |c00FFFF00text |c009999FFas |c00FF66FFfollow|c00FFFFFF: +"|00HEXCOLOR your text here" + + + + + +(edit this text in conf/bnmotd_w3.txt) + +This text will not displayed, because there is limitation of 11 lines \ No newline at end of file diff --git a/conf/command_groups.conf.in b/conf/command_groups.conf.in index b094d03..bf7a7f5 100644 --- a/conf/command_groups.conf.in +++ b/conf/command_groups.conf.in @@ -158,9 +158,9 @@ 6 /operator /admin /flag /tag -7 /set /commandgroups /cg /clearstats +7 /set /commandgroups /cg /clearstats /icon -8 /shutdown /rehash /save +8 /shutdown /rehash /find /save # ////////////////////////////////////// # ///// End of Command Groups File ///// diff --git a/conf/icons.conf.in b/conf/icons.conf.in new file mode 100644 index 0000000..2c5ff98 --- /dev/null +++ b/conf/icons.conf.in @@ -0,0 +1,106 @@ +############################################################################## +# icons.conf - Custom icons configuration file # +#----------------------------------------------------------------------------# +# # +# Allowed clients: # +# W3XP, WAR3, STAR, SEXP, JSTR, SSHR, W2BN, DRTL, DSHR # +# # +# W3XP: It also disables icon selection from user portrait # +# # +# [icons] table format (first variable always corresponds to icon_key: # +# icon_key | rank | icon_code # +# # +# [stats] output format: # +# initialize variables under a client tag # +# band variables with figure brackets {{var}} # +# use {{variable->rank}} to display an icon rank for a custom variable # +# # +############################################################################## + + +############################################################################## +# General settings # +#----------------------------------------------------------------------------# + +# Enable icon sets below +custom_icons = false + + + +############################################################################## +# Warcraft 3 icon set # +# Use MPQ editor to edit icons-WAR3.bni (just change extension bni->mpq) # +#----------------------------------------------------------------------------# + +[W3XP] +solo_level = "Record\W3XP\solo_level" +solo_xp = "Record\W3XP\solo_xp" +solo_wins = "Record\W3XP\solo_wins" +solo_losses = "Record\W3XP\solo_losses" +team_level = "Record\W3XP\team_level" +team_xp = "Record\W3XP\team_xp" +team_wins = "Record\W3XP\team_wins" +team_losses = "Record\W3XP\team_losses" +ffa_level = "Record\W3XP\ffa_level" +ffa_xp = "Record\W3XP\ffa_xp" +ffa_wins = "Record\W3XP\ffa_wins" +ffa_losses = "Record\W3XP\ffa_losses" +username = "BNET\acct\username" + +[icons] +0 Beginner KBKB +1 Dungeon KBKD +2 Expert KBKE +3 Mid KBKM +4 Pro KBKP +5 World KBKW +6 Universe WCYB +[/icons] + +[stats] +{{username}}'s record: +Solo games: [{{solo_level->rank}}] {{solo_xp}} xp ({{solo_wins}} - {{solo_losses}}) +Team games: [{{team_level->rank}}] {{team_xp}} xp ({{team_wins}} - {{team_losses}}) +FFA games: [{{ffa_level->rank}}] {{ffa_xp}} xp ({{ffa_wins}} - {{ffa_losses}}) +[/stats] + + + +############################################################################## +# Starcraft icon set # +# Use Bni Icon Builder to edit icons.bni (icons_STAR.bni is not used) # +# https://github.com/HarpyWar/bni-icon-builder # +#----------------------------------------------------------------------------# + +[SEXP] +rating1 = "Record\SEXP\1_rating" +wins1 = "Record\SEXP\1_wins" +losses1 = "Record\SEXP\1_losses" +disconnects1 = "Record\SEXP\1_disconnects" +rating0 = "Record\SEXP\0_rating" +wins0 = "Record\SEXP\0_wins" +losses0 = "Record\SEXP\0_losses" +disconnects0 = "Record\SEXP\0_disconnects" +username = "BNET\acct\username" + +[icons] +1000 n00b NOOB +1250 Chobo+ CHO1 +1500 Chobo++ CHO2 +1750 Chobo+++ CHO3 +2000 Hasu+ HAS1 +2300 Hasu++ HAS2 +2650 Hasu+++ HAS3 +3000 Gosu+ GOS1 +3300 Gosu++ GOS2 +3650 Gosu+++ GOS3 +4000 Mega Gosu GOSU +5500 Father MEGA +[/icons] + +[stats] +{{username}}'s record: +Ladder games: [{{rating1->rank}}] {{rating1}} pts ({{wins1}}/{{losses1}}/{{disconnects1}}) +Normal games: [{{rating0->rank}}] {{rating0}} pts ({{wins0}}/{{losses0}}/{{disconnects0}}) +[/stats] + diff --git a/conf/news.txt.in b/conf/news.txt.in index a48a6fc..1d1310e 100644 --- a/conf/news.txt.in +++ b/conf/news.txt.in @@ -1,26 +1,32 @@ +{03/28/2014} +(edit this text in conf/news.txt) + + +Note that Warcraft 3 client caches news in bncache.dat +(remove the file on the client side before login to see the changes immediately) + + +New support channel at: +http://pvpgn.pro + + {10/01/2004} Welcome To The Player-vs-Player Gaming Network! Bringing Emulation To New Levels! - + =-=-=-=-=-=-=-=-=-=-=-=-=-=-==-=-=-=-=-=-=-=-=-=-=-=-=-=-==-=-=-=-=-=-=-= - + ** IF YOU EXPERIENCE PROBLEMS USING THIS SERVER PLEASE REPORT IT TO THE ** ********* ADMINISTRATOR OF THE SERVER NOT TO THE PVPGN TEAM ************ - + Project development homepage: http://pvpgn.berlios.de - + Support channels (ONLY for the admins): ======================================== -1. BugTracker (preffered support method): -http://sourceforge.net/tracker/?atid=470605&group_id=53514&func=browse - -2. Mailing List: pvpgn-users@lists.sourceforge.net (to subscribe go here -http://lists.sourceforge.net/lists/listinfo/pvpgn-users ) - -3. Forums: http://forums.pvpgn.org - -4. IRC live support: #pvpgn on irc.pvpgn.org - + +1. Forums: http://forums.pvpgn.org + +2. IRC live support: #pvpgn on irc.pvpgn.org + Enjoy! The PvPGN Team -http://www.PvPGN.org diff --git a/files/icons.bni b/files/icons.bni index 619bf16..30a88c2 100644 Binary files a/files/icons.bni and b/files/icons.bni differ diff --git a/files/newaccount-default.txt b/files/newaccount-default.txt index d457818..6b53ef9 100644 --- a/files/newaccount-default.txt +++ b/files/newaccount-default.txt @@ -19,3 +19,5 @@ Battle.net(R) and Blizzard Entertainment(R) are trademarks or registered tradema Besides all this... Happy gaming.. PvPGN Project Page: http://pvpgn.berlios.de/ + +(edit this text in var/files/newaccount-default.txt) \ No newline at end of file diff --git a/files/newaccount-enUS.txt b/files/newaccount-enUS.txt index d457818..d97e629 100644 --- a/files/newaccount-enUS.txt +++ b/files/newaccount-enUS.txt @@ -19,3 +19,5 @@ Battle.net(R) and Blizzard Entertainment(R) are trademarks or registered tradema Besides all this... Happy gaming.. PvPGN Project Page: http://pvpgn.berlios.de/ + +(edit this text in var/files/newaccount-enUS.txt) \ No newline at end of file diff --git a/files/termsofservice-default.txt b/files/termsofservice-default.txt index d457818..7e8591f 100644 --- a/files/termsofservice-default.txt +++ b/files/termsofservice-default.txt @@ -19,3 +19,5 @@ Battle.net(R) and Blizzard Entertainment(R) are trademarks or registered tradema Besides all this... Happy gaming.. PvPGN Project Page: http://pvpgn.berlios.de/ + +(edit this text in var/files/termsofservice-default.txt) \ No newline at end of file diff --git a/files/termsofservice-enUS.txt b/files/termsofservice-enUS.txt index d457818..40dfcfc 100644 --- a/files/termsofservice-enUS.txt +++ b/files/termsofservice-enUS.txt @@ -19,3 +19,5 @@ Battle.net(R) and Blizzard Entertainment(R) are trademarks or registered tradema Besides all this... Happy gaming.. PvPGN Project Page: http://pvpgn.berlios.de/ + +(edit this text in var/files/termsofservice-enUS.txt) \ No newline at end of file diff --git a/files/tos-unicode_default.txt b/files/tos-unicode_default.txt index d457818..519ddba 100644 --- a/files/tos-unicode_default.txt +++ b/files/tos-unicode_default.txt @@ -19,3 +19,5 @@ Battle.net(R) and Blizzard Entertainment(R) are trademarks or registered tradema Besides all this... Happy gaming.. PvPGN Project Page: http://pvpgn.berlios.de/ + +(edit this text in var/files/tos-unicode_default.txt) \ No newline at end of file diff --git a/files/tos.txt b/files/tos.txt index d457818..5fe368b 100644 --- a/files/tos.txt +++ b/files/tos.txt @@ -19,3 +19,5 @@ Battle.net(R) and Blizzard Entertainment(R) are trademarks or registered tradema Besides all this... Happy gaming.. PvPGN Project Page: http://pvpgn.berlios.de/ + +(edit this text in var/files/tos.txt) \ No newline at end of file diff --git a/files/tos_default.txt b/files/tos_default.txt index d457818..452a180 100644 --- a/files/tos_default.txt +++ b/files/tos_default.txt @@ -19,3 +19,5 @@ Battle.net(R) and Blizzard Entertainment(R) are trademarks or registered tradema Besides all this... Happy gaming.. PvPGN Project Page: http://pvpgn.berlios.de/ + +(edit this text in var/files/tos-defaut.txt) \ No newline at end of file diff --git a/src/bnetd/CMakeLists.txt b/src/bnetd/CMakeLists.txt index 4349032..1ac66ec 100644 --- a/src/bnetd/CMakeLists.txt +++ b/src/bnetd/CMakeLists.txt @@ -31,7 +31,7 @@ set(BNETD_SOURCES storage.cpp storage_file.cpp storage_file.h storage.h storage_sql2.cpp storage_sql2.h storage_sql.cpp storage_sql.h support.cpp support.h team.cpp team.h tick.cpp tick.h timer.cpp timer.h topic.cpp topic.h - tournament.cpp tournament.h tracker.cpp tracker.h udptest_send.cpp + tournament.cpp tournament.h icons.cpp icons.h tracker.cpp tracker.h udptest_send.cpp udptest_send.h versioncheck.cpp versioncheck.h watch.cpp watch.h anongame_wol.cpp anongame_wol.h handle_wserv.cpp handle_wserv.h ../win32/winmain.cpp ../win32/winmain.h diff --git a/src/bnetd/account.cpp b/src/bnetd/account.cpp index 8a84a98..43d0a93 100644 --- a/src/bnetd/account.cpp +++ b/src/bnetd/account.cpp @@ -545,6 +545,38 @@ namespace pvpgn } + extern char const *accountlist_find_vague_account(t_account * account, char const *vague_username) + { + char const *tname; + int i; + + if (!vague_username) { + eventlog(eventlog_level_error, __FUNCTION__, "got NULL vague_username"); + return NULL; + } + if (!account) { + eventlog(eventlog_level_error, __FUNCTION__, "got NULL account"); + return NULL; + } + + + if (tname = account_get_name(account)) { + char temp[MAX_USERNAME_LEN]; + for (i = 0; i < std::strlen(tname); i++) { + temp[i] = tname[i]; + if (isupper((int)temp[i])) { + temp[i] = tolower((int)temp[i]); + } + } + if (strstr(temp, vague_username)) { + return tname; + } + return NULL; + } + return NULL; + } + + extern int accountlist_allow_add(void) { if (force_account_add) diff --git a/src/bnetd/account.h b/src/bnetd/account.h index 67230b1..e0b4395 100644 --- a/src/bnetd/account.h +++ b/src/bnetd/account.h @@ -106,6 +106,7 @@ namespace pvpgn extern int accountlist_flush(unsigned flags); extern t_account * accountlist_find_account(char const * username); extern t_account * accountlist_find_account_by_uid(unsigned int uid); + extern char const *accountlist_find_vague_account(t_account * account, char const *vague_username); extern int accountlist_allow_add(void); extern t_account * accountlist_create_account(const char *username, const char *passhash1); extern void accounts_get_attr(char const *); diff --git a/src/bnetd/account_wrap.cpp b/src/bnetd/account_wrap.cpp index 874ade2..74c7098 100644 --- a/src/bnetd/account_wrap.cpp +++ b/src/bnetd/account_wrap.cpp @@ -453,6 +453,11 @@ namespace pvpgn /****************************************************************/ + /* Account creation time */ + extern unsigned int account_get_ll_ctime(t_account * account) + { + return account_get_numattr(account, "BNET\\acct\\ctime"); + } extern unsigned int account_get_ll_time(t_account * account) { diff --git a/src/bnetd/account_wrap.h b/src/bnetd/account_wrap.h index 63f050b..32c8a47 100644 --- a/src/bnetd/account_wrap.h +++ b/src/bnetd/account_wrap.h @@ -89,6 +89,7 @@ namespace pvpgn extern char const * account_get_desc(t_account * account); /* last login */ + extern unsigned int account_get_ll_ctime(t_account * account); extern unsigned int account_get_ll_time(t_account * account); extern int account_set_ll_time(t_account * account, unsigned int t); extern char const * account_get_ll_user(t_account * account); diff --git a/src/bnetd/command.cpp b/src/bnetd/command.cpp index def82a2..4c6c5e0 100644 --- a/src/bnetd/command.cpp +++ b/src/bnetd/command.cpp @@ -50,6 +50,7 @@ #include "common/xstr.h" #include "common/trans.h" #include "common/lstr.h" +#include "common/hashtable.h" #include "connection.h" #include "message.h" @@ -75,6 +76,7 @@ #include "clan.h" #include "common/setup_after.h" #include "common/flags.h" +#include "icons.h" #include "attrlayer.h" @@ -333,6 +335,7 @@ namespace pvpgn static int _handle_gameinfo_command(t_connection * c, char const * text); static int _handle_ladderactivate_command(t_connection * c, char const * text); static int _handle_rehash_command(t_connection * c, char const * text); + static int _handle_find_command(t_connection * c, char const *text); static int _handle_save_command(t_connection * c, char const * text); //static int _handle_rank_all_accounts_command(t_connection * c, char const * text); @@ -358,6 +361,7 @@ namespace pvpgn static int _handle_moderate_command(t_connection * c, char const * text); static int _handle_clearstats_command(t_connection * c, char const * text); static int _handle_tos_command(t_connection * c, char const * text); + static int _handle_icon_command(t_connection * c, char const * text); static const t_command_table_row standard_command_table[] = { @@ -445,6 +449,7 @@ namespace pvpgn { "/gameinfo", _handle_gameinfo_command }, { "/ladderactivate", _handle_ladderactivate_command }, { "/rehash", _handle_rehash_command }, + { "/find", _handle_find_command }, { "/save", _handle_save_command }, // { "/rank_all_accounts" , _handle_rank_all_accounts_command }, { "/shutdown", _handle_shutdown_command }, @@ -473,6 +478,7 @@ namespace pvpgn { "/topic", _handle_topic_command }, { "/moderate", _handle_moderate_command }, { "/clearstats", _handle_clearstats_command }, + { "/icon", _handle_icon_command }, { NULL, NULL } @@ -1665,7 +1671,7 @@ namespace pvpgn return 0; } } - else if (strstart(text, "list") == 0 || strstart(text, "l") == 0) { + else if (strstart(text, "list") == 0 || strstart(text, "l") == 0 || strstart(text, "online") == 0 || strstart(text, "o") == 0) { char const * frienduid; char status[128]; char software[64]; @@ -1678,8 +1684,17 @@ namespace pvpgn t_list * flist; int num; unsigned int uid; + bool online_only = false; - message_send_text(c, message_type_info, c, "Your PvPGN - Friends List"); + if (strstart(text, "online") == 0 || strstart(text, "o") == 0) { + online_only = true; + } + if (!online_only) { + message_send_text(c, message_type_info, c, "Your PvPGN - Friends List"); + } + else { + message_send_text(c, message_type_info, c, "Your PvPGN - Online Friends List"); + } message_send_text(c, message_type_info, c, "=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-="); num = account_get_friendcount(my_acc); @@ -1694,8 +1709,12 @@ namespace pvpgn } software[0] = '\0'; friend_acc = friend_get_account(fr); - if (!(dest_c = connlist_find_connection_by_account(friend_acc))) + if (!(dest_c = connlist_find_connection_by_account(friend_acc))) { + if (online_only) { + continue; + } std::sprintf(status, ", offline"); + } else { std::sprintf(software, " using %s", clienttag_get_title(conn_get_clienttag(dest_c))); @@ -1737,6 +1756,7 @@ namespace pvpgn message_send_text(c, message_type_info, c, "Type: /f promote <username> (promote a friend in your list)"); message_send_text(c, message_type_info, c, "Type: /f demote <username> (demote a friend in your list)"); message_send_text(c, message_type_info, c, "Type: /f list (shows your full friends list)"); + message_send_text(c, message_type_info, c, "Type: /f online (shows your online friends list)"); message_send_text(c, message_type_info, c, "Type: /f msg (whispers a message to all your friends at once)"); } @@ -2168,6 +2188,29 @@ namespace pvpgn clienttag_uint = tag_case_str_to_uint(clienttag); + + // custom stats + if (prefs_get_custom_icons() == 1) + { + const char *text; + + // if text is not empty + if (text = get_custom_stats_text(account, clienttag_uint)) + { + // split by lines + char* output_array = strtok((char*)text, "\n"); + while (output_array) + { + message_send_text(c, message_type_info, c, output_array); + output_array = strtok(NULL, "\n"); + } + xfree((char*)text); + + return 0; + } + } + + switch (clienttag_uint) { case CLIENTTAG_BNCHATBOT_UINT: @@ -2982,6 +3025,7 @@ namespace pvpgn t_game_difficulty diff; t_clienttag tag; t_connection *c; + bool lobby; }; static int _glist_cb(t_game *game, void *data) @@ -2990,7 +3034,8 @@ namespace pvpgn if ((!cbdata->tag || !prefs_get_hide_pass_games() || game_get_flag(game) != game_flag_private) && (!cbdata->tag || game_get_clienttag(game) == cbdata->tag) && - (cbdata->diff == game_difficulty_none || game_get_difficulty(game) == cbdata->diff)) + (cbdata->diff == game_difficulty_none || game_get_difficulty(game) == cbdata->diff) && + (cbdata->lobby == false || (game_get_status(game) != game_status_started && game_get_status(game) != game_status_done))) { snprintf(msgtemp, sizeof(msgtemp), " %-16.16s %1.1s %-8.8s %-21.21s %5u ", game_get_name(game), @@ -3020,7 +3065,7 @@ namespace pvpgn unsigned int i; unsigned int j; char clienttag_str[5]; - char dest[5]; + char dest[6]; struct glist_cb_struct cbdata; for (i = 0; text[i] != ' ' && text[i] != '\0'; i++); /* skip command */ @@ -3031,6 +3076,7 @@ namespace pvpgn for (; text[i] == ' '; i++); cbdata.c = c; + cbdata.lobby = false; if (std::strcmp(&text[i], "norm") == 0) cbdata.diff = game_difficulty_normal; @@ -3051,6 +3097,12 @@ namespace pvpgn cbdata.tag = 0; message_send_text(c, message_type_info, c, "All current games:"); } + else if (strcasecmp(&dest[0], "lobby") == 0 || strcasecmp(&dest[0], "l") == 0) + { + cbdata.tag = conn_get_clienttag(c); + cbdata.lobby = true; + message_send_text(c, message_type_info, c, "Games in lobby:"); + } else { cbdata.tag = tag_case_str_to_uint(&dest[0]); @@ -3415,6 +3467,8 @@ namespace pvpgn char const * ip; char * tok; t_clanmember * clanmemb; + std::time_t then; + struct std::tm * tmthen; for (i = 0; text[i] != ' ' && text[i] != '\0'; i++); /* skip command */ for (; text[i] == ' '; i++); @@ -3434,12 +3488,19 @@ namespace pvpgn message_send_text(c, message_type_error, c, "Invalid user."); return 0; } + + then = account_get_ll_ctime(account); + tmthen = std::localtime(&then); /* FIXME: determine user's timezone */ + snprintf(msgtemp, sizeof(msgtemp), "Login: %-16.16s "UID_FORMAT" Sex: %.14s", account_get_name(account), account_get_uid(account), account_get_sex(account)); message_send_text(c, message_type_info, c, msgtemp); + std::strftime(msgtemp, sizeof(msgtemp), "Created: %a %b %d %H:%M %Y ", tmthen); + message_send_text(c, message_type_info, c, msgtemp); + if ((clanmemb = account_get_clanmember(account))) { t_clan * clan; @@ -3491,8 +3552,6 @@ namespace pvpgn ip = "unknown"; { - std::time_t then; - struct std::tm * tmthen; then = account_get_ll_time(account); tmthen = std::localtime(&then); /* FIXME: determine user's timezone */ @@ -3514,13 +3573,17 @@ namespace pvpgn if ((account_get_command_groups(conn_get_account(c)) & command_get_group("/admin-addr"))) { /* the player who requested /finger has admin privileges - give him more info about the one he querys; - is_admin, is_operator, is_locked, email */ - snprintf(msgtemp, sizeof(msgtemp), "email:%.128s , is_operator: %d , is_admin: %d , is_acc_locked: %d", + give him more info about the one he querys; + is_admin, is_operator, is_locked, email */ + snprintf(msgtemp, sizeof(msgtemp), "Email: %.128s, Operator: %s, Admin: %s, Locked: %s, Muted: %s", account_get_email(account), - account_get_auth_operator(account, NULL), - account_get_auth_admin(account, NULL), - account_get_auth_lock(account)); + account_get_auth_operator(account, NULL) == 1 ? "Yes" : "No", + account_get_auth_admin(account, NULL) == 1 ? "Yes" : "No", + account_get_auth_lock(account) == 1 ? "Yes" : "No", + account_get_auth_mute(account) == 1 ? "Yes" : "No"); + message_send_text(c, message_type_info, c, msgtemp); + snprintf(msgtemp, sizeof(msgtemp), "Last login Owner: %.128s", + account_get_ll_owner(account)); message_send_text(c, message_type_info, c, msgtemp); } @@ -3854,6 +3917,48 @@ namespace pvpgn return 0; } + /** + * /find <substr to search for inside username> + */ + static int _handle_find_command(t_connection * c, char const *text) + { + unsigned int i = 0; + t_account *account; + char const *tname; + t_entry *curr; + t_hashtable *accountlist_head = accountlist(); + + text = skip_command(text); + + if (text[0] == '\0') { + /* In need of a better description */ + message_send_text(c, message_type_info, c, "Usage: /find <substring to search in acct name>"); + message_send_text(c, message_type_info, c, " <substring> has to be in lower case"); + return -1; + } + + std::sprintf(msgtemp, " -- name -- similar to %s", text); + message_send_text(c, message_type_info, c, msgtemp); + + + HASHTABLE_TRAVERSE(accountlist_head, curr) + { + if (!curr) + { + eventlog(eventlog_level_error, __FUNCTION__, "found NULL account in list"); + } + else + { + account = (t_account *)entry_get_data(curr); + if ((tname = accountlist_find_vague_account(account, text)) != NULL) { + message_send_text(c, message_type_info, c, tname); + return 0; + } + } + } + return 0; + } + /** * Save changes of accounts and clans from the cache to a storage */ @@ -4599,11 +4704,22 @@ namespace pvpgn key = arg2; value = arg3; + // disallow get/set value for password hash and username (hash can be cracked easily, account name should be permanent) + if (strcasecmp(key, "bnet\\acct\\passhash1") == 0 || strcasecmp(key, "bnet\\acct\\username") == 0 || strcasecmp(key, "bnet\\username") == 0) + { + message_send_text(c, message_type_info, c, "Access denied due to security reason."); + return 0; + } + if ((arg1[0] == '\0') || (arg2[0] == '\0')) { message_send_text(c, message_type_info, c, "usage: /set <username> <key> [value]"); + message_send_text(c, message_type_info, c, " example: /set joe BNET\\auth\\botlogin true"); + message_send_text(c, message_type_info, c, " example: /set joe Record\\W3XP\\ffa_wins 123"); + message_send_text(c, message_type_info, c, " (set value = null to unset value)"); + return 0; } - + if (!(account = accountlist_find_account(accname))) { message_send_text(c, message_type_error, c, "Invalid user."); @@ -4614,7 +4730,7 @@ namespace pvpgn { if (account_get_strattr(account, key)) { - snprintf(msgtemp, sizeof(msgtemp), "current value of %.64s is \"%.128s\"", key, account_get_strattr(account, key)); + snprintf(msgtemp, sizeof(msgtemp), "Current value of %.64s is \"%.128s\"", key, account_get_strattr(account, key)); message_send_text(c, message_type_error, c, msgtemp); } else @@ -4622,11 +4738,22 @@ namespace pvpgn return 0; } - if (account_set_strattr(account, key, value) < 0) - message_send_text(c, message_type_error, c, "Unable to set key"); - else{ - message_send_text(c, message_type_error, c, "Key set succesfully"); + // unset value + if (strcasecmp(value, "null") == 0) + value = NULL; + std::sprintf(msgtemp, "for \"%s\" (%.64s = \"%.128s\")", account_get_name(account), key, value); + + if (account_set_strattr(account, key, value) < 0) + { + std::sprintf(msgtemp2, "Unable to set key %s", msgtemp); + message_send_text(c, message_type_error, c, msgtemp2); + } + else + { + std::sprintf(msgtemp2, "Key set succesfully %s", msgtemp); + message_send_text(c, message_type_error, c, msgtemp2); + eventlog(eventlog_level_warn, __FUNCTION__, "Key set by \"%s\" %s", account_get_name(conn_get_account(c)), msgtemp); } return 0; } @@ -5201,6 +5328,94 @@ namespace pvpgn return 0; } + /* Set usericon */ + static int _handle_icon_command(t_connection * c, char const *text) + { + t_account * user_account; + t_connection * user_c; + char *accname; + char *code; + const char *usericon; + t_clienttag user_clienttag; + char t[MAX_MESSAGE_LEN]; + unsigned int i, j; + char arg1[256]; + char arg2[256]; + + std::strncpy(t, text, MAX_MESSAGE_LEN - 1); + for (i = 0; t[i] != ' ' && t[i] != '\0'; i++); /* skip command /icon */ + + for (; t[i] == ' '; i++); /* skip spaces */ + for (j = 0; t[i] != ' ' && t[i] != '\0'; i++) /* get username */ + if (j < sizeof(arg1)-1) arg1[j++] = t[i]; + arg1[j] = '\0'; + + for (; t[i] == ' '; i++); /* skip spaces */ + for (j = 0; t[i] != ' ' && t[i] != '\0'; i++) /* get code */ + if (j < sizeof(arg2)-1) arg2[j++] = t[i]; + arg2[j] = '\0'; + + accname = arg1; + code = arg2; + + if (accname == '\0') + { + message_send_text(c, message_type_info, c, "usage: /icon <username> [CODE]"); + message_send_text(c, message_type_info, c, " for example: /icon joe W3D6"); + message_send_text(c, message_type_info, c, " (set code = null to unset icon)"); + return 0; + } + + if (!(user_account = accountlist_find_account(accname))) + { + message_send_text(c, message_type_error, c, "Invalid user."); + return 0; + } + + if (user_c = account_get_conn(user_account)) + user_clienttag = conn_get_clienttag(user_c); + else + user_clienttag = account_get_ll_clienttag(user_account); // if user offline then retrieve last clienttag + + // output current usericon code + if (code == '\0' || strlen(arg2) != 4) + { + if (usericon = account_get_user_icon(user_account, user_clienttag)) + { + snprintf(msgtemp, sizeof(msgtemp), "%.64s has custom icon \"%.4s\"", account_get_name(user_account), strreverse((char*)usericon)); + message_send_text(c, message_type_error, c, msgtemp); + } + else + { + snprintf(msgtemp, sizeof(msgtemp), "Custom icon for %.64s currently not set", account_get_name(user_account)); + message_send_text(c, message_type_error, c, msgtemp); + } + + return 0; + } + for (int i = 0; i < strlen(code); i++) + code[i] = toupper(code[i]); + + // unset value + if (strcasecmp(code, "null") == 0) + usericon = NULL; + else + usericon = strreverse(xstrdup(code)); + + + snprintf(msgtemp, sizeof(msgtemp), "Set icon \"%.4s\" to %.64s", code, account_get_name(user_account)); + message_send_text(c, message_type_error, c, msgtemp); + + account_set_user_icon(user_account, user_clienttag, usericon); + + // if user online then force him to rejoin channel + if (user_c) + { + conn_update_w3_playerinfo(user_c); + channel_rejoin(user_c); + } + } + } } diff --git a/src/bnetd/connection.cpp b/src/bnetd/connection.cpp index 31d4ba4..04c8c71 100644 --- a/src/bnetd/connection.cpp +++ b/src/bnetd/connection.cpp @@ -74,6 +74,7 @@ #include "attrlayer.h" #include "anongame_wol.h" #include "common/setup_after.h" +#include "icons.h" namespace pvpgn { @@ -2521,13 +2522,14 @@ namespace pvpgn return 0; } - + /* Player icon that displayed in a channel in all games (except Warcraft 3) */ extern char const * conn_get_playerinfo(t_connection const * c) { t_account * account; static char playerinfo[MAX_PLAYERINFO_STR]; t_clienttag clienttag; char revtag[5]; + char const * usericon; if (!c) { @@ -2547,7 +2549,23 @@ namespace pvpgn } tag_uint_to_revstr(revtag, clienttag); - if (clienttag == CLIENTTAG_BNCHATBOT_UINT) + // allow set icon to a user directly from the database (override default tag always if not null) + if (usericon = account_get_user_icon(account, clienttag)) + std::sprintf(revtag, usericon); + + // if custom_icons is enabled then set a custom client tag by player rating + if (prefs_get_custom_icons() == 1) + { + t_icon_info * icon; + + // do not override userselectedicon if it's not null + if (!usericon && (icon = get_custom_icon(account, clienttag))) + strcpy(revtag, icon->icon_code); + + // FIXME: it replaces tag with icon on a client side for all clients (HarpyWar) + std::strcpy(playerinfo, revtag); + } + else if (clienttag == CLIENTTAG_BNCHATBOT_UINT) { std::strcpy(playerinfo, revtag); /* FIXME: what to return here? */ } @@ -3674,6 +3692,7 @@ namespace pvpgn return count; } + /* Warcraft 3 icon that displayed in a channel */ extern int conn_update_w3_playerinfo(t_connection * c) { t_account * account; @@ -3725,15 +3744,35 @@ namespace pvpgn while ((*clantag_str) == 0) clantag_str++; } - if (acctlevel == 0) { + // allow set icon to a user directly from the database (override default icon always if not null) + usericon = account_get_user_icon(account, clienttag); + + // if custom stats is enabled then set a custom client icon by player rating + if (prefs_get_custom_icons() == 1) + { + t_icon_info * icon; + + // do not override userselectedicon if it's not null + if (!usericon && (icon = get_custom_icon(account, clienttag))) + usericon = xstrdup(icon->icon_code); + + acctlevel = 0; + if (clantag) + std::sprintf(tempplayerinfo, "%s %s %u %s", revtag, usericon, acctlevel, clantag_str); + else + std::sprintf(tempplayerinfo, "%s %s %u", revtag, usericon, acctlevel); + } + // default icon "WAR3" or "W3XP" + else if (acctlevel == 0 && !usericon) { if (clantag) std::sprintf(tempplayerinfo, "%s %s 0 %s", revtag, revtag, clantag_str); else std::strcpy(tempplayerinfo, revtag); eventlog(eventlog_level_info, __FUNCTION__, "[%d] %s", conn_get_socket(c), revtag); } - else { - usericon = account_get_user_icon(account, clienttag); + // display race icon with a level number + else + { if (!usericon) { if (clantag) std::sprintf(tempplayerinfo, "%s %1u%c3W %u %s", revtag, raceiconnumber, raceicon, acctlevel, clantag_str); diff --git a/src/bnetd/handle_anongame.cpp b/src/bnetd/handle_anongame.cpp index 92eb819..803db19 100644 --- a/src/bnetd/handle_anongame.cpp +++ b/src/bnetd/handle_anongame.cpp @@ -38,6 +38,7 @@ #include "tournament.h" #include "channel.h" #include "common/setup_after.h" +#include "icons.h" namespace pvpgn { @@ -439,10 +440,10 @@ namespace pvpgn return 0; } + /* Open portrait in Warcraft 3 user profile */ static int _client_anongame_get_icon(t_connection * c, t_packet const * const packet) { t_packet * rpacket; - //BlacKDicK 04/20/2003 Need some huge re-work on this. { struct @@ -491,7 +492,16 @@ namespace pvpgn packet_set_type(rpacket, SERVER_FINDANONGAME_ICONREPLY); bn_int_set(&rpacket->u.server_findanongame_iconreply.count, bn_int_get(packet->u.client_findanongame_inforeq.count)); bn_byte_set(&rpacket->u.server_findanongame_iconreply.option, CLIENT_FINDANONGAME_GET_ICON); - if ((uicon = account_get_user_icon(acc, clienttag))) + + + if (prefs_get_custom_icons() == 1) + { + // get current custom icon + t_icon_info * icon; + if (icon = get_custom_icon(acc, clienttag)) + std::memcpy(&rpacket->u.server_findanongame_iconreply.curricon, icon->icon_code, 4); + } + else if ((uicon = account_get_user_icon(acc, clienttag))) { std::memcpy(&rpacket->u.server_findanongame_iconreply.curricon, uicon, 4); } @@ -517,7 +527,10 @@ namespace pvpgn //Building the icon for the races bn_short_set(&tempicon.required_wins, icon_req_race_wins); if (account_get_racewins(acc, race[i], clienttag) >= icon_req_race_wins) { - tempicon.client_enabled = 1; + if (prefs_get_custom_icons() == 1) + tempicon.client_enabled = 0; + else + tempicon.client_enabled = 1; } else{ tempicon.client_enabled = 0; @@ -528,7 +541,10 @@ namespace pvpgn icon_req_tourney_wins = anongame_infos_get_ICON_REQ_TOURNEY(j + 1); bn_short_set(&tempicon.required_wins, icon_req_tourney_wins); if (account_get_racewins(acc, race[i], clienttag) >= icon_req_tourney_wins) { - tempicon.client_enabled = 1; + if (prefs_get_custom_icons() == 1) + tempicon.client_enabled = 0; + else + tempicon.client_enabled = 1; } else{ tempicon.client_enabled = 0; @@ -544,6 +560,7 @@ namespace pvpgn return 0; } + /* Choose icon by user from profile > portrait */ static int _client_anongame_set_icon(t_connection * c, t_packet const * const packet) { //BlacKDicK 04/20/2003 @@ -552,6 +569,12 @@ namespace pvpgn t_account * account; t_clienttag ctag; + // disable with custom icons + if (prefs_get_custom_icons() == 1) + { + return 0; + } + /*FIXME: In this case we do not get a 'count' but insted of it we get the icon that the client wants to set.'W3H2' for an example. For now it is ok, since they share the same position on the packet*/ @@ -568,6 +591,7 @@ namespace pvpgn account = conn_get_account(c); + // ICON SWITCH HACK PROTECTION if (check_user_icon(account, user_icon) == 0) { eventlog(eventlog_level_info, __FUNCTION__, "[%s] \"%s\" ICON SWITCH hack attempt, icon set to default ", conn_get_username(c), user_icon); @@ -585,7 +609,7 @@ namespace pvpgn return 0; } - // check user for illegal icon + /* Check user choice for illegal icon */ static int check_user_icon(t_account * account, const char * user_icon) { unsigned int i, len; diff --git a/src/bnetd/handle_bnet.cpp b/src/bnetd/handle_bnet.cpp index 64e6d5d..76fd504 100644 --- a/src/bnetd/handle_bnet.cpp +++ b/src/bnetd/handle_bnet.cpp @@ -23,6 +23,8 @@ #include "common/setup_before.h" #include "handle_bnet.h" +#include <fstream> +#include <cerrno> #include <sstream> #include <cstring> #include <cctype> @@ -2700,6 +2702,7 @@ namespace pvpgn return 0; } + // motd for warcraft 3 (http://img21.imageshack.us/img21/1808/j2py.png) static int _client_motdw3(t_connection * c, t_packet const *const packet) { t_packet *rpacket; @@ -2740,7 +2743,19 @@ namespace pvpgn bn_int_set(&rpacket->u.server_motd_w3.timestamp, motdd.fnews + 1); bn_int_set(&rpacket->u.server_motd_w3.timestamp2, SERVER_MOTD_W3_WELCOME); - snprintf(serverinfo, sizeof(serverinfo), "Welcome to the " PVPGN_SOFTWARE " Version " PVPGN_VERSION "\r\n\r\nThere are currently %u user(s) in %u games of %s, and %u user(s) playing %u games and chatting in %u channels in %s.\r\n%s", conn_get_user_count_by_clienttag(conn_get_clienttag(c)), game_get_count_by_clienttag(ctag), clienttag_get_title(conn_get_clienttag(c)), connlist_login_get_length(), gamelist_get_length(), channellist_get_length(), prefs_get_servername(), prefs_get_server_info()); + + // read text from bnmotd_w3.txt + char const * filename; + char * buff; + std::FILE * fp; + + std::ifstream in(filename = prefs_get_motdw3file()); + if (in) { + std::string contents((std::istreambuf_iterator<char>(in)), std::istreambuf_iterator<char>()); + strcpy(serverinfo, contents.substr(0,511).c_str()); + } else + eventlog(eventlog_level_error, __FUNCTION__, "Could not open file motdw3 \"%s\" (std::fopen: %s)", filename, std::strerror(errno)); + packet_append_string(rpacket, serverinfo); diff --git a/src/bnetd/icons.cpp b/src/bnetd/icons.cpp new file mode 100644 index 0000000..3d79d18 --- /dev/null +++ b/src/bnetd/icons.cpp @@ -0,0 +1,513 @@ +/* +* 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 +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 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. +*/ +#include "common/setup_before.h" + +#include <cstdio> +#include <cerrno> +#include <cstring> +#include <ctime> +#include <cstdlib> + +#include "compat/strcasecmp.h" +#include "compat/snprintf.h" + +#include "common/token.h" + +#include "common/list.h" +#include "common/eventlog.h" +#include "common/xalloc.h" +#include "common/xstring.h" +#include "common/util.h" +#include "common/tag.h" + +#include "account.h" +#include "connection.h" +#include "icons.h" +#include "account_wrap.h" +#include "common/setup_after.h" + +namespace pvpgn +{ + + namespace bnetd + { + + static t_list * icon_head = NULL; + // TODO: wrapper to get value + static int enable_custom_icons = 0; + + + static int skip_comments(char *buff); + static t_icon_var_info * _read_option(char *str, unsigned lineno); + static t_icon_info * _find_custom_icon(int rating, char * clienttag); + static char * _find_attr_key(char * clienttag); + + + extern int prefs_get_custom_icons() + { + return enable_custom_icons; + } + + + /* Format stats text, with attributes from a storage, and output text to a user */ + extern const char * get_custom_stats_text(t_account * account, t_clienttag clienttag) + { + const char *value; + const char *text; + char clienttag_str[5], tmp[64]; + t_icon_info * icon; + t_iconset_info * iconset; + t_icon_var_info * var; + t_elem * curr; + t_elem * curr_var; + + tag_uint_to_str(clienttag_str, clienttag); + + text = NULL; + + if (icon_head) { + LIST_TRAVERSE(icon_head, curr) + { + if (!(iconset = (t_iconset_info*)elem_get_data(curr))) + { + eventlog(eventlog_level_error, __FUNCTION__, "icon list contains NULL item"); + continue; + } + + // find a needed tag + if (std::strcmp(iconset->clienttag, clienttag_str) != 0) + continue; + + if (!iconset->stats) + return NULL; + + text = xstrdup(iconset->stats); + + LIST_TRAVERSE(iconset->vars, curr_var) + { + if (!(var = (t_icon_var_info*)elem_get_data(curr_var))) + { + eventlog(eventlog_level_error, __FUNCTION__, "vars list contains NULL item"); + continue; + } + + // replace NULL attributes to "0" + if (!(value = account_get_strattr(account, var->value))) + value = "0"; + + // replace in a text + snprintf(tmp, sizeof(tmp), "{{%s}}", var->key); + text = str_replace((char*)text, tmp, (char*)value); + + // also replace {var}->rank + if (icon = _find_custom_icon(atoi(value), clienttag_str)) + { + snprintf(tmp, sizeof(tmp), "{{%s->rank}}", var->key); + text = str_replace((char*)text, tmp, icon->rank); + } + } + } + } + + return text; + } + + + /* find icon code by rating for the clienttag */ + extern t_icon_info * get_custom_icon(t_account * account, t_clienttag clienttag) + { + char * attr_key; + int rating; + char clienttag_str[5]; + t_icon_info * icon; + t_icon_info * uicon; + const char * usericon; + + tag_uint_to_str(clienttag_str, clienttag); + + // get attribute field name from a storage + if (!(attr_key = _find_attr_key((char*)clienttag_str))) + { + eventlog(eventlog_level_trace, __FUNCTION__, "could not find attr_key in iconset for tag %s", clienttag_str); + return NULL; + } + + rating = account_get_numattr(account, attr_key); + + icon = _find_custom_icon(rating, clienttag_str); + return icon; + } + + + extern int customicons_unload(void) + { + t_elem * curr; + t_iconset_info * iconset; + + if (icon_head) { + LIST_TRAVERSE(icon_head, curr) + { + if (!(iconset = (t_iconset_info*)elem_get_data(curr))) { + eventlog(eventlog_level_error, __FUNCTION__, "icon list contains NULL item"); + continue; + } + + if (list_remove_elem(icon_head, &curr) < 0) + eventlog(eventlog_level_error, __FUNCTION__, "could not remove item from list"); + + xfree(iconset); + } + + if (list_destroy(icon_head) < 0) + return -1; + icon_head = NULL; + } + return 0; + } + + + /*****/ + extern int customicons_load(char const * filename) + { + std::FILE * fp; + unsigned int line, pos, counter = 0; + bool end_of_iconset = false; + char *buff, *value; + char *rating, *rank, *icon; + t_icon_var_info * option; + + icon_head = list_create(); + + + if (!filename) { + eventlog(eventlog_level_error, __FUNCTION__, "got NULL filename"); + return -1; + } + + if (!(fp = std::fopen(filename, "r"))) { + eventlog(eventlog_level_error, __FUNCTION__, "could not open file \"%s\" for reading (std::fopen: %s)", filename, std::strerror(errno)); + return -1; + } + + /* 1) parse root config options */ + for (line = 1; (buff = file_get_line(fp)); line++) + { + if (skip_comments(buff) > 0) + { + continue; + } + // read root options + if (option = _read_option(buff, line)) + { + if (std::strcmp(option->key, "custom_icons") == 0) + if (std::strcmp(option->value, "true") == 0) + enable_custom_icons = 1; + else + enable_custom_icons = 0; + } + + /* 2) parse clienttags */ + if (std::strcmp(buff, "[W3XP]") == 0 || + std::strcmp(buff, "[WAR3]") == 0 || + std::strcmp(buff, "[STAR]") == 0 || + std::strcmp(buff, "[SEXP]") == 0 || + std::strcmp(buff, "[JSTR]") == 0 || + std::strcmp(buff, "[SSHR]") == 0 || + std::strcmp(buff, "[W2BN]") == 0 || + std::strcmp(buff, "[DRTL]") == 0 || + std::strcmp(buff, "[DSHR]") == 0) + { + if (skip_comments(buff) > 0) + { + continue; + } + value = std::strtok(buff, " []"); + + // new iconset for a clienttag + t_iconset_info * icon_set = (t_iconset_info*)xmalloc(sizeof(t_iconset_info)); + icon_set->clienttag = xstrdup(value); + icon_set->attr_key = NULL; + icon_set->icon_info = list_create(); + icon_set->vars = list_create(); + icon_set->stats = NULL; + + + /* 3) parse inner options under a clienttag */ + for (; (buff = file_get_line(fp)); line++) + { + if (end_of_iconset) + { + end_of_iconset = false; + break; + } + if (skip_comments(buff) > 0) + { + continue; + } + // fill variables list + if (option = _read_option(buff, line)) + { + // set attr_key with a first variable + if (!icon_set->attr_key) + icon_set->attr_key = xstrdup(option->value); + + // add to variables + list_append_data(icon_set->vars, option); + } + + /* 3) parse icons section */ + if (std::strcmp(buff, "[icons]") == 0) + { + counter = 0; + for (; (buff = file_get_line(fp)); line++) + { + if (skip_comments(buff) > 0) + { + continue; + } + // end if icons + if (std::strcmp(buff, "[/icons]") == 0) { + break; + } + + pos = 0; + if (!(rating = next_token(buff, &pos))) + { + eventlog(eventlog_level_error, __FUNCTION__, "missing value in line %u in file \"%s\"", line, filename); + continue; + } + if (!(rank = next_token(buff, &pos))) + { + eventlog(eventlog_level_error, __FUNCTION__, "missing rank in line %u in file \"%s\"", line, filename); + continue; + } + if (!(icon = next_token(buff, &pos))) + { + eventlog(eventlog_level_error, __FUNCTION__, "missing icon in line %u in file \"%s\"", line, filename); + continue; + } + counter++; + + t_icon_info * icon_info = (t_icon_info*)xmalloc(sizeof(t_icon_info)); + icon_info->rating = atoi(rating); + icon_info->rank = xstrdup(rank); + icon_info->icon_code = xstrdup(strreverse(icon)); // save reversed icon code + list_prepend_data(icon_set->icon_info, icon_info); + } + } + + /* 3) parse stats section */ + if (std::strcmp(buff, "[stats]") == 0) + { + std::string tmp; + for (; (buff = file_get_line(fp)); line++) + { + // end of stats + if (std::strcmp(buff, "[/stats]") == 0) { + // put whole text of stats after read + icon_set->stats = xstrdup(tmp.c_str()); + end_of_iconset = true; + break; + } + + tmp = tmp + buff + "\n"; + } + } + } + + if (!icon_set->attr_key) + { + eventlog(eventlog_level_error, __FUNCTION__, "attr_key is null for iconset %s", icon_set->clienttag); + continue; + } + list_append_data(icon_head, icon_set); + + eventlog(eventlog_level_trace, __FUNCTION__, "loaded %u custom icons for %s", counter, icon_set->clienttag); + } + } + + + return 0; + } + + static int skip_comments(char *buff) + { + char *temp; + int pos; + + for (pos = 0; buff[pos] == '\t' || buff[pos] == ' '; pos++); + if (buff[pos] == '\0' || buff[pos] == '#') { + return 1; + } + if ((temp = std::strrchr(buff, '#'))) { + unsigned int len; + unsigned int endpos; + + *temp = '\0'; + len = std::strlen(buff) + 1; + for (endpos = len - 1; buff[endpos] == '\t' || buff[endpos] == ' '; endpos--); + buff[endpos + 1] = '\0'; + } + return 0; + } + + /* Read an option like "key = value" from a str line, and split in into a pair: key, value */ + static t_icon_var_info * _read_option(char *str, unsigned lineno) + { + char *cp, prev, *directive; + t_icon_var_info * icon_var = (t_icon_var_info*)xmalloc(sizeof(t_icon_var_info)); + + directive = str; + str = str_skip_word(str + 1); + if (*str) *(str++) = '\0'; + + str = str_skip_space(str); + if (*str != '=') { + return NULL; + } + + str = str_skip_space(str + 1); + if (!*str) { + eventlog(eventlog_level_error, __FUNCTION__, "missing value at line %u", lineno); + return NULL; + } + + if (*str == '"') { + for (cp = ++str, prev = '\0'; *cp; cp++) { + switch (*cp) { + case '"': + if (prev != '\\') break; + prev = '"'; + continue; + case '\\': + if (prev == '\\') prev = '\0'; + else prev = '\\'; + continue; + default: + prev = *cp; + continue; + } + break; + } + + if (*cp != '"') { + eventlog(eventlog_level_error, __FUNCTION__, "missing end quota at line %u", lineno); + return NULL; + } + + *cp = '\0'; + cp = str_skip_space(cp + 1); + if (*cp) { + eventlog(eventlog_level_error, __FUNCTION__, "extra characters in value after ending quote at line %u", lineno); + return NULL; + } + } + else { + cp = str_skip_word(str); + if (*cp) { + *cp = '\0'; + cp = str_skip_space(cp + 1); + if (*cp) { + eventlog(eventlog_level_error, __FUNCTION__, "extra characters after the value at line %u", lineno); + return NULL; + } + } + } + + //if (!find && std::strcmp(find, directive) == 0) + // return str_skip_space(str); + //else + // return NULL; + + icon_var->key = xstrdup(directive); + icon_var->value = xstrdup(str_skip_space(str)); + + return icon_var; + } + + + + + /* Get custom icon by rating for clienttag */ + static t_icon_info * _find_custom_icon(int rating, char * clienttag) + { + t_elem * curr; + t_elem * curr_icon; + t_iconset_info * iconset; + t_icon_info * icon; + + if (icon_head) { + LIST_TRAVERSE(icon_head, curr) + { + if (!(iconset = (t_iconset_info*)elem_get_data(curr))) + { + eventlog(eventlog_level_error, __FUNCTION__, "icon list contains NULL item"); + continue; + } + + // find a needed tag + if (std::strcmp(iconset->clienttag, clienttag) != 0) + continue; + + // iterate all icons for the tag + LIST_TRAVERSE(iconset->icon_info, curr_icon) + { + if (!(icon = (t_icon_info*)elem_get_data(curr_icon))) + { + eventlog(eventlog_level_error, __FUNCTION__, "icon list contains NULL item"); + continue; + } + + if (rating >= icon->rating) + return icon; + } + // if nothing found then return last icon + return icon; + } + } + return NULL; + } + + + /* Get attr_key for clienttag */ + static char * _find_attr_key(char * clienttag) + { + t_elem * curr; + t_elem * curr_icon; + t_iconset_info * iconset; + + if (icon_head) { + LIST_TRAVERSE(icon_head, curr) + { + if (!(iconset = (t_iconset_info*)elem_get_data(curr))) + { + eventlog(eventlog_level_error, __FUNCTION__, "icon list contains NULL item"); + continue; + } + + // find a needed tag + if (std::strcmp(iconset->clienttag, clienttag) == 0) + return iconset->attr_key; + } + } + return NULL; + } + + + + + } +} diff --git a/src/bnetd/icons.h b/src/bnetd/icons.h new file mode 100644 index 0000000..2812b03 --- /dev/null +++ b/src/bnetd/icons.h @@ -0,0 +1,80 @@ +/* +* 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 +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 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. +*/ +#ifndef INCLUDED_ICONS_TYPES +#define INCLUDED_ICONS_TYPES + +namespace pvpgn +{ + + namespace bnetd + { + + typedef struct + { + unsigned int rating; // rating or something else + char * rank; // any string value + char * icon_code; // icon code + } t_icon_info; + + typedef struct + { + char * clienttag; + char * attr_key; + t_list * icon_info; // list of t_icon_info + + t_list * vars; // list of t_icon_var_info + const char * stats; + } t_iconset_info; + + typedef struct + { + char * key; + char * value; + } t_icon_var_info; + } + +} + +#endif + +#ifndef JUST_NEED_TYPES +#ifndef INCLUDED_ICONS_PROTOS +#define INCLUDED_ICONS_PROTOS + +#define JUST_NEED_TYPES +# include "account.h" +#undef JUST_NEED_TYPES + +namespace pvpgn +{ + + namespace bnetd + { + extern int prefs_get_custom_icons(); + extern t_icon_info * get_custom_icon(t_account * account, t_clienttag clienttag); + extern const char * get_custom_stats_text(t_account * account, t_clienttag clienttag); + + + extern int customicons_load(char const * filename); + extern int customicons_unload(void); + + } + +} + +/*****/ +#endif +#endif diff --git a/src/bnetd/main.cpp b/src/bnetd/main.cpp index c48c430..ab475ee 100644 --- a/src/bnetd/main.cpp +++ b/src/bnetd/main.cpp @@ -81,6 +81,7 @@ #include "command_groups.h" #include "alias_command.h" #include "tournament.h" +#include "icons.h" #include "anongame_infos.h" #include "anongame_wol.h" #include "clan.h" @@ -294,6 +295,7 @@ char * write_to_pidfile(void) return pidfile; } +/* Initialize config files */ int pre_server_startup(void) { pvpgn_greeting(); @@ -364,6 +366,7 @@ int pre_server_startup(void) if (trans_load(prefs_get_transfile(), TRANS_BNETD) < 0) eventlog(eventlog_level_error, __FUNCTION__, "could not load trans list"); tournament_init(prefs_get_tournament_file()); + customicons_load(prefs_get_customicons_file()); anongame_infos_load(prefs_get_anongame_infos_file()); anongame_wol_matchlist_create(); clanlist_load(); diff --git a/src/bnetd/prefs.cpp b/src/bnetd/prefs.cpp index ba436a1..1ce760c 100644 --- a/src/bnetd/prefs.cpp +++ b/src/bnetd/prefs.cpp @@ -43,6 +43,7 @@ namespace pvpgn char const * logfile; char const * loglevels; char const * motdfile; + char const * motdw3file; char const * newsfile; char const * channelfile; char const * pidfile; @@ -142,6 +143,7 @@ namespace pvpgn unsigned int account_force_username; char const * command_groups_file; char const * tournament_file; + char const * customicons_file; char const * aliasfile; char const * anongame_infos_file; char const * magicfile; @@ -198,6 +200,10 @@ namespace pvpgn static const char *conf_get_motdfile(void); static int conf_setdef_motdfile(void); + static int conf_set_motdw3file(const char *valstr); + static const char *conf_get_motdw3file(void); + static int conf_setdef_motdw3file(void); + static int conf_set_newsfile(const char *valstr); static const char *conf_get_newsfile(void); static int conf_setdef_newsfile(void); @@ -586,6 +592,10 @@ namespace pvpgn static const char *conf_get_tournament_file(void); static int conf_setdef_tournament_file(void); + static int conf_set_customicons_file(const char *valstr); + static const char *conf_get_customicons_file(void); + static int conf_setdef_customicons_file(void); + static int conf_set_aliasfile(const char *valstr); static const char *conf_get_aliasfile(void); static int conf_setdef_aliasfile(void); @@ -712,6 +722,7 @@ namespace pvpgn { "logfile", conf_set_logfile, conf_get_logfile, conf_setdef_logfile }, { "loglevels", conf_set_loglevels, conf_get_loglevels, conf_setdef_loglevels }, { "motdfile", conf_set_motdfile, conf_get_motdfile, conf_setdef_motdfile }, + { "motdw3file", conf_set_motdw3file, conf_get_motdw3file, conf_setdef_motdw3file }, { "newsfile", conf_set_newsfile, conf_get_newsfile, conf_setdef_newsfile }, { "channelfile", conf_set_channelfile, conf_get_channelfile, conf_setdef_channelfile }, { "pidfile", conf_set_pidfile, conf_get_pidfile, conf_setdef_pidfile }, @@ -809,6 +820,7 @@ namespace pvpgn { "account_force_username", conf_set_account_force_username, conf_get_account_force_username, conf_setdef_account_force_username }, { "command_groups_file", conf_set_command_groups_file, conf_get_command_groups_file, conf_setdef_command_groups_file }, { "tournament_file", conf_set_tournament_file, conf_get_tournament_file, conf_setdef_tournament_file }, + { "customicons_file", conf_set_customicons_file, conf_get_customicons_file, conf_setdef_customicons_file }, { "aliasfile", conf_set_aliasfile, conf_get_aliasfile, conf_setdef_aliasfile }, { "anongame_infos_file", conf_set_anongame_infos_file, conf_get_anongame_infos_file, conf_setdef_anongame_infos_file }, @@ -982,6 +994,27 @@ namespace pvpgn } + extern char const * prefs_get_motdw3file(void) + { + return prefs_runtime_config.motdw3file; + } + + static int conf_set_motdw3file(const char *valstr) + { + return conf_set_str(&prefs_runtime_config.motdw3file, valstr, NULL); + } + + static int conf_setdef_motdw3file(void) + { + return conf_set_str(&prefs_runtime_config.motdw3file, NULL, BNETD_MOTDW3_FILE); + } + + static const char* conf_get_motdw3file(void) + { + return prefs_runtime_config.motdw3file; + } + + extern char const * prefs_get_newsfile(void) { return prefs_runtime_config.newsfile; @@ -3031,6 +3064,27 @@ namespace pvpgn } + extern char const * prefs_get_customicons_file(void) + { + return prefs_runtime_config.customicons_file; + } + + static int conf_set_customicons_file(const char *valstr) + { + return conf_set_str(&prefs_runtime_config.customicons_file, valstr, NULL); + } + + static int conf_setdef_customicons_file(void) + { + return conf_set_str(&prefs_runtime_config.customicons_file, NULL, BNETD_CUSTOMICONS_FILE); + } + + static const char* conf_get_customicons_file(void) + { + return prefs_runtime_config.customicons_file; + } + + extern char const * prefs_get_aliasfile(void) { return prefs_runtime_config.aliasfile; diff --git a/src/bnetd/prefs.h b/src/bnetd/prefs.h index 62897f6..f5ea3f2 100644 --- a/src/bnetd/prefs.h +++ b/src/bnetd/prefs.h @@ -40,6 +40,7 @@ namespace pvpgn extern char const * prefs_get_logfile(void); extern char const * prefs_get_loglevels(void); extern char const * prefs_get_motdfile(void); + extern char const * prefs_get_motdw3file(void); extern char const * prefs_get_newsfile(void); extern char const * prefs_get_adfile(void); extern char const * prefs_get_topicfile(void); @@ -156,6 +157,7 @@ namespace pvpgn extern char const * prefs_get_command_groups_file(void); extern char const * prefs_get_tournament_file(void); + extern char const * prefs_get_customicons_file(void); extern char const * prefs_get_aliasfile(void); extern char const * prefs_get_anongame_infos_file(void); diff --git a/src/bnetd/server.cpp b/src/bnetd/server.cpp index f97feb0..4d10e0e 100644 --- a/src/bnetd/server.cpp +++ b/src/bnetd/server.cpp @@ -83,6 +83,7 @@ #include "command_groups.h" #include "alias_command.h" #include "tournament.h" +#include "icons.h" #include "anongame_infos.h" #include "topic.h" #include "common/setup_after.h" @@ -1409,6 +1410,9 @@ namespace pvpgn tournament_reload(prefs_get_tournament_file()); + customicons_unload(); + customicons_load(prefs_get_customicons_file()); + anongame_infos_unload(); anongame_infos_load(prefs_get_anongame_infos_file()); diff --git a/src/client/bnchat.cpp b/src/client/bnchat.cpp index e134f6e..2eb66bf 100644 --- a/src/client/bnchat.cpp +++ b/src/client/bnchat.cpp @@ -132,6 +132,7 @@ namespace char curr_gamepass[MAX_GAMEPASS_LEN]; int count, clantag; char const * inviter; + int ignoreversion; } t_user_info; @@ -368,6 +369,7 @@ namespace " -o NAME, --owner=NAME report CD owner as NAME\n" " -k KEY, --cdkey=KEY report CD key as KEY\n" " -l LANG --lang=LANG report language as LANG (default \"enUS\")\n" + " -i, --ignore-version ignore version request (do not send game version, CD owner/key)\n" " -h, --help, --usage show this information and exit\n" " -v, --version print version number and exit\n"); std::exit(EXIT_FAILURE); @@ -382,6 +384,7 @@ namespace char const * * cdowner, char const * * cdkey, char const * * gamelang, + int * ignoreversion, int * useansi) { int a; @@ -636,6 +639,10 @@ namespace std::fprintf(stderr, "%s: option \"%s\" requires an argument\n", argv[0], argv[a]); usage(argv[0]); } + else if (std::strcmp(argv[a], "-i") == 0 || std::strcmp(argv[a], "--ignore-version") == 0) + { + *ignoreversion = 1; + } else { std::fprintf(stderr, "%s: unknown option \"%s\"\n", argv[0], argv[a]); @@ -721,9 +728,10 @@ extern int main(int argc, char * argv[]) /* default values */ user.archtag = ARCHTAG_WINX86; user.gamelang = CLIENT_COUNTRYINFO_109_GAMELANG; + user.ignoreversion = 0; read_commandline(argc, argv, &servname, &servport, &user.clienttag, &user.archtag, &changepass, - &newacct, &user.channel, &user.cdowner, &user.cdkey, &user.gamelang, &client.useansi); + &newacct, &user.channel, &user.cdowner, &user.cdkey, &user.gamelang, &user.ignoreversion, &client.useansi); client.fd_stdin = fileno(stdin); if (tcgetattr(client.fd_stdin, &client.in_attr_old) >= 0) @@ -771,7 +779,7 @@ extern int main(int argc, char * argv[]) } if ((client.sd = client_connect(argv[0], - servname, servport, user.cdowner, user.cdkey, user.clienttag, + servname, servport, user.cdowner, user.cdkey, user.clienttag, user.ignoreversion, &client.saddr, &client.sessionkey, &client.sessionnum, user.archtag, user.gamelang)) < 0) { std::fprintf(stderr, "%s: fatal error during handshake\n", argv[0]); diff --git a/src/client/bnstat.cpp b/src/client/bnstat.cpp index 7f0ce3d..dcf90d9 100644 --- a/src/client/bnstat.cpp +++ b/src/client/bnstat.cpp @@ -97,6 +97,7 @@ namespace std::fprintf(stderr, " -o NAME, --owner=NAME report CD owner as NAME\n" " -k KEY, --cdkey=KEY report CD key as KEY\n" + " -i, --ignore-version ignore version request (do not send game version, CD owner/key)\n" " -p PLR, --player=PLR print stats for player PLR\n" " --bnetd also print BNETD-specific stats\n" " --fsgs also print FSGS-specific stats\n" @@ -134,6 +135,7 @@ extern int main(int argc, char * argv[]) int use_fsgs = 0; unsigned int screen_width, screen_height; int munged = 0; + int ignoreversion = 0; if (argc < 1 || !argv || !argv[0]) { @@ -332,6 +334,8 @@ extern int main(int argc, char * argv[]) else if (std::strcmp(argv[a], "-h") == 0 || std::strcmp(argv[a], "--help") == 0 || std::strcmp(argv[a], "--usage") == 0) usage(argv[0]); + else if (std::strcmp(argv[a], "-i") == 0 || std::strcmp(argv[a], "--ignore-version") == 0) + ignoreversion = 1; else if (std::strcmp(argv[a], "-v") == 0 || std::strcmp(argv[a], "--version") == 0) { std::printf("version "PVPGN_VERSION"\n"); @@ -388,7 +392,7 @@ extern int main(int argc, char * argv[]) } } - if ((sd = client_connect(argv[0], servname, servport, cdowner, cdkey, clienttag, &saddr, &sessionkey, &sessionnum, ARCHTAG_WINX86, CLIENT_COUNTRYINFO_109_GAMELANG)) < 0) + if ((sd = client_connect(argv[0], servname, servport, cdowner, cdkey, clienttag, ignoreversion, &saddr, &sessionkey, &sessionnum, ARCHTAG_WINX86, CLIENT_COUNTRYINFO_109_GAMELANG)) < 0) { std::fprintf(stderr, "%s: fatal error during handshake\n", argv[0]); if (changed_in) diff --git a/src/client/client_connect.cpp b/src/client/client_connect.cpp index 3317865..1c2b9cd 100644 --- a/src/client/client_connect.cpp +++ b/src/client/client_connect.cpp @@ -142,6 +142,9 @@ namespace { *exeinfo = ""; *checksum = 0; + if (std::strcmp(clienttag, CLIENTTAG_BNCHATBOT) == 0) + return 0; + std::fprintf(stderr, "%s: unsupported clienttag \"%s\"\n", progname, clienttag); // aaron: dunno what we should return in case of this.. but returning nothing was definetly wrong return -1; @@ -155,7 +158,7 @@ namespace pvpgn namespace client { - extern int client_connect(char const * progname, char const * servname, unsigned short servport, char const * cdowner, char const * cdkey, char const * clienttag, struct sockaddr_in * saddr, unsigned int * sessionkey, unsigned int * sessionnum, char const * archtag, char const * gamelang) + extern int client_connect(char const * progname, char const * servname, unsigned short servport, char const * cdowner, char const * cdkey, char const * clienttag, int ignoreversion, struct sockaddr_in * saddr, unsigned int * sessionkey, unsigned int * sessionnum, char const * archtag, char const * gamelang) { struct hostent * host; char const * username; @@ -329,45 +332,49 @@ namespace pvpgn *sessionnum = bn_int_get(rpacket->u.server_authreq_109.sessionnum); /* FIXME: also get filename and equation */ - if (!(packet = packet_create(packet_class_bnet))) + if (!ignoreversion) { - std::fprintf(stderr, "%s: could not create packet\n", progname); - goto error_rpacket; - } - packet_set_size(packet, sizeof(t_client_authreq_109)); - packet_set_type(packet, CLIENT_AUTHREQ_109); - bn_int_set(&packet->u.client_authreq_109.ticks, std::time(NULL)); - { - t_cdkey_info cdkey_info; + if (!(packet = packet_create(packet_class_bnet))) + { + std::fprintf(stderr, "%s: could not create packet\n", progname); + goto error_rpacket; + } + packet_set_size(packet, sizeof(t_client_authreq_109)); + packet_set_type(packet, CLIENT_AUTHREQ_109); + bn_int_set(&packet->u.client_authreq_109.ticks, std::time(NULL)); - bn_int_set(&packet->u.client_authreq_109.gameversion, gameversion); + { + t_cdkey_info cdkey_info; - bn_int_set(&packet->u.client_authreq_109.cdkey_number, 1); /* only one */ - std::memset(&cdkey_info, '0', sizeof(cdkey_info)); - /* FIXME: put the input cdkey here */ - packet_append_data(packet, &cdkey_info, sizeof(cdkey_info)); - packet_append_string(packet, exeinfo); - packet_append_string(packet, cdowner); - } - bn_int_set(&packet->u.client_authreq_109.spawn, 0x0000); - bn_int_set(&packet->u.client_authreq_109.checksum, checksum); - client_blocksend_packet(sd, packet); - packet_del_ref(packet); + bn_int_set(&packet->u.client_authreq_109.gameversion, gameversion); - /* now wait for reply */ - do - if (client_blockrecv_packet(sd, rpacket) < 0) - { - std::fprintf(stderr, "%s: server closed connection\n", progname); - goto error_rpacket; - } - while (packet_get_type(rpacket) != SERVER_AUTHREPLY_109); - //FIXME: check if AUTHREPLY_109 is success or fail - if (bn_int_get(rpacket->u.server_authreply_109.message) != SERVER_AUTHREPLY_109_MESSAGE_OK) - { - std::fprintf(stderr, "AUTHREPLY_109 failed - closing connection\n"); - goto error_rpacket; + bn_int_set(&packet->u.client_authreq_109.cdkey_number, 1); /* only one */ + std::memset(&cdkey_info, '0', sizeof(cdkey_info)); + /* FIXME: put the input cdkey here */ + packet_append_data(packet, &cdkey_info, sizeof(cdkey_info)); + packet_append_string(packet, exeinfo); + packet_append_string(packet, cdowner); + } + bn_int_set(&packet->u.client_authreq_109.spawn, 0x0000); + bn_int_set(&packet->u.client_authreq_109.checksum, checksum); + client_blocksend_packet(sd, packet); + packet_del_ref(packet); + + /* now wait for reply */ + do + if (client_blockrecv_packet(sd, rpacket) < 0) + { + std::fprintf(stderr, "%s: server closed connection\n", progname); + goto error_rpacket; + } + while (packet_get_type(rpacket) != SERVER_AUTHREPLY_109); + //FIXME: check if AUTHREPLY_109 is success or fail + if (bn_int_get(rpacket->u.server_authreply_109.message) != SERVER_AUTHREPLY_109_MESSAGE_OK) + { + std::fprintf(stderr, "AUTHREPLY_109 failed - closing connection\n"); + goto error_rpacket; + } } } else diff --git a/src/client/client_connect.h b/src/client/client_connect.h index 514a00c..a2133d5 100644 --- a/src/client/client_connect.h +++ b/src/client/client_connect.h @@ -83,10 +83,9 @@ namespace pvpgn namespace client { - extern int client_connect(char const * progname, char const * servname, unsigned short servport, char const * cdowner, char const * cdkey, char const * clienttag, struct sockaddr_in * saddr, unsigned int * sessionkey, unsigned int * sessionnum, char const * archtag, char const * gamelang); + extern int client_connect(char const * progname, char const * servname, unsigned short servport, char const * cdowner, char const * cdkey, char const * clienttag, int ignoreversion, struct sockaddr_in * saddr, unsigned int * sessionkey, unsigned int * sessionnum, char const * archtag, char const * gamelang); } - } #endif #endif diff --git a/src/common/setup_before.h b/src/common/setup_before.h index 793526a..639a14c 100644 --- a/src/common/setup_before.h +++ b/src/common/setup_before.h @@ -130,6 +130,7 @@ const char * const BNETD_STORAGE_PATH = ""; const char * const BNETD_REPORT_DIR = "reports"; const char * const BNETD_LOG_FILE = "logs/bnetd.log"; const char * const BNETD_MOTD_FILE = "conf/bnmotd.txt"; +const char * const BNETD_MOTDW3_FILE = "conf/bnmotd_w3.txt"; const char * const BNETD_NEWS_DIR = "news"; const char * const BNETD_AD_FILE = "conf/ad.conf"; const char * const BNETD_CHANNEL_FILE = "conf/channel.conf"; @@ -152,6 +153,7 @@ const char * const BNETD_SUPPORT_FILE = "conf/supportfile.conf"; const char * const BNETD_COMMAND_GROUPS_FILE = "conf/command_groups.conf"; const char * const BNETD_TOURNAMENT_FILE = "conf/tournament.conf"; +const char * const BNETD_CUSTOMICONS_FILE = "conf/icons.conf"; const char * const BNETD_ALIASFILE = "conf/bnalias.conf"; /* time limit for new member as newer(whom cannot be promoted) in clan, (hrs) */ const unsigned CLAN_NEWER_TIME = 168; diff --git a/src/common/version.h b/src/common/version.h index 2fecb14..9d0fd5a 100644 --- a/src/common/version.h +++ b/src/common/version.h @@ -14,7 +14,7 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #ifndef PVPGN_VERSION -#define PVPGN_VERSION "1.99.0-SVN" +#define PVPGN_VERSION "1.99.0-GIT" #endif #ifndef PVPGN_SOFTWARE #define PVPGN_SOFTWARE "PvPGN" diff --git a/src/common/xstring.cpp b/src/common/xstring.cpp index 98ad6be..aac40fc 100644 --- a/src/common/xstring.cpp +++ b/src/common/xstring.cpp @@ -21,6 +21,7 @@ #include <cstdio> #include <cctype> #include <cstring> +#include <string> #include "compat/strdup.h" #include "common/xalloc.h" @@ -267,4 +268,51 @@ namespace pvpgn return result; } + + // You must free the result if result is non-NULL. + extern const char *str_replace(char *orig, char *rep, char *with) + { + char *result; // the return string + char *ins; // the next insert point + char *tmp; // varies + int len_rep; // length of rep + int len_with; // length of with + int len_front; // distance between rep and end of last rep + int count; // number of replacements + + if (!orig) + return NULL; + if (!rep) + rep = ""; + len_rep = strlen(rep); + if (!with) + with = ""; + len_with = strlen(with); + + ins = orig; + for (count = 0; tmp = strstr(ins, rep); ++count) { + ins = tmp + len_rep; + } + + // first time through the loop, all the variable are set correctly + // from here on, + // tmp points to the end of the result string + // ins points to the next occurrence of rep in orig + // orig points to the remainder of orig after "end of rep" + tmp = result = (char*)malloc(strlen(orig) + (len_with - len_rep) * count + 1); + + if (!result) + return NULL; + + while (count--) { + ins = strstr(orig, rep); + len_front = ins - orig; + tmp = strncpy(tmp, orig, len_front) + len_front; + tmp = strcpy(tmp, with) + len_with; + orig += len_front + len_rep; // move to next "end of rep" + } + strcpy(tmp, orig); + return result; + } + } diff --git a/src/common/xstring.h b/src/common/xstring.h index b5346f1..d3d2be4 100644 --- a/src/common/xstring.h +++ b/src/common/xstring.h @@ -28,6 +28,8 @@ namespace pvpgn extern char * * strtoargv(char const * str, unsigned int * count); extern char * arraytostr(char * * array, char const * delim, int count); extern char * str_strip_affix(char * str, char const * affix); + extern const char *str_replace(char *orig, char *rep, char *with); + }